From c5d5c9ee5b4d9e698a152b5f0622b3d8288b3466 Mon Sep 17 00:00:00 2001 From: Jack <46790855@qq.com> Date: Mon, 8 Sep 2025 17:58:18 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=86=E8=B4=A6=E9=80=BB=E8=BE=91=E8=B0=83?= =?UTF-8?q?=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/impl/LakalaApiServiceImpl.java | 242 ++++++++++-------- .../listener/RedisKeyExpiredListener.java | 4 +- .../service/impl/SFExpressApiServiceImpl.java | 1 + 3 files changed, 142 insertions(+), 105 deletions(-) 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 52919d64..0fdf76a8 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 @@ -57,6 +57,7 @@ import java.math.BigDecimal; import java.time.LocalDate; import java.time.LocalDateTime; import java.util.ArrayList; +import java.util.Collections; import java.util.List; @@ -1646,17 +1647,14 @@ public class LakalaApiServiceImpl implements LakalaApiService { // 6. 获取订单分账相关参数 String merchantNo = shopOrderLkl.getLkl_merchant_no(); + // 分账金额 = 应付总金额-运费(支付时已计算好) Integer splitAmount = shopOrderLkl.getSplit_amt(); splitAmount = CheckUtil.isEmpty(splitAmount) ? 0 : splitAmount; - Integer shoppingFee = shopOrderLkl.getShopping_fee(); - shoppingFee = CheckUtil.isEmpty(shoppingFee) ? 0 : shoppingFee; - // 商家分账比例 - BigDecimal splitRatioMch = shopOrderLkl.getSplit_ratio(); // 7. 分账金额校验 if (splitAmount <= 0) { - String errorMsg = String.format("店铺[%s]订单[%s]分账金额[%d]异常,跳过分账", + String errorMsg = String.format("店铺[%s]订单[%s]分账金额[%d]低于1分钱,跳过分账", shopOrderLkl.getStore_id(), orderId, splitAmount); log.error(errorMsg); errorMessages.append(errorMsg).append("; "); @@ -1666,9 +1664,8 @@ public class LakalaApiServiceImpl implements LakalaApiService { continue; } - // 8. 获取分账接收方信息 + // 获取分账平台接收方信息 LklLedgerMerReceiverBind platform = lklLedgerMerReceiverBindService.getPlatformByMerCupNo(merchantNo); - List distributors = lklLedgerMerReceiverBindService.selectDistributorByMerCupNo(merchantNo); if (platform == null) { String errorMsg = String.format("店铺[%s]未绑定平台方接收账户,跳过分账", shopOrderLkl.getStore_id()); @@ -1677,17 +1674,140 @@ public class LakalaApiServiceImpl implements LakalaApiService { continue; } - // 9. 判断是否可以分账(商家比例不超过100%) - boolean canSplit = splitRatioMch != null && splitRatioMch.compareTo(new BigDecimal(100)) <= 0; - if (!canSplit) { - String errorMsg = String.format("店铺[%s]分账比例[%s]异常,无法分账", + // 8. 构建分账接收方列表 + List recvDatas = new ArrayList<>(); + + // 9. 获取商家分账比例并校验 + BigDecimal splitRatioMch = shopOrderLkl.getSplit_ratio(); + // 判断商家分账比例是否有效(必须在(0, 100]范围内) + boolean canSplitForMch = splitRatioMch != null + && splitRatioMch.compareTo(BigDecimal.ZERO) > 0 + && splitRatioMch.compareTo(new BigDecimal(100)) <= 0; + if (!canSplitForMch) { + String errorMsg = String.format("店铺[%s]商家分账比例[%s]不在(0-100]范围内,无法分账", shopOrderLkl.getStore_id(), splitRatioMch); 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) { + V3SacsSeparateRecvDatas receiver = new V3SacsSeparateRecvDatas(); + receiver.setRecvMerchantNo(merchantNo); + receiver.setSeparateValue(mchSplitCent.toString()); + recvDatas.add(receiver); + + log.debug("商家分账:金额={}分,商户号={}", mchSplitCent, merchantNo); + } } - // 10. 构建分账请求对象 + // 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 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) { + V3SacsSeparateRecvDatas receiver = new V3SacsSeparateRecvDatas(); + receiver.setRecvNo(platform.getReceiver_no()); + receiver.setSeparateValue(platformValue.toString()); + recvDatas.add(receiver); + log.debug("平台分账:金额={}分,接收方={}", platformValue, platform.getReceiver_no()); + } + + // 代理商分账(扣除平台20%后的剩余比例) + Integer distributorValue = pdSplitAmount - platformValue; + if (distributorValue >= 1) { + V3SacsSeparateRecvDatas receiver = new V3SacsSeparateRecvDatas(); + receiver.setRecvNo(distributors.get(0).getReceiver_no()); + receiver.setSeparateValue(distributorValue.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. 构建分账请求对象 V3SacsSeparateRequest request = new V3SacsSeparateRequest(); request.setMerchantNo(merchantNo); request.setLogNo(shopOrderLkl.getLkl_split_log_no()); // 合单和非合单的流水号保存在此字段 @@ -1695,101 +1815,17 @@ public class LakalaApiServiceImpl implements LakalaApiService { request.setOutSeparateNo(shopOrderLkl.getOut_separate_no()); request.setTotalAmt(splitAmount.toString()); request.setLklOrgNo(orgCode); - request.setCalType("0"); + request.setCalType("0"); // 0- 按照指定金额,1- 按照指定比例。默认 0 request.setNotifyUrl(projectDomain + "/api/mobile/shop/lakala/sacs/separateNotify"); - // 11. 构建分账接收方列表 - List recvDatas = new ArrayList<>(); - - Integer totalSeparateValue = 0;// 平台方和代理商总计分账金额 - // 12. 处理分账逻辑(如果可以分账) - if (canSplit) { - // 计算平台+代理商的总比例 - BigDecimal splitRatioNoMch = new BigDecimal(100).subtract(splitRatioMch); - - // 13. 根据是否有代理商决定分账模式 - if (!CollectionUtils.isEmpty(distributors) && splitRatioNoMch.compareTo(BigDecimal.ONE) > 0) { - // 平台+代理商分账模式 - log.debug("订单[{}]采用平台+代理商分账模式", orderId); - - // 平台收取1%手续费 - BigDecimal platformValue = CommonUtil.DecimalRoundHalfDown( - new BigDecimal(splitAmount).multiply(new BigDecimal("0.01"))); - if (platformValue.compareTo(BigDecimal.ZERO) > 0) { - V3SacsSeparateRecvDatas receiver = new V3SacsSeparateRecvDatas(); - receiver.setRecvNo(platform.getReceiver_no()); - receiver.setSeparateValue(platformValue.toString()); - recvDatas.add(receiver); - - totalSeparateValue += platformValue.intValue(); - log.debug("平台分账:金额={}分,接收方={}", platformValue, platform.getReceiver_no()); - } - - // 代理商分账(扣除平台1%后的剩余比例) - BigDecimal distributorRatio = splitRatioNoMch.subtract(new BigDecimal("1")).divide(new BigDecimal(100)); - BigDecimal distributorValue = CommonUtil.DecimalRoundHalfDown( - new BigDecimal(splitAmount).multiply(distributorRatio)); - if (distributorValue.compareTo(BigDecimal.ZERO) > 0 && !distributors.isEmpty()) { - V3SacsSeparateRecvDatas receiver = new V3SacsSeparateRecvDatas(); - receiver.setRecvNo(distributors.get(0).getReceiver_no()); - receiver.setSeparateValue(distributorValue.toString()); - recvDatas.add(receiver); - - totalSeparateValue += distributorValue.intValue(); - log.debug("代理商分账:金额={}分,接收方={}", distributorValue, distributors.get(0).getReceiver_no()); - } - } else { - // 仅平台分账模式 - log.debug("订单[{}]采用仅平台分账模式", orderId); - - BigDecimal platformRatio = splitRatioNoMch.divide(new BigDecimal(100)); - BigDecimal platformValue = new BigDecimal(splitAmount).multiply(platformRatio); - if (platformValue.compareTo(BigDecimal.ZERO) > 0) { - V3SacsSeparateRecvDatas receiver = new V3SacsSeparateRecvDatas(); - receiver.setRecvNo(platform.getReceiver_no()); - receiver.setSeparateValue(platformValue.toString()); - recvDatas.add(receiver); - - totalSeparateValue += platformValue.intValue(); - log.debug("平台分账:金额={}分,接收方={}", platformValue, platform.getReceiver_no()); - } - } - } - - // 14. 设置分账接收方列表 + // 15. 设置分账接收方列表 request.setRecvDatas(recvDatas); log.info("分账请求参数: 订单={}, 商户={}, 金额={}分, 分账接收方数量={}", orderId, merchantNo, splitAmount, recvDatas.size()); - // 记录详细的分账信息,便于部署后排查问题 - 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(shoppingFee).append("分, "); - detailLog.append("商家分账比例=").append(splitRatioMch).append("%, "); - detailLog.append("平台接收方=").append(platform.getReceiver_no()).append(", "); - - if (!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()); - } - log.debug("分账请求详细参数: {}", JSONUtil.toJsonStr(request)); - // 15. 发送分账请求 + // 16. 发送分账请求 log.info("向拉卡拉发送分账请求:订单={}, 商户={}, 分账流水号={}", orderId, merchantNo, shopOrderLkl.getLkl_split_log_no()); String response = LKLSDK.httpPost(request); @@ -1803,7 +1839,7 @@ public class LakalaApiServiceImpl implements LakalaApiService { log.debug("分账响应结果: {}", response); - // 16. 解析响应结果 + // 17. 解析响应结果 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", @@ -1813,7 +1849,7 @@ public class LakalaApiServiceImpl implements LakalaApiService { continue; } - // 17. 保存分账记录 + // 18. 保存分账记录 JSONObject respData = respJson.getJSONObject("resp_data"); LklOrderSeparate lklOrderSeparate = new LklOrderSeparate(); lklOrderSeparate.setSeparate_no(respData.getStr("separate_no")); @@ -1827,7 +1863,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(totalSeparateValue); + lklOrderSeparate.setTotal_separate_value(pdSplitAmount); try { if (lklOrderSeparateService.addOrUpdateByReceiverNo(lklOrderSeparate)) { @@ -1852,7 +1888,7 @@ public class LakalaApiServiceImpl implements LakalaApiService { } } - // 18. 返回最终处理结果 + // 19. 返回最终处理结果 log.info("订单[{}]分账处理完成:总订单数={},成功处理数={}", orderId, totalCount, successCount); if (successCount == 0) { String result = "分账全部失败: " + errorMessages; diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/order/listener/RedisKeyExpiredListener.java b/mall-shop/src/main/java/com/suisung/mall/shop/order/listener/RedisKeyExpiredListener.java index b580bf9f..eb815b08 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/order/listener/RedisKeyExpiredListener.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/order/listener/RedisKeyExpiredListener.java @@ -41,7 +41,7 @@ public class RedisKeyExpiredListener implements MessageListener { String patternStr = pattern != null ? new String(pattern) : "无模式"; // 基本日志记录 - log.info("[Redis过期监听] 接收到Redis键过期事件. 过期键: {}, 订阅模式: {}", expiredKey, patternStr); + log.debug("[Redis过期监听] 接收到Redis键过期事件. 过期键: {}, 订阅模式: {}", expiredKey, patternStr); // 参数验证 if (StrUtil.isBlank(expiredKey)) { @@ -68,7 +68,7 @@ public class RedisKeyExpiredListener implements MessageListener { log.error("[Redis过期监听] 订单超时事件处理失败. 店铺ID: {}, 订单号: {}", args[0], args[1]); } } else { - log.debug("[Redis过期监听] 忽略非订单超时事件. 过期键: {}", expiredKey); + //log.debug("[Redis过期监听] 忽略非订单超时事件. 过期键: {}", expiredKey); } } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/sfexpress/service/impl/SFExpressApiServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/sfexpress/service/impl/SFExpressApiServiceImpl.java index 9d6a4556..faea0471 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/sfexpress/service/impl/SFExpressApiServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/sfexpress/service/impl/SFExpressApiServiceImpl.java @@ -488,6 +488,7 @@ public class SFExpressApiServiceImpl implements SFExpressApiService { ShopStoreSfOrder shopStoreSfOrder = JSONUtil.toBean(sfExpressApiRes.get("result").toString(), ShopStoreSfOrder.class); shopStoreSfOrder.setDev_id(sfCreateOrderReq.getDev_id()); shopStoreSfOrder.setOrder_status(SFExpressConstant.Cons_CreatedOrder); + shopStoreSfOrder.setShop_id(sfCreateOrderReq.getShop_id()); shopStoreSfOrder.setStatus_desc("已创建顺丰同城订单"); // 下单成功,保存顺丰同城订单记录到 shop_store_sf_order 表里