订单命名-改成_下划线,拉卡拉要求的规则,否则无法分账
This commit is contained in:
parent
ab9c68fb8f
commit
d55dd93b05
@ -356,13 +356,104 @@ public class CommonUtil {
|
||||
|
||||
/**
|
||||
* 对象去重工具
|
||||
*
|
||||
* @param keyExtractor
|
||||
* @return
|
||||
* @param <T>
|
||||
* @return
|
||||
*/
|
||||
public static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
|
||||
Set<Object> seen = new HashSet<>();
|
||||
return t -> seen.add(keyExtractor.apply(t));
|
||||
}
|
||||
|
||||
/**
|
||||
* 按照指定比例计算分账金额
|
||||
* 分配优先级: 商家 > 平台 > 代理商
|
||||
*
|
||||
* @param totalAmount 分账总金额(单位:分)
|
||||
* @param merchantRatio 商家分账比例
|
||||
* @param platformRatioInRemaining 平台在剩余比例中的分账比例
|
||||
* @param agentRatioInRemaining 代理商在剩余比例中的分账比例
|
||||
* @return 包含商家、平台、代理商分得金额的Map
|
||||
*/
|
||||
public static Map<String, Integer> calculateProfitSharing(int totalAmount,
|
||||
BigDecimal merchantRatio,
|
||||
BigDecimal platformRatioInRemaining,
|
||||
BigDecimal agentRatioInRemaining) {
|
||||
Map<String, Integer> result = new HashMap<>();
|
||||
|
||||
// 初始化各方法定金额
|
||||
int merchantAmount = 0;
|
||||
int platformAmount = 0;
|
||||
int agentAmount = 0;
|
||||
|
||||
// 1. 计算商家按比例应得的金额(优先级最高)
|
||||
if (merchantRatio != null && merchantRatio.compareTo(BigDecimal.ZERO) > 0) {
|
||||
BigDecimal merchantAmountDecimal = merchantRatio.multiply(new BigDecimal(totalAmount));
|
||||
merchantAmount = merchantAmountDecimal.setScale(0, RoundingMode.DOWN).intValue();
|
||||
|
||||
// 确保商家至少获得1分钱(如果商家参与分账但分配为0,且总金额大于0)
|
||||
if (merchantAmount == 0 && totalAmount > 0) {
|
||||
merchantAmount = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 计算剩余金额
|
||||
int remainingAmount = totalAmount - merchantAmount;
|
||||
|
||||
// 3. 只有当有剩余金额时,才计算平台和代理商的分配
|
||||
if (remainingAmount > 0) {
|
||||
// 计算剩余比例(1 - 商家比例)
|
||||
BigDecimal remainingRatio = new BigDecimal("1");
|
||||
if (merchantRatio != null && merchantRatio.compareTo(BigDecimal.ZERO) > 0) {
|
||||
remainingRatio = new BigDecimal("1").subtract(merchantRatio);
|
||||
}
|
||||
|
||||
// 如果代理商不参与分账
|
||||
if (agentRatioInRemaining == null || agentRatioInRemaining.compareTo(BigDecimal.ZERO) <= 0) {
|
||||
// 所有剩余金额都给平台
|
||||
platformAmount = remainingAmount;
|
||||
} else {
|
||||
// 计算平台应得金额(基于剩余金额)
|
||||
if (platformRatioInRemaining != null && platformRatioInRemaining.compareTo(BigDecimal.ZERO) > 0) {
|
||||
// 平台在剩余部分中的分配 = 剩余金额 * 平台在剩余中的比例
|
||||
BigDecimal platformShareOfRemaining = platformRatioInRemaining.multiply(new BigDecimal(remainingAmount));
|
||||
platformAmount = platformShareOfRemaining.setScale(0, RoundingMode.DOWN).intValue();
|
||||
}
|
||||
|
||||
// 计算代理商应得金额(基于剩余金额)
|
||||
if (agentRatioInRemaining != null && agentRatioInRemaining.compareTo(BigDecimal.ZERO) > 0) {
|
||||
// 代理商在剩余部分中的分配 = 剩余金额 * 代理商在剩余中的比例
|
||||
BigDecimal agentShareOfRemaining = agentRatioInRemaining.multiply(new BigDecimal(remainingAmount));
|
||||
agentAmount = agentShareOfRemaining.setScale(0, RoundingMode.DOWN).intValue();
|
||||
}
|
||||
|
||||
// 重新计算剩余金额用于最终分配
|
||||
int finalRemainingAmount = remainingAmount - platformAmount - agentAmount;
|
||||
|
||||
// 确保平台至少获得1分钱(如果平台参与分账但分配为0,且还有剩余金额)
|
||||
if (platformRatioInRemaining != null && platformRatioInRemaining.compareTo(BigDecimal.ZERO) > 0
|
||||
&& platformAmount == 0 && finalRemainingAmount > 0) {
|
||||
platformAmount = 1;
|
||||
finalRemainingAmount--;
|
||||
}
|
||||
|
||||
// 按优先级分配剩余金额: 商家 > 平台 > 代理商
|
||||
// 剩余金额给商家(因为商家优先级最高)
|
||||
merchantAmount += finalRemainingAmount;
|
||||
}
|
||||
}
|
||||
|
||||
result.put("merchantAmount", merchantAmount);
|
||||
result.put("platformAmount", platformAmount);
|
||||
result.put("agentAmount", agentAmount);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println("测试1分钱分配:");
|
||||
System.out.println(calculateProfitSharing(9800, new BigDecimal("0.94"), new BigDecimal("0.2"), new BigDecimal("0")));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -48,7 +48,6 @@ import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
@ -57,8 +56,8 @@ import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
@Slf4j
|
||||
@ -1653,7 +1652,7 @@ public class LakalaApiServiceImpl implements LakalaApiService {
|
||||
splitAmount = CheckUtil.isEmpty(splitAmount) ? 0 : splitAmount;
|
||||
|
||||
// 7. 分账金额校验
|
||||
if (splitAmount <= 0) {
|
||||
if (splitAmount < 1) {
|
||||
String errorMsg = String.format("店铺[%s]订单[%s]分账金额[%d]低于1分钱,跳过分账",
|
||||
shopOrderLkl.getStore_id(), orderId, splitAmount);
|
||||
log.error(errorMsg);
|
||||
@ -1678,134 +1677,64 @@ public class LakalaApiServiceImpl implements LakalaApiService {
|
||||
List<V3SacsSeparateRecvDatas> recvDatas = new ArrayList<>();
|
||||
|
||||
// 9. 获取商家分账比例并校验
|
||||
BigDecimal splitRatioMch = shopOrderLkl.getSplit_ratio();
|
||||
BigDecimal splitRatioValMch = shopOrderLkl.getSplit_ratio(); // 如:94 代表94%
|
||||
// 判断商家分账比例是否有效(必须在(0, 100]范围内)
|
||||
boolean canSplitForMch = splitRatioMch != null
|
||||
&& splitRatioMch.compareTo(BigDecimal.ZERO) > 0
|
||||
&& splitRatioMch.compareTo(new BigDecimal(100)) <= 0;
|
||||
boolean canSplitForMch = splitRatioValMch != null
|
||||
&& splitRatioValMch.compareTo(BigDecimal.ZERO) > 0
|
||||
&& splitRatioValMch.compareTo(new BigDecimal(100)) <= 0;
|
||||
if (!canSplitForMch) {
|
||||
String errorMsg = String.format("店铺[%s]商家分账比例[%s]不在(0-100]范围内,无法分账",
|
||||
shopOrderLkl.getStore_id(), splitRatioMch);
|
||||
shopOrderLkl.getStore_id(), splitRatioValMch);
|
||||
log.error(errorMsg);
|
||||
errorMessages.append(errorMsg).append("; ");
|
||||
continue;
|
||||
} else {
|
||||
log.info("店铺[%s]商家分账比例[%s]在(0-100]范围内,可以分账",
|
||||
shopOrderLkl.getStore_id(), splitRatioMch);
|
||||
}
|
||||
// 商家分账
|
||||
BigDecimal mchRatio = splitRatioMch.divide(new BigDecimal(100)); // 比如:94/100
|
||||
Integer mchSplitCent = new BigDecimal(splitAmount).multiply(mchRatio).intValue();
|
||||
if (mchSplitCent > 0 || splitAmount >= 1) {
|
||||
// 总分账金额大于1分,商家则分账
|
||||
BigDecimal mchRatio = splitRatioValMch.divide(new BigDecimal(100)); // 比如:94%
|
||||
|
||||
BigDecimal distributorRatio = BigDecimal.ZERO;
|
||||
BigDecimal platformRatio = BigDecimal.ONE;
|
||||
// 分账代理商接收方信息
|
||||
List<LklLedgerMerReceiverBind> distributors = lklLedgerMerReceiverBindService.selectDistributorByMerCupNo(merchantNo);
|
||||
if (distributors != null && distributors.size() > 0) {
|
||||
distributorRatio = new BigDecimal("0.8");
|
||||
platformRatio = new BigDecimal("0.2");
|
||||
}
|
||||
|
||||
// 记录关键分账参数,便于问题排查
|
||||
log.info("分账参数信息:订单={}, 商户={}, 总金额={}分, 商家比例={}, 平台比例={}, 代理商比例={}, 是否有代理商={}",
|
||||
orderId, merchantNo, splitAmount, mchRatio, platformRatio, distributorRatio,
|
||||
(distributors != null && !distributors.isEmpty()));
|
||||
|
||||
// 返回值如下:{platformAmount=6, merchantAmount=94, agentAmount=0}
|
||||
Map<String, Integer> splitAmountMap = CommonUtil.calculateProfitSharing(splitAmount, mchRatio, platformRatio, distributorRatio);
|
||||
Integer merchantAmount = splitAmountMap.get("merchantAmount");
|
||||
Integer platformAmount = splitAmountMap.get("platformAmount");
|
||||
Integer agentAmount = splitAmountMap.get("agentAmount");
|
||||
|
||||
// 记录分账结果,便于问题排查
|
||||
log.info("分账金额计算结果:订单={}, 商户={}, 总金额={}分, 商家分得={}分, 平台分得={}分, 代理商分得={}分",
|
||||
orderId, merchantNo, splitAmount, merchantAmount, platformAmount, agentAmount);
|
||||
|
||||
if (merchantAmount > 0) {
|
||||
V3SacsSeparateRecvDatas receiver = new V3SacsSeparateRecvDatas();
|
||||
receiver.setRecvMerchantNo(merchantNo);
|
||||
receiver.setSeparateValue(mchSplitCent.toString());
|
||||
receiver.setSeparateValue(merchantAmount.toString());
|
||||
recvDatas.add(receiver);
|
||||
|
||||
log.debug("商家分账:金额={}分,商户号={}", mchSplitCent, merchantNo);
|
||||
}
|
||||
}
|
||||
|
||||
// 10. 计算平台和代理商分账金额
|
||||
Integer pdSplitAmount = 0;
|
||||
|
||||
// 计算平台+代理商的总比例=100-商家分账比例
|
||||
BigDecimal splitRatioNoMch = new BigDecimal(100).subtract(splitRatioMch);
|
||||
// 判断平台和代理商分账比例是否有效(必须在[0, 100)范围内)
|
||||
boolean canSplitForNoMch = splitRatioNoMch != null
|
||||
&& splitRatioNoMch.compareTo(BigDecimal.ZERO) > 0
|
||||
&& splitRatioNoMch.compareTo(new BigDecimal(100)) < 0;
|
||||
if (!canSplitForNoMch) {
|
||||
String errorMsg = String.format("店铺[%s]平台和代理商分账比例[%s]不在[0-100)范围内,无法分账",
|
||||
shopOrderLkl.getStore_id(), splitRatioNoMch);
|
||||
log.warn(errorMsg);
|
||||
} else {
|
||||
log.info("店铺[%s]平台和代理商分账比例[%s]在[0-100)范围内,可以分账",
|
||||
shopOrderLkl.getStore_id(), splitRatioNoMch);
|
||||
|
||||
// 分账代理商接收方信息
|
||||
List<LklLedgerMerReceiverBind> distributors = Collections.emptyList();
|
||||
|
||||
// 判断要不要分账给平台和代理商(分账金额太低或者没有平台、代理商,就不用分账)
|
||||
// 计算平台和代理商分账金额,小于1分钱,不进行平台和代理商分账
|
||||
BigDecimal notMchRatio = splitRatioNoMch.divide(new BigDecimal(100)); // 比如:6/100
|
||||
|
||||
// 平台方和代理商总计分账金额
|
||||
pdSplitAmount = notMchRatio.multiply(new BigDecimal(splitAmount)).intValue();
|
||||
if (pdSplitAmount > 1) {
|
||||
|
||||
// 11. 判断是否能分账给代理商
|
||||
// 如果有平台和代理商同时存在,平台分账剩余资金20%;代理商分账剩余资金80%;
|
||||
// 能分账给代理商的条件:总分账金额*0.2要大于1分钱
|
||||
boolean canSplitForDistributors = pdSplitAmount * 0.2 > 1;
|
||||
|
||||
// 12. 根据是否能分账给代理商决定分账模式
|
||||
if (canSplitForDistributors) {
|
||||
// 获取分账代理商接收方信息
|
||||
distributors = lklLedgerMerReceiverBindService.selectDistributorByMerCupNo(merchantNo);
|
||||
// 根据是否有代理商决定分账模式
|
||||
if (!CollectionUtils.isEmpty(distributors)) {
|
||||
// 平台+代理商分账模式
|
||||
log.debug("订单[{}]采用平台+代理商分账模式", orderId);
|
||||
|
||||
// 平台收取剩余资金20%手续费
|
||||
Integer platformValue = pdSplitAmount * 20 / 100;
|
||||
if (platformValue >= 1) {
|
||||
if (platformAmount > 0) {
|
||||
V3SacsSeparateRecvDatas receiver = new V3SacsSeparateRecvDatas();
|
||||
receiver.setRecvNo(platform.getReceiver_no());
|
||||
receiver.setSeparateValue(platformValue.toString());
|
||||
receiver.setSeparateValue(platformAmount.toString());
|
||||
recvDatas.add(receiver);
|
||||
log.debug("平台分账:金额={}分,接收方={}", platformValue, platform.getReceiver_no());
|
||||
}
|
||||
|
||||
// 代理商分账(扣除平台20%后的剩余比例)
|
||||
Integer distributorValue = pdSplitAmount - platformValue;
|
||||
if (distributorValue >= 1) {
|
||||
if (agentAmount > 0 && distributors != null && !distributors.isEmpty()) {
|
||||
V3SacsSeparateRecvDatas receiver = new V3SacsSeparateRecvDatas();
|
||||
receiver.setRecvNo(distributors.get(0).getReceiver_no());
|
||||
receiver.setSeparateValue(distributorValue.toString());
|
||||
receiver.setSeparateValue(agentAmount.toString());
|
||||
recvDatas.add(receiver);
|
||||
log.debug("代理商分账:金额={}分,接收方={}", distributorValue, distributors.get(0).getReceiver_no());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 仅平台分账模式
|
||||
log.debug("订单[{}]采用仅平台分账模式", orderId);
|
||||
|
||||
if (pdSplitAmount > 1) {
|
||||
V3SacsSeparateRecvDatas receiver = new V3SacsSeparateRecvDatas();
|
||||
receiver.setRecvNo(platform.getReceiver_no());
|
||||
receiver.setSeparateValue(pdSplitAmount.toString());
|
||||
recvDatas.add(receiver);
|
||||
log.debug("平台分账:金额={}分,接收方={}", pdSplitAmount, platform.getReceiver_no());
|
||||
}
|
||||
}
|
||||
|
||||
// 13. 记录详细的分账信息,便于部署后排查问题
|
||||
if (log.isDebugEnabled()) {
|
||||
StringBuilder detailLog = new StringBuilder();
|
||||
detailLog.append("详细分账信息:");
|
||||
detailLog.append("订单ID=").append(shopOrderLkl.getOrder_id()).append(", ");
|
||||
detailLog.append("商户号=").append(merchantNo).append(", ");
|
||||
detailLog.append("分账流水号=").append(shopOrderLkl.getLkl_split_log_no()).append(", ");
|
||||
detailLog.append("外部分账单号=").append(shopOrderLkl.getOut_separate_no()).append(", ");
|
||||
detailLog.append("分账总金额=").append(splitAmount).append("分, ");
|
||||
detailLog.append("商家分账比例=").append(splitRatioMch).append("%, ");
|
||||
detailLog.append("平台接收方=").append(platform.getReceiver_no()).append(", ");
|
||||
|
||||
if (canSplitForDistributors && !CollectionUtils.isEmpty(distributors)) {
|
||||
detailLog.append("代理商接收方=[");
|
||||
for (int i = 0; i < distributors.size(); i++) {
|
||||
if (i > 0) detailLog.append(",");
|
||||
detailLog.append(distributors.get(i).getReceiver_no());
|
||||
}
|
||||
detailLog.append("], ");
|
||||
}
|
||||
|
||||
detailLog.append("分账接收方数量=").append(recvDatas.size());
|
||||
log.debug(detailLog.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 14. 构建分账请求对象
|
||||
@ -1864,7 +1793,7 @@ public class LakalaApiServiceImpl implements LakalaApiService {
|
||||
lklOrderSeparate.setLkl_org_no(request.getLklOrgNo());
|
||||
lklOrderSeparate.setRecv_datas(JSONUtil.toJsonStr(request.getRecvDatas()));
|
||||
lklOrderSeparate.setStatus(respData.getStr("status"));
|
||||
lklOrderSeparate.setTotal_separate_value(pdSplitAmount);
|
||||
lklOrderSeparate.setTotal_separate_value(platformAmount + agentAmount);
|
||||
|
||||
try {
|
||||
if (lklOrderSeparateService.addOrUpdateByReceiverNo(lklOrderSeparate)) {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user