diff --git a/mall-common/src/main/java/com/suisung/mall/common/pojo/dto/LklSeparateDTO.java b/mall-common/src/main/java/com/suisung/mall/common/pojo/dto/LklSeparateDTO.java index f9bf2a6f..46a00198 100644 --- a/mall-common/src/main/java/com/suisung/mall/common/pojo/dto/LklSeparateDTO.java +++ b/mall-common/src/main/java/com/suisung/mall/common/pojo/dto/LklSeparateDTO.java @@ -13,6 +13,7 @@ import java.math.RoundingMode; @Data @EqualsAndHashCode(callSuper = false) public class LklSeparateDTO { + // 基础金额属性 private Integer totalSeparateAmount; // 分账总金额(分) private Integer canSeparateAmount; // 可分账金额(分) @@ -41,8 +42,8 @@ public class LklSeparateDTO { LklSeparateDTO dto = new LklSeparateDTO(); // 设置测试参数 - 正常情况 - dto.setTotalSeparateAmount(800); // 分账总额 1000分 - dto.setShippingFee(500); // 配送费 100分 + dto.setTotalSeparateAmount(1000); // 分账总额 1000分 + dto.setShippingFee(100); // 配送费 100分 dto.setLklRatio(new BigDecimal("0.0025")); // 拉卡拉分账比例 0.0025 dto.setMchRatio(new BigDecimal("0.94")); // 商家分账比例 0.94 dto.setPlatRatio(new BigDecimal("0.06")); // 平台分账比例 0.01 @@ -60,11 +61,12 @@ public class LklSeparateDTO { // 测试基于可分账金额的分账算法(正常情况) System.out.println("\n=== 基于可分账金额的分账算法测试(正常情况) ==="); LklSeparateDTO dto2 = new LklSeparateDTO(); - dto2.setTotalSeparateAmount(800); // 分账总额 1000分 + dto2.setTotalSeparateAmount(990); // 分账总额 1000分 dto2.setShippingFee(500); // 配送费 100分 + dto2.setRefCanSeparateAmount(null); dto2.setLklRatio(new BigDecimal("0.0025")); // 拉卡拉分账比例 0.0025 dto2.setMchRatio(new BigDecimal("0.94")); // 商家分账比例 0.857 (会产生小数) - dto2.setPlatRatio(new BigDecimal("0.06")); // 平台分账比例 0.01 + dto2.setPlatRatio(new BigDecimal("0.01")); // 平台分账比例 0.01 // 不设置一级和二级代理商分账比例,测试不参与分账的情况 // dto2.setAgent1stRatio(new BigDecimal("0.01")); // 一级代理商分账比例 0.023 (会产生小数) // dto2.setAgent2ndRatio(new BigDecimal("0.04")); // 二级代理商分账比例 0.031 (会产生小数) @@ -77,13 +79,6 @@ public class LklSeparateDTO { } // 测试toJSON和toString方法 - System.out.println("\n=== toJSON和toString方法测试 ==="); - System.out.println("基于分账总额算法的JSON输出:"); - System.out.println(dto.toJSON()); - - System.out.println("\n基于分账总额算法的toString输出:"); - System.out.println(dto); - System.out.println("\n=== toJSON和toString方法测试 ==="); System.out.println("基于可分账金额算法的JSON输出:"); System.out.println(dto2.toJSON()); @@ -92,6 +87,22 @@ public class LklSeparateDTO { System.out.println(dto2); } + /** + * 计算百分比 + * + * @param amount 金额 + * @param total 总金额 + * @return 百分比字符串,保留两位小数 + */ + public static String calculatePercentage(Integer amount, Integer total) { + if (amount == null || total == null || total == 0) { + return "0.00"; + } + BigDecimal percentage = new BigDecimal(amount).multiply(new BigDecimal("100")) + .divide(new BigDecimal(total), 2, RoundingMode.HALF_UP); + return percentage.toString(); + } + /** * 打印分账详情 * @@ -116,238 +127,40 @@ public class LklSeparateDTO { if (dto.getCanSeparateAmount() != null) { System.out.println(" 可分账金额: " + dto.getCanSeparateAmount() + "分"); } - // 打印平台分账金额(即使为0也要显示) + if (dto.getRefCanSeparateAmount() != null) { + System.out.println(" 参考可分账金额: " + dto.getRefCanSeparateAmount() + "分"); + } + if (dto.getCanSeparateAmount() != null && dto.getRefCanSeparateAmount() != null) { + System.out.println(" 参考可分账差值: " + (dto.getRefCanSeparateAmount() - dto.getCanSeparateAmount()) + "分"); + } if (dto.getPlatAmount() != null) { System.out.println(" 平台分账金额: " + dto.getPlatAmount() + "分" + - (dto.getTotalSeparateAmount() != null - ? " (总金额占比: " + calculatePercentage(dto.getPlatAmount(), dto.getTotalSeparateAmount()) - + "%)" - : "") - + - (dto.getCanSeparateAmount() != null - ? " (可分账占比: " + calculatePercentage(dto.getPlatAmount(), dto.getCanSeparateAmount()) + "%)" - : "")); + (dto.getTotalSeparateAmount() != null ? + " (总金额占比: " + calculatePercentage(dto.getPlatAmount(), dto.getTotalSeparateAmount()) + "%)" : "") + + (dto.getCanSeparateAmount() != null && dto.getCanSeparateAmount() > 0 ? + " (可分账占比: " + calculatePercentage(dto.getPlatAmount(), dto.getCanSeparateAmount()) + "%)" : "")); } - // 打印一级代理商分账金额(即使为0也要显示) if (dto.getAgent1stAmount() != null) { System.out.println(" 一级代理商分账金额: " + dto.getAgent1stAmount() + "分" + - (dto.getTotalSeparateAmount() != null - ? " (总金额占比: " + calculatePercentage(dto.getAgent1stAmount(), dto.getTotalSeparateAmount()) - + "%)" - : "") - + - (dto.getCanSeparateAmount() != null - ? " (可分账占比: " + calculatePercentage(dto.getAgent1stAmount(), dto.getCanSeparateAmount()) - + "%)" - : "")); + (dto.getTotalSeparateAmount() != null ? + " (总金额占比: " + calculatePercentage(dto.getAgent1stAmount(), dto.getTotalSeparateAmount()) + "%)" : "") + + (dto.getCanSeparateAmount() != null && dto.getCanSeparateAmount() > 0 ? + " (可分账占比: " + calculatePercentage(dto.getAgent1stAmount(), dto.getCanSeparateAmount()) + "%)" : "")); } - // 打印二级代理商分账金额(即使为0也要显示) if (dto.getAgent2ndAmount() != null) { System.out.println(" 二级代理商分账金额: " + dto.getAgent2ndAmount() + "分" + - (dto.getTotalSeparateAmount() != null - ? " (总金额占比: " + calculatePercentage(dto.getAgent2ndAmount(), dto.getTotalSeparateAmount()) - + "%)" - : "") - + - (dto.getCanSeparateAmount() != null - ? " (可分账占比: " + calculatePercentage(dto.getAgent2ndAmount(), dto.getCanSeparateAmount()) - + "%)" - : "")); + (dto.getTotalSeparateAmount() != null ? + " (总金额占比: " + calculatePercentage(dto.getAgent2ndAmount(), dto.getTotalSeparateAmount()) + "%)" : "") + + (dto.getCanSeparateAmount() != null && dto.getCanSeparateAmount() > 0 ? + " (可分账占比: " + calculatePercentage(dto.getAgent2ndAmount(), dto.getCanSeparateAmount()) + "%)" : "")); } - // 打印商家分账金额 if (dto.getMchAmount() != null) { System.out.println(" 商家分账金额: " + dto.getMchAmount() + "分" + - (dto.getTotalSeparateAmount() != null - ? " (总金额占比: " + calculatePercentage(dto.getMchAmount(), dto.getTotalSeparateAmount()) + "%)" - : "") - + - (dto.getCanSeparateAmount() != null - ? " (可分账占比: " + calculatePercentage(dto.getMchAmount(), dto.getCanSeparateAmount()) + "%)" - : "")); + (dto.getTotalSeparateAmount() != null ? + " (总金额占比: " + calculatePercentage(dto.getMchAmount(), dto.getTotalSeparateAmount()) + "%)" : "") + + (dto.getCanSeparateAmount() != null && dto.getCanSeparateAmount() > 0 ? + " (可分账占比: " + calculatePercentage(dto.getMchAmount(), dto.getCanSeparateAmount()) + "%)" : "")); } - - // 验证分账是否平衡 - if (dto.getTotalSeparateAmount() != null) { - int totalDistributed = (dto.getLklAmount() != null ? dto.getLklAmount() : 0) + - (dto.getShippingFee() != null ? dto.getShippingFee() : 0) + - (dto.getPlatAmount() != null ? dto.getPlatAmount() : 0) + - (dto.getAgent1stAmount() != null ? dto.getAgent1stAmount() : 0) + - (dto.getAgent2ndAmount() != null ? dto.getAgent2ndAmount() : 0) + - (dto.getMchAmount() != null ? dto.getMchAmount() : 0); - System.out.println(" 分账平衡验证: " + (totalDistributed == dto.getTotalSeparateAmount() ? "通过" : "失败")); - System.out.println(" 计算的分账总额: " + totalDistributed + "分"); - } - } - - /** - * 计算金额占总额的百分比 - * - * @param amount 金额 - * @param total 总金额 - * @return 百分比字符串 - */ - public static String calculatePercentage(Integer amount, Integer total) { - if (amount == null || total == null || total == 0) { - return "0.00"; - } - BigDecimal percentage = new BigDecimal(amount).multiply(new BigDecimal("100")) - .divide(new BigDecimal(total), 2, RoundingMode.HALF_UP); - return percentage.toString(); - } - - - /** - * 将分账对象转换为JSON格式字符串 - * - * @return JSON格式字符串 - */ - public String toJSON() { - StringBuilder json = new StringBuilder(); - json.append("{\n"); - - // 基础信息 - json.append(" \"分账算法类型\": \"拉卡拉订单分账信息处理\",\n"); - json.append(" \"分账总金额\": ").append(totalSeparateAmount != null ? totalSeparateAmount : 0).append(",\n"); - json.append(" \"配送费\": ").append(shippingFee != null ? shippingFee : 0).append(",\n"); - - // 分账比例 - json.append(" \"分账比例\": {\n"); - json.append(" \"拉卡拉分账比例\": \"").append(lklRatio != null ? lklRatio.toString() : "0").append("\",\n"); - json.append(" \"商家分账比例\": \"").append(mchRatio != null ? mchRatio.toString() : "0").append("\",\n"); - json.append(" \"平台分账比例\": \"").append(platRatio != null ? platRatio.toString() : "0").append("\",\n"); - json.append(" \"一级代理商分账比例\": \"").append(agent1stRatio != null ? agent1stRatio.toString() : "0") - .append("\",\n"); - json.append(" \"二级代理商分账比例\": \"").append(agent2ndRatio != null ? agent2ndRatio.toString() : "0") - .append("\"\n"); - json.append(" },\n"); - - // 分账金额结果 - json.append(" \"分账金额结果\": {\n"); - json.append(" \"拉卡拉分账金额\": ").append(lklAmount != null ? lklAmount : 0).append(",\n"); - json.append(" \"可分账金额\": ").append(canSeparateAmount != null ? canSeparateAmount : 0).append(",\n"); - json.append(" \"平台分账金额\": ").append(platAmount != null ? platAmount : 0).append(",\n"); - json.append(" \"一级代理商分账金额\": ").append(agent1stAmount != null ? agent1stAmount : 0).append(",\n"); - json.append(" \"二级代理商分账金额\": ").append(agent2ndAmount != null ? agent2ndAmount : 0).append(",\n"); - json.append(" \"商家分账金额\": ").append(mchAmount != null ? mchAmount : 0).append("\n"); - json.append(" },\n"); - - // 分账百分比(基于分账总金额) - json.append(" \"基于分账总金额的百分比\": {\n"); - if (totalSeparateAmount != null && totalSeparateAmount > 0) { - json.append(" \"拉卡拉分账占比\": \"").append(calculatePercentage(lklAmount, totalSeparateAmount)) - .append("%\",\n"); - json.append(" \"配送费占比\": \"").append(calculatePercentage(shippingFee, totalSeparateAmount)) - .append("%\",\n"); - json.append(" \"平台分账占比\": \"").append(calculatePercentage(platAmount, totalSeparateAmount)) - .append("%\",\n"); - json.append(" \"一级代理商分账占比\": \"").append(calculatePercentage(agent1stAmount, totalSeparateAmount)) - .append("%\",\n"); - json.append(" \"二级代理商分账占比\": \"").append(calculatePercentage(agent2ndAmount, totalSeparateAmount)) - .append("%\",\n"); - json.append(" \"商家分账占比\": \"").append(calculatePercentage(mchAmount, totalSeparateAmount)) - .append("%\"\n"); - } else { - json.append(" \"拉卡拉分账占比\": \"0.00%\",\n"); - json.append(" \"配送费占比\": \"0.00%\",\n"); - json.append(" \"平台分账占比\": \"0.00%\",\n"); - json.append(" \"一级代理商分账占比\": \"0.00%\",\n"); - json.append(" \"二级代理商分账占比\": \"0.00%\",\n"); - json.append(" \"商家分账占比\": \"0.00%\"\n"); - } - json.append(" },\n"); - - // 分账百分比(基于可分账金额) - json.append(" \"基于可分账金额的百分比\": {\n"); - if (canSeparateAmount != null && canSeparateAmount > 0) { - json.append(" \"平台分账占比\": \"").append(calculatePercentage(platAmount, canSeparateAmount)) - .append("%\",\n"); - json.append(" \"一级代理商分账占比\": \"").append(calculatePercentage(agent1stAmount, canSeparateAmount)) - .append("%\",\n"); - json.append(" \"二级代理商分账占比\": \"").append(calculatePercentage(agent2ndAmount, canSeparateAmount)) - .append("%\",\n"); - json.append(" \"商家分账占比\": \"").append(calculatePercentage(mchAmount, canSeparateAmount)).append("%\"\n"); - } else { - json.append(" \"平台分账占比\": \"0.00%\",\n"); - json.append(" \"一级代理商分账占比\": \"0.00%\",\n"); - json.append(" \"二级代理商分账占比\": \"0.00%\",\n"); - json.append(" \"商家分账占比\": \"0.00%\"\n"); - } - json.append(" }\n"); - json.append("}"); - - return json.toString(); - } - - /** - * 重写toString方法,输出分账算法的关键信息 - * - * @return 分账对象的字符串表示 - */ - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("LklSeparateDTO{\n"); - - // 基础信息 - sb.append(" 分账算法类型: 拉卡拉订单分账信息处理\n"); - sb.append(" 分账总金额: ").append(totalSeparateAmount != null ? totalSeparateAmount : 0).append("分\n"); - sb.append(" 配送费: ").append(shippingFee != null ? shippingFee : 0).append("分\n"); - - // 分账比例 - sb.append(" 分账比例: {\n"); - sb.append(" 拉卡拉分账比例: ").append(lklRatio != null ? lklRatio.toString() : "0").append("\n"); - sb.append(" 商家分账比例: ").append(mchRatio != null ? mchRatio.toString() : "0").append("\n"); - sb.append(" 平台分账比例: ").append(platRatio != null ? platRatio.toString() : "0").append("\n"); - sb.append(" 一级代理商分账比例: ").append(agent1stRatio != null ? agent1stRatio.toString() : "0").append("\n"); - sb.append(" 二级代理商分账比例: ").append(agent2ndRatio != null ? agent2ndRatio.toString() : "0").append("\n"); - sb.append(" }\n"); - - // 分账金额结果 - sb.append(" 分账金额结果: {\n"); - sb.append(" 拉卡拉分账金额: ").append(lklAmount != null ? lklAmount : 0).append("分\n"); - sb.append(" 可分账金额: ").append(canSeparateAmount != null ? canSeparateAmount : 0).append("分\n"); - sb.append(" 平台分账金额: ").append(platAmount != null ? platAmount : 0).append("分\n"); - sb.append(" 一级代理商分账金额: ").append(agent1stAmount != null ? agent1stAmount : 0).append("分\n"); - sb.append(" 二级代理商分账金额: ").append(agent2ndAmount != null ? agent2ndAmount : 0).append("分\n"); - sb.append(" 商家分账金额: ").append(mchAmount != null ? mchAmount : 0).append("分\n"); - sb.append(" }\n"); - - // 分账百分比(基于分账总金额) - sb.append(" 基于分账总金额的百分比: {\n"); - if (totalSeparateAmount != null && totalSeparateAmount > 0) { - sb.append(" 拉卡拉分账占比: ").append(calculatePercentage(lklAmount, totalSeparateAmount)).append("%\n"); - sb.append(" 配送费占比: ").append(calculatePercentage(shippingFee, totalSeparateAmount)).append("%\n"); - sb.append(" 平台分账占比: ").append(calculatePercentage(platAmount, totalSeparateAmount)).append("%\n"); - sb.append(" 一级代理商分账占比: ").append(calculatePercentage(agent1stAmount, totalSeparateAmount)).append("%\n"); - sb.append(" 二级代理商分账占比: ").append(calculatePercentage(agent2ndAmount, totalSeparateAmount)).append("%\n"); - sb.append(" 商家分账占比: ").append(calculatePercentage(mchAmount, totalSeparateAmount)).append("%\n"); - } else { - sb.append(" 拉卡拉分账占比: 0.00%\n"); - sb.append(" 配送费占比: 0.00%\n"); - sb.append(" 平台分账占比: 0.00%\n"); - sb.append(" 一级代理商分账占比: 0.00%\n"); - sb.append(" 二级代理商分账占比: 0.00%\n"); - sb.append(" 商家分账占比: 0.00%\n"); - } - sb.append(" }\n"); - - // 分账百分比(基于可分账金额) - sb.append(" 基于可分账金额的百分比: {\n"); - if (canSeparateAmount != null && canSeparateAmount > 0) { - sb.append(" 平台分账占比: ").append(calculatePercentage(platAmount, canSeparateAmount)).append("%\n"); - sb.append(" 一级代理商分账占比: ").append(calculatePercentage(agent1stAmount, canSeparateAmount)).append("%\n"); - sb.append(" 二级代理商分账占比: ").append(calculatePercentage(agent2ndAmount, canSeparateAmount)).append("%\n"); - sb.append(" 商家分账占比: ").append(calculatePercentage(mchAmount, canSeparateAmount)).append("%\n"); - } else { - sb.append(" 平台分账占比: 0.00%\n"); - sb.append(" 一级代理商分账占比: 0.00%\n"); - sb.append(" 二级代理商分账占比: 0.00%\n"); - sb.append(" 商家分账占比: 0.00%\n"); - } - sb.append(" }\n"); - sb.append("}"); - - return sb.toString(); } /** @@ -387,11 +200,7 @@ public class LklSeparateDTO { } // 2. 计算拉卡拉分账金额 - int lklAmount = 0; - if (lklRatio != null && lklRatio.compareTo(BigDecimal.ZERO) > 0) { - lklAmount = lklRatio.multiply(new BigDecimal(totalSeparateAmount)) - .setScale(0, RoundingMode.HALF_UP).intValue(); - } + int lklAmount = calculateAmountWithRatio(lklRatio, totalSeparateAmount, RoundingMode.HALF_UP); // 3. 处理配送费(可以为空或0,表示免配送费) int effectiveShippingFee = (shippingFee != null && shippingFee > 0) ? shippingFee : 0; @@ -408,7 +217,28 @@ public class LklSeparateDTO { } int canSeparateAmount = availableAmount; - int refCanSeparateAmount = availableAmount; + // 保持canSeparateAmount和refCanSeparateAmount的独立性,不进行相互赋值 + + // 记录refCanSeparateAmount相关信息 + System.out.println("基于总金额算法 - 可分账金额计算完成: canSeparateAmount=" + canSeparateAmount + + ", refCanSeparateAmount=" + this.refCanSeparateAmount); + + // 5.1 检查refCanSeparateAmount是否为有效值,如果是有效值且与计算出的canSeparateAmount不一致,则使用refCanSeparateAmount作为分账金额 + int separateAmountForCalculation = canSeparateAmount; // 默认使用计算出的可分账金额 + if (this.refCanSeparateAmount != null && this.refCanSeparateAmount > 0 && this.refCanSeparateAmount < totalSeparateAmount) { + // refCanSeparateAmount是非空非零且比totalSeparateAmount小的有效值 + if (!this.refCanSeparateAmount.equals(canSeparateAmount)) { + // 有效值如果和计算出来的canSeparateAmount的值不一致 + separateAmountForCalculation = this.refCanSeparateAmount; // 使用refCanSeparateAmount作为分账算法中的可分金额 + System.out.println("基于总金额算法 - 使用refCanSeparateAmount作为分账金额: refCanSeparateAmount=" + + this.refCanSeparateAmount + ", canSeparateAmount=" + canSeparateAmount + + ", 差值=" + (this.refCanSeparateAmount - canSeparateAmount)); + } else { + System.out.println("基于总金额算法 - refCanSeparateAmount与canSeparateAmount相等,无需调整"); + } + } else { + System.out.println("基于总金额算法 - refCanSeparateAmount无效,使用计算出的canSeparateAmount"); + } // 6. 初始化各分账金额 int platAmount = 0; @@ -416,18 +246,19 @@ public class LklSeparateDTO { int agent2ndAmount = 0; int mchAmount = 0; - // 7. 根据参与方动态调整分账比例 + // 7. 根据参与方动态调整分账比例(基于总金额的独立逻辑) BigDecimal effectivePlatRatio = platRatio != null ? platRatio : BigDecimal.ZERO; BigDecimal effectiveAgent1stRatio = agent1stRatio != null ? agent1stRatio : BigDecimal.ZERO; BigDecimal effectiveAgent2ndRatio = agent2ndRatio != null ? agent2ndRatio : BigDecimal.ZERO; + BigDecimal effectiveMchRatio = mchRatio != null ? mchRatio : BigDecimal.ZERO; - // 判断哪些代理商参与分账 + // 判断代理商是否参与分账(在调整比例前进行判断) boolean hasAgent1st = effectiveAgent1stRatio.compareTo(BigDecimal.ZERO) > 0; boolean hasAgent2nd = effectiveAgent2ndRatio.compareTo(BigDecimal.ZERO) > 0; - // 根据商家分账比例动态调整其他方比例 - if (mchRatio != null && mchRatio.compareTo(BigDecimal.ZERO) > 0) { - BigDecimal remainingRatio = BigDecimal.ONE.subtract(mchRatio); + // 根据商家分账比例动态调整其他方比例(独立于基于可分账金额的算法) + if (effectiveMchRatio.compareTo(BigDecimal.ZERO) > 0) { + BigDecimal remainingRatio = BigDecimal.ONE.subtract(effectiveMchRatio); BigDecimal onePercent = new BigDecimal("0.01"); if (hasAgent1st && hasAgent2nd) { @@ -449,44 +280,46 @@ public class LklSeparateDTO { // 只有平台参与 effectivePlatRatio = remainingRatio; } + + // 重新判断代理商是否参与分账(基于调整后的比例) + hasAgent1st = effectiveAgent1stRatio.compareTo(BigDecimal.ZERO) > 0; + hasAgent2nd = effectiveAgent2ndRatio.compareTo(BigDecimal.ZERO) > 0; } + // 如果商家比例不存在或为0,使用各自设置的固定比例,代理商参与状态已在前面确定 // 8. 按优先级顺序计算各分账方金额 // 平台分账(优先级1)- 基于总金额计算 if (effectivePlatRatio.compareTo(BigDecimal.ZERO) > 0) { - platAmount = effectivePlatRatio.multiply(new BigDecimal(totalSeparateAmount)) - .setScale(0, RoundingMode.HALF_UP).intValue(); + platAmount = calculateAmountWithRatio(effectivePlatRatio, totalSeparateAmount, RoundingMode.HALF_UP); // 确保平台分账金额不超过可分账金额 - if (platAmount > availableAmount) { - platAmount = availableAmount; + if (platAmount > separateAmountForCalculation) { + platAmount = separateAmountForCalculation; } - availableAmount -= platAmount; + separateAmountForCalculation -= platAmount; } // 一级代理商分账(优先级2)- 基于总金额计算 if (hasAgent1st && effectiveAgent1stRatio.compareTo(BigDecimal.ZERO) > 0) { - agent1stAmount = effectiveAgent1stRatio.multiply(new BigDecimal(totalSeparateAmount)) - .setScale(0, RoundingMode.HALF_UP).intValue(); + agent1stAmount = calculateAmountWithRatio(effectiveAgent1stRatio, totalSeparateAmount, RoundingMode.HALF_UP); // 确保不超过剩余金额 - if (agent1stAmount > availableAmount) { - agent1stAmount = availableAmount; + if (agent1stAmount > separateAmountForCalculation) { + agent1stAmount = separateAmountForCalculation; } - availableAmount -= agent1stAmount; + separateAmountForCalculation -= agent1stAmount; } // 二级代理商分账(优先级3)- 基于总金额计算 if (hasAgent2nd && effectiveAgent2ndRatio.compareTo(BigDecimal.ZERO) > 0) { - agent2ndAmount = effectiveAgent2ndRatio.multiply(new BigDecimal(totalSeparateAmount)) - .setScale(0, RoundingMode.HALF_UP).intValue(); + agent2ndAmount = calculateAmountWithRatio(effectiveAgent2ndRatio, totalSeparateAmount, RoundingMode.HALF_UP); // 确保不超过剩余金额 - if (agent2ndAmount > availableAmount) { - agent2ndAmount = availableAmount; + if (agent2ndAmount > separateAmountForCalculation) { + agent2ndAmount = separateAmountForCalculation; } - availableAmount -= agent2ndAmount; + separateAmountForCalculation -= agent2ndAmount; } // 9. 商家分账(优先级4,获得剩余所有金额) - mchAmount = availableAmount; + mchAmount = separateAmountForCalculation; // 10. 检查商家分账金额是否合法 if (mchAmount < 0) { @@ -497,7 +330,7 @@ public class LklSeparateDTO { SharingCalculationResult calculationResult = new SharingCalculationResult(true, null); calculationResult.setLklAmount(lklAmount); calculationResult.setCanSeparateAmount(canSeparateAmount); - calculationResult.setRefCanSeparateAmount(refCanSeparateAmount); + calculationResult.setRefCanSeparateAmount(this.refCanSeparateAmount); calculationResult.setShippingFee(effectiveShippingFee); calculationResult.setPlatAmount(platAmount); calculationResult.setAgent1stAmount(agent1stAmount); @@ -553,11 +386,7 @@ public class LklSeparateDTO { int amountAfterShipping = totalSeparateAmount - effectiveShippingFee; // 4. 计算拉卡拉分账金额(手续费)= 分账总金额 * 拉卡拉分账比例 - int lklAmount = 0; - if (lklRatio != null && lklRatio.compareTo(BigDecimal.ZERO) > 0) { - lklAmount = lklRatio.multiply(new BigDecimal(totalSeparateAmount)) - .setScale(0, RoundingMode.HALF_UP).intValue(); - } + int lklAmount = calculateAmountWithRatio(lklRatio, totalSeparateAmount, RoundingMode.HALF_UP); // 5. 检查拉卡拉分账金额是否合法 if (lklAmount >= amountAfterShipping) { @@ -571,7 +400,26 @@ public class LklSeparateDTO { } int canSeparateAmount = availableAmount; - int refCanSeparateAmount = availableAmount; + // 记录refCanSeparateAmount相关信息 + System.out.println("基于可分账金额算法 - 可分账金额计算完成: canSeparateAmount=" + canSeparateAmount + + ", refCanSeparateAmount=" + this.refCanSeparateAmount); + + // 6.1 检查refCanSeparateAmount是否为有效值,如果是有效值且与计算出的canSeparateAmount不一致,则使用refCanSeparateAmount作为分账金额 + int separateAmountForCalculation = canSeparateAmount; // 默认使用计算出的可分账金额 + if (this.refCanSeparateAmount != null && this.refCanSeparateAmount > 0 && this.refCanSeparateAmount < totalSeparateAmount) { + // refCanSeparateAmount是非空非零且比totalSeparateAmount小的有效值 + if (!this.refCanSeparateAmount.equals(canSeparateAmount)) { + // 有效值如果和计算出来的canSeparateAmount的值不一致 + separateAmountForCalculation = this.refCanSeparateAmount; // 使用refCanSeparateAmount作为分账算法中的可分金额 + System.out.println("基于可分账金额算法 - 使用refCanSeparateAmount作为分账金额: refCanSeparateAmount=" + + this.refCanSeparateAmount + ", canSeparateAmount=" + canSeparateAmount + + ", 差值=" + (this.refCanSeparateAmount - canSeparateAmount)); + } else { + System.out.println("基于可分账金额算法 - refCanSeparateAmount与canSeparateAmount相等,无需调整"); + } + } else { + System.out.println("基于可分账金额算法 - refCanSeparateAmount无效,使用计算出的canSeparateAmount"); + } // 7. 初始化各分账金额 int platAmount = 0; @@ -579,18 +427,19 @@ public class LklSeparateDTO { int agent2ndAmount = 0; int mchAmount = 0; - // 8. 根据参与方动态调整分账比例 + // 8. 根据参与方动态调整分账比例(基于可分账金额的独立逻辑) BigDecimal effectivePlatRatio = platRatio != null ? platRatio : BigDecimal.ZERO; BigDecimal effectiveAgent1stRatio = agent1stRatio != null ? agent1stRatio : BigDecimal.ZERO; BigDecimal effectiveAgent2ndRatio = agent2ndRatio != null ? agent2ndRatio : BigDecimal.ZERO; + BigDecimal effectiveMchRatio = mchRatio != null ? mchRatio : BigDecimal.ZERO; - // 判断哪些代理商参与分账 + // 判断代理商是否参与分账(在调整比例前进行判断) boolean hasAgent1st = effectiveAgent1stRatio.compareTo(BigDecimal.ZERO) > 0; boolean hasAgent2nd = effectiveAgent2ndRatio.compareTo(BigDecimal.ZERO) > 0; - // 根据商家分账比例动态调整其他方比例 - if (mchRatio != null && mchRatio.compareTo(BigDecimal.ZERO) > 0) { - BigDecimal remainingRatio = BigDecimal.ONE.subtract(mchRatio); + // 根据商家分账比例动态调整其他方比例(独立于基于总金额的算法) + if (effectiveMchRatio.compareTo(BigDecimal.ZERO) > 0) { + BigDecimal remainingRatio = BigDecimal.ONE.subtract(effectiveMchRatio); BigDecimal onePercent = new BigDecimal("0.01"); if (hasAgent1st && hasAgent2nd) { @@ -612,56 +461,57 @@ public class LklSeparateDTO { // 只有平台参与 effectivePlatRatio = remainingRatio; } + + // 重新判断代理商是否参与分账(基于调整后的比例) + hasAgent1st = effectiveAgent1stRatio.compareTo(BigDecimal.ZERO) > 0; + hasAgent2nd = effectiveAgent2ndRatio.compareTo(BigDecimal.ZERO) > 0; } + // 如果商家比例不存在或为0,使用各自设置的固定比例,代理商参与状态已在前面确定 // 9. 按新的优先级顺序计算各分账方金额(基于可分账金额计算) // 商家分账(优先级1)- 基于可分账金额计算,采用向上进位方式 - if (mchRatio != null && mchRatio.compareTo(BigDecimal.ZERO) > 0) { - mchAmount = mchRatio.multiply(new BigDecimal(canSeparateAmount)) - .setScale(0, RoundingMode.UP).intValue(); - // 确保商家分账金额不超过可分账金额 - if (mchAmount > availableAmount) { - mchAmount = availableAmount; + if (effectiveMchRatio.compareTo(BigDecimal.ZERO) > 0) { + mchAmount = calculateAmountWithRatio(effectiveMchRatio, canSeparateAmount, RoundingMode.UP); + // 确保商家分账金额不超过剩余金额 + if (mchAmount > separateAmountForCalculation) { + mchAmount = separateAmountForCalculation; } - availableAmount -= mchAmount; + separateAmountForCalculation -= mchAmount; } // 平台分账(优先级2)- 基于可分账金额计算,采用四舍五入方式 if (effectivePlatRatio.compareTo(BigDecimal.ZERO) > 0) { - platAmount = effectivePlatRatio.multiply(new BigDecimal(canSeparateAmount)) - .setScale(0, RoundingMode.HALF_UP).intValue(); + platAmount = calculateAmountWithRatio(effectivePlatRatio, canSeparateAmount, RoundingMode.HALF_UP); // 确保平台分账金额不超过剩余金额 - if (platAmount > availableAmount) { - platAmount = availableAmount; + if (platAmount > separateAmountForCalculation) { + platAmount = separateAmountForCalculation; } - availableAmount -= platAmount; + separateAmountForCalculation -= platAmount; } // 一级代理商分账(优先级3)- 基于可分账金额计算,采用四舍五入方式 if (hasAgent1st && effectiveAgent1stRatio.compareTo(BigDecimal.ZERO) > 0) { - agent1stAmount = effectiveAgent1stRatio.multiply(new BigDecimal(canSeparateAmount)) - .setScale(0, RoundingMode.HALF_UP).intValue(); + agent1stAmount = calculateAmountWithRatio(effectiveAgent1stRatio, canSeparateAmount, RoundingMode.HALF_UP); // 确保不超过剩余金额 - if (agent1stAmount > availableAmount) { - agent1stAmount = availableAmount; + if (agent1stAmount > separateAmountForCalculation) { + agent1stAmount = separateAmountForCalculation; } - availableAmount -= agent1stAmount; + separateAmountForCalculation -= agent1stAmount; } // 二级代理商分账(优先级4)- 基于可分账金额计算,采用四舍五入方式 if (hasAgent2nd && effectiveAgent2ndRatio.compareTo(BigDecimal.ZERO) > 0) { - agent2ndAmount = effectiveAgent2ndRatio.multiply(new BigDecimal(canSeparateAmount)) - .setScale(0, RoundingMode.HALF_UP).intValue(); + agent2ndAmount = calculateAmountWithRatio(effectiveAgent2ndRatio, canSeparateAmount, RoundingMode.HALF_UP); // 确保不超过剩余金额 - if (agent2ndAmount > availableAmount) { - agent2ndAmount = availableAmount; + if (agent2ndAmount > separateAmountForCalculation) { + agent2ndAmount = separateAmountForCalculation; } - availableAmount -= agent2ndAmount; + separateAmountForCalculation -= agent2ndAmount; } // 10. 如果还有剩余金额,将其分配给商家 - if (availableAmount > 0) { - mchAmount += availableAmount; + if (separateAmountForCalculation > 0) { + mchAmount += separateAmountForCalculation; } // 11. 检查商家分账金额是否合法 @@ -673,7 +523,7 @@ public class LklSeparateDTO { SharingCalculationResult calculationResult = new SharingCalculationResult(true, null); calculationResult.setLklAmount(lklAmount); calculationResult.setCanSeparateAmount(canSeparateAmount); - calculationResult.setRefCanSeparateAmount(refCanSeparateAmount); + calculationResult.setRefCanSeparateAmount(this.refCanSeparateAmount); calculationResult.setShippingFee(effectiveShippingFee); calculationResult.setPlatAmount(platAmount); calculationResult.setAgent1stAmount(agent1stAmount); @@ -683,14 +533,113 @@ public class LklSeparateDTO { return calculationResult; } + /** + * 将分账信息转换为格式化的JSON字符串 + * + * @return JSON格式的字符串 + */ + public String toJSON() { + StringBuilder sb = new StringBuilder(); + sb.append("{"); + + // 基础金额信息 + sb.append("基础金额信息:{"); + sb.append("分账总金额:").append(totalSeparateAmount != null ? totalSeparateAmount : 0).append("分,"); + sb.append("配送费:").append(shippingFee != null ? shippingFee : 0); + sb.append("},"); + + // 分账比例信息 + sb.append("分账比例信息:{"); + sb.append("拉卡拉分账比例:").append(lklRatio != null ? lklRatio.stripTrailingZeros().toPlainString() : "0").append(","); + sb.append("商家分账比例:").append(mchRatio != null ? mchRatio.stripTrailingZeros().toPlainString() : "0").append(","); + sb.append("平台分账比例:").append(platRatio != null ? platRatio.stripTrailingZeros().toPlainString() : "0").append(","); + sb.append("一级代理商分账比例:").append(agent1stRatio != null ? agent1stRatio.stripTrailingZeros().toPlainString() : "0").append(","); + sb.append("二级代理商分账比例:").append(agent2ndRatio != null ? agent2ndRatio.stripTrailingZeros().toPlainString() : "0"); + sb.append("},"); + + // 分账金额结果 + sb.append("分账金额结果:{"); + sb.append("拉卡拉分账金额:").append(lklAmount != null ? lklAmount : 0).append("分,"); + sb.append("可分账金额:").append(canSeparateAmount != null ? canSeparateAmount : 0).append("分,"); + sb.append("参考可分账金额:").append(refCanSeparateAmount != null ? refCanSeparateAmount : 0).append("分,"); + if (canSeparateAmount != null && refCanSeparateAmount != null) { + sb.append("参考可分账差值:").append(refCanSeparateAmount - canSeparateAmount).append("分,"); + } + sb.append("配送费:").append(shippingFee != null ? shippingFee : 0).append("分,"); + sb.append("平台分账金额:").append(platAmount != null ? platAmount : 0).append("分,"); + sb.append("一级代理商分账金额:").append(agent1stAmount != null ? agent1stAmount : 0).append("分,"); + sb.append("二级代理商分账金额:").append(agent2ndAmount != null ? agent2ndAmount : 0).append("分,"); + sb.append("商家分账金额:").append(mchAmount != null ? mchAmount : 0).append("分"); + sb.append("}"); + + sb.append("}"); + return sb.toString(); + } + + /** + * 根据比例计算金额 + * + * @param ratio 比例 + * @param baseAmount 基础金额 + * @param roundingMode 舍入模式 + * @return 计算后的金额 + */ + private int calculateAmountWithRatio(BigDecimal ratio, int baseAmount, RoundingMode roundingMode) { + if (ratio == null || ratio.compareTo(BigDecimal.ZERO) <= 0) { + return 0; + } + return ratio.multiply(new BigDecimal(baseAmount)) + .setScale(0, roundingMode).intValue(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("LklSeparateDTO{"); + + // 基础金额信息 + sb.append("基础金额信息:{"); + sb.append("分账总金额:").append(totalSeparateAmount != null ? totalSeparateAmount : 0).append("分,"); + sb.append("配送费:").append(shippingFee != null ? shippingFee : 0); + sb.append("},"); + + // 分账比例信息 + sb.append("分账比例信息:{"); + sb.append("拉卡拉分账比例:").append(lklRatio != null ? lklRatio.stripTrailingZeros().toPlainString() : "0").append(","); + sb.append("商家分账比例:").append(mchRatio != null ? mchRatio.stripTrailingZeros().toPlainString() : "0").append(","); + sb.append("平台分账比例:").append(platRatio != null ? platRatio.stripTrailingZeros().toPlainString() : "0").append(","); + sb.append("一级代理商分账比例:").append(agent1stRatio != null ? agent1stRatio.stripTrailingZeros().toPlainString() : "0").append(","); + sb.append("二级代理商分账比例:").append(agent2ndRatio != null ? agent2ndRatio.stripTrailingZeros().toPlainString() : "0"); + sb.append("},"); + + // 分账金额结果 + sb.append("分账金额结果:{"); + sb.append("拉卡拉分账金额:").append(lklAmount != null ? lklAmount : 0).append("分,"); + sb.append("可分账金额:").append(canSeparateAmount != null ? canSeparateAmount : 0).append("分,"); + sb.append("参考可分账金额:").append(refCanSeparateAmount != null ? refCanSeparateAmount : 0).append("分,"); + if (canSeparateAmount != null && refCanSeparateAmount != null) { + sb.append("参考可分账差值:").append(refCanSeparateAmount - canSeparateAmount).append("分,"); + } + sb.append("配送费:").append(shippingFee != null ? shippingFee : 0).append("分,"); + sb.append("平台分账金额:").append(platAmount != null ? platAmount : 0).append("分,"); + sb.append("一级代理商分账金额:").append(agent1stAmount != null ? agent1stAmount : 0).append("分,"); + sb.append("二级代理商分账金额:").append(agent2ndAmount != null ? agent2ndAmount : 0).append("分,"); + sb.append("商家分账金额:").append(mchAmount != null ? mchAmount : 0).append("分"); + sb.append("}"); + + sb.append("}"); + return sb.toString(); + } + /** * 分账结果类,包含分账是否成功以及失败原因 */ - @Data - @EqualsAndHashCode(callSuper = false) public static class SharingResult { - private final boolean success; - private final String errorMessage; + private boolean success; + private String errorMessage; + + public SharingResult() { + } public SharingResult(boolean success, String errorMessage) { this.success = success; @@ -701,6 +650,18 @@ public class LklSeparateDTO { return success; } + public void setSuccess(boolean success) { + this.success = success; + } + + public String getErrorMessage() { + return errorMessage; + } + + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } + @Override public String toString() { return success ? "分账成功" : "分账失败: " + errorMessage; @@ -721,56 +682,20 @@ public class LklSeparateDTO { private Integer agent2ndAmount; // 二级代理商分账金额(分) private Integer mchAmount; // 商户分账金额(分) + public SharingCalculationResult() { + } + public SharingCalculationResult(boolean success, String errorMessage) { super(success, errorMessage); } - public Integer getMchAmount() { - return mchAmount; + // Getters and Setters + public Integer getLklAmount() { + return lklAmount; } - public void setMchAmount(Integer mchAmount) { - this.mchAmount = mchAmount; - } - - public Integer getAgent2ndAmount() { - return agent2ndAmount; - } - - public void setAgent2ndAmount(Integer agent2ndAmount) { - this.agent2ndAmount = agent2ndAmount; - } - - public Integer getAgent1stAmount() { - return agent1stAmount; - } - - public void setAgent1stAmount(Integer agent1stAmount) { - this.agent1stAmount = agent1stAmount; - } - - public Integer getPlatAmount() { - return platAmount; - } - - public void setPlatAmount(Integer platAmount) { - this.platAmount = platAmount; - } - - public Integer getShippingFee() { - return shippingFee; - } - - public void setShippingFee(Integer shippingFee) { - this.shippingFee = shippingFee; - } - - public Integer getRefCanSeparateAmount() { - return refCanSeparateAmount; - } - - public void setRefCanSeparateAmount(Integer refCanSeparateAmount) { - this.refCanSeparateAmount = refCanSeparateAmount; + public void setLklAmount(Integer lklAmount) { + this.lklAmount = lklAmount; } public Integer getCanSeparateAmount() { @@ -781,12 +706,52 @@ public class LklSeparateDTO { this.canSeparateAmount = canSeparateAmount; } - public Integer getLklAmount() { - return lklAmount; + public Integer getRefCanSeparateAmount() { + return refCanSeparateAmount; } - public void setLklAmount(Integer lklAmount) { - this.lklAmount = lklAmount; + public void setRefCanSeparateAmount(Integer refCanSeparateAmount) { + this.refCanSeparateAmount = refCanSeparateAmount; + } + + public Integer getShippingFee() { + return shippingFee; + } + + public void setShippingFee(Integer shippingFee) { + this.shippingFee = shippingFee; + } + + public Integer getPlatAmount() { + return platAmount; + } + + public void setPlatAmount(Integer platAmount) { + this.platAmount = platAmount; + } + + public Integer getAgent1stAmount() { + return agent1stAmount; + } + + public void setAgent1stAmount(Integer agent1stAmount) { + this.agent1stAmount = agent1stAmount; + } + + public Integer getAgent2ndAmount() { + return agent2ndAmount; + } + + public void setAgent2ndAmount(Integer agent2ndAmount) { + this.agent2ndAmount = agent2ndAmount; + } + + public Integer getMchAmount() { + return mchAmount; + } + + public void setMchAmount(Integer mchAmount) { + this.mchAmount = mchAmount; } } -} +} \ No newline at end of file diff --git a/mall-common/src/main/java/com/suisung/mall/common/pojo/dto/LklSeparateDTOBak.java b/mall-common/src/main/java/com/suisung/mall/common/pojo/dto/LklSeparateDTOBak.java deleted file mode 100644 index 1038f51b..00000000 --- a/mall-common/src/main/java/com/suisung/mall/common/pojo/dto/LklSeparateDTOBak.java +++ /dev/null @@ -1,849 +0,0 @@ -package com.suisung.mall.common.pojo.dto; - -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.Data; -import lombok.EqualsAndHashCode; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.data.util.Pair; - -import java.math.BigDecimal; -import java.math.RoundingMode; - -/** - * 拉卡拉订单分账信息对象 - *

- * 分账计算支持两种模式: - * 1. 基于可分账金额模式(默认):先扣除拉卡拉手续费和配送费,再对剩余金额进行分账 - * 2. 基于总金额模式:基于总分账金额进行分账计算 - *

- * 分账优先级顺序:拉卡拉 > 平台 > 一级代理商 > 二级代理商 > 商户 - * 商户作为最后分账方,其金额为剩余金额,不强制遵循分账比例 - */ -@Data -@EqualsAndHashCode(callSuper = false) -@ApiModel(value = "拉卡拉订单分账信息对象", description = "拉卡拉订单分账信息对象") -public class LklSeparateDTOBak implements java.io.Serializable { - private static final Logger logger = LoggerFactory.getLogger(LklSeparateDTOBak.class); - - private static final long serialVersionUID = 1L; - - // ================================ 基础金额属性 ================================ - - @ApiModelProperty(value = "分账总金额(分)") - private Integer totalSeparateAmount; - - @ApiModelProperty(value = "可分账金额(分)") - private Integer canSeparateAmount; - - @ApiModelProperty(value = "拉卡拉参考可分账金额(分)") - private Integer refCanSeparateAmount; - - @ApiModelProperty(value = "配送费(分)") - private Integer shippingFee; - - // ================================ 分账比例属性 ================================ - - @ApiModelProperty(value = "拉卡拉分账比例(如 0.0025=0.25%)") - private BigDecimal lklRatio; - - @ApiModelProperty(value = "商户分账比例(如 0.96=96%)") - private BigDecimal mchRatio; - - @ApiModelProperty(value = "平台分账比例(如 0.01=1%)") - private BigDecimal platRatio; - - @ApiModelProperty(value = "一级代理商分账比例(如 0.01=1%)") - private BigDecimal agent1stRatio; - - @ApiModelProperty(value = "二级代理商分账比例(如 0.03=3%)") - private BigDecimal agent2ndRatio; - - // ================================ 分账金额结果属性 ================================ - - @ApiModelProperty(value = "拉卡拉分账金额(分)") - private Integer lklAmount; - - @ApiModelProperty(value = "商户分账金额(分)") - private Integer mchAmount; - - @ApiModelProperty(value = "平台分账金额(分)") - private Integer platAmount; - - @ApiModelProperty(value = "一级代理商分账金额(分)") - private Integer agent1stAmount; - - @ApiModelProperty(value = "二级代理商分账金额(分)") - private Integer agent2ndAmount; - - // ================================ 内部状态属性 ================================ - - /** - * 分账计算方法类型 - * true表示基于总金额分账(calcOnTotalAmount方法被调用) - * false表示基于可分账金额分账(calcOnCanAmount方法被调用) - */ - private boolean isBasedOnTotalAmount = false; - - // ================================ 构造方法 ================================ - - public LklSeparateDTOBak() { - // 默认构造函数 - } - - // ================================ 公共方法 ================================ - - /** - * 测试方法 - */ - public static void main(String[] args) { - logger.info("开始测试分账计算功能..."); - - // 临界点测试用例2: 小金额测试 - logger.info("\n临界点测试用例2 - 小金额测试:"); - LklSeparateDTOBak dto2 = new LklSeparateDTOBak(); - dto2.setTotalSeparateAmount(800); - dto2.setShippingFee(600); - dto2.setLklRatio(new BigDecimal("0.0025")); - dto2.setMchRatio(new BigDecimal("0.96")); - dto2.setPlatRatio(new BigDecimal("0.04")); - dto2.setBasedOnTotalAmount(true); - -// dto2.setAgent1stRatio(new BigDecimal("0.01")); -// dto2.setAgent2ndRatio(new BigDecimal("0.04")); -// dto2.setRefCanSeparateAmount(8079); // 设置参考可分账金额 - - logger.info("测试参数: 总分账金额={}分, 配送费={}分, 拉卡拉比例={}, 商户比例={}, 平台比例={}", - dto2.getTotalSeparateAmount(), dto2.getShippingFee(), dto2.getLklRatio(), - dto2.getMchRatio(), dto2.getPlatRatio()); - - Pair result2 = dto2.calcOnCanSeparateAmount(); - logger.info("分账计算结果: {}", (result2.getFirst() ? "成功" : "失败")); - if (result2.getFirst()) { - logger.info("分账结果: 总金额={}分, 拉卡拉={}分, 配送费={}分, 可分账={}分, 参考可分账={}分, 商户={}分, 平台={}分, 一级代理商={}分, 二级代理商={}分", - dto2.getTotalSeparateAmount(), dto2.getLklAmount(), dto2.getShippingFee(), dto2.getCanSeparateAmount(), dto2.getRefCanSeparateAmount(), - dto2.getMchAmount(), dto2.getPlatAmount(), dto2.getAgent1stAmount(), dto2.getAgent2ndAmount()); - - // 计算并打印各分账方占可分账金额和总金额的百分比 - int canSeparateAmount = dto2.getCanSeparateAmount(); - int totalSeparateAmount = dto2.getTotalSeparateAmount(); - - if (canSeparateAmount > 0) { - double lklRatioOfTotal = (double) dto2.getLklAmount() / totalSeparateAmount * 100; - double mchRatioOfTotal = (double) dto2.getMchAmount() / totalSeparateAmount * 100; - double platRatioOfTotal = (double) dto2.getPlatAmount() / totalSeparateAmount * 100; - double agent1stRatioOfTotal = 0.0; - double agent2ndRatioOfTotal = 0.0; - - // 安全检查,避免空指针异常 - if (dto2.getAgent1stAmount() != null) { - agent1stRatioOfTotal = (double) dto2.getAgent1stAmount() / totalSeparateAmount * 100; - } - if (dto2.getAgent2ndAmount() != null) { - agent2ndRatioOfTotal = (double) dto2.getAgent2ndAmount() / totalSeparateAmount * 100; - } - - double lklRatioOfAvailable = (double) dto2.getLklAmount() / canSeparateAmount * 100; - double mchRatioOfAvailable = (double) dto2.getMchAmount() / canSeparateAmount * 100; - double platRatioOfAvailable = (double) dto2.getPlatAmount() / canSeparateAmount * 100; - double agent1stRatioOfAvailable = 0.0; - double agent2ndRatioOfAvailable = 0.0; - - // 安全检查,避免空指针异常 - if (dto2.getAgent1stAmount() != null) { - agent1stRatioOfAvailable = (double) dto2.getAgent1stAmount() / canSeparateAmount * 100; - } - if (dto2.getAgent2ndAmount() != null) { - agent2ndRatioOfAvailable = (double) dto2.getAgent2ndAmount() / canSeparateAmount * 100; - } - - logger.info("占比详情 (占总金额/占可分账金额): 拉卡拉={}%/{}%, 商户={}%/{}%, 平台={}%/{}%, 一级代理商={}%/{}%, 二级代理商={}%/{}%", - String.format("%.2f", lklRatioOfTotal), String.format("%.2f", lklRatioOfAvailable), - String.format("%.2f", mchRatioOfTotal), String.format("%.2f", mchRatioOfAvailable), - String.format("%.2f", platRatioOfTotal), String.format("%.2f", platRatioOfAvailable), - String.format("%.2f", agent1stRatioOfTotal), String.format("%.2f", agent1stRatioOfAvailable), - String.format("%.2f", agent2ndRatioOfTotal), String.format("%.2f", agent2ndRatioOfAvailable)); - } - - int total = dto2.getLklAmount() + dto2.getMchAmount() + dto2.getPlatAmount() + - (dto2.getAgent1stAmount() != null ? dto2.getAgent1stAmount() : 0) + - (dto2.getAgent2ndAmount() != null ? dto2.getAgent2ndAmount() : 0) + dto2.getShippingFee(); - logger.info("金额校验: {} (计算总金额={}分, 原始总金额={}分)", (total == dto2.getTotalSeparateAmount() ? "通过" : "不通过"), total, dto2.getTotalSeparateAmount()); - } - } - - /** - * 基于可分账金额的分账计算方法(默认) - *

- * 计算逻辑: - * 1. 计算拉卡拉分账金额 = 总分账金额 × 拉卡拉分账比例(向上取整) - * 2. 计算可分账金额 = 总分账金额 - 配送费 - 拉卡拉分账金额 - * 3. 如果refCanSeparateAmount有效且与计算出的canSeparateAmount不一致,则使用refCanSeparateAmount作为分账基数 - * 4. 调整分账比例,确保有效比例之和等于1.0 - * 5. 按优先级计算各参与方分账金额(商户 > 平台 > 一级代理商 > 二级代理商) - * 6. 确保总额平衡并保障各参与方分账比例 - * - * @return Pair 分账结果是否成功和失败的原因 - */ - public Pair calcOnCanSeparateAmount() { - // 设置分账计算方法类型 - isBasedOnTotalAmount = false; - - // 检查前提条件 - if (!validateInputs()) { - return Pair.of(false, "分账参数不全"); - } - - logger.info("开始基于可分账金额的分账计算,总金额={}分,配送费={}分", totalSeparateAmount, shippingFee); - - // 计算拉卡拉分账金额 - calculateLklAmount(); - - // 计算可分账金额 - calculateCanSeparateAmount(); - if (canSeparateAmount <= 0) { - String errorMsg = "分账计算失败:可分账金额必须大于0,当前值=" + canSeparateAmount; - logger.info(errorMsg); - return Pair.of(false, errorMsg); - } - - // 检查并应用参考可分账金额 - checkAndApplyRefCanSeparateAmount(); - - // 调整分账比例 - adjustRatios(); - - // 按优先级分账 - performSeparate(); - - // 确保总额平衡 - balanceAmounts(); - - // 保障各参与方分账比例 - guaranteeRatios(); - - String successMsg = String.format("基于可分账金额的分账计算完成:拉卡拉=%d分, 平台=%d分, 一级代理商=%d分, 二级代理商=%d分, 商户=%d分", - lklAmount, platAmount, agent1stAmount, agent2ndAmount, mchAmount); - logger.info(successMsg); - return Pair.of(true, successMsg); - } - - /** - * 基于总金额的分账计算方法 - *

- * 计算逻辑: - * 1. 计算拉卡拉分账金额 = 总分账金额 × 拉卡拉分账比例(四舍五入保留两位小数) - * 2. 计算可分账金额 = 总分账金额 - 配送费 - 拉卡拉分账金额 - * 3. 如果refCanSeparateAmount有效且与计算出的canSeparateAmount不一致,则使用refCanSeparateAmount作为分账基数 - * 4. 调整分账比例,确保有效比例之和等于1.0 - * 5. 按优先级计算各参与方分账金额(平台 > 一级代理商 > 二级代理商 > 商户),基于可分账金额进行分账 - * 6. 确保总额平衡并保障各参与方分账比例 - * - * @return Pair 分账结果是否成功和失败的原因 - */ - public Pair calcOnTotalAmount() { - // 设置分账计算方法类型 - isBasedOnTotalAmount = true; - - // 检查前提条件 - if (!validateInputsForTotalAmount()) { - return Pair.of(false, "分账参数不全"); - } - - logger.info("开始基于总金额的分账计算,总金额={}分,配送费={}分", totalSeparateAmount, shippingFee); - - // 计算拉卡拉分账金额 - calculateLklAmount(); - - // 计算可分账金额 - calculateCanSeparateAmount(); - if (canSeparateAmount <= 0) { - String errorMsg = "基于总金额的分账计算失败:可分账金额必须大于0,当前值=" + canSeparateAmount; - logger.info(errorMsg); - return Pair.of(false, errorMsg); - } - - // 调整分账比例 - adjustRatios(); - - // 检查并应用参考可分账金额 - checkAndApplyRefCanSeparateAmount(); - - // 按优先级分账(基于总金额) - performSeparateBasedOnTotalAmount(); - - // 确保总额平衡 - balanceAmounts(); - - // 保障各参与方分账比例(忽略商户比例保障) - guaranteeRatiosForTotalAmount(); - - String successMsg = String.format("基于总金额的分账计算完成:拉卡拉=%d分, 平台=%d分, 一级代理商=%d分, 二级代理商=%d分, 商户=%d分", - lklAmount, platAmount, agent1stAmount, agent2ndAmount, mchAmount); - logger.info(successMsg); - return Pair.of(true, successMsg); - } - - /** - * 输出具体的分账结果 - * - * @return 分账结果字符串 - */ - @Override - public String toString() { - int canSeparateAmount = getCanSeparateAmount(); - int totalSeparateAmount = getTotalSeparateAmount(); - - // 计算各分账方占总金额和可分账金额的百分比 - double lklRatioOfTotal = 0.0; - double mchRatioOfTotal = 0.0; - double platRatioOfTotal = 0.0; - double agent1stRatioOfTotal = 0.0; - double agent2ndRatioOfTotal = 0.0; - double shippingFeeRatioOfTotal = 0.0; - - double lklRatioOfAvailable = 0.0; - double mchRatioOfAvailable = 0.0; - double platRatioOfAvailable = 0.0; - double agent1stRatioOfAvailable = 0.0; - double agent2ndRatioOfAvailable = 0.0; - double shippingFeeRatioOfAvailable = 0.0; - - if (totalSeparateAmount > 0) { - if (getLklAmount() != null) { - lklRatioOfTotal = (double) getLklAmount() / totalSeparateAmount * 100; - } - if (getMchAmount() != null) { - mchRatioOfTotal = (double) getMchAmount() / totalSeparateAmount * 100; - } - if (getPlatAmount() != null) { - platRatioOfTotal = (double) getPlatAmount() / totalSeparateAmount * 100; - } - if (getAgent1stAmount() != null) { - agent1stRatioOfTotal = (double) getAgent1stAmount() / totalSeparateAmount * 100; - } - if (getAgent2ndAmount() != null) { - agent2ndRatioOfTotal = (double) getAgent2ndAmount() / totalSeparateAmount * 100; - } - if (getShippingFee() != null) { - shippingFeeRatioOfTotal = (double) getShippingFee() / totalSeparateAmount * 100; - } - } - - if (canSeparateAmount > 0) { - if (getLklAmount() != null) { - lklRatioOfAvailable = (double) getLklAmount() / canSeparateAmount * 100; - } - if (getMchAmount() != null) { - mchRatioOfAvailable = (double) getMchAmount() / canSeparateAmount * 100; - } - if (getPlatAmount() != null) { - platRatioOfAvailable = (double) getPlatAmount() / canSeparateAmount * 100; - } - if (getAgent1stAmount() != null) { - agent1stRatioOfAvailable = (double) getAgent1stAmount() / canSeparateAmount * 100; - } - if (getAgent2ndAmount() != null) { - agent2ndRatioOfAvailable = (double) getAgent2ndAmount() / canSeparateAmount * 100; - } - if (getShippingFee() != null) { - shippingFeeRatioOfAvailable = (double) getShippingFee() / canSeparateAmount * 100; - } - } - - String calculationMethod = isBasedOnTotalAmount ? "基于总交易额方式计算" : "基于可分账额方式计算"; - - return String.format("分账结果%s,总交易额=%d分, 可分账额=%d分, 拉卡拉手续费=%d分(%.2f%%/%.2f%%), 配送费=%d分(%.2f%%/%.2f%%), 商户=%d分(%.2f%%/%.2f%%), 平台=%d分(%.2f%%/%.2f%%), 一级代理商=%d分(%.2f%%/%.2f%%), 二级代理商=%d分(%.2f%%/%.2f%%)", - calculationMethod, - totalSeparateAmount, - canSeparateAmount, - getLklAmount() != null ? getLklAmount() : 0, - lklRatioOfTotal, lklRatioOfAvailable, - getShippingFee() != null ? getShippingFee() : 0, - shippingFeeRatioOfTotal, shippingFeeRatioOfAvailable, - getMchAmount() != null ? getMchAmount() : 0, - mchRatioOfTotal, mchRatioOfAvailable, - getPlatAmount() != null ? getPlatAmount() : 0, - platRatioOfTotal, platRatioOfAvailable, - getAgent1stAmount() != null ? getAgent1stAmount() : 0, - agent1stRatioOfTotal, agent1stRatioOfAvailable, - getAgent2ndAmount() != null ? getAgent2ndAmount() : 0, - agent2ndRatioOfTotal, agent2ndRatioOfAvailable); - } - - /** - * 将对象转换为JSON字符串格式 - * - * @return 包含所有属性的JSON字符串 - */ - public String toJSON() { - StringBuilder json = new StringBuilder(); - json.append("{"); - - // 添加基本属性 - appendProperty(json, "totalSeparateAmount", totalSeparateAmount, true); - appendProperty(json, "canSeparateAmount", canSeparateAmount, false); - appendProperty(json, "refCanSeparateAmount", refCanSeparateAmount, false); - appendProperty(json, "shippingFee", shippingFee, false); - - // 添加比例属性 - appendProperty(json, "lklRatio", lklRatio, false); - appendProperty(json, "mchRatio", mchRatio, false); - appendProperty(json, "platRatio", platRatio, false); - appendProperty(json, "agent1stRatio", agent1stRatio, false); - appendProperty(json, "agent2ndRatio", agent2ndRatio, false); - - // 添加金额属性 - appendProperty(json, "lklAmount", lklAmount, false); - appendProperty(json, "mchAmount", mchAmount, false); - appendProperty(json, "platAmount", platAmount, false); - appendProperty(json, "agent1stAmount", agent1stAmount, false); - appendProperty(json, "agent2ndAmount", agent2ndAmount, false); - - // 移除最后的逗号并关闭JSON对象 - if (json.charAt(json.length() - 1) == ',') { - json.setLength(json.length() - 1); - } - json.append("}"); - - return json.toString(); - } - - // ================================ 私有方法 ================================ - - /** - * 验证基于可分账金额分账的输入参数 - */ - private boolean validateInputs() { - if (totalSeparateAmount == null || totalSeparateAmount <= 0) { - logger.info("分账计算失败:分账总金额必须大于0,当前值={}", totalSeparateAmount); - return false; - } - - if (shippingFee == null || shippingFee < 0) { - logger.info("分账计算失败:配送费不能小于0,当前值={}", shippingFee); - return false; - } - - if (lklRatio == null || lklRatio.compareTo(BigDecimal.ZERO) <= 0) { - logger.info("分账计算失败:拉卡拉分账比例必须大于0,当前值={}", lklRatio); - return false; - } - - if (mchRatio == null || mchRatio.compareTo(BigDecimal.ZERO) <= 0) { - logger.info("分账计算失败:商户分账比例必须大于0,当前值={}", mchRatio); - return false; - } - - if (platRatio == null || platRatio.compareTo(BigDecimal.ZERO) <= 0) { - logger.info("分账计算失败:平台分账比例必须大于0,当前值={}", platRatio); - return false; - } - - return true; - } - - /** - * 验证基于总金额分账的输入参数 - */ - private boolean validateInputsForTotalAmount() { - // 基于总金额的分账计算参数验证与基于可分账金额的验证相同 - return validateInputs(); - } - - /** - * 计算拉卡拉分账金额 - */ - private void calculateLklAmount() { - BigDecimal lklAmountDecimal = new BigDecimal(totalSeparateAmount).multiply(lklRatio); - lklAmount = lklAmountDecimal.setScale(2, RoundingMode.HALF_UP).intValue(); - logger.debug("拉卡拉分账计算:总金额{} × 拉卡拉比例{} = {},四舍五入保留两位小数后={}", - totalSeparateAmount, lklRatio, lklAmountDecimal, lklAmount); - } - - /** - * 计算可分账金额 - */ - private void calculateCanSeparateAmount() { - canSeparateAmount = totalSeparateAmount - shippingFee - lklAmount; - logger.debug("可分账金额计算:总金额{} - 配送费{} - 拉卡拉分账{} = {}", - totalSeparateAmount, shippingFee, lklAmount, canSeparateAmount); - } - - /** - * 检查refCanSeparateAmount是否有效 - * 有效条件:非空且大于0且小于totalSeparateAmount - * - * @return true表示有效,false表示无效 - */ - private boolean isRefCanSeparateAmountValid() { - return refCanSeparateAmount != null && refCanSeparateAmount > 0 && refCanSeparateAmount < totalSeparateAmount; - } - - /** - * 获取分账基数金额 - * 如果refCanSeparateAmount有效,则使用refCanSeparateAmount,否则使用canSeparateAmount - * - * @return 分账基数金额 - */ - private int getSeparateBaseAmount() { - if (isRefCanSeparateAmountValid()) { - return refCanSeparateAmount; - } - return canSeparateAmount; - } - - /** - * 检查并应用参考可分账金额 - * 当refCanSeparateAmount有效且与计算出的canSeparateAmount不一致时, - * 将差额分配给指定优先级的分账对象(平台 > 一级代理商 > 二级代理商 > 商户) - */ - private void checkAndApplyRefCanSeparateAmount() { - // 判断refCanSeparateAmount是否有效(非空且大于0且小于totalSeparateAmount) - if (isRefCanSeparateAmountValid()) { - // 比较refCanSeparateAmount与计算出的canSeparateAmount - if (!refCanSeparateAmount.equals(canSeparateAmount)) { - int difference = refCanSeparateAmount - canSeparateAmount; - logger.info("检测到refCanSeparateAmount与计算出的canSeparateAmount不一致,差额={}分。" + - "refCanSeparateAmount={}分,计算出的canSeparateAmount={}分。", - difference, refCanSeparateAmount, canSeparateAmount); - - // 将差额分配给指定优先级的分账对象(商户 > 二级代理商 > 一级代理商 > 平台) - if (difference != 0) { - if (mchAmount == null) mchAmount = 0; - if (agent2ndAmount == null) agent2ndAmount = 0; - if (agent1stAmount == null) agent1stAmount = 0; - if (platAmount == null) platAmount = 0; - - if (difference > 0) { - // 如果差额为正,优先增加高优先级参与方的金额 - mchAmount += difference; - } else { - // 如果差额为负,优先从低优先级参与方扣除 - int diff = -difference; - if (mchAmount >= diff) { - mchAmount -= diff; - } else if (agent2ndAmount > 0 && agent2ndAmount >= diff) { - agent2ndAmount -= diff; - } else if (agent1stAmount > 0 && agent1stAmount >= diff) { - agent1stAmount -= diff; - } else { - platAmount -= diff; - } - } - logger.debug("已将差额{}分应用于分账金额调整", difference); - } - } else { - logger.debug("refCanSeparateAmount与计算出的canSeparateAmount一致,值={}分", canSeparateAmount); - } - } else { - logger.debug("refCanSeparateAmount无效或未设置,使用计算出的canSeparateAmount={}分作为分账基数", canSeparateAmount); - } - } - - /** - * 调整分账比例,确保有效值比例相加等于1.0 - */ - private void adjustRatios() { - // 计算有效的分账比例总和 - BigDecimal effectiveRatioSum = BigDecimal.ZERO - .add(mchRatio) - .add(platRatio) - .add(agent1stRatio != null ? agent1stRatio : BigDecimal.ZERO) - .add(agent2ndRatio != null ? agent2ndRatio : BigDecimal.ZERO); - - logger.debug("调整前各分账比例:商户={},平台={},一级代理商={},二级代理商={},有效比例总和={}", - mchRatio, platRatio, agent1stRatio, agent2ndRatio, effectiveRatioSum); - - // 动态调整最后一个分账方的比例,确保总和为1.0 - BigDecimal adjustmentRatio = BigDecimal.ONE.subtract(effectiveRatioSum); - if (agent2ndRatio != null && agent2ndRatio.compareTo(BigDecimal.ZERO) > 0) { - // 调整二级代理商比例 - agent2ndRatio = agent2ndRatio.add(adjustmentRatio); - } else if (agent1stRatio != null && agent1stRatio.compareTo(BigDecimal.ZERO) > 0) { - // 调整一级代理商比例 - agent1stRatio = agent1stRatio.add(adjustmentRatio); - } else { - // 调整平台比例 - platRatio = platRatio.add(adjustmentRatio); - } - - logger.debug("调整后各分账比例:商户={},平台={},一级代理商={},二级代理商={}", - mchRatio, platRatio, agent1stRatio, agent2ndRatio); - } - - /** - * 按优先级进行分账(基于可分账金额) - */ - private void performSeparate() { - // 确定分账基数 - int separateBaseAmount = getSeparateBaseAmount(); - - // 商户分账金额 = 可分账金额 × 商户分账比例(四舍五入) - BigDecimal mchAmountDecimal = new BigDecimal(separateBaseAmount).multiply(mchRatio); - mchAmount = mchAmountDecimal.setScale(0, RoundingMode.HALF_UP).intValue(); - logger.debug("商户分账计算:可分账金额{} × 商户比例{} = {},四舍五入后={}", separateBaseAmount, mchRatio, mchAmountDecimal, mchAmount); - - // 平台分账金额 = 可分账金额 × 平台分账比例(四舍五入) - BigDecimal platAmountDecimal = new BigDecimal(separateBaseAmount).multiply(platRatio); - platAmount = platAmountDecimal.setScale(0, RoundingMode.HALF_UP).intValue(); - logger.debug("平台分账计算:可分账金额{} × 平台比例{} = {},四舍五入后={}", separateBaseAmount, platRatio, platAmountDecimal, platAmount); - - // 一级代理商分账金额 = 可分账金额 × 一级代理商分账比例(四舍五入) - if (agent1stRatio != null && agent1stRatio.compareTo(BigDecimal.ZERO) > 0) { - BigDecimal agent1stAmountDecimal = new BigDecimal(separateBaseAmount).multiply(agent1stRatio); - agent1stAmount = agent1stAmountDecimal.setScale(0, RoundingMode.HALF_UP).intValue(); - logger.debug("一级代理商分账计算:可分账金额{} × 一级代理商比例{} = {},四舍五入后={}", separateBaseAmount, agent1stRatio, agent1stAmountDecimal, agent1stAmount); - } else { - agent1stAmount = 0; - } - - // 二级代理商分账金额 = 可分账金额 × 二级代理商分账比例(四舍五入) - if (agent2ndRatio != null && agent2ndRatio.compareTo(BigDecimal.ZERO) > 0) { - BigDecimal agent2ndAmountDecimal = new BigDecimal(separateBaseAmount).multiply(agent2ndRatio); - agent2ndAmount = agent2ndAmountDecimal.setScale(0, RoundingMode.HALF_UP).intValue(); - logger.debug("二级代理商分账计算:可分账金额{} × 二级代理商比例{} = {},四舍五入后={}", separateBaseAmount, agent2ndRatio, agent2ndAmountDecimal, agent2ndAmount); - } else { - agent2ndAmount = 0; - } - } - - /** - * 按优先级进行分账(基于总金额) - */ - private void performSeparateBasedOnTotalAmount() { - // 确定分账基数 - int separateBaseAmount = getSeparateBaseAmount(); - - // 平台分账金额 = 可分账金额 × 平台分账比例(四舍五入) - BigDecimal platAmountDecimal = new BigDecimal(separateBaseAmount).multiply(platRatio); - platAmount = platAmountDecimal.setScale(0, RoundingMode.HALF_UP).intValue(); - logger.debug("平台分账计算:可分账金额{} × 平台比例{} = {},四舍五入后={}", separateBaseAmount, platRatio, platAmountDecimal, platAmount); - - // 一级代理商分账金额 = 可分账金额 × 一级代理商分账比例(四舍五入) - if (agent1stRatio != null && agent1stRatio.compareTo(BigDecimal.ZERO) > 0) { - BigDecimal agent1stAmountDecimal = new BigDecimal(separateBaseAmount).multiply(agent1stRatio); - agent1stAmount = agent1stAmountDecimal.setScale(0, RoundingMode.HALF_UP).intValue(); - logger.debug("一级代理商分账计算:可分账金额{} × 一级代理商比例{} = {},四舍五入后={}", separateBaseAmount, agent1stRatio, agent1stAmountDecimal, agent1stAmount); - } else { - agent1stAmount = 0; - } - - // 二级代理商分账金额 = 可分账金额 × 二级代理商分账比例(四舍五入) - if (agent2ndRatio != null && agent2ndRatio.compareTo(BigDecimal.ZERO) > 0) { - BigDecimal agent2ndAmountDecimal = new BigDecimal(separateBaseAmount).multiply(agent2ndRatio); - agent2ndAmount = agent2ndAmountDecimal.setScale(0, RoundingMode.HALF_UP).intValue(); - logger.debug("二级代理商分账计算:可分账金额{} × 二级代理商比例{} = {},四舍五入后={}", separateBaseAmount, agent2ndRatio, agent2ndAmountDecimal, agent2ndAmount); - } else { - agent2ndAmount = 0; - } - - // 商户分账金额 = 可分账金额 - 平台分账金额 - 一级代理商分账金额 - 二级代理商分账金额 - mchAmount = separateBaseAmount - platAmount - agent1stAmount - agent2ndAmount; - logger.debug("商户分账计算:可分账金额{} - 平台分账{} - 一级代理商分账{} - 二级代理商分账{} = {}", - separateBaseAmount, platAmount, agent1stAmount, agent2ndAmount, mchAmount); - } - - /** - * 确保总额平衡 - */ - private void balanceAmounts() { - // 确定分账基数 - int separateBaseAmount = getSeparateBaseAmount(); - - int totalAmount = mchAmount + platAmount + agent1stAmount + agent2ndAmount; - if (totalAmount != separateBaseAmount) { - int diff = separateBaseAmount - totalAmount; - logger.debug("分账总额与可分账金额不符,差额={},开始调整", diff); - - // 将差额分配给优先级最低的参与方,确保总额平衡 - if (mchAmount + diff >= 0) { - mchAmount += diff; - logger.debug("调整商户分账金额:{} + {} = {}", mchAmount - diff, diff, mchAmount); - } else if (agent2ndAmount > 0 && agent2ndAmount + diff >= 0) { - agent2ndAmount += diff; - logger.debug("调整二级代理商分账金额:{} + {} = {}", agent2ndAmount - diff, diff, agent2ndAmount); - } else if (agent1stAmount > 0 && agent1stAmount + diff >= 0) { - agent1stAmount += diff; - logger.debug("调整一级代理商分账金额:{} + {} = {}", agent1stAmount - diff, diff, agent1stAmount); - } else if (platAmount + diff >= 0) { - platAmount += diff; - logger.debug("调整平台分账金额:{} + {} = {}", platAmount - diff, diff, platAmount); - } - } - } - - /** - * 保障各参与方分账比例不低于指定值(基于总金额的分账计算专用) - * 忽略商户比例保障,只保障平台、一级代理商、二级代理商的比例 - */ - private void guaranteeRatiosForTotalAmount() { - // 平台优先级最高 - guaranteePlatformRatio(); - - // 一级代理商优先级次之 - guaranteeAgent1stRatio(); - - // 不保障商户比例,商户只分到剩余余额 - } - - /** - * 保障各参与方分账比例不低于指定值 - */ - private void guaranteeRatios() { - // 商户优先级最高 - guaranteeMerchantRatio(); - - // 平台优先级次之 - guaranteePlatformRatio(); - - // 一级代理商优先级再次之 - guaranteeAgent1stRatio(); - - // 最终验证和调整,确保所有参与方分账比例不低于指定值 - finalGuaranteeMerchantRatio(); - } - - /** - * 保障商户分账比例 - */ - private void guaranteeMerchantRatio() { - // 确定分账基数 - int separateBaseAmount = getSeparateBaseAmount(); - - BigDecimal actualMchRatio = new BigDecimal(mchAmount).divide(new BigDecimal(separateBaseAmount), 6, RoundingMode.HALF_UP); - if (actualMchRatio.compareTo(mchRatio) < 0) { - int requiredMchAmount = mchRatio.multiply(new BigDecimal(separateBaseAmount)).setScale(0, RoundingMode.HALF_UP).intValue(); - int diff = requiredMchAmount - mchAmount; - if (diff > 0) { - logger.debug("商户分账比例不足,需要调整金额={},商户当前金额={},应得金额={}", diff, mchAmount, requiredMchAmount); - - if (agent2ndAmount > 0 && agent2ndAmount >= diff) { - agent2ndAmount -= diff; - mchAmount += diff; - logger.debug("从二级代理商调整{}给商户,调整后:商户={},二级代理商={}", diff, mchAmount, agent2ndAmount); - } else if (agent1stAmount > 0 && agent1stAmount >= diff) { - agent1stAmount -= diff; - mchAmount += diff; - logger.debug("从一级代理商调整{}给商户,调整后:商户={},一级代理商={}", diff, mchAmount, agent1stAmount); - } else if (platAmount >= diff) { - platAmount -= diff; - mchAmount += diff; - logger.debug("从平台调整{}给商户,调整后:商户={},平台={}", diff, mchAmount, platAmount); - } - } - } - } - - /** - * 保障平台分账比例 - */ - private void guaranteePlatformRatio() { - // 确定分账基数 - int separateBaseAmount = getSeparateBaseAmount(); - - BigDecimal actualPlatRatio = new BigDecimal(platAmount).divide(new BigDecimal(separateBaseAmount), 6, RoundingMode.HALF_UP); - if (actualPlatRatio.compareTo(platRatio) < 0) { - int requiredPlatAmount = platRatio.multiply(new BigDecimal(separateBaseAmount)).setScale(0, RoundingMode.HALF_UP).intValue(); - int diff = requiredPlatAmount - platAmount; - if (diff > 0) { - logger.debug("平台分账比例不足,需要调整金额={},平台当前金额={},应得金额={}", diff, platAmount, requiredPlatAmount); - - if (agent2ndAmount > 0 && agent2ndAmount >= diff) { - agent2ndAmount -= diff; - platAmount += diff; - logger.debug("从二级代理商调整{}给平台,调整后:平台={},二级代理商={}", diff, platAmount, agent2ndAmount); - } else if (agent1stAmount > 0 && agent1stAmount >= diff) { - agent1stAmount -= diff; - platAmount += diff; - logger.debug("从一级代理商调整{}给平台,调整后:平台={},一级代理商={}", diff, platAmount, agent1stAmount); - } - } - } - } - - /** - * 保障一级代理商分账比例 - */ - private void guaranteeAgent1stRatio() { - // 确定分账基数 - int separateBaseAmount = getSeparateBaseAmount(); - - if (agent1stRatio != null && agent1stRatio.compareTo(BigDecimal.ZERO) > 0) { - BigDecimal actualAgent1stRatio = new BigDecimal(agent1stAmount).divide(new BigDecimal(separateBaseAmount), 6, RoundingMode.HALF_UP); - if (actualAgent1stRatio.compareTo(agent1stRatio) < 0) { - int requiredAgent1stAmount = agent1stRatio.multiply(new BigDecimal(separateBaseAmount)).setScale(0, RoundingMode.HALF_UP).intValue(); - int diff = requiredAgent1stAmount - agent1stAmount; - if (diff > 0) { - logger.debug("一级代理商分账比例不足,需要调整金额={},一级代理商当前金额={},应得金额={}", diff, agent1stAmount, requiredAgent1stAmount); - - if (agent2ndAmount > 0 && agent2ndAmount >= diff) { - agent2ndAmount -= diff; - agent1stAmount += diff; - logger.debug("从二级代理商调整{}给一级代理商,调整后:一级代理商={},二级代理商={}", diff, agent1stAmount, agent2ndAmount); - } - } - } - } - } - - /** - * 最终保障商户分账比例 - */ - private void finalGuaranteeMerchantRatio() { - // 确定分账基数 - int separateBaseAmount = getSeparateBaseAmount(); - - BigDecimal finalMchRatio = new BigDecimal(mchAmount).divide(new BigDecimal(separateBaseAmount), 6, RoundingMode.HALF_UP); - if (finalMchRatio.compareTo(mchRatio) < 0) { - int requiredMchAmount = mchRatio.multiply(new BigDecimal(separateBaseAmount)).setScale(0, RoundingMode.UP).intValue(); - int diff = requiredMchAmount - mchAmount; - if (diff > 0) { - logger.debug("商户最终分账比例仍不足,需要调整金额={},商户当前金额={},应得金额={}", diff, mchAmount, requiredMchAmount); - - if (agent2ndAmount > 0 && agent2ndAmount >= diff) { - agent2ndAmount -= diff; - mchAmount += diff; - logger.debug("最终调整:从二级代理商调整{}给商户,调整后:商户={},二级代理商={}", diff, mchAmount, agent2ndAmount); - } else { - int remainingDiff = diff - agent2ndAmount; - if (agent1stAmount > 0 && agent1stAmount >= remainingDiff) { - agent1stAmount -= remainingDiff; - mchAmount += diff; - logger.debug("最终调整:从一级代理商调整{}给商户,调整后:商户={},一级代理商={}", remainingDiff, mchAmount, agent1stAmount); - } else { - int remainingDiff2 = remainingDiff - agent1stAmount; - if (platAmount >= remainingDiff2) { - platAmount -= remainingDiff2; - mchAmount += diff; - logger.debug("最终调整:从平台调整{}给商户,调整后:商户={},平台={}", remainingDiff2, mchAmount, platAmount); - } - } - } - } - } - } - - /** - * 向JSON字符串中添加属性 - * - * @param json StringBuilder对象 - * @param key 属性名 - * @param value 属性值 - * @param first 是否为第一个属性 - */ - private void appendProperty(StringBuilder json, String key, Object value, boolean first) { - if (!first) { - json.append(","); - } - json.append("\"").append(key).append("\":"); - if (value == null) { - json.append("null"); - } else if (value instanceof String) { - json.append("\"").append(value).append("\""); - } else { - json.append(value); - } - } -} \ No newline at end of file diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/components/quartz/job/UpdateOrderSeparateJob.java b/mall-shop/src/main/java/com/suisung/mall/shop/components/quartz/job/UpdateOrderSeparateJob.java new file mode 100644 index 00000000..2a01e4b0 --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/components/quartz/job/UpdateOrderSeparateJob.java @@ -0,0 +1,26 @@ +package com.suisung.mall.shop.components.quartz.job; + +import com.suisung.mall.shop.config.SpringUtil; +import com.suisung.mall.shop.lakala.service.LakalaApiService; +import org.quartz.JobExecutionContext; +import org.quartz.JobExecutionException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.scheduling.quartz.QuartzJobBean; + +/** + * 分账状态更改补偿 定时任务 + */ +public class UpdateOrderSeparateJob extends QuartzJobBean { + + private static final Logger logger = LoggerFactory.getLogger(UpdateOrderSeparateJob.class); + + @Override + protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException { + LakalaApiService lakalaApiService = SpringUtil.getBean(LakalaApiService.class); + + // lakalaApiService.fixedOrderSeparateStatus(); + + } + +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/mobile/LakalaController.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/mobile/LakalaController.java index 921fa37a..4c11a08c 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/mobile/LakalaController.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/mobile/LakalaController.java @@ -73,6 +73,10 @@ public class LakalaController extends BaseControllerImpl { @Resource private MqMessageService mqMessageService; + @Lazy + @Resource + private LakalaApiService lakalaApiService; + @Resource private LklLedgerEcService lklLedgerEcService; @@ -110,8 +114,9 @@ public class LakalaController extends BaseControllerImpl { // return shopOrderBaseService.sameCityOrderExpireSeconds(10000L); - return sfExpressApiService.createSfExpressShop(66, "能辉超市", "桂平市", "广西壮族自治区贵港市桂平市广佰汇超市(桂平店)", "谢能坤", "17777525395", "110.07165452271", "23.369069486251"); + // return sfExpressApiService.createSfExpressShop(66, "能辉超市", "桂平市", "广西壮族自治区贵港市桂平市广佰汇超市(桂平店)", "谢能坤", "17777525395", "110.07165452271", "23.369069486251"); + return lakalaApiService.sacsQuery("8226330541100GU", "20250918770188017227140800").toString(); } @ApiOperation(value = "批量发送推送消息 - 测试案例", notes = "批量发送推送消息 - 测试案例") @@ -224,7 +229,7 @@ public class LakalaController extends BaseControllerImpl { @ApiOperation(value = "分账关系绑定申请异步回调通知", notes = "分账关系绑定申请异步回调通知") @RequestMapping(value = "/sacs/separateNotify", method = RequestMethod.POST) public ResponseEntity separateNotify(HttpServletRequest request) { - JSONObject resp = lakalaPayService.sacsSeparateNotify(request); + JSONObject resp = lakalaPayService.sacsSeparateNotify(request, "", ""); if (resp != null && "SUCCESS".equals(resp.get("code"))) { return ResponseEntity.ok(resp); } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LakalaApiService.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LakalaApiService.java index abfdb6b7..5fad2584 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LakalaApiService.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LakalaApiService.java @@ -213,9 +213,11 @@ public interface LakalaApiService { * 参考:https://o.lakala.com/#/home/document/detail?id=393 * * @param request + * @param merchantNo 分账方商户号,非空表示是事后补偿 + * @param separateNo 分账指令流水号,非空表示是事后补偿 * @return */ - JSONObject sacsSeparateNotify(HttpServletRequest request); + JSONObject sacsSeparateNotify(HttpServletRequest request, String merchantNo, String separateNo); /** * 查询拉卡拉商户可分账的金额 @@ -252,6 +254,19 @@ public interface LakalaApiService { */ JSONObject queryMchCanSplitAmtInner(String merchantNo, String logNo, String logDate); + + /** + * 分账查询结果 + *

+ * 用于查询已发起的分账交易的处理结果状态 + * 参考:https://o.lakala.com/#/home/document/detail?id=392 + * + * @param merchantNo 分账方商户号 + * @param separateNo 分账指令流水号 + * @return 分账结果数据,包含分账状态等信息;查询失败时返回null + */ + JSONObject sacsQuery(String merchantNo, String separateNo); + /** * 订单分账撤销 * 参考:https://o.lakala.com/#/home/document/detail?id=390 diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklOrderSeparateService.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklOrderSeparateService.java index 923802f0..567499b6 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklOrderSeparateService.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklOrderSeparateService.java @@ -11,6 +11,9 @@ package com.suisung.mall.shop.lakala.service; import com.suisung.mall.common.modules.lakala.LklOrderSeparate; import com.suisung.mall.core.web.service.IBaseService; +import java.util.Date; +import java.util.List; + public interface LklOrderSeparateService extends IBaseService { /** @@ -58,4 +61,14 @@ public interface LklOrderSeparateService extends IBaseService * @return */ Boolean updateRemark(String logNo, String separateNo, String remark); + + + /** + * 查询未成功分账的记录 + * + * @param + * @return + */ + List unSuccessSeparateList(Date beginDate, Date endDate); + } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LakalaApiServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LakalaApiServiceImpl.java index a5c2db54..1f78f4af 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LakalaApiServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LakalaApiServiceImpl.java @@ -8,7 +8,6 @@ package com.suisung.mall.shop.lakala.service.impl; - import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.convert.Convert; @@ -32,7 +31,7 @@ import com.suisung.mall.common.modules.lakala.*; import com.suisung.mall.common.modules.order.ShopOrderLkl; import com.suisung.mall.common.modules.store.ShopMchEntry; import com.suisung.mall.common.modules.store.ShopStoreBase; -import com.suisung.mall.common.pojo.dto.LklSeparateDTOBak; +import com.suisung.mall.common.pojo.dto.LklSeparateDTO; import com.suisung.mall.common.service.impl.CommonService; import com.suisung.mall.common.utils.*; import com.suisung.mall.shop.lakala.service.*; @@ -1851,6 +1850,77 @@ public class LakalaApiServiceImpl implements LakalaApiService { } } + /** + * 分账查询结果 + *

+ * 用于查询已发起的分账交易的处理结果状态 + * 参考:https://o.lakala.com/#/home/document/detail?id=392 + * + * @param merchantNo 分账方商户号 + * @param separateNo 分账指令流水号 + * @return 分账结果数据,包含分账状态等信息;查询失败时返回null + */ + @Override + public JSONObject sacsQuery(String merchantNo, String separateNo) { + // 1. 参数校验 + if (StrUtil.hasBlank(merchantNo, separateNo)) { + log.warn("[分账查询结果] 参数缺失, merchantNo={}, separateNo={}", merchantNo, separateNo); + return null; + } + + try { + // 2. 初始化拉卡拉SDK配置 + initLKLSDK(); + + // 3. 构造请求参数 + V3SacsQueryRequest v3QueryRequest = new V3SacsQueryRequest(); + v3QueryRequest.setMerchantNo(merchantNo); + v3QueryRequest.setSeparateNo(separateNo); + + // 4. 发送HTTP请求到拉卡拉服务器 + String responseStr = LKLSDK.httpPost(v3QueryRequest); + + // 5. 检查响应结果 + if (StrUtil.isBlank(responseStr)) { + log.warn("[分账查询结果] 服务器无返回值, merchantNo={}, separateNo={}", merchantNo, separateNo); + return null; + } + + // 6. 解析响应JSON + JSONObject lakalaRespJSON = JSONUtil.parseObj(responseStr); + if (lakalaRespJSON == null) { + log.error("[分账查询结果] 响应数据解析失败, merchantNo={}, separateNo={}, response={}", + merchantNo, separateNo, responseStr); + return null; + } + + // 7. 检查业务状态码 + String code = lakalaRespJSON.getStr("code"); + if (!"SACS0000".equals(code)) { + log.warn("[分账查询结果] 业务处理失败, merchantNo={}, separateNo={}, code={}, message={}", + merchantNo, separateNo, code, lakalaRespJSON.getStr("message")); + return null; + } + + // 8. 检查响应数据 + JSONObject respData = lakalaRespJSON.getJSONObject("resp_data"); + if (respData == null) { + log.warn("[分账查询结果] 响应数据为空, merchantNo={}, separateNo={}, response={}", + merchantNo, separateNo, responseStr); + return null; + } + + log.info("[分账查询结果] 查询成功, merchantNo={}, separateNo={}", merchantNo, separateNo); + return respData; + } catch (SDKException e) { + log.error("[分账查询结果] SDK调用异常, merchantNo={}, separateNo={}", merchantNo, separateNo, e); + return null; + } catch (Exception e) { + log.error("[分账查询结果] 查询过程中发生未知异常, merchantNo={}, separateNo={}", merchantNo, separateNo, e); + return null; + } + } + /** * 执行拉卡拉订单分账操作 @@ -2221,31 +2291,32 @@ public class LakalaApiServiceImpl implements LakalaApiService { BigDecimal wxFeeRatio = StrUtil.isEmpty(wxFee) ? BigDecimal.valueOf(0.0025) : new BigDecimal(wxFee).divide(BigDecimal.valueOf(100)); // 构建分账参数对象 - LklSeparateDTOBak lklSeparateDTOBak = new LklSeparateDTOBak(); - lklSeparateDTOBak.setTotalSeparateAmount(shopOrderLkl.getTotal_amt()); - lklSeparateDTOBak.setShippingFee(shoppingFeeInner); - lklSeparateDTOBak.setLklRatio(wxFeeRatio); // 拉卡拉给的微信分账比例 0.0025 千分之2.5 - lklSeparateDTOBak.setMchRatio(mchSplitRatio); - lklSeparateDTOBak.setPlatRatio(platformSplitRatio); + LklSeparateDTO lklSeparateDTO = new LklSeparateDTO(); + lklSeparateDTO.setTotalSeparateAmount(shopOrderLkl.getTotal_amt()); + lklSeparateDTO.setShippingFee(shoppingFeeInner); + lklSeparateDTO.setLklRatio(wxFeeRatio); // 拉卡拉给的微信分账比例 0.0025 千分之2.5 + lklSeparateDTO.setMchRatio(mchSplitRatio); + lklSeparateDTO.setPlatRatio(platformSplitRatio); + if (distributorSplitRatio.compareTo(BigDecimal.ZERO) > 0) { // 二级代理商参与分账 - lklSeparateDTOBak.setAgent2ndRatio(distributorSplitRatio); + lklSeparateDTO.setAgent2ndRatio(distributorSplitRatio); } - lklSeparateDTOBak.setRefCanSeparateAmount(canSeparateAmt); // 拉卡拉实时返回的可分账金额 + lklSeparateDTO.setRefCanSeparateAmount(canSeparateAmt); // 拉卡拉实时返回的可分账金额 // 分账方式:根据可分账金额分账 - Pair canSeparateAmtResult = lklSeparateDTOBak.calcOnCanSeparateAmount(); - if (!canSeparateAmtResult.getFirst()) { - log.error("[分账操作] 分账参数评估,结果无法分账 {}", lklSeparateDTOBak); + LklSeparateDTO.SharingResult canSeparateAmtResult = lklSeparateDTO.sharingOnCanSeparateAmount(); + if (!canSeparateAmtResult.isSuccess()) { + log.error("[分账操作] 分账参数评估,结果无法分账 {}", lklSeparateDTO); return Pair.of(false, "分账参数评估,结果无法分账"); } - log.debug("[分账操作] 分账参数计算结果:{}", lklSeparateDTOBak); + log.debug("[分账操作] 分账参数计算结果:{}", lklSeparateDTO); // 更新分账计算结果 - shopOrderLkl.setSeparate_remark(lklSeparateDTOBak.toString()); + shopOrderLkl.setSeparate_remark(lklSeparateDTO.toString()); if (CheckUtil.isEmpty(canSeparateAmt)) { - shopOrderLkl.setSplit_amt(lklSeparateDTOBak.getCanSeparateAmount()); - canSeparateAmt = lklSeparateDTOBak.getCanSeparateAmount(); + shopOrderLkl.setSplit_amt(lklSeparateDTO.getCanSeparateAmount()); + canSeparateAmt = lklSeparateDTO.getCanSeparateAmount(); } else { shopOrderLkl.setSplit_amt_ref(canSeparateAmt); } @@ -2265,9 +2336,9 @@ public class LakalaApiServiceImpl implements LakalaApiService { // 构建分账接收方列表 List recvDatas = new ArrayList<>(); - Integer merchantAmount = lklSeparateDTOBak.getMchAmount(); - Integer platformAmount = lklSeparateDTOBak.getPlatAmount(); - Integer agentAmount = lklSeparateDTOBak.getAgent2ndAmount(); + Integer merchantAmount = lklSeparateDTO.getMchAmount(); + Integer platformAmount = lklSeparateDTO.getPlatAmount(); + Integer agentAmount = lklSeparateDTO.getAgent2ndAmount(); log.info("[分账操作] 金额计算结果:订单={}, 商户={}, 总金额={}分, 可分金额={}分, 商家比例={}, 商家分得={}分, 平台比例={}, 平台分得={}分, 代理商比例={}, 代理商分得={}分", orderId, merchantNo, shopOrderLkl.getTotal_amt(), canSeparateAmt, mchSplitRatio, merchantAmount, @@ -2362,7 +2433,7 @@ public class LakalaApiServiceImpl implements LakalaApiService { separateRecord.setStatus(respData.getStr("status")); separateRecord.setTotal_amt(separateRequest.getTotalAmt()); separateRecord.setActual_separate_amt(Convert.toStr(canSeparateAmt)); - separateRecord.setTotal_fee_amt(Convert.toStr(lklSeparateDTOBak.getLklAmount())); + separateRecord.setTotal_fee_amt(Convert.toStr(lklSeparateDTO.getLklAmount())); if (lklOrderSeparateService.addOrUpdateByReceiverNo(separateRecord)) { log.info("[分账操作] 记录保存成功:订单={}, 分账单号={}, 状态={}, 分账流水号={}", @@ -2394,30 +2465,39 @@ public class LakalaApiServiceImpl implements LakalaApiService { * 参考文档:https://o.lakala.com/#/home/document/detail?id=393 *

* - * @param request HTTP请求对象,包含拉卡拉分账结果通知的参数 - * @return JSONObject 响应结果对象,包含处理结果状态 - * + * @param request + * @param merchantNo 分账方商户号,非空表示是事后补偿 + * @param separateNo 分账指令流水号,非空表示是事后补偿 + * */ @Override - public JSONObject sacsSeparateNotify(HttpServletRequest request) { - log.info("[拉卡拉分账通知] 开始处理拉卡拉分账结果通知异步回调"); - + public JSONObject sacsSeparateNotify(HttpServletRequest request, String merchantNo, String separateNo) { try { - // 1. 验签处理 - 验证通知来源的合法性 - Pair signCheckResult = LakalaUtil.chkLklApiNotifySign(request, lklNotifyCerPath, false); - if (!signCheckResult.getFirst()) { - String errorMsg = "分账通知验签失败: " + signCheckResult.getSecond(); - log.warn("[拉卡拉分账通知] {}", errorMsg); - return JSONUtil.createObj() - .set("code", "FAIL") - .set("message", signCheckResult.getSecond()); + JSONObject paramsJson = null; + if (!StrUtil.hasBlank(merchantNo, separateNo)) { + log.info("[拉卡拉分账通知] 开始处理拉卡拉分账结果查询补偿"); + paramsJson = sacsQuery(merchantNo, separateNo); + } else { + log.info("[拉卡拉分账通知] 开始处理拉卡拉分账结果通知异步回调"); + + // 1. 验签处理 - 验证通知来源的合法性 + Pair signCheckResult = LakalaUtil.chkLklApiNotifySign(request, lklNotifyCerPath, false); + if (!signCheckResult.getFirst()) { + String errorMsg = "分账通知验签失败: " + signCheckResult.getSecond(); + log.warn("[拉卡拉分账通知] {}", errorMsg); + return JSONUtil.createObj() + .set("code", "FAIL") + .set("message", signCheckResult.getSecond()); + } + + // 2. 解析请求参数 - 将验签后的参数转换为JSON对象 + paramsJson = JSONUtil.parseObj(signCheckResult.getSecond()); } - // 2. 解析请求参数 - 将验签后的参数转换为JSON对象 - JSONObject paramsJson = JSONUtil.parseObj(signCheckResult.getSecond()); + if (paramsJson == null) { String errorMsg = "分账通知参数解析失败: 请求参数为空"; log.error("[拉卡拉分账通知] {}", errorMsg); @@ -2428,7 +2508,7 @@ public class LakalaApiServiceImpl implements LakalaApiService { // 3. 提取关键参数并校验 - 确保必要参数完整 String logNo = paramsJson.getStr("log_no"); // 合单订单是子单(确认收货)流水号,非合单时是主单(确认收货)流水号 - String separateNo = paramsJson.getStr("separate_no"); + String separateNoNew = paramsJson.getStr("separate_no"); String outSeparateNo = paramsJson.getStr("out_separate_no"); String status = paramsJson.getStr("status"); String finalStatus = paramsJson.getStr("final_status"); @@ -2436,7 +2516,7 @@ public class LakalaApiServiceImpl implements LakalaApiService { // 必要参数 List missingParams = new ArrayList<>(); if (StrUtil.isBlank(outSeparateNo)) missingParams.add("outSeparateNo"); - if (StrUtil.isBlank(separateNo)) missingParams.add("separateNo"); + if (StrUtil.isBlank(separateNoNew)) missingParams.add("separateNo"); if (StrUtil.isBlank(status)) missingParams.add("status"); if (!missingParams.isEmpty()) { @@ -2460,7 +2540,7 @@ public class LakalaApiServiceImpl implements LakalaApiService { // 5. 检查分账记录状态,避免重复处理 String existingFinalStatus = lklOrderSeparateExist.getFinal_status(); - if ("SUCCESS".equals(existingFinalStatus)) { + if ("SUCCESS".equals(existingFinalStatus) && "SUCCESS".equals(lklOrderSeparateExist.getStatus())) { String warnMsg = "分账已处理成功,请不要重复通知"; log.warn("[拉卡拉分账通知] {},订单号={},外部分账单号={},参数详情: {}", warnMsg, logNo, outSeparateNo, paramsJson); @@ -2489,7 +2569,7 @@ public class LakalaApiServiceImpl implements LakalaApiService { lklOrderSeparate.setTotal_fee_amt(paramsJson.getStr("total_fee_amt", "0")); lklOrderSeparate.setRemark("分账已完成"); lklOrderSeparate.setFinish_date(paramsJson.getStr("finish_date")); - lklOrderSeparate.setNotify_resp(signCheckResult.getSecond()); + lklOrderSeparate.setNotify_resp(paramsJson.toString()); // 处理detail_datas(避免空指针) JSONArray detailDatas = paramsJson.getJSONArray("detail_datas"); diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklOrderSeparateServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklOrderSeparateServiceImpl.java index 6c6f99b8..3afa46b8 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklOrderSeparateServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklOrderSeparateServiceImpl.java @@ -18,6 +18,8 @@ import com.suisung.mall.shop.lakala.service.LklOrderSeparateService; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; +import java.util.Collections; +import java.util.Date; import java.util.List; @Slf4j @@ -150,4 +152,51 @@ public class LklOrderSeparateServiceImpl extends BaseServiceImpl unSuccessSeparateList(Date beginDate, Date endDate) { + // 1. 参数校验 + if (beginDate == null) { + log.warn("[查询未成功分账记录] 开始时间不能为空"); + return Collections.emptyList(); // 返回空列表而非null,避免NPE + } + + // 2. 处理结束时间默认值 + Date actualEndDate = (endDate != null) ? endDate : new Date(); + + // 3. 参数合理性校验 + if (beginDate.after(actualEndDate)) { + log.warn("[查询未成功分账记录] 开始时间{}不能晚于结束时间{}", beginDate, actualEndDate); + return Collections.emptyList(); + } + + try { + // 4. 构造查询条件 + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper + .ne("status", "SUCCESS") + .ne("final_status", "SUCCESS") + .ge("created_at", beginDate) + .le("created_at", actualEndDate) + .orderByDesc("id"); + + // 5. 执行查询 + List result = list(queryWrapper); + + log.info("[查询未成功分账记录] 查询完成,开始时间={},结束时间={},结果数量={}", + beginDate, actualEndDate, (result != null ? result.size() : 0)); + + return result != null ? result : Collections.emptyList(); + } catch (Exception e) { + log.error("[查询未成功分账记录] 查询过程中发生异常,开始时间={},结束时间={}", beginDate, actualEndDate, e); + return Collections.emptyList(); // 发生异常时返回空列表而非null + } + } } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/order/service/impl/ShopOrderReturnServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/order/service/impl/ShopOrderReturnServiceImpl.java index 7fd2efb2..b41e77a6 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/order/service/impl/ShopOrderReturnServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/order/service/impl/ShopOrderReturnServiceImpl.java @@ -1490,7 +1490,6 @@ public class ShopOrderReturnServiceImpl extends BaseServiceImpl