Forráskód Böngészése

feat(order): 添加订单分账逻辑与微信手续费计算功能

- 在 OrderServiceImpl 中实现分账验证逻辑,确保下单前分账可执行
- 新增 calculate 方法用于计算微信手续费,处理临界值问题
- 引入 RatiosUtil 工具类用于分账比例分配
- 增加对商户和门店类型的分账规则判断
- 添加静态常量 MIN_THRESHOLD 用于定义最小手续费阈值
-优化拍照验课表单类 CoursesVerificationRecordForm 和 VerifyForm, 增加 Serial 注解和 serialVersionUID 字段以支持序列化兼容性
wzq 1 hete
szülő
commit
d187190f03

+ 67 - 0
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/service/impl/OrderServiceImpl.java

@@ -34,6 +34,7 @@ import org.jeecg.modules.app.vo.AppGameScheduleVO;
 import org.jeecg.modules.app.vo.OrderVO;
 import org.jeecg.modules.app.vo.PageOrdersVO;
 import org.jeecg.modules.app.vo.QueryOrderVerifyRecordsVO;
+import org.jeecg.modules.pay.config.RatiosUtil;
 import org.jeecg.modules.pay.config.WechatConstants;
 import org.jeecg.modules.pay.config.WechatPayV3Utils;
 import org.jeecg.modules.pay.config.WechatUrlConstants;
@@ -1214,6 +1215,47 @@ public class OrderServiceImpl extends ServiceImpl<AppOrderMapper, AppOrder> impl
         if ((ObjectUtil.isNotEmpty(appOrder.getOrderOrFree()) && appOrder.getOrderOrFree() == 1) || appOrder.getPrice().compareTo(BigDecimal.ZERO)== 0) {
             payForm.setOrPayOrder(0);
         } else {
+            //分账能否成功,判断是否可以下单
+            List<AppOrderProInfo> orderProInfoList =
+                    proInfoList.stream().filter(appOrderProInfo -> Objects.equals(appOrderProInfo.getType(), CommonConstant.ORDER_PRO_INFO_TYPE_6)).collect(Collectors.toList());
+            BigDecimal insurePrice = BigDecimal.ZERO;
+            if (CollUtil.isNotEmpty(orderProInfoList)) {
+                BigDecimal reduce = orderProInfoList.stream().map(AppOrderProInfo::getPrice).reduce(BigDecimal.ZERO, BigDecimal::add);
+                insurePrice = insurePrice.add(reduce);
+            }
+            //创建预分账详情
+            String orgCode = appOrder.getOrgCode();
+            SysDepart depart = sysDepartMapper.selectOne(Wrappers.lambdaQuery(SysDepart.class).eq(SysDepart::getOrgCode, orgCode).last("limit 1"));
+
+            if (depart.getSystemType() != 0) {
+                SeparateAccounts separateAccounts = separateAccountsMapper.selectOne(Wrappers.lambdaQuery(SeparateAccounts.class).eq(SeparateAccounts::getDeptId, depart.getId()));
+                //获取分账比例
+                BigDecimal PT = separateAccounts.getPtSeparateAccounts();
+                BigDecimal SH = separateAccounts.getShSeparateAccounts();
+                BigDecimal MD = separateAccounts.getMdSeparateAccounts();
+                //分账金额(支付金额-保险金额)
+                BigDecimal price = appOrder.getPrice().subtract(insurePrice);
+                //微信手续费,不足1分按1分算(当计算值小于0.01时强制提升至0.01)
+                BigDecimal FEE = calculate(price, new BigDecimal("0.006"));
+
+                price = price.subtract(FEE);
+
+                //商户(分账给平台)
+                if (depart.getSystemType() == 1) {
+                    BigDecimal[] allocate = RatiosUtil.allocate(price, new BigDecimal[]{SH, PT});
+                    if((appOrder.getPrice().subtract(FEE)).multiply(BigDecimal.valueOf(0.3)).compareTo(allocate[1].add(insurePrice)) < 0){
+                        throw new JeecgBootException("订单金额不支持分账,无法下单!");
+                    }
+                }
+                //门店(分账给平台及商户)
+                if (depart.getSystemType() == 2) {
+                    BigDecimal[] allocate = RatiosUtil.allocate(price, MD, SH, PT);
+                    if((appOrder.getPrice().subtract(FEE)).multiply(BigDecimal.valueOf(0.3)).compareTo(allocate[1].add(allocate[2]).add(insurePrice)) < 0){
+                        throw new JeecgBootException("订单金额不支持分账,无法下单!");
+                    }
+                }
+            }
+
             Map<String, String> result = payment(appOrder.getId());
             payForm.setParams(result);
 
@@ -1227,6 +1269,31 @@ public class OrderServiceImpl extends ServiceImpl<AppOrderMapper, AppOrder> impl
         }
         return payForm;
     }
+    private static final BigDecimal MIN_THRESHOLD = new BigDecimal("0.01"); // 最小阈值
+    /**
+     * 计算千分之6并处理临界值
+     *
+     * @param input 输入金额(单位:元)
+     * @return 计算结果(保留两位小数,不足0.01按0.01计算)
+     * @throws IllegalArgumentException 输入为null或负数时抛出
+     */
+    public static BigDecimal calculate(BigDecimal input, BigDecimal multiplier) {
+        if (input == null) {
+            throw new IllegalArgumentException("输入金额不能为null");
+        }
+        if (input.compareTo(BigDecimal.ZERO) < 0) {
+            throw new IllegalArgumentException("输入金额不能为负数");
+        }
+
+        // 精确乘法运算(保留4位中间精度)
+        BigDecimal product = input.multiply(multiplier)
+                .setScale(4, RoundingMode.HALF_UP);
+
+        // 临界值判断与补偿
+        return product.compareTo(MIN_THRESHOLD) < 0
+                ? MIN_THRESHOLD
+                : product.setScale(2, RoundingMode.DOWN);
+    }
 
     public Map<String, String> payment(String appOrderId){
         AppOrder appOrder = appOrderMapper.selectById(appOrderId);

+ 2 - 0
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/system/app/form/CoursesVerificationRecordForm.java

@@ -7,6 +7,7 @@ import lombok.EqualsAndHashCode;
 import lombok.NoArgsConstructor;
 import lombok.experimental.Accessors;
 
+import java.io.Serial;
 import java.io.Serializable;
 
 @Data
@@ -16,6 +17,7 @@ import java.io.Serializable;
 @NoArgsConstructor
 @Schema(description = "拍照验课上传图片表单对象")
 public class CoursesVerificationRecordForm implements Serializable {
+    @Serial
     private static final long serialVersionUID = 1L;
 
     /**

+ 2 - 0
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/system/app/form/VerifyForm.java

@@ -7,6 +7,7 @@ import lombok.EqualsAndHashCode;
 import lombok.NoArgsConstructor;
 import lombok.experimental.Accessors;
 
+import java.io.Serial;
 import java.io.Serializable;
 import java.util.List;
 
@@ -17,6 +18,7 @@ import java.util.List;
 @NoArgsConstructor
 @Schema(description = "拍照验课上传图片表单对象")
 public class VerifyForm implements Serializable {
+    @Serial
     private static final long serialVersionUID = 1L;
 
     @Schema(description = "课时ID")