diff --git a/mall-common/src/main/java/com/suisung/mall/common/modules/lakala/LklOrderSeparate.java b/mall-common/src/main/java/com/suisung/mall/common/modules/lakala/LklOrderSeparate.java
index 86928dc4..46536d69 100644
--- a/mall-common/src/main/java/com/suisung/mall/common/modules/lakala/LklOrderSeparate.java
+++ b/mall-common/src/main/java/com/suisung/mall/common/modules/lakala/LklOrderSeparate.java
@@ -49,9 +49,6 @@ public class LklOrderSeparate {
@ApiModelProperty(value = "平台订单Id")
private String order_id;
- @ApiModelProperty(value = "分账总金额,单位:分")
- private String total_amt;
-
@ApiModelProperty(value = "分账计算类型:0- 按照指定金额,1- 按照指定比例。默认 0")
private String cal_type;
@@ -79,8 +76,14 @@ public class LklOrderSeparate {
@ApiModelProperty(value = "最终分账明细,JSON 格式")
private String detail_datas;
- @ApiModelProperty(value = "总计分账金额")
- private Integer total_separate_value;
+ @ApiModelProperty(value = "分账发生总金额")
+ private String total_amt;
+
+ @ApiModelProperty(value = "实际分账金额")
+ private String actual_separate_amt;
+
+ @ApiModelProperty(value = "分账费用")
+ private String total_fee_amt;
@ApiModelProperty(value = "拉卡拉机构编号")
private String lkl_org_no;
@@ -91,6 +94,9 @@ public class LklOrderSeparate {
@ApiModelProperty(value = "处理状态:ACCEPTED-已受理, PROCESSING-处理中, FAIL-失败, SUCCESS-成功")
private String final_status;
+ @ApiModelProperty(value = "异步通知数据")
+ private String notify_resp;
+
@ApiModelProperty(value = "分账(失败后)的标记")
private String remark;
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 abcba871..f9bf2a6f 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
@@ -1,848 +1,792 @@
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 LklSeparateDTO implements java.io.Serializable {
- private static final Logger logger = LoggerFactory.getLogger(LklSeparateDTO.class);
+public class LklSeparateDTO {
+ // 基础金额属性
+ private Integer totalSeparateAmount; // 分账总金额(分)
+ private Integer canSeparateAmount; // 可分账金额(分)
+ private Integer refCanSeparateAmount; // 拉卡拉参考可分账金额(分)
+ private Integer shippingFee; // 配送费(分)
- private static final long serialVersionUID = 1L;
+ // 分账比例属性
+ private BigDecimal lklRatio; // 拉卡拉分账比例(如 0.0025=0.25%)
+ private BigDecimal mchRatio; // 商户分账比例(如 0.96=96%)
+ private BigDecimal platRatio; // 平台分账比例(如 0.01=1%)
+ private BigDecimal agent1stRatio; // 一级代理商分账比例(如 0.01=1%)
+ private BigDecimal agent2ndRatio; // 二级代理商分账比例(如 0.03=3%)
- // ================================ 基础金额属性 ================================
-
- @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 LklSeparateDTO() {
- // 默认构造函数
- }
-
- // ================================ 公共方法 ================================
+ // 分账金额结果属性
+ private Integer lklAmount; // 拉卡拉分账金额(分)
+ private Integer mchAmount; // 商户分账金额(分)
+ private Integer platAmount; // 平台分账金额(分)
+ private Integer agent1stAmount; // 一级代理商分账金额(分)
+ private Integer agent2ndAmount; // 二级代理商分账金额(分)
/**
* 测试方法
*/
public static void main(String[] args) {
- logger.info("开始测试分账计算功能...");
+ // 创建分账对象
+ LklSeparateDTO dto = new LklSeparateDTO();
- // 临界点测试用例2: 小金额测试
- logger.info("\n临界点测试用例2 - 小金额测试:");
+ // 设置测试参数 - 正常情况
+ dto.setTotalSeparateAmount(800); // 分账总额 1000分
+ dto.setShippingFee(500); // 配送费 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
+ // dto.setAgent1stRatio(new BigDecimal("0.01")); // 一级代理商分账比例 0.01
+ // dto.setAgent2ndRatio(new BigDecimal("0.01")); // 二级代理商分账比例 0.01
+
+ // 执行基于总金额的分账算法
+ System.out.println("=== 基于总金额的分账算法测试(正常情况) ===");
+ SharingResult result1 = dto.sharingOnTotalAmount();
+ System.out.println(result1);
+ if (result1.isSuccess()) {
+ printSharingDetails(dto, "基于总金额");
+ }
+
+ // 测试基于可分账金额的分账算法(正常情况)
+ System.out.println("\n=== 基于可分账金额的分账算法测试(正常情况) ===");
LklSeparateDTO dto2 = new LklSeparateDTO();
- dto2.setTotalSeparateAmount(1);
- dto2.setShippingFee(0);
- dto2.setLklRatio(new BigDecimal("0.0025"));
- dto2.setMchRatio(new BigDecimal("0.96"));
- dto2.setPlatRatio(new BigDecimal("0.01"));
+ dto2.setTotalSeparateAmount(800); // 分账总额 1000分
+ dto2.setShippingFee(500); // 配送费 100分
+ 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.setAgent1stRatio(new BigDecimal("0.01")); // 一级代理商分账比例 0.023 (会产生小数)
+ // dto2.setAgent2ndRatio(new BigDecimal("0.04")); // 二级代理商分账比例 0.031 (会产生小数)
-// dto2.setAgent1stRatio(new BigDecimal("0.01"));
-// dto2.setAgent2ndRatio(new BigDecimal("0.04"));
-// dto2.setRefCanSeparateAmount(8079); // 设置参考可分账金额
+ SharingResult result2 = dto2.sharingOnCanSeparateAmount();
+ System.out.println(result2);
+ if (result2.isSuccess()) {
+ printSharingDetails(dto2, "基于可分账金额");
- 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());
}
+
+ // 测试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());
+
+ System.out.println("\n基于可分账金额算法的toString输出:");
+ System.out.println(dto2);
}
/**
- * 基于可分账金额的分账计算方法(默认)
- *
- * 计算逻辑:
- * 1. 计算拉卡拉分账金额 = 总分账金额 × 拉卡拉分账比例(向上取整)
- * 2. 计算可分账金额 = 总分账金额 - 配送费 - 拉卡拉分账金额
- * 3. 如果refCanSeparateAmount有效且与计算出的canSeparateAmount不一致,则使用refCanSeparateAmount作为分账基数
- * 4. 调整分账比例,确保有效比例之和等于1.0
- * 5. 按优先级计算各参与方分账金额(商户 > 平台 > 一级代理商 > 二级代理商)
- * 6. 确保总额平衡并保障各参与方分账比例
+ * 打印分账详情
*
- * @return Pair 分账结果是否成功和失败的原因
+ * @param dto 分账对象
+ * @param type 分账类型
*/
- public Pair calcOnCanSeparateAmount() {
- // 设置分账计算方法类型
- isBasedOnTotalAmount = false;
-
- // 检查前提条件
- if (!validateInputs()) {
- return Pair.of(false, "分账参数不全");
+ private static void printSharingDetails(LklSeparateDTO dto, String type) {
+ System.out.println(type + "分账详情:");
+ if (dto.getTotalSeparateAmount() != null) {
+ System.out.println(" 分账总金额: " + dto.getTotalSeparateAmount() + "分");
+ }
+ // 打印拉卡拉分账金额(即使为0也要显示)
+ if (dto.getLklAmount() != null) {
+ System.out.println(" 拉卡拉分账金额: " + dto.getLklAmount() + "分" +
+ " (占比: " + calculatePercentage(dto.getLklAmount(), dto.getTotalSeparateAmount()) + "%)");
+ }
+ // 打印配送费(即使为0也要显示)
+ if (dto.getShippingFee() != null) {
+ System.out.println(" 配送费: " + dto.getShippingFee() + "分" +
+ " (占比: " + calculatePercentage(dto.getShippingFee(), dto.getTotalSeparateAmount()) + "%)");
+ }
+ if (dto.getCanSeparateAmount() != null) {
+ System.out.println(" 可分账金额: " + dto.getCanSeparateAmount() + "分");
+ }
+ // 打印平台分账金额(即使为0也要显示)
+ 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()) + "%)"
+ : ""));
+ }
+ // 打印一级代理商分账金额(即使为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())
+ + "%)"
+ : ""));
+ }
+ // 打印二级代理商分账金额(即使为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())
+ + "%)"
+ : ""));
+ }
+ // 打印商家分账金额
+ 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()) + "%)"
+ : ""));
}
- logger.info("开始基于可分账金额的分账计算,总金额={}分,配送费={}分", totalSeparateAmount, shippingFee);
-
- // 计算拉卡拉分账金额
- calculateLklAmount();
-
- // 计算可分账金额
- calculateCanSeparateAmount();
- if (canSeparateAmount <= 0) {
- String errorMsg = "分账计算失败:可分账金额必须大于0,当前值=" + canSeparateAmount;
- logger.info(errorMsg);
- return Pair.of(false, errorMsg);
+ // 验证分账是否平衡
+ 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 + "分");
}
-
- // 检查并应用参考可分账金额
- 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 分账结果是否成功和失败的原因
+ * @param amount 金额
+ * @param total 总金额
+ * @return 百分比字符串
*/
- public Pair calcOnTotalAmount() {
- // 设置分账计算方法类型
- isBasedOnTotalAmount = true;
-
- // 检查前提条件
- if (!validateInputsForTotalAmount()) {
- return Pair.of(false, "分账参数不全");
+ public static String calculatePercentage(Integer amount, Integer total) {
+ if (amount == null || total == null || total == 0) {
+ return "0.00";
}
-
- 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);
+ BigDecimal percentage = new BigDecimal(amount).multiply(new BigDecimal("100"))
+ .divide(new BigDecimal(total), 2, RoundingMode.HALF_UP);
+ return percentage.toString();
}
- /**
- * 输出具体的分账结果
- *
- * @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字符串格式
+ * 将分账对象转换为JSON格式字符串
*
- * @return 包含所有属性的JSON字符串
+ * @return JSON格式字符串
*/
public String toJSON() {
StringBuilder json = new StringBuilder();
- json.append("{");
+ json.append("{\n");
- // 添加基本属性
- appendProperty(json, "totalSeparateAmount", totalSeparateAmount, true);
- appendProperty(json, "canSeparateAmount", canSeparateAmount, false);
- appendProperty(json, "refCanSeparateAmount", refCanSeparateAmount, false);
- appendProperty(json, "shippingFee", shippingFee, false);
+ // 基础信息
+ json.append(" \"分账算法类型\": \"拉卡拉订单分账信息处理\",\n");
+ json.append(" \"分账总金额\": ").append(totalSeparateAmount != null ? totalSeparateAmount : 0).append(",\n");
+ json.append(" \"配送费\": ").append(shippingFee != null ? shippingFee : 0).append(",\n");
- // 添加比例属性
- 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);
+ // 分账比例
+ 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");
- // 添加金额属性
- 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.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对象
- if (json.charAt(json.length() - 1) == ',') {
- json.setLength(json.length() - 1);
+ // 分账百分比(基于分账总金额)
+ 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();
+ }
/**
- * 验证基于可分账金额分账的输入参数
+ * 分账算法 - 基于总金额进行分账
+ *
+ * @return SharingResult 分账结果,包含是否成功和失败原因
*/
- private boolean validateInputs() {
+ public SharingResult sharingOnTotalAmount() {
+ // 执行基于总金额的分账计算
+ SharingCalculationResult result = calculateBasedOnTotalAmount();
+
+ if (result.isSuccess()) {
+ // 更新实例变量
+ this.lklAmount = result.getLklAmount();
+ this.canSeparateAmount = result.getCanSeparateAmount();
+ this.refCanSeparateAmount = result.getRefCanSeparateAmount();
+ this.shippingFee = result.getShippingFee();
+ this.platAmount = result.getPlatAmount();
+ this.agent1stAmount = result.getAgent1stAmount();
+ this.agent2ndAmount = result.getAgent2ndAmount();
+ this.mchAmount = result.getMchAmount();
+ return new SharingResult(true, null);
+ } else {
+ return new SharingResult(false, result.getErrorMessage());
+ }
+ }
+
+ /**
+ * 基于总金额的分账计算(独立算法)
+ *
+ * @return SharingCalculationResult 计算结果
+ */
+ private SharingCalculationResult calculateBasedOnTotalAmount() {
+ // 1. 参数校验
if (totalSeparateAmount == null || totalSeparateAmount <= 0) {
- logger.info("分账计算失败:分账总金额必须大于0,当前值={}", totalSeparateAmount);
- return false;
+ return new SharingCalculationResult(false, "分账总金额不能为空或小于等于0");
}
- if (shippingFee == null || shippingFee < 0) {
- logger.info("分账计算失败:配送费不能小于0,当前值={}", shippingFee);
- return false;
+ // 2. 计算拉卡拉分账金额
+ int lklAmount = 0;
+ if (lklRatio != null && lklRatio.compareTo(BigDecimal.ZERO) > 0) {
+ lklAmount = lklRatio.multiply(new BigDecimal(totalSeparateAmount))
+ .setScale(0, RoundingMode.HALF_UP).intValue();
}
- if (lklRatio == null || lklRatio.compareTo(BigDecimal.ZERO) <= 0) {
- logger.info("分账计算失败:拉卡拉分账比例必须大于0,当前值={}", lklRatio);
- return false;
+ // 3. 处理配送费(可以为空或0,表示免配送费)
+ int effectiveShippingFee = (shippingFee != null && shippingFee > 0) ? shippingFee : 0;
+
+ // 4. 检查配送费是否合法(不能大于等于可分账金额)
+ if (effectiveShippingFee >= totalSeparateAmount - lklAmount) {
+ return new SharingCalculationResult(false, "配送费不能大于等于可分账金额");
}
- if (mchRatio == null || mchRatio.compareTo(BigDecimal.ZERO) <= 0) {
- logger.info("分账计算失败:商户分账比例必须大于0,当前值={}", mchRatio);
- return false;
+ // 5. 计算可分账金额(总金额 - 拉卡拉分账金额 - 配送费)
+ int availableAmount = totalSeparateAmount - lklAmount - effectiveShippingFee;
+ if (availableAmount < 0) {
+ return new SharingCalculationResult(false, "可分账金额不能为负数");
}
- if (platRatio == null || platRatio.compareTo(BigDecimal.ZERO) <= 0) {
- logger.info("分账计算失败:平台分账比例必须大于0,当前值={}", platRatio);
- return false;
- }
+ int canSeparateAmount = availableAmount;
+ int refCanSeparateAmount = availableAmount;
- return true;
- }
+ // 6. 初始化各分账金额
+ int platAmount = 0;
+ int agent1stAmount = 0;
+ int agent2ndAmount = 0;
+ int mchAmount = 0;
- /**
- * 验证基于总金额分账的输入参数
- */
- private boolean validateInputsForTotalAmount() {
- // 基于总金额的分账计算参数验证与基于可分账金额的验证相同
- return validateInputs();
- }
+ // 7. 根据参与方动态调整分账比例
+ BigDecimal effectivePlatRatio = platRatio != null ? platRatio : BigDecimal.ZERO;
+ BigDecimal effectiveAgent1stRatio = agent1stRatio != null ? agent1stRatio : BigDecimal.ZERO;
+ BigDecimal effectiveAgent2ndRatio = agent2ndRatio != null ? agent2ndRatio : BigDecimal.ZERO;
- /**
- * 计算拉卡拉分账金额
- */
- private void calculateLklAmount() {
- BigDecimal lklAmountDecimal = new BigDecimal(totalSeparateAmount).multiply(lklRatio);
- lklAmount = lklAmountDecimal.setScale(2, RoundingMode.HALF_UP).intValue();
- logger.debug("拉卡拉分账计算:总金额{} × 拉卡拉比例{} = {},四舍五入保留两位小数后={}",
- totalSeparateAmount, lklRatio, lklAmountDecimal, lklAmount);
- }
+ // 判断哪些代理商参与分账
+ boolean hasAgent1st = effectiveAgent1stRatio.compareTo(BigDecimal.ZERO) > 0;
+ boolean hasAgent2nd = effectiveAgent2ndRatio.compareTo(BigDecimal.ZERO) > 0;
- /**
- * 计算可分账金额
- */
- private void calculateCanSeparateAmount() {
- canSeparateAmount = totalSeparateAmount - shippingFee - lklAmount;
- logger.debug("可分账金额计算:总金额{} - 配送费{} - 拉卡拉分账{} = {}",
- totalSeparateAmount, shippingFee, lklAmount, canSeparateAmount);
- }
+ // 根据商家分账比例动态调整其他方比例
+ if (mchRatio != null && mchRatio.compareTo(BigDecimal.ZERO) > 0) {
+ BigDecimal remainingRatio = BigDecimal.ONE.subtract(mchRatio);
+ BigDecimal onePercent = new BigDecimal("0.01");
- /**
- * 检查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);
+ if (hasAgent1st && hasAgent2nd) {
+ // 平台、一级代理商、二级代理商都参与
+ // 平台固定1%,一级代理商固定1%,二级代理商为剩余比例
+ effectivePlatRatio = onePercent;
+ effectiveAgent1stRatio = onePercent;
+ effectiveAgent2ndRatio = remainingRatio.subtract(onePercent).subtract(onePercent);
+ } else if (hasAgent1st || hasAgent2nd) {
+ // 只有平台和一个代理商参与
+ effectivePlatRatio = onePercent;
+ // 代理商为剩余比例
+ if (hasAgent1st) {
+ effectiveAgent1stRatio = remainingRatio.subtract(onePercent);
+ } else {
+ effectiveAgent2ndRatio = remainingRatio.subtract(onePercent);
}
} 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);
+ // 只有平台参与
+ effectivePlatRatio = remainingRatio;
}
}
- }
- /**
- * 保障各参与方分账比例不低于指定值(基于总金额的分账计算专用)
- * 忽略商户比例保障,只保障平台、一级代理商、二级代理商的比例
- */
- 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);
- }
+ // 8. 按优先级顺序计算各分账方金额
+ // 平台分账(优先级1)- 基于总金额计算
+ if (effectivePlatRatio.compareTo(BigDecimal.ZERO) > 0) {
+ platAmount = effectivePlatRatio.multiply(new BigDecimal(totalSeparateAmount))
+ .setScale(0, RoundingMode.HALF_UP).intValue();
+ // 确保平台分账金额不超过可分账金额
+ if (platAmount > availableAmount) {
+ platAmount = availableAmount;
}
+ availableAmount -= 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);
- }
+ // 一级代理商分账(优先级2)- 基于总金额计算
+ if (hasAgent1st && effectiveAgent1stRatio.compareTo(BigDecimal.ZERO) > 0) {
+ agent1stAmount = effectiveAgent1stRatio.multiply(new BigDecimal(totalSeparateAmount))
+ .setScale(0, RoundingMode.HALF_UP).intValue();
+ // 确保不超过剩余金额
+ if (agent1stAmount > availableAmount) {
+ agent1stAmount = availableAmount;
}
+ availableAmount -= 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);
- }
- }
+ // 二级代理商分账(优先级3)- 基于总金额计算
+ if (hasAgent2nd && effectiveAgent2ndRatio.compareTo(BigDecimal.ZERO) > 0) {
+ agent2ndAmount = effectiveAgent2ndRatio.multiply(new BigDecimal(totalSeparateAmount))
+ .setScale(0, RoundingMode.HALF_UP).intValue();
+ // 确保不超过剩余金额
+ if (agent2ndAmount > availableAmount) {
+ agent2ndAmount = availableAmount;
}
+ availableAmount -= agent2ndAmount;
}
+
+ // 9. 商家分账(优先级4,获得剩余所有金额)
+ mchAmount = availableAmount;
+
+ // 10. 检查商家分账金额是否合法
+ if (mchAmount < 0) {
+ return new SharingCalculationResult(false, "商家分账金额不能为负数");
+ }
+
+ // 创建并返回计算结果
+ SharingCalculationResult calculationResult = new SharingCalculationResult(true, null);
+ calculationResult.setLklAmount(lklAmount);
+ calculationResult.setCanSeparateAmount(canSeparateAmount);
+ calculationResult.setRefCanSeparateAmount(refCanSeparateAmount);
+ calculationResult.setShippingFee(effectiveShippingFee);
+ calculationResult.setPlatAmount(platAmount);
+ calculationResult.setAgent1stAmount(agent1stAmount);
+ calculationResult.setAgent2ndAmount(agent2ndAmount);
+ calculationResult.setMchAmount(mchAmount);
+
+ return calculationResult;
}
/**
- * 最终保障商户分账比例
- */
- 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 是否为第一个属性
+ * @return SharingResult 分账结果,包含是否成功和失败原因
*/
- 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("\"");
+ public SharingResult sharingOnCanSeparateAmount() {
+ // 执行基于可分账金额的分账计算
+ SharingCalculationResult result = calculateBasedOnCanSeparateAmount();
+
+ if (result.isSuccess()) {
+ // 更新实例变量
+ this.lklAmount = result.getLklAmount();
+ this.canSeparateAmount = result.getCanSeparateAmount();
+ this.refCanSeparateAmount = result.getRefCanSeparateAmount();
+ this.shippingFee = result.getShippingFee();
+ this.platAmount = result.getPlatAmount();
+ this.agent1stAmount = result.getAgent1stAmount();
+ this.agent2ndAmount = result.getAgent2ndAmount();
+ this.mchAmount = result.getMchAmount();
+ return new SharingResult(true, null);
} else {
- json.append(value);
+ return new SharingResult(false, result.getErrorMessage());
}
}
-}
\ No newline at end of file
+
+ /**
+ * 基于可分账金额的分账计算(独立算法)
+ *
+ * @return SharingCalculationResult 计算结果
+ */
+ private SharingCalculationResult calculateBasedOnCanSeparateAmount() {
+ // 1. 参数校验
+ if (totalSeparateAmount == null || totalSeparateAmount <= 0) {
+ return new SharingCalculationResult(false, "分账总金额不能为空或小于等于0");
+ }
+
+ // 2. 先扣除配送费(可以为空或0,表示免配送费)
+ int effectiveShippingFee = (shippingFee != null && shippingFee > 0) ? shippingFee : 0;
+ if (effectiveShippingFee >= totalSeparateAmount) {
+ return new SharingCalculationResult(false, "配送费不能大于等于分账总金额");
+ }
+
+ // 3. 计算扣除配送费后的金额
+ 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();
+ }
+
+ // 5. 检查拉卡拉分账金额是否合法
+ if (lklAmount >= amountAfterShipping) {
+ return new SharingCalculationResult(false, "拉卡拉分账金额不能大于等于扣除配送费后的金额");
+ }
+
+ // 6. 计算可分账金额 = 分账总金额 - 配送费 - 拉卡拉分账金额
+ int availableAmount = amountAfterShipping - lklAmount;
+ if (availableAmount < 0) {
+ return new SharingCalculationResult(false, "可分账金额不能为负数");
+ }
+
+ int canSeparateAmount = availableAmount;
+ int refCanSeparateAmount = availableAmount;
+
+ // 7. 初始化各分账金额
+ int platAmount = 0;
+ int agent1stAmount = 0;
+ int agent2ndAmount = 0;
+ int mchAmount = 0;
+
+ // 8. 根据参与方动态调整分账比例
+ BigDecimal effectivePlatRatio = platRatio != null ? platRatio : BigDecimal.ZERO;
+ BigDecimal effectiveAgent1stRatio = agent1stRatio != null ? agent1stRatio : BigDecimal.ZERO;
+ BigDecimal effectiveAgent2ndRatio = agent2ndRatio != null ? agent2ndRatio : 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);
+ BigDecimal onePercent = new BigDecimal("0.01");
+
+ if (hasAgent1st && hasAgent2nd) {
+ // 平台、一级代理商、二级代理商都参与
+ // 平台固定1%,一级代理商固定1%,二级代理商为剩余比例
+ effectivePlatRatio = onePercent;
+ effectiveAgent1stRatio = onePercent;
+ effectiveAgent2ndRatio = remainingRatio.subtract(onePercent).subtract(onePercent);
+ } else if (hasAgent1st || hasAgent2nd) {
+ // 只有平台和一个代理商参与
+ effectivePlatRatio = onePercent;
+ // 代理商为剩余比例
+ if (hasAgent1st) {
+ effectiveAgent1stRatio = remainingRatio.subtract(onePercent);
+ } else {
+ effectiveAgent2ndRatio = remainingRatio.subtract(onePercent);
+ }
+ } else {
+ // 只有平台参与
+ effectivePlatRatio = remainingRatio;
+ }
+ }
+
+ // 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;
+ }
+ availableAmount -= mchAmount;
+ }
+
+ // 平台分账(优先级2)- 基于可分账金额计算,采用四舍五入方式
+ if (effectivePlatRatio.compareTo(BigDecimal.ZERO) > 0) {
+ platAmount = effectivePlatRatio.multiply(new BigDecimal(canSeparateAmount))
+ .setScale(0, RoundingMode.HALF_UP).intValue();
+ // 确保平台分账金额不超过剩余金额
+ if (platAmount > availableAmount) {
+ platAmount = availableAmount;
+ }
+ availableAmount -= platAmount;
+ }
+
+ // 一级代理商分账(优先级3)- 基于可分账金额计算,采用四舍五入方式
+ if (hasAgent1st && effectiveAgent1stRatio.compareTo(BigDecimal.ZERO) > 0) {
+ agent1stAmount = effectiveAgent1stRatio.multiply(new BigDecimal(canSeparateAmount))
+ .setScale(0, RoundingMode.HALF_UP).intValue();
+ // 确保不超过剩余金额
+ if (agent1stAmount > availableAmount) {
+ agent1stAmount = availableAmount;
+ }
+ availableAmount -= agent1stAmount;
+ }
+
+ // 二级代理商分账(优先级4)- 基于可分账金额计算,采用四舍五入方式
+ if (hasAgent2nd && effectiveAgent2ndRatio.compareTo(BigDecimal.ZERO) > 0) {
+ agent2ndAmount = effectiveAgent2ndRatio.multiply(new BigDecimal(canSeparateAmount))
+ .setScale(0, RoundingMode.HALF_UP).intValue();
+ // 确保不超过剩余金额
+ if (agent2ndAmount > availableAmount) {
+ agent2ndAmount = availableAmount;
+ }
+ availableAmount -= agent2ndAmount;
+ }
+
+ // 10. 如果还有剩余金额,将其分配给商家
+ if (availableAmount > 0) {
+ mchAmount += availableAmount;
+ }
+
+ // 11. 检查商家分账金额是否合法
+ if (mchAmount < 0) {
+ return new SharingCalculationResult(false, "商家分账金额不能为负数");
+ }
+
+ // 创建并返回计算结果
+ SharingCalculationResult calculationResult = new SharingCalculationResult(true, null);
+ calculationResult.setLklAmount(lklAmount);
+ calculationResult.setCanSeparateAmount(canSeparateAmount);
+ calculationResult.setRefCanSeparateAmount(refCanSeparateAmount);
+ calculationResult.setShippingFee(effectiveShippingFee);
+ calculationResult.setPlatAmount(platAmount);
+ calculationResult.setAgent1stAmount(agent1stAmount);
+ calculationResult.setAgent2ndAmount(agent2ndAmount);
+ calculationResult.setMchAmount(mchAmount);
+
+ return calculationResult;
+ }
+
+ /**
+ * 分账结果类,包含分账是否成功以及失败原因
+ */
+ @Data
+ @EqualsAndHashCode(callSuper = false)
+ public static class SharingResult {
+ private final boolean success;
+ private final String errorMessage;
+
+ public SharingResult(boolean success, String errorMessage) {
+ this.success = success;
+ this.errorMessage = errorMessage;
+ }
+
+ public boolean isSuccess() {
+ return success;
+ }
+
+ @Override
+ public String toString() {
+ return success ? "分账成功" : "分账失败: " + errorMessage;
+ }
+ }
+
+ /**
+ * 分账计算结果类,包含分账计算的详细结果
+ */
+ public static class SharingCalculationResult extends SharingResult {
+ // 分账金额结果属性
+ private Integer lklAmount; // 拉卡拉分账金额(分)
+ private Integer canSeparateAmount; // 可分账金额(分)
+ private Integer refCanSeparateAmount; // 拉卡拉参考可分账金额(分)
+ private Integer shippingFee; // 配送费(分)
+ private Integer platAmount; // 平台分账金额(分)
+ private Integer agent1stAmount; // 一级代理商分账金额(分)
+ private Integer agent2ndAmount; // 二级代理商分账金额(分)
+ private Integer mchAmount; // 商户分账金额(分)
+
+ public SharingCalculationResult(boolean success, String errorMessage) {
+ super(success, errorMessage);
+ }
+
+ public Integer getMchAmount() {
+ return mchAmount;
+ }
+
+ 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 Integer getCanSeparateAmount() {
+ return canSeparateAmount;
+ }
+
+ public void setCanSeparateAmount(Integer canSeparateAmount) {
+ this.canSeparateAmount = canSeparateAmount;
+ }
+
+ public Integer getLklAmount() {
+ return lklAmount;
+ }
+
+ public void setLklAmount(Integer lklAmount) {
+ this.lklAmount = lklAmount;
+ }
+ }
+}
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
new file mode 100644
index 00000000..1038f51b
--- /dev/null
+++ b/mall-common/src/main/java/com/suisung/mall/common/pojo/dto/LklSeparateDTOBak.java
@@ -0,0 +1,849 @@
+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/lakala/service/impl/LakalaApiServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LakalaApiServiceImpl.java
index 9929309a..a5c2db54 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
@@ -32,7 +32,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.LklSeparateDTO;
+import com.suisung.mall.common.pojo.dto.LklSeparateDTOBak;
import com.suisung.mall.common.service.impl.CommonService;
import com.suisung.mall.common.utils.*;
import com.suisung.mall.shop.lakala.service.*;
@@ -2064,12 +2064,12 @@ public class LakalaApiServiceImpl implements LakalaApiService {
separateRecord.setLog_no(separateRequest.getLogNo()); // 发货完成交易流水号后14位 。分账商户用该流水号发起分账
separateRecord.setLog_date(separateRequest.getLogDate());
separateRecord.setOrder_id(shopOrderLkl.getOrder_id());
- separateRecord.setTotal_amt(separateRequest.getTotalAmt());
separateRecord.setNotify_url(separateRequest.getNotifyUrl());
separateRecord.setLkl_org_no(separateRequest.getLklOrgNo());
separateRecord.setRecv_datas(JSONUtil.toJsonStr(separateRequest.getRecvDatas()));
separateRecord.setStatus(respData.getStr("status"));
- separateRecord.setTotal_separate_value(platformAmount + agentAmount);
+ separateRecord.setTotal_amt(separateRequest.getTotalAmt());
+ separateRecord.setActual_separate_amt(Convert.toStr(shopOrderLkl.getSplit_amt()));
try {
if (lklOrderSeparateService.addOrUpdateByReceiverNo(separateRecord)) {
@@ -2160,19 +2160,11 @@ public class LakalaApiServiceImpl implements LakalaApiService {
LklOrderSeparate existingSeparateRecord = lklOrderSeparateService.getByLogNoAndOutTradeNo(
shopOrderLkl.getLkl_receive_log_no(), shopOrderLkl.getOut_separate_no());
- if (existingSeparateRecord != null) {
- String status = existingSeparateRecord.getStatus();
- switch (status) {
- case "SUCCESS":
- log.info("[分账操作] 订单[{}]交易对账流水号[{}]已完成分账,跳过处理", orderId, shopOrderLkl.getLkl_receive_log_no());
- return Pair.of(true, "订单已处理");
- case "PROCESSING":
- case "ACCEPTED":
- log.info("[分账操作] 订单[{}]交易对账流水号[{}]分账处理中或已受理,跳过处理", orderId, shopOrderLkl.getLkl_receive_log_no());
- return Pair.of(true, "订单已处理中或已受理");
- }
- } else if (CommonConstant.Enable.equals(shopOrderLkl.getSeparate_status())) {
- log.warn("[分账操作] 订单[{}]交易流水号[{}]订单已分账,跳过处理", orderId, receiveTradeNo);
+ if (existingSeparateRecord != null
+ && "SUCCESS".equals(existingSeparateRecord.getStatus())
+ && "SUCCESS".equals(existingSeparateRecord.getFinal_status())
+ && CommonConstant.Enable.equals(shopOrderLkl.getSeparate_status())) {
+ log.info("[分账操作] 订单[{}]交易对账流水号[{}]已完成分账,跳过处理", orderId, shopOrderLkl.getLkl_receive_log_no());
return Pair.of(true, "订单已分账,请勿重复操作");
}
@@ -2229,31 +2221,31 @@ public class LakalaApiServiceImpl implements LakalaApiService {
BigDecimal wxFeeRatio = StrUtil.isEmpty(wxFee) ? BigDecimal.valueOf(0.0025) : new BigDecimal(wxFee).divide(BigDecimal.valueOf(100));
// 构建分账参数对象
- 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);
+ 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);
if (distributorSplitRatio.compareTo(BigDecimal.ZERO) > 0) { // 二级代理商参与分账
- lklSeparateDTO.setAgent2ndRatio(distributorSplitRatio);
+ lklSeparateDTOBak.setAgent2ndRatio(distributorSplitRatio);
}
- lklSeparateDTO.setRefCanSeparateAmount(canSeparateAmt); // 拉卡拉实时返回的可分账金额
+ lklSeparateDTOBak.setRefCanSeparateAmount(canSeparateAmt); // 拉卡拉实时返回的可分账金额
// 分账方式:根据可分账金额分账
- Pair canSeparateAmtResult = lklSeparateDTO.calcOnCanSeparateAmount();
+ Pair canSeparateAmtResult = lklSeparateDTOBak.calcOnCanSeparateAmount();
if (!canSeparateAmtResult.getFirst()) {
- log.error("[分账操作] 分账参数评估,结果无法分账 {}", lklSeparateDTO);
+ log.error("[分账操作] 分账参数评估,结果无法分账 {}", lklSeparateDTOBak);
return Pair.of(false, "分账参数评估,结果无法分账");
}
- log.debug("[分账操作] 分账参数计算结果:{}", lklSeparateDTO);
+ log.debug("[分账操作] 分账参数计算结果:{}", lklSeparateDTOBak);
// 更新分账计算结果
- shopOrderLkl.setSeparate_remark(lklSeparateDTO.toString());
+ shopOrderLkl.setSeparate_remark(lklSeparateDTOBak.toString());
if (CheckUtil.isEmpty(canSeparateAmt)) {
- shopOrderLkl.setSplit_amt(lklSeparateDTO.getCanSeparateAmount());
- canSeparateAmt = lklSeparateDTO.getCanSeparateAmount();
+ shopOrderLkl.setSplit_amt(lklSeparateDTOBak.getCanSeparateAmount());
+ canSeparateAmt = lklSeparateDTOBak.getCanSeparateAmount();
} else {
shopOrderLkl.setSplit_amt_ref(canSeparateAmt);
}
@@ -2273,9 +2265,9 @@ public class LakalaApiServiceImpl implements LakalaApiService {
// 构建分账接收方列表
List recvDatas = new ArrayList<>();
- Integer merchantAmount = lklSeparateDTO.getMchAmount();
- Integer platformAmount = lklSeparateDTO.getPlatAmount();
- Integer agentAmount = lklSeparateDTO.getAgent2ndAmount();
+ Integer merchantAmount = lklSeparateDTOBak.getMchAmount();
+ Integer platformAmount = lklSeparateDTOBak.getPlatAmount();
+ Integer agentAmount = lklSeparateDTOBak.getAgent2ndAmount();
log.info("[分账操作] 金额计算结果:订单={}, 商户={}, 总金额={}分, 可分金额={}分, 商家比例={}, 商家分得={}分, 平台比例={}, 平台分得={}分, 代理商比例={}, 代理商分得={}分",
orderId, merchantNo, shopOrderLkl.getTotal_amt(), canSeparateAmt, mchSplitRatio, merchantAmount,
@@ -2363,12 +2355,14 @@ public class LakalaApiServiceImpl implements LakalaApiService {
separateRecord.setLog_no(separateRequest.getLogNo());
separateRecord.setLog_date(separateRequest.getLogDate());
separateRecord.setOrder_id(shopOrderLkl.getOrder_id());
- separateRecord.setTotal_amt(separateRequest.getTotalAmt());
+
separateRecord.setNotify_url(separateRequest.getNotifyUrl());
separateRecord.setLkl_org_no(separateRequest.getLklOrgNo());
separateRecord.setRecv_datas(JSONUtil.toJsonStr(separateRequest.getRecvDatas()));
separateRecord.setStatus(respData.getStr("status"));
- separateRecord.setTotal_separate_value(canSeparateAmt);
+ separateRecord.setTotal_amt(separateRequest.getTotalAmt());
+ separateRecord.setActual_separate_amt(Convert.toStr(canSeparateAmt));
+ separateRecord.setTotal_fee_amt(Convert.toStr(lklSeparateDTOBak.getLklAmount()));
if (lklOrderSeparateService.addOrUpdateByReceiverNo(separateRecord)) {
log.info("[分账操作] 记录保存成功:订单={}, 分账单号={}, 状态={}, 分账流水号={}",
@@ -2390,260 +2384,6 @@ public class LakalaApiServiceImpl implements LakalaApiService {
}
}
-
- public Pair innerDoOrderSeparateByMerchantAndLogNoBak(String lklMerchantNo, String receiveTradeNo, String receiveLogNo) {
- // 1. 输入参数校验
- if (StrUtil.isBlank(lklMerchantNo) || StrUtil.isBlank(receiveTradeNo) || StrUtil.isBlank(receiveLogNo)) {
- log.warn("[分账操作] 参数校验失败:缺少必要参数, lklMerchantNo={}, receiveTradeNo={}, receiveLogNo={}",
- lklMerchantNo, receiveTradeNo, receiveLogNo);
- return Pair.of(false, "缺少必要参数");
- }
-
- try {
- log.info("[分账操作] 开始处理分账请求, lklMerchantNo={}, receiveTradeNo={}, receiveLogNo={}",
- lklMerchantNo, receiveTradeNo, receiveLogNo);
-
- // 2. 查询订单信息
- ShopOrderLkl shopOrderLkl = shopOrderLklService.getByLklMchNoAndReceiveTradeNoAndReceiveLogNo(lklMerchantNo, receiveTradeNo, receiveLogNo);
- if (shopOrderLkl == null) {
- log.warn("[分账操作] 失败:对账流水号[{}]不存在", receiveLogNo);
- return Pair.of(false, "订单不存在");
- }
-
- // TODO 检查可分账余额是否足够?
- Pair balanceCheckResult = queryMchCanSplitAmt(lklMerchantNo, receiveLogNo, shopOrderLkl.getLkl_log_date());
- if (balanceCheckResult == null) {
- log.error("[分账操作] 查询可分账余额失败:lklMerchantNo={} logDate={} receiveLogNo={}", lklMerchantNo, shopOrderLkl.getLkl_log_date(), receiveLogNo);
- }
-
- log.warn("[分账操作] 可分账余额检查结果:分账总余额={}分 可分账金额={}分", balanceCheckResult.getFirst(), balanceCheckResult.getSecond());
- Integer canSeparateAmt = Convert.toInt(balanceCheckResult.getSecond());
- if (canSeparateAmt == null || canSeparateAmt <= 0) {
- log.warn("[分账操作] lklMerchantNo={} receiveTradeNo={} receiveLogNo={} 可分账金额={}分 可分账余额不足,跳过处理", lklMerchantNo, receiveTradeNo, receiveLogNo, balanceCheckResult.getSecond());
- return Pair.of(false, "可分账余额不足");
- }
-
- String orderId = shopOrderLkl.getOrder_id();
- log.info("[分账操作] 开始处理订单[{}]的分账", orderId);
-
- // 3. 检查是否已确认收货
- if (!CommonConstant.Enable.equals(shopOrderLkl.getReceive_status())) {
- log.warn("[分账操作] 订单[{}]交易流水号[{}]未被确认收货,跳过处理", orderId, receiveTradeNo);
- return Pair.of(false, "订单未确认收货,暂无法分账");
- }
-
- if (CommonConstant.Enable.equals(shopOrderLkl.getSeparate_status())) {
- log.warn("[分账操作] 订单[{}]交易流水号[{}]未被确认收货,跳过处理", orderId, receiveTradeNo);
- return Pair.of(true, "订单已分账,请勿重复操作");
- }
-
- // 4. 检查分账状态,避免重复处理
- LklOrderSeparate existingSeparateRecord = lklOrderSeparateService.getByLogNoAndOutTradeNo(shopOrderLkl.getLkl_receive_log_no(), shopOrderLkl.getOut_separate_no());
- if (existingSeparateRecord != null) {
- String status = existingSeparateRecord.getStatus();
- if ("SUCCESS".equals(status)) {
- log.info("[分账操作] 订单[{}]交易对账流水号[{}]已完成分账,跳过处理", orderId, shopOrderLkl.getLkl_sub_log_no());
- return Pair.of(true, "订单已处理");
- }
- if ("PROCESSING".equals(status) || "ACCEPTED".equals(status)) {
- log.info("[分账操作] 订单[{}]交易对账流水号[{}]分账处理中或已受理,跳过处理", orderId, shopOrderLkl.getLkl_sub_log_no());
- return Pair.of(true, "订单已处理中或已受理");
- }
- }
-
- // 5. 获取订单分账相关参数
- String merchantNo = shopOrderLkl.getLkl_merchant_no();
-
- // 分账金额 = 应付总金额-运费(支付时已计算好)
- Integer splitAmount = shopOrderLkl.getSplit_amt();
- splitAmount = CheckUtil.isEmpty(splitAmount) ? 0 : splitAmount;
-
- // 6. 分账金额校验
- if (splitAmount < 1) {
- String errorMsg = String.format("[分账操作] 店铺[%s]订单[%s]分账金额[%d]低于1分钱,跳过分账",
- shopOrderLkl.getStore_id(), orderId, splitAmount);
- log.error(errorMsg);
- if (existingSeparateRecord != null) {
- lklOrderSeparateService.updateRemark(existingSeparateRecord.getId(), errorMsg);
- }
- return Pair.of(false, "订单分账金额低于1分钱");
- }
-
- // 7. 获取分账平台接收方信息
- LklLedgerMerReceiverBind platformReceiver = lklLedgerMerReceiverBindService.getPlatformByMerCupNo(merchantNo);
- if (platformReceiver == null) {
- String errorMsg = String.format("[分账操作] 店铺[%s]未绑定平台方接收账户,跳过分账", shopOrderLkl.getStore_id());
- log.error(errorMsg);
- return Pair.of(false, "平台方未绑定账户");
- }
-
- // 8. 构建分账接收方列表
- List recvDatas = new ArrayList<>();
-
- // 9. 获取商家分账比例并校验
- BigDecimal merchantSplitRatioRaw = shopOrderLkl.getSplit_ratio();
- // 判断商家分账比例是否有效(必须在(0, 100]范围内)
- boolean canSplitForMerchant = merchantSplitRatioRaw != null
- && merchantSplitRatioRaw.compareTo(BigDecimal.ZERO) > 0
- && merchantSplitRatioRaw.compareTo(new BigDecimal(100)) <= 0;
- if (!canSplitForMerchant) {
- String errorMsg = String.format("[分账操作] 店铺[%s]商家分账比例[%s]不在(0-100]范围内,无法分账",
- shopOrderLkl.getStore_id(), merchantSplitRatioRaw);
- log.error(errorMsg);
- return Pair.of(false, "商家分账比例无效");
- }
-
- // 10. 计算商家分账比例(转换为小数)
- BigDecimal merchantSplitRatio = merchantSplitRatioRaw.divide(new BigDecimal(100));
-
- // 11. 获取代理商分账信息
- BigDecimal distributorSplitRatio = BigDecimal.ZERO;
- BigDecimal platformSplitRatio = BigDecimal.ONE;
- List distributorReceivers = lklLedgerMerReceiverBindService.selectDistributorByMerCupNo(merchantNo);
- if (distributorReceivers != null && !distributorReceivers.isEmpty()) {
- distributorSplitRatio = new BigDecimal("0.8");
- platformSplitRatio = new BigDecimal("0.2");
- log.debug("[分账操作] 检测到代理商存在,调整分账比例: 代理商比例={}, 平台比例={}", distributorSplitRatio, platformSplitRatio);
- }
-
- // 12. 记录关键分账参数,便于问题排查
- log.info("[分账操作] 参数信息:订单={}, 商户={}, 总金额={}分, 商家比例={}, 平台比例={}, 代理商比例={}, 是否有代理商={}",
- orderId, merchantNo, splitAmount, merchantSplitRatio, platformSplitRatio, distributorSplitRatio,
- (distributorReceivers != null && !distributorReceivers.isEmpty()));
-
- // 13. 计算各参与方分账金额
- Map splitAmountMap = CommonUtil.calculateProfitSharing(splitAmount, merchantSplitRatio, platformSplitRatio, distributorSplitRatio);
- Integer merchantAmount = splitAmountMap.get("merchantAmount");
- Integer platformAmount = splitAmountMap.get("platformAmount");
- Integer agentAmount = splitAmountMap.get("agentAmount");
-
- // 14. 记录分账结果,便于问题排查
- log.info("[分账操作] 金额计算结果:订单={}, 商户={}, 总金额={}分, 商家分得={}分, 平台分得={}分, 代理商分得={}分",
- orderId, merchantNo, splitAmount, merchantAmount, platformAmount, agentAmount);
-
- // 15. 构建分账接收方列表
- if (merchantAmount > 0) {
- V3SacsSeparateRecvDatas receiver = new V3SacsSeparateRecvDatas();
- receiver.setRecvMerchantNo(merchantNo);
- receiver.setSeparateValue(merchantAmount.toString());
- recvDatas.add(receiver);
- log.debug("[分账操作] 添加商家接收方: merchantNo={}, amount={}", merchantNo, merchantAmount);
- }
-
- if (platformAmount > 0) {
- V3SacsSeparateRecvDatas receiver = new V3SacsSeparateRecvDatas();
- receiver.setRecvNo(platformReceiver.getReceiver_no());
- receiver.setSeparateValue(platformAmount.toString());
- recvDatas.add(receiver);
- log.debug("[分账操作] 添加平台接收方: receiverNo={}, amount={}", platformReceiver.getReceiver_no(), platformAmount);
- }
-
- if (agentAmount > 0 && distributorReceivers != null && !distributorReceivers.isEmpty()) {
- V3SacsSeparateRecvDatas receiver = new V3SacsSeparateRecvDatas();
- receiver.setRecvNo(distributorReceivers.get(0).getReceiver_no());
- receiver.setSeparateValue(agentAmount.toString());
- recvDatas.add(receiver);
- log.debug("[分账操作] 添加代理商接收方: receiverNo={}, amount={}", distributorReceivers.get(0).getReceiver_no(), agentAmount);
- }
-
- // 16. 初始化拉卡拉SDK
- log.debug("[分账操作] 初始化拉卡拉SDK");
- initLKLSDK();
-
- // 17. 构建分账请求对象
- V3SacsSeparateRequest separateRequest = new V3SacsSeparateRequest();
- separateRequest.setMerchantNo(merchantNo);
- separateRequest.setOutSeparateNo(shopOrderLkl.getOut_separate_no());
- separateRequest.setLogNo(shopOrderLkl.getLkl_receive_log_no()); // 使用确认收货流水号作为分账流水号
- separateRequest.setLogDate(shopOrderLkl.getLkl_log_date());
- separateRequest.setTotalAmt(splitAmount.toString());
- separateRequest.setLklOrgNo(orgCode);
- separateRequest.setCalType("0"); // 0- 按照指定金额,1- 按照指定比例。默认 0
- separateRequest.setNotifyUrl(projectDomain + "/api/mobile/shop/lakala/sacs/separateNotify");
-
- // 18. 设置分账接收方列表
- separateRequest.setRecvDatas(recvDatas);
- log.info("[分账操作] 请求参数: 订单={}, 商户={}, 金额={}分, 分账接收方数量={}",
- orderId, merchantNo, splitAmount, recvDatas.size());
-
- log.debug("[分账操作] 请求详细参数: {}", JSONUtil.toJsonStr(separateRequest));
-
- // 19. 发送分账请求
- log.info("[分账操作] 向拉卡拉发送分账请求:订单={}, 商户={}, 分账流水号={}",
- orderId, merchantNo, shopOrderLkl.getLkl_receive_log_no());
- String response = LKLSDK.httpPost(separateRequest);
- if (StrUtil.isBlank(response)) {
- String errorMsg = String.format("[分账操作] 拉卡拉无响应,订单=%s,商户=%s,分账流水号=%s",
- orderId, merchantNo, shopOrderLkl.getLkl_receive_log_no());
- // 更改分账状态:分账失败
- shopOrderLklService.updateSeparateStatusByReceiveLogNo(shopOrderLkl.getLkl_receive_log_no(), CommonConstant.Sta_Separate_Fail, errorMsg);
- log.error(errorMsg);
- return Pair.of(false, "拉卡拉无响应");
- }
-
- log.debug("[分账操作] 响应结果: {}", response);
-
- // 20. 解析响应结果
- JSONObject respJson = JSONUtil.parseObj(response);
- if (respJson == null || !lklSacsSuccessCode.equals(respJson.getStr("code")) || respJson.getJSONObject("resp_data") == null) {
- String errorMsg = String.format("[分账操作] 拉卡拉返回格式异常,订单=%s,商户=%s,分账流水号=%s,响应=%s,respJson=%s",
- orderId, merchantNo, shopOrderLkl.getLkl_receive_log_no(), response, respJson);
- // 更改分账状态:分账失败
- shopOrderLklService.updateSeparateStatusByReceiveLogNo(shopOrderLkl.getLkl_receive_log_no(), CommonConstant.Sta_Separate_Fail, errorMsg);
- log.error(errorMsg);
- return Pair.of(false, "拉卡拉分账异常:[" + respJson.getStr("code") + "]" + respJson.getStr("msg"));
- }
-
- // 21. 保存分账记录
- JSONObject respData = respJson.getJSONObject("resp_data");
- LklOrderSeparate separateRecord = new LklOrderSeparate();
- separateRecord.setSeparate_no(respData.getStr("separate_no"));
- separateRecord.setOut_separate_no(separateRequest.getOutSeparateNo());
- separateRecord.setMerchant_no(merchantNo);
- separateRecord.setLog_no(separateRequest.getLogNo());
- separateRecord.setLog_date(separateRequest.getLogDate());
- separateRecord.setOrder_id(shopOrderLkl.getOrder_id());
- separateRecord.setTotal_amt(separateRequest.getTotalAmt());
- separateRecord.setNotify_url(separateRequest.getNotifyUrl());
- separateRecord.setLkl_org_no(separateRequest.getLklOrgNo());
- separateRecord.setRecv_datas(JSONUtil.toJsonStr(separateRequest.getRecvDatas()));
- separateRecord.setStatus(respData.getStr("status"));
- separateRecord.setTotal_separate_value(platformAmount + agentAmount);
-
- try {
- if (lklOrderSeparateService.addOrUpdateByReceiverNo(separateRecord)) {
- log.info("[分账操作] 记录保存成功:订单={}, 分账单号={}, 状态={}, 分账流水号={}",
- orderId, separateRecord.getSeparate_no(), separateRecord.getStatus(), separateRecord.getLog_no());
- } else {
- String errorMsg = String.format("[分账操作] 保存分账记录失败,订单=%s,分账单号=%s,分账流水号=%s",
- orderId, separateRecord.getSeparate_no(), separateRecord.getLog_no());
- log.error(errorMsg);
- lklOrderSeparateService.updateRemark(separateRecord.getLog_no(), separateRecord.getSeparate_no(), errorMsg);
- return Pair.of(false, "保存分账记录失败");
- }
-
- // 保存 shop_order_lkl 关键字段
-
- String result = "订单分账已提交处理";
- log.info("[分账操作] 结果:订单[{}] {}", orderId, result);
- return Pair.of(true, result);
- } catch (Exception e) {
- String errorMsg = String.format("[分账操作] 保存分账记录异常,订单=%s,分账单号=%s,流水号=%s,错误=%s",
- orderId,
- separateRecord.getSeparate_no(),
- separateRecord.getLog_no(),
- e.getMessage());
- log.error(errorMsg, e);
- return Pair.of(false, "保存分账记录异常");
- }
-
- } catch (Exception e) {
- String errorMsg = String.format("[分账操作] 系统异常,分账对账流水号=%s,错误=%s", receiveLogNo, e.getMessage());
- log.error(errorMsg, e);
- return Pair.of(false, "系统异常,请稍后重试");
- }
- }
-
/**
* 拉卡拉分账结果通知处理
*
@@ -2729,15 +2469,6 @@ public class LakalaApiServiceImpl implements LakalaApiService {
.put("message", "分账已处理成功,请不要重复通知");
}
- if (!"FAIL".equals(existingFinalStatus) && StrUtil.isNotBlank(existingFinalStatus)) {
- String warnMsg = "已受理或处理中,成功后再通知";
- log.warn("[拉卡拉分账通知] {},订单号={},外部分账单号={},参数详情: {}",
- warnMsg, logNo, outSeparateNo, paramsJson);
- return JSONUtil.createObj()
- .put("code", "FAIL")
- .put("message", "已受理或处理中,成功后再通知");
- }
-
// 6. 记录关键参数信息,便于问题排查
log.info("[拉卡拉分账通知] 接收到分账通知,分账单号={},外部分账单号={},状态={},最终状态={}",
separateNo, outSeparateNo, status, finalStatus);
@@ -2753,9 +2484,12 @@ public class LakalaApiServiceImpl implements LakalaApiService {
lklOrderSeparate.setSeparate_type(paramsJson.getStr("separate_type"));
lklOrderSeparate.setSeparate_date(paramsJson.getStr("separate_date"));
// 总计分账金额
- lklOrderSeparate.setTotal_separate_value(paramsJson.getInt("total_separate_value", 0));
+ lklOrderSeparate.setTotal_amt(paramsJson.getStr("total_amt", "0"));
+ lklOrderSeparate.setActual_separate_amt(paramsJson.getStr("actual_separate_amt", "0"));
+ lklOrderSeparate.setTotal_fee_amt(paramsJson.getStr("total_fee_amt", "0"));
lklOrderSeparate.setRemark("分账已完成");
lklOrderSeparate.setFinish_date(paramsJson.getStr("finish_date"));
+ lklOrderSeparate.setNotify_resp(signCheckResult.getSecond());
// 处理detail_datas(避免空指针)
JSONArray detailDatas = paramsJson.getJSONArray("detail_datas");
@@ -2774,7 +2508,7 @@ public class LakalaApiServiceImpl implements LakalaApiService {
}
// 更改分账状态:分账成功
- shopOrderLklService.updateSeparateStatusByReceiveLogNo(logNo, CommonConstant.Sta_Separate_Success, "分账成功");
+ shopOrderLklService.updateSeparateStatusByReceiveLogNo(logNo, CommonConstant.Sta_Separate_Success, "");
// 9. 记录处理成功日志
log.info("[拉卡拉分账通知] 分账通知处理成功, separateNo={}, status={}", separateNo, status);