generator/src/main/java/com/ruoyi/system/controller/TOrderBillController.java
New file @@ -0,0 +1,21 @@ package com.ruoyi.system.controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * <p> * 订单表与账单的关联表 前端控制器 * </p> * * @author xiaochen * @since 2025-02-07 */ @RestController @RequestMapping("/t-order-bill") public class TOrderBillController { } generator/src/main/java/com/ruoyi/system/controller/TPayOrderController.java
New file @@ -0,0 +1,21 @@ package com.ruoyi.system.controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * <p> * 支付订单表 前端控制器 * </p> * * @author xiaochen * @since 2025-02-07 */ @RestController @RequestMapping("/t-pay-order") public class TPayOrderController { } generator/src/main/java/com/ruoyi/system/mapper/TOrderBillMapper.java
New file @@ -0,0 +1,16 @@ package com.ruoyi.system.mapper; import com.ruoyi.system.model.TOrderBill; import com.baomidou.mybatisplus.core.mapper.BaseMapper; /** * <p> * 订单表与账单的关联表 Mapper 接口 * </p> * * @author xiaochen * @since 2025-02-07 */ public interface TOrderBillMapper extends BaseMapper<TOrderBill> { } generator/src/main/java/com/ruoyi/system/mapper/TPayOrderMapper.java
New file @@ -0,0 +1,16 @@ package com.ruoyi.system.mapper; import com.ruoyi.system.model.TPayOrder; import com.baomidou.mybatisplus.core.mapper.BaseMapper; /** * <p> * 支付订单表 Mapper 接口 * </p> * * @author xiaochen * @since 2025-02-07 */ public interface TPayOrderMapper extends BaseMapper<TPayOrder> { } generator/src/main/java/com/ruoyi/system/model/TOrderBill.java
New file @@ -0,0 +1,47 @@ package com.ruoyi.system.model; import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableId; import java.time.LocalDateTime; import com.baomidou.mybatisplus.annotation.TableField; import java.io.Serializable; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import lombok.EqualsAndHashCode; /** * <p> * 订单表与账单的关联表 * </p> * * @author xiaochen * @since 2025-02-07 */ @Data @EqualsAndHashCode(callSuper = false) @TableName("t_order_bill") @ApiModel(value="TOrderBill对象", description="订单表与账单的关联表") public class TOrderBill implements Serializable { private static final long serialVersionUID = 1L; @TableId("id") private String id; @ApiModelProperty(value = "订单号") @TableField("order_no") private String orderNo; @ApiModelProperty(value = "账单编号") @TableField("bill_id") private String billId; @TableField("create_time") private LocalDateTime createTime; @TableField("update_time") private LocalDateTime updateTime; } generator/src/main/java/com/ruoyi/system/model/TPayOrder.java
New file @@ -0,0 +1,86 @@ package com.ruoyi.system.model; import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableId; import java.time.LocalDateTime; import com.baomidou.mybatisplus.annotation.TableField; import java.io.Serializable; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import lombok.EqualsAndHashCode; /** * <p> * 支付订单表 * </p> * * @author xiaochen * @since 2025-02-07 */ @Data @EqualsAndHashCode(callSuper = false) @TableName("t_pay_order") @ApiModel(value="TPayOrder对象", description="支付订单表") public class TPayOrder implements Serializable { private static final long serialVersionUID = 1L; @ApiModelProperty(value = "订单号") @TableId("id") private String id; @ApiModelProperty(value = "发起支付的用户ID") @TableField("user_id") private String userId; @ApiModelProperty(value = "用户名称") @TableField("user_name") private String userName; @ApiModelProperty(value = "用户微信openid或支付宝userid") @TableField("open_id") private String openId; @ApiModelProperty(value = "用户手机号码") @TableField("phone") private String phone; @ApiModelProperty(value = "订单金额") @TableField("amount") private Long amount; @ApiModelProperty(value = "实付金额") @TableField("act_pay_amount") private Long actPayAmount; @ApiModelProperty(value = "支付时间") @TableField("pay_time") private LocalDateTime payTime; @ApiModelProperty(value = "支付方式") @TableField("pay_type") private String payType; @ApiModelProperty(value = "支付的回调信息") @TableField("pay_info") private String payInfo; @ApiModelProperty(value = "银行的支付流水编号") @TableField("pay_no") private String payNo; @ApiModelProperty(value = "支付的回调时间") @TableField("callback_time") private LocalDateTime callbackTime; @ApiModelProperty(value = "订单创建时间") @TableField("create_time") private LocalDateTime createTime; @ApiModelProperty(value = "订单更新时间") @TableField("update_time") private LocalDateTime updateTime; } generator/src/main/java/com/ruoyi/system/service/TOrderBillService.java
New file @@ -0,0 +1,16 @@ package com.ruoyi.system.service; import com.ruoyi.system.model.TOrderBill; import com.baomidou.mybatisplus.extension.service.IService; /** * <p> * 订单表与账单的关联表 服务类 * </p> * * @author xiaochen * @since 2025-02-07 */ public interface TOrderBillService extends IService<TOrderBill> { } generator/src/main/java/com/ruoyi/system/service/TPayOrderService.java
New file @@ -0,0 +1,16 @@ package com.ruoyi.system.service; import com.ruoyi.system.model.TPayOrder; import com.baomidou.mybatisplus.extension.service.IService; /** * <p> * 支付订单表 服务类 * </p> * * @author xiaochen * @since 2025-02-07 */ public interface TPayOrderService extends IService<TPayOrder> { } generator/src/main/java/com/ruoyi/system/service/impl/TOrderBillServiceImpl.java
New file @@ -0,0 +1,20 @@ package com.ruoyi.system.service.impl; import com.ruoyi.system.model.TOrderBill; import com.ruoyi.system.mapper.TOrderBillMapper; import com.ruoyi.system.service.TOrderBillService; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import org.springframework.stereotype.Service; /** * <p> * 订单表与账单的关联表 服务实现类 * </p> * * @author xiaochen * @since 2025-02-07 */ @Service public class TOrderBillServiceImpl extends ServiceImpl<TOrderBillMapper, TOrderBill> implements TOrderBillService { } generator/src/main/java/com/ruoyi/system/service/impl/TPayOrderServiceImpl.java
New file @@ -0,0 +1,20 @@ package com.ruoyi.system.service.impl; import com.ruoyi.system.model.TPayOrder; import com.ruoyi.system.mapper.TPayOrderMapper; import com.ruoyi.system.service.TPayOrderService; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import org.springframework.stereotype.Service; /** * <p> * 支付订单表 服务实现类 * </p> * * @author xiaochen * @since 2025-02-07 */ @Service public class TPayOrderServiceImpl extends ServiceImpl<TPayOrderMapper, TPayOrder> implements TPayOrderService { } generator/src/main/resources/mapping/TOrderBillMapper.xml
New file @@ -0,0 +1,19 @@ <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.ruoyi.system.mapper.TOrderBillMapper"> <!-- 通用查询映射结果 --> <resultMap id="BaseResultMap" type="com.ruoyi.system.model.TOrderBill"> <id column="id" property="id" /> <result column="order_no" property="orderNo" /> <result column="bill_id" property="billId" /> <result column="create_time" property="createTime" /> <result column="update_time" property="updateTime" /> </resultMap> <!-- 通用查询结果列 --> <sql id="Base_Column_List"> id, order_no, bill_id, create_time, update_time </sql> </mapper> generator/src/main/resources/mapping/TPayOrderMapper.xml
New file @@ -0,0 +1,28 @@ <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.ruoyi.system.mapper.TPayOrderMapper"> <!-- 通用查询映射结果 --> <resultMap id="BaseResultMap" type="com.ruoyi.system.model.TPayOrder"> <id column="id" property="id" /> <result column="user_id" property="userId" /> <result column="user_name" property="userName" /> <result column="open_id" property="openId" /> <result column="phone" property="phone" /> <result column="amount" property="amount" /> <result column="act_pay_amount" property="actPayAmount" /> <result column="pay_time" property="payTime" /> <result column="pay_type" property="payType" /> <result column="pay_info" property="payInfo" /> <result column="pay_no" property="payNo" /> <result column="callback_time" property="callbackTime" /> <result column="create_time" property="createTime" /> <result column="update_time" property="updateTime" /> </resultMap> <!-- 通用查询结果列 --> <sql id="Base_Column_List"> id, user_id, user_name, open_id, phone, amount, act_pay_amount, pay_time, pay_type, pay_info, pay_no, callback_time, create_time, update_time </sql> </mapper> generator/src/test/java/com/xizang/CodeGeneratorTests.java
@@ -5,11 +5,13 @@ import com.baomidou.mybatisplus.generator.InjectionConfig; import com.baomidou.mybatisplus.generator.config.*; import com.baomidou.mybatisplus.generator.config.po.LikeTable; import com.baomidou.mybatisplus.generator.config.po.TableFill; import com.baomidou.mybatisplus.generator.config.po.TableInfo; import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy; import org.junit.Test; import java.util.ArrayList; import java.util.Arrays; import java.util.List; /** @@ -35,7 +37,7 @@ // 全局配置 GlobalConfig gc = new GlobalConfig(); String projectPath = "F:\\workSpace\\xizang\\generator"; String projectPath = "D:\\workspaces\\Project\\company\\changyun\\xizang\\xizang\\generator"; gc.setOutputDir(projectPath + "/src/main/java") .setAuthor("xiaochen") .setMapperName("%sMapper") @@ -144,7 +146,7 @@ // strategy.setTablePrefix(pc.getModuleName() + ""); // strategy.setLikeTable(new LikeTable("room")); //strategy.setLikeTable(new LikeTable("member")); strategy.setLikeTable(new LikeTable("t_"));// 生成表名 strategy.setLikeTable(new LikeTable("order"));// 生成表名 // strategy.setLikeTable(new LikeTable("t_hotel"));// 生成表名 // strategy.setLikeTable(new LikeTable("t_scan_message"));// 生成表名 // strategy.setNotLikeTable(new LikeTable("hotel_info"));// 不生成表名 ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/TBillController.java
@@ -3,6 +3,7 @@ import com.ruoyi.common.basic.PageInfo; import com.ruoyi.common.core.domain.R; import com.ruoyi.system.dto.TBillDto; import com.ruoyi.system.model.TBill; import com.ruoyi.system.query.TBillQuery; import com.ruoyi.system.service.TBillService; @@ -28,8 +29,8 @@ TBillService tBillService; @PostMapping("list") public R<PageInfo<TBill>> list(@RequestBody TBillQuery query){ PageInfo<TBill> pageInfo = tBillService.queryPage(query); public R<PageInfo<TBillDto>> list(@RequestBody TBillQuery query){ PageInfo<TBillDto> pageInfo = tBillService.queryPage(query); return R.ok(pageInfo); } ruoyi-applet/src/main/java/com/ruoyi/web/controller/api/PayController.java
@@ -1,7 +1,15 @@ package com.ruoyi.web.controller.api; import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.core.domain.R; import com.ruoyi.system.dto.MakeOrderDto; import com.ruoyi.system.dto.MakeOrderResp; import com.ruoyi.system.service.TPayOrderService; import io.swagger.annotations.ApiOperation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -11,12 +19,14 @@ @Autowired TPayOrderService tPayOrderService; @ApiOperation(value = "创建支付订单") @PostMapping("makeOrder") public AjaxResult makeOrder(){ return null; public R<MakeOrderResp> makeOrder(@Validated @RequestBody MakeOrderDto dto){ MakeOrderResp resp = tPayOrderService.makeOrder(dto); return R.ok(resp); } ruoyi-common/src/main/java/com/ruoyi/common/constant/AmountConstant.java
New file @@ -0,0 +1,15 @@ package com.ruoyi.common.constant; import java.math.BigDecimal; public class AmountConstant { public static final BigDecimal b100 = new BigDecimal("100"); public static final BigDecimal b1000 = new BigDecimal("1000"); public static final BigDecimal b001 = new BigDecimal("0.01"); } ruoyi-common/src/main/java/com/ruoyi/common/constant/WxConstant.java
@@ -16,4 +16,7 @@ * 高德地图坐标转换 */ public static final String ADDRESS_CONVERT_TO_COORDINATE = "https://restapi.amap.com/v3/geocode/geo?key=KEY&address=ADDRESS"; } ruoyi-common/src/main/java/com/ruoyi/common/utils/OrderNos.java
New file @@ -0,0 +1,164 @@ package com.ruoyi.common.utils; import com.ruoyi.common.utils.ip.IpUtils; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.concurrent.atomic.AtomicLong; public class OrderNos { public static final char PADCHAR = '0'; /** * 长度24位全球唯一标识 */ /** * 统一不重复内部订单号 * * @param systemCode * 4字节系统编码 * @return 24字节不重复编码 */ public static String oid(String systemCode) { StringBuilder sb = new StringBuilder(); sb.append(padding(systemCode, 4)); sb.append(Did.getInstance().getId(20)); return sb.toString(); } public static String oid() { return oid("O001"); } /** * 获取分布式Id * * @return 默认20字符长度的数字不重复编码 */ public static String getDid() { return Did.getInstance().getId(); } public static String getDid(int size) { return Did.getInstance().getId(size); } public static String getDid(String prefix) { return prefix + Did.getInstance().getId(); } private static String padding(String text, int size) { String txt = StringUtils.trimToEmpty(text); if (StringUtils.length(txt) > size) { txt = StringUtils.substring(txt, StringUtils.length(txt) - size); } return StringUtils.leftPad(txt, size, PADCHAR); } /** * ID生成器 * * 20字符长度 yyMMddHHmmss+3位本机IP末三位+5位随机数字 * * @author zhangpu * */ public static class Did { private static final Logger logger = LoggerFactory.getLogger(OrderNos.class); private static final int MIN_LENGTH = 19; private static final int SEQU_MAX = 99999; private static final int SEQU_19_MAX = 9999; private volatile static long BASE = 0; private AtomicLong sequence = new AtomicLong(0); private String nodeFlag; private Object nodeFlagLock = new Object(); private static Did did = new Did(); public static Did getInstance() { return did; } /** * 生产新Id * * @return */ public String getId() { return getId(20); } public String getId(int size) { if (size < MIN_LENGTH) { throw new RuntimeException("did最小长度为" + MIN_LENGTH); } StringBuilder sb = new StringBuilder(); sb.append(DateUtils.dateTimeNow("yyMMddHHmmss")); sb.append(getNodeFlag()); sb.append(getSequ(size-15)); return sb.toString(); } public synchronized String getSequ(int size) { long timeCount = System.currentTimeMillis() / 1000; while (true) { long now = sequence.get(); if (timeCount > now) { // 已经过了本秒,则设置新的值 if (sequence.compareAndSet(now, timeCount)) { break; } } else { if (sequence.compareAndSet(now, now + 1)) { timeCount = now + 1; break; } } } int sn = (int) (timeCount % (size>=5?SEQU_MAX:SEQU_19_MAX)); return StringUtils.leftPad(String.valueOf(sn), size, '0'); } private String getNodeFlag(){ if (this.nodeFlag == null) { synchronized (Did.class){ if (this.nodeFlag==null){ this.nodeFlag = generateNodeFlag(); } } } return this.nodeFlag; } /** * 简单节点编码 * * 逻辑:Ip地址后三位,便于快速知道是哪个节点 * * @return */ private String generateNodeFlag() { String ipPostfix = null; try { String ip = IpUtils.getFirstNoLoopbackIPV4Address(); ipPostfix = StringUtils.substringAfterLast(ip, "."); } catch (Exception e) { logger.warn("生产DID要素本机IP获取失败:" + e.getMessage()); } return StringUtils.leftPad(ipPostfix, 3, "0"); } private Did() { super(); } } } ruoyi-common/src/main/java/com/ruoyi/common/utils/ip/IpUtils.java
@@ -1,16 +1,20 @@ package com.ruoyi.common.utils.ip; import java.net.InetAddress; import java.net.UnknownHostException; import java.net.*; import java.util.ArrayList; import java.util.Collection; import java.util.Enumeration; import javax.servlet.http.HttpServletRequest; import com.ruoyi.common.utils.ServletUtils; import com.ruoyi.common.utils.StringUtils; import lombok.extern.slf4j.Slf4j; /** * 获取IP方法 * * @author ruoyi */ @Slf4j public class IpUtils { public final static String REGX_0_255 = "(25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]\\d|\\d)"; @@ -379,4 +383,72 @@ } return false; } private static final String LOOP_BACK = "127.0.0.1"; private static String firstNoLoopbackIPV4Address = null; private static Collection<InetAddress> allHostIPV4Address = null; /** * 获取ipv4地址,如果有多个网卡的情况,获取第一个非loopback ip地址 * * @return */ public static String getFirstNoLoopbackIPV4Address() { if (firstNoLoopbackIPV4Address != null) { return firstNoLoopbackIPV4Address; } Collection<String> allNoLoopbackAddresses = null; try { allNoLoopbackAddresses = getAllNoLoopbackIPV4Addresses(); } catch (Exception e) { log.error("获取ip失败", e); return LOOP_BACK; } if (allNoLoopbackAddresses.isEmpty()) { return LOOP_BACK; } return firstNoLoopbackIPV4Address = allNoLoopbackAddresses.iterator().next(); } public static Collection<String> getAllNoLoopbackIPV4Addresses() { Collection<String> noLoopbackAddresses = new ArrayList<String>(); Collection<InetAddress> allInetAddresses = getAllHostIPV4Address(); for (InetAddress address : allInetAddresses) { if (!address.isLoopbackAddress()) { noLoopbackAddresses.add(address.getHostAddress()); } } return noLoopbackAddresses; } public static Collection<InetAddress> getAllHostIPV4Address() { if (allHostIPV4Address == null) { try { Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces(); Collection<InetAddress> addresses = new ArrayList<InetAddress>(); while (networkInterfaces.hasMoreElements()) { NetworkInterface networkInterface = networkInterfaces.nextElement(); Enumeration<InetAddress> inetAddresses = networkInterface.getInetAddresses(); while (inetAddresses.hasMoreElements()) { InetAddress inetAddress = inetAddresses.nextElement(); if (inetAddress instanceof Inet4Address) { addresses.add(inetAddress); } } } allHostIPV4Address = addresses; } catch (SocketException e) { log.error("获取ip地址失败", e); throw new RuntimeException(e.getMessage(), e); } } return allHostIPV4Address; } } ruoyi-system/src/main/java/com/ruoyi/system/dto/MakeOrderDto.java
New file @@ -0,0 +1,38 @@ package com.ruoyi.system.dto; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotEmpty; import javax.validation.constraints.NotNull; import java.io.Serializable; import java.util.List; @Data @ApiModel(value = "使用账单创建订单请求") public class MakeOrderDto implements Serializable { /** * 用户ID */ @ApiModelProperty(value = "用户ID") @NotBlank(message = "用户ID不能为空") private String userId; /** * 用户openid */ @ApiModelProperty(value = "用户微信或支付宝openid") private String openId; @ApiModelProperty(value = "支付金额,单位:分") @NotNull(message = "用户ID不能为空") private Long amount; @ApiModelProperty(value = "账单ID列表",notes = "如果只有1个账单ID,金额可以小于账单金额,进行部分缴费;如果是多个账单,将会核对金额,未交费金额需要与缴费金额一致") @NotEmpty(message = "用户ID不能为空") private List<String> billIds; } ruoyi-system/src/main/java/com/ruoyi/system/dto/MakeOrderResp.java
New file @@ -0,0 +1,23 @@ package com.ruoyi.system.dto; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import java.io.Serializable; @Data @ApiModel(value = "使用账单创建订单请求") public class MakeOrderResp implements Serializable { /** * 订单编号 */ @ApiModelProperty("订单编号") private String orderNo; @ApiModelProperty("金额,分") private Long amount; @ApiModelProperty("微信小程序支付跳转链接,用于生成二维码") private String appletUrl; } ruoyi-system/src/main/java/com/ruoyi/system/dto/TBillDto.java
New file @@ -0,0 +1,17 @@ package com.ruoyi.system.dto; import com.ruoyi.system.model.TBill; import lombok.Data; import java.util.List; @Data public class TBillDto extends TBill { private String residentName; private String phone; private String account; } ruoyi-system/src/main/java/com/ruoyi/system/mapper/TBillMapper.java
@@ -1,7 +1,12 @@ package com.ruoyi.system.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.ruoyi.common.basic.PageInfo; import com.ruoyi.system.dto.TBillDto; import com.ruoyi.system.model.TBill; import com.ruoyi.system.query.TBillQuery; import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Select; /** * <p> @@ -13,4 +18,6 @@ */ public interface TBillMapper extends BaseMapper<TBill> { PageInfo<TBillDto> page(@Param("pageInfo") PageInfo<TBill> pageInfo, @Param("query") TBillQuery query); } ruoyi-system/src/main/java/com/ruoyi/system/mapper/TOrderBillMapper.java
New file @@ -0,0 +1,16 @@ package com.ruoyi.system.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.ruoyi.system.model.TOrderBill; /** * <p> * 订单表与账单的关联表 Mapper 接口 * </p> * * @author xiaochen * @since 2025-02-07 */ public interface TOrderBillMapper extends BaseMapper<TOrderBill> { } ruoyi-system/src/main/java/com/ruoyi/system/mapper/TPayOrderMapper.java
New file @@ -0,0 +1,16 @@ package com.ruoyi.system.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.ruoyi.system.model.TPayOrder; /** * <p> * 支付订单表 Mapper 接口 * </p> * * @author xiaochen * @since 2025-02-07 */ public interface TPayOrderMapper extends BaseMapper<TPayOrder> { } ruoyi-system/src/main/java/com/ruoyi/system/model/TOrderBill.java
New file @@ -0,0 +1,54 @@ package com.ruoyi.system.model; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; import java.io.Serializable; import java.time.LocalDateTime; /** * <p> * 订单表与账单的关联表 * </p> * * @author xiaochen * @since 2025-02-07 */ @Data @NoArgsConstructor @EqualsAndHashCode(callSuper = false) @TableName("t_order_bill") @ApiModel(value="TOrderBill对象", description="订单表与账单的关联表") public class TOrderBill implements Serializable { private static final long serialVersionUID = 1L; @TableId(value = "id", type = IdType.ASSIGN_ID) private String id; @ApiModelProperty(value = "订单号") @TableField("order_no") private String orderNo; @ApiModelProperty(value = "账单编号") @TableField("bill_id") private String billId; @TableField("create_time") private LocalDateTime createTime; @TableField("update_time") private LocalDateTime updateTime; public TOrderBill(String orderNo, String billId) { this.orderNo = orderNo; this.billId = billId; } } ruoyi-system/src/main/java/com/ruoyi/system/model/TPayOrder.java
New file @@ -0,0 +1,88 @@ package com.ruoyi.system.model; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import lombok.EqualsAndHashCode; import java.io.Serializable; import java.time.LocalDateTime; /** * <p> * 支付订单表 * </p> * * @author xiaochen * @since 2025-02-07 */ @Data @EqualsAndHashCode(callSuper = false) @TableName("t_pay_order") @ApiModel(value="TPayOrder对象", description="支付订单表") public class TPayOrder implements Serializable { private static final long serialVersionUID = 1L; @ApiModelProperty(value = "订单号") @TableId("id") private String id; @ApiModelProperty(value = "发起支付的用户ID") @TableField("user_id") private String userId; @ApiModelProperty(value = "用户名称") @TableField("user_name") private String userName; @ApiModelProperty(value = "用户微信openid或支付宝userid") @TableField("open_id") private String openId; @ApiModelProperty(value = "用户手机号码") @TableField("phone") private String phone; @ApiModelProperty(value = "订单金额") @TableField("amount") private Long amount; @ApiModelProperty(value = "实付金额") @TableField("act_pay_amount") private Long actPayAmount; @ApiModelProperty(value = "支付时间") @TableField("pay_time") private LocalDateTime payTime; @ApiModelProperty(value = "支付方式") @TableField("pay_type") private String payType; @ApiModelProperty(value = "支付的回调信息") @TableField("pay_info") private String payInfo; @ApiModelProperty(value = "银行的支付流水编号") @TableField("pay_no") private String payNo; @ApiModelProperty(value = "支付的回调时间") @TableField("callback_time") private LocalDateTime callbackTime; @ApiModelProperty(value = "订单创建时间") @TableField("create_time") private LocalDateTime createTime; @ApiModelProperty(value = "订单更新时间") @TableField("update_time") private LocalDateTime updateTime; } ruoyi-system/src/main/java/com/ruoyi/system/query/TBillQuery.java
@@ -10,6 +10,12 @@ */ private Integer payFeesStatus; private String phone; private String residentName; private String contractNumber; } ruoyi-system/src/main/java/com/ruoyi/system/service/TBillService.java
@@ -2,6 +2,7 @@ import com.baomidou.mybatisplus.extension.service.IService; import com.ruoyi.common.basic.PageInfo; import com.ruoyi.system.dto.TBillDto; import com.ruoyi.system.model.TBill; import com.ruoyi.system.query.TBillQuery; @@ -15,6 +16,6 @@ */ public interface TBillService extends IService<TBill> { PageInfo<TBill> queryPage(TBillQuery query); PageInfo<TBillDto> queryPage(TBillQuery query); } ruoyi-system/src/main/java/com/ruoyi/system/service/TOrderBillService.java
New file @@ -0,0 +1,16 @@ package com.ruoyi.system.service; import com.baomidou.mybatisplus.extension.service.IService; import com.ruoyi.system.model.TOrderBill; /** * <p> * 订单表与账单的关联表 服务类 * </p> * * @author xiaochen * @since 2025-02-07 */ public interface TOrderBillService extends IService<TOrderBill> { } ruoyi-system/src/main/java/com/ruoyi/system/service/TPayOrderService.java
New file @@ -0,0 +1,19 @@ package com.ruoyi.system.service; import com.baomidou.mybatisplus.extension.service.IService; import com.ruoyi.system.dto.MakeOrderDto; import com.ruoyi.system.dto.MakeOrderResp; import com.ruoyi.system.model.TPayOrder; /** * <p> * 支付订单表 服务类 * </p> * * @author xiaochen * @since 2025-02-07 */ public interface TPayOrderService extends IService<TPayOrder> { MakeOrderResp makeOrder(MakeOrderDto dto); } ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TBillServiceImpl.java
@@ -1,16 +1,22 @@ package com.ruoyi.system.service.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.ruoyi.common.basic.PageInfo; import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.core.redis.RedisCache; import com.ruoyi.system.dto.TBillDto; import com.ruoyi.system.mapper.TBillMapper; import com.ruoyi.system.model.TBill; import com.ruoyi.system.model.TContract; import com.ruoyi.system.model.THouse; import com.ruoyi.system.query.TBillQuery; import com.ruoyi.system.service.TBillService; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import io.jsonwebtoken.lang.Assert; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.time.LocalDateTime; /** * <p> @@ -29,8 +35,10 @@ @Autowired TBillMapper tBillMapper; public PageInfo<TBill> queryPage(TBillQuery query){ return null; public PageInfo<TBillDto> queryPage(TBillQuery query){ PageInfo<TBill> pageInfo = new PageInfo<>(query.getPageNum(), query.getPageSize()); PageInfo<TBillDto> info = tBillMapper.page(pageInfo, query); return info; } ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TOrderBillServiceImpl.java
New file @@ -0,0 +1,20 @@ package com.ruoyi.system.service.impl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.ruoyi.system.mapper.TOrderBillMapper; import com.ruoyi.system.model.TOrderBill; import com.ruoyi.system.service.TOrderBillService; import org.springframework.stereotype.Service; /** * <p> * 订单表与账单的关联表 服务实现类 * </p> * * @author xiaochen * @since 2025-02-07 */ @Service public class TOrderBillServiceImpl extends ServiceImpl<TOrderBillMapper, TOrderBill> implements TOrderBillService { } ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TPayOrderServiceImpl.java
New file @@ -0,0 +1,130 @@ package com.ruoyi.system.service.impl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.ruoyi.common.constant.AmountConstant; import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.utils.OrderNos; import com.ruoyi.system.dto.MakeOrderDto; import com.ruoyi.system.dto.MakeOrderResp; import com.ruoyi.system.mapper.TPayOrderMapper; import com.ruoyi.system.model.TBill; import com.ruoyi.system.model.TOrderBill; import com.ruoyi.system.model.TPayOrder; import com.ruoyi.system.model.TTenant; import com.ruoyi.system.service.TBillService; import com.ruoyi.system.service.TOrderBillService; import com.ruoyi.system.service.TPayOrderService; import com.ruoyi.system.service.TTenantService; import org.apache.poi.ss.formula.functions.T; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.math.BigDecimal; import java.math.RoundingMode; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; /** * <p> * 支付订单表 服务实现类 * </p> * * @author xiaochen * @since 2025-02-07 */ @Service public class TPayOrderServiceImpl extends ServiceImpl<TPayOrderMapper, TPayOrder> implements TPayOrderService { @Autowired TBillService billService; @Autowired TTenantService tTenantService; @Autowired TOrderBillService tOrderBillService; public long caculateRentFee(TBill bill){ return bill.getPayableFeesMoney().add(bill.getPayableFeesPenalty()) .subtract(bill.getActualMoney()) .multiply(AmountConstant.b100) .setScale(0, RoundingMode.HALF_DOWN) .longValue(); } public String createAppletUrl(String orderNo){ return ""+orderNo; } @Override public MakeOrderResp makeOrder(MakeOrderDto dto) { TTenant user = tTenantService.getById(dto.getUserId()); if (user==null){ throw new ServiceException("租户不存在"); } MakeOrderResp resp = new MakeOrderResp(); if (dto.getBillIds().size()==1){ TBill bill = billService.getById(dto.getBillIds().get(0)); if (bill == null) { throw new ServiceException("账单不存在"); } //计算欠费金额:租金+违约金-实收金额 long rent = caculateRentFee(bill); if (rent==0){ throw new ServiceException("该订单已缴费"); } if (rent>dto.getAmount()){ throw new ServiceException("支付金额超过了账单欠费金额"); } TPayOrder order = new TPayOrder(); order.setId(OrderNos.getDid(32)); order.setAmount(dto.getAmount()); order.setUserId(user.getId()); order.setPhone(user.getPhone()); order.setUserName(user.getResidentName()); save(order); TOrderBill tOrderBill = new TOrderBill(); tOrderBill.setBillId(bill.getId()); tOrderBill.setOrderNo(order.getId()); tOrderBillService.save(tOrderBill); resp.setAmount(dto.getAmount()); resp.setOrderNo(order.getId()); resp.setAppletUrl(createAppletUrl(order.getId())); return resp; } List<TOrderBill> orderBills = new ArrayList<>(); String orderNo = OrderNos.getDid(32); List<TBill> bills = dto.getBillIds().stream().map(id -> { TBill bill = billService.getById(id); if (bill == null) { throw new ServiceException("billId:" + id + "不存在"); } orderBills.add(new TOrderBill(orderNo,bill.getId())); return bill; }).collect(Collectors.toList()); long sumRent = bills.stream().mapToLong((bill) -> caculateRentFee(bill)).sum(); if (sumRent==0){ throw new ServiceException("账单已缴费"); } if (dto.getAmount()>sumRent){ throw new ServiceException("支付金额超过所选账单欠费金额"); } TPayOrder order = new TPayOrder(); order.setId(orderNo); order.setAmount(dto.getAmount()); order.setUserId(user.getId()); order.setPhone(user.getPhone()); order.setUserName(user.getResidentName()); save(order); tOrderBillService.saveBatch(orderBills); resp.setAmount(dto.getAmount()); resp.setOrderNo(orderNo); resp.setAppletUrl(createAppletUrl(orderNo)); return resp; } } ruoyi-system/src/main/resources/mapper/system/TBillMapper.xml
@@ -32,4 +32,29 @@ id, contract_id, payable_fees_money, payable_fees_time, pay_fees_status, pay_fees_money, pay_fees_time, pay_fees_type, bill_type, over_days, payable_fees_penalty, start_time, end_time, bank_serial_number, actual_money, voucher, create_time, update_time, create_by, update_by, disabled </sql> <select id="page" resultType="com.ruoyi.system.dto.TBillDto"> SELECT b.*, t.resident_name as residentName, t.phone, t.account FROM t_bill b LEFT JOIN t_contract c ON c.contract_number = b.contract_number LEFT JOIN t_tenant t ON t.id = c.tenant_id <where> <if test="query.payFeesStatus != null"> and b.pay_fees_status = #{query.payFeesStatus} </if> <if test="query.phone != null and query.phone !=''"> and t.phone = #{query.phone} </if> <if test="query.residentName != null and query.residentName !=''"> and t.resident_name like concat('%',#{query.residentName},'%') </if> <if test="query.contractNumber != null and query.contractNumber !=''"> and b.contract_number = #{contractNumber} </if> </where> </select> </mapper>