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 92919ef1..ea5c63ee 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 @@ -28,6 +28,8 @@ public class LklSeparateDTO implements java.io.Serializable { private static final long serialVersionUID = 1L; + // ================================ 基础金额属性 ================================ + @ApiModelProperty(value = "分账总金额(分)") private Integer totalSeparateAmount; @@ -40,6 +42,7 @@ public class LklSeparateDTO implements java.io.Serializable { @ApiModelProperty(value = "配送费(分)") private Integer shippingFee; + // ================================ 分账比例属性 ================================ @ApiModelProperty(value = "拉卡拉分账比例(如 0.0025=0.25%)") private BigDecimal lklRatio; @@ -56,6 +59,7 @@ public class LklSeparateDTO implements java.io.Serializable { @ApiModelProperty(value = "二级代理商分账比例(如 0.03=3%)") private BigDecimal agent2ndRatio; + // ================================ 分账金额结果属性 ================================ @ApiModelProperty(value = "拉卡拉分账金额(分)") private Integer lklAmount; @@ -72,6 +76,23 @@ public class LklSeparateDTO implements java.io.Serializable { @ApiModelProperty(value = "二级代理商分账金额(分)") private Integer agent2ndAmount; + // ================================ 内部状态属性 ================================ + + /** + * 分账计算方法类型 + * true表示基于总金额分账(calcOnTotalAmount方法被调用) + * false表示基于可分账金额分账(calcOnCanAmount方法被调用) + */ + private boolean isBasedOnTotalAmount = false; + + // ================================ 构造方法 ================================ + + public LklSeparateDTO() { + // 默认构造函数 + } + + // ================================ 公共方法 ================================ + /** * 测试方法 */ @@ -81,14 +102,15 @@ public class LklSeparateDTO implements java.io.Serializable { // 临界点测试用例2: 小金额测试 logger.info("\n临界点测试用例2 - 小金额测试:"); LklSeparateDTO dto2 = new LklSeparateDTO(); - dto2.setTotalSeparateAmount(2); + 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.setAgent1stRatio(new BigDecimal("0.01")); - dto2.setAgent2ndRatio(new BigDecimal("0.04")); - dto2.setRefCanSeparateAmount(8079); // 设置参考可分账金额 + +// dto2.setAgent1stRatio(new BigDecimal("0.01")); +// dto2.setAgent2ndRatio(new BigDecimal("0.04")); +// dto2.setRefCanSeparateAmount(8079); // 设置参考可分账金额 logger.info("测试参数: 总分账金额={}分, 配送费={}分, 拉卡拉比例={}, 商户比例={}, 平台比例={}", dto2.getTotalSeparateAmount(), dto2.getShippingFee(), dto2.getLklRatio(), @@ -149,66 +171,6 @@ public class LklSeparateDTO implements java.io.Serializable { } } - /** - * 将对象转换为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(); - } - - /** - * 向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); - } - } - /** * 基于可分账金额的分账计算方法(默认) *

@@ -223,6 +185,9 @@ public class LklSeparateDTO implements java.io.Serializable { * @return 分账结果是否成功 */ public boolean calcOnCanAmount() { + // 设置分账计算方法类型 + isBasedOnTotalAmount = false; + // 检查前提条件 if (!validateInputs()) { return false; @@ -274,6 +239,9 @@ public class LklSeparateDTO implements java.io.Serializable { * @return 分账结果是否成功 */ public boolean calcOnTotalAmount() { + // 设置分账计算方法类型 + isBasedOnTotalAmount = true; + // 检查前提条件 if (!validateInputsForTotalAmount()) { return false; @@ -311,6 +279,133 @@ public class LklSeparateDTO implements java.io.Serializable { return true; } + /** + * 输出具体的分账结果 + * + * @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(); + } + + // ================================ 私有方法 ================================ + /** * 验证基于可分账金额分账的输入参数 */ @@ -724,4 +819,25 @@ public class LklSeparateDTO implements java.io.Serializable { } } + /** + * 向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-pay/src/main/java/com/suisung/mall/pay/service/impl/LakalaPayServiceImpl.java b/mall-pay/src/main/java/com/suisung/mall/pay/service/impl/LakalaPayServiceImpl.java index bbc342af..1b662ccf 100644 --- a/mall-pay/src/main/java/com/suisung/mall/pay/service/impl/LakalaPayServiceImpl.java +++ b/mall-pay/src/main/java/com/suisung/mall/pay/service/impl/LakalaPayServiceImpl.java @@ -476,9 +476,11 @@ public class LakalaPayServiceImpl implements LakalaPayService { return new JSONObject().set("code", "BBS00001").set("msg", "拉卡拉合单交易失败:" + respBody.getStr("msg")).set("resp_data", null); } - log.info("[拉卡拉合单预下单] 支付成功,准备保存订单记录, orderId={}", orderId); + log.info("[拉卡拉合单预下单] 支付成功,准备保存订单记录, orderId={} shopping_fee_inner={}", orderId, agentAmountInt); // 新增一个拉卡拉订单记录 shop_order_lkl 表 JSONObject lklPayReqAndRespJson = new JSONObject(); + reqData.set("shopping_fee_inner", agentAmountInt); // 内部配送费 + lklPayReqAndRespJson.put("req", reqData); lklPayReqAndRespJson.put("resp", respBody); // 返回原始响应数据 diff --git a/mall-pay/src/main/java/com/suisung/mall/pay/service/impl/PayUserPayServiceImpl.java b/mall-pay/src/main/java/com/suisung/mall/pay/service/impl/PayUserPayServiceImpl.java index 894cc5ea..76ac9e18 100644 --- a/mall-pay/src/main/java/com/suisung/mall/pay/service/impl/PayUserPayServiceImpl.java +++ b/mall-pay/src/main/java/com/suisung/mall/pay/service/impl/PayUserPayServiceImpl.java @@ -130,6 +130,10 @@ public class PayUserPayServiceImpl extends BaseServiceImpl - *

- * 分账操作流程: - * 1. 参数校验和订单查询 - * 2. 检查订单状态(是否已确认收货) - * 3. 检查是否已分账,避免重复处理 - * 4. 计算分账金额 - * 5. 构建分账请求并发送至拉卡拉 - * 6. 保存分账结果 - *

* * @param lklMerchantNo 拉卡拉商户号 * @param receiveTradeNo 收货交易号(对应拉卡拉的trade_no) @@ -2145,6 +2137,268 @@ public class LakalaApiServiceImpl implements LakalaApiService { 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, "订单不存在"); + } + + String orderId = shopOrderLkl.getOrder_id(); + log.info("[分账操作] 开始处理订单[{}]的分账", orderId); + + // 3. 检查订单状态 + if (!CommonConstant.Enable.equals(shopOrderLkl.getReceive_status())) { + log.warn("[分账操作] 订单[{}]交易流水号[{}]未被确认收货,跳过处理", orderId, receiveTradeNo); + return Pair.of(false, "订单未确认收货,暂无法分账"); + } + + // 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_receive_log_no()); + return Pair.of(true, "订单已处理"); + } + if ("PROCESSING".equals(status) || "ACCEPTED".equals(status)) { + log.info("[分账操作] 订单[{}]交易对账流水号[{}]分账处理中或已受理,跳过处理", orderId, shopOrderLkl.getLkl_receive_log_no()); + return Pair.of(true, "订单已处理中或已受理"); + } + } else { + if (CommonConstant.Enable.equals(shopOrderLkl.getSeparate_status())) { + log.warn("[分账操作] 订单[{}]交易流水号[{}]订单已分账,跳过处理", orderId, receiveTradeNo); + return Pair.of(true, "订单已分账,请勿重复操作"); + } + } + + // 可分账金额 + Integer canSeparateAmt = null; + // 5. 检查可分账余额 + Pair mchCanSplitAmt = queryMchCanSplitAmt(lklMerchantNo, receiveLogNo, shopOrderLkl.getLkl_log_date()); + if (mchCanSplitAmt != null) { + log.error("[分账操作] 查询可分账余额失败:lklMerchantNo={} logDate={} receiveLogNo={}", lklMerchantNo, shopOrderLkl.getLkl_log_date(), receiveLogNo); + + // 可分账金额 + canSeparateAmt = Convert.toInt(mchCanSplitAmt.getSecond()); + if (canSeparateAmt == null || canSeparateAmt <= 0) { + log.warn("[分账操作] lklMerchantNo={} receiveTradeNo={} receiveLogNo={} 查询拉卡拉返回的可分账金额={}分,系统将自动计算可分账金额", + lklMerchantNo, receiveTradeNo, receiveLogNo, canSeparateAmt); + } + } + + + // 6. 获取订单分账相关参数 + String merchantNo = shopOrderLkl.getLkl_merchant_no(); + + // 获取商家分账比例并校验 + BigDecimal merchantSplitRatioRaw = shopOrderLkl.getSplit_ratio(); + boolean canSplitForMerchant = merchantSplitRatioRaw != null + && merchantSplitRatioRaw.compareTo(BigDecimal.ZERO) > 0 + && merchantSplitRatioRaw.compareTo(new BigDecimal(100)) <= 0; + if (!canSplitForMerchant) { + log.error("[分账操作] 店铺[{}]商家分账比例[{}]不在(0-100]范围内,无法分账", + shopOrderLkl.getStore_id(), merchantSplitRatioRaw); + return Pair.of(false, "商家分账比例有误"); + } + + // 计算商家分账比例(转换为小数) + BigDecimal merchantSplitRatio = merchantSplitRatioRaw.divide(new BigDecimal(100)); + + // 获取分账平台接收方信息 + LklLedgerMerReceiverBind platformReceiver = lklLedgerMerReceiverBindService.getPlatformByMerCupNo(merchantNo); + if (platformReceiver == null) { + log.error("[分账操作] 店铺[{}]未绑定平台方接收账户,跳过分账", shopOrderLkl.getStore_id()); + return Pair.of(false, "平台方未绑定账户"); + } + + // 获取代理商分账信息 + BigDecimal platformSplitRatio = BigDecimal.valueOf(0.01); + BigDecimal distributorSplitRatio = BigDecimal.ZERO; + + List distributorReceivers = lklLedgerMerReceiverBindService.selectDistributorByMerCupNo(merchantNo); + if (distributorReceivers != null && !distributorReceivers.isEmpty()) { + distributorSplitRatio = BigDecimal.valueOf(1).subtract(platformSplitRatio).subtract(merchantSplitRatio); + log.debug("[分账操作] 检测到代理商存在,调整分账比例: 代理商比例={}, 平台比例={}", distributorSplitRatio, platformSplitRatio); + } + + // 内部配送费 + Integer shoppingFeeInner = CheckUtil.isEmpty(shopOrderLkl.getShopping_fee_inner()) ? 0 : shopOrderLkl.getShopping_fee_inner(); + 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(merchantSplitRatio); + lklSeparateDTO.setPlatRatio(platformSplitRatio); + if (distributorSplitRatio.compareTo(BigDecimal.ZERO) > 0) { // 二级代理商参与分账 + lklSeparateDTO.setAgent2ndRatio(distributorSplitRatio); + } + lklSeparateDTO.setRefCanSeparateAmount(canSeparateAmt); // 拉卡拉实时返回的可分账金额 + + + // 分账方式:根据可分账金额分账 + if (!lklSeparateDTO.calcOnCanAmount()) { + log.error("[分账操作] 分账系统评估各项参数,发现无法分账 {}", lklSeparateDTO); + return Pair.of(false, "分账系统评估各项参数,发现无法分账"); + } + + if (CheckUtil.isEmpty(canSeparateAmt)) { + canSeparateAmt = lklSeparateDTO.getCanSeparateAmount(); + } + + log.debug("[分账操作] 分账参数计算结果:{}", lklSeparateDTO); + + // 更新分账计算结果 + shopOrderLkl.setSeparate_remark(lklSeparateDTO.toString()); + shopOrderLkl.setSplit_amt(canSeparateAmt); + shopOrderLklService.updateById(shopOrderLkl); + + // 分账金额校验 + if (canSeparateAmt <= 0) { + String errorMsg = String.format("[分账操作] 店铺[%s]订单[%s]分账金额[%d]低于1分钱,跳过分账", + shopOrderLkl.getStore_id(), orderId, canSeparateAmt); + log.error(errorMsg); + if (existingSeparateRecord != null) { + lklOrderSeparateService.updateRemark(existingSeparateRecord.getId(), errorMsg); + } + return Pair.of(false, "订单分账金额低于1分钱"); + } + + // 构建分账接收方列表 + List recvDatas = new ArrayList<>(); + + Integer merchantAmount = lklSeparateDTO.getMchAmount(); + Integer platformAmount = lklSeparateDTO.getPlatAmount(); + Integer agentAmount = lklSeparateDTO.getAgent2ndAmount(); + + log.info("[分账操作] 金额计算结果:订单={}, 商户={}, 总金额={}分, 可分金额={}分, 商家比例={}, 商家分得={}分, 平台比例={}, 平台分得={}分, 代理商比例={}, 代理商分得={}分", + orderId, merchantNo, shopOrderLkl.getTotal_amt(), canSeparateAmt, merchantSplitRatio, merchantAmount, platformSplitRatio, platformAmount, distributorSplitRatio, agentAmount); + + // 构建分账接收方分账参数 + // 商家分账参数 + 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); + } + + // 初始化拉卡拉SDK + log.debug("[分账操作] 初始化拉卡拉SDK"); + initLKLSDK(); + + // 构建分账请求对象 + 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(canSeparateAmt.toString()); + separateRequest.setLklOrgNo(orgCode); + separateRequest.setCalType("0"); // 0- 按照指定金额,1- 按照指定比例。默认 0 + separateRequest.setNotifyUrl(projectDomain + "/api/mobile/shop/lakala/sacs/separateNotify"); + separateRequest.setRecvDatas(recvDatas); + + log.info("[分账操作] 分账接收方数量={}", recvDatas.size()); + log.debug("[分账操作] 请求详细参数: {}", JSONUtil.toJsonStr(separateRequest)); + + // 发送分账请求 + 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); + + // 解析响应结果 + 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", + orderId, merchantNo, shopOrderLkl.getLkl_receive_log_no(), response); + shopOrderLklService.updateSeparateStatusByReceiveLogNo(shopOrderLkl.getLkl_receive_log_no(), CommonConstant.Sta_Separate_Fail, errorMsg); + log.error(errorMsg); + return Pair.of(false, "拉卡拉分账异常:[" + (respJson != null ? respJson.getStr("code") : "未知错误码") + "]" + + (respJson != null ? respJson.getStr("msg") : "未知错误")); + } + + // 保存分账记录 + 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(canSeparateAmt); + + if (lklOrderSeparateService.addOrUpdateByReceiverNo(separateRecord)) { + log.info("[分账操作] 记录保存成功:订单={}, 分账单号={}, 状态={}, 分账流水号={}", + orderId, separateRecord.getSeparate_no(), separateRecord.getStatus(), separateRecord.getLog_no()); + log.info("[分账操作] 结果:订单[{}] 订单分账已提交处理", orderId); + return Pair.of(true, "订单分账已提交处理"); + } 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, "保存分账记录失败"); + } + + } catch (Exception e) { + String errorMsg = String.format("[分账操作] 系统异常,分账对账流水号=%s,错误=%s", receiveLogNo, e.getMessage()); + log.error(errorMsg, e); + return Pair.of(false, "系统异常,请稍后重试"); + } + } + + + 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); @@ -2175,7 +2429,12 @@ public class LakalaApiServiceImpl implements LakalaApiService { // 3. 检查是否已确认收货 if (!CommonConstant.Enable.equals(shopOrderLkl.getReceive_status())) { log.warn("[分账操作] 订单[{}]交易流水号[{}]未被确认收货,跳过处理", orderId, receiveTradeNo); - return Pair.of(false, "订单未确认收货"); + return Pair.of(false, "订单未确认收货,暂无法分账"); + } + + if (CommonConstant.Enable.equals(shopOrderLkl.getSeparate_status())) { + log.warn("[分账操作] 订单[{}]交易流水号[{}]未被确认收货,跳过处理", orderId, receiveTradeNo); + return Pair.of(true, "订单已分账,请勿重复操作"); } // 4. 检查分账状态,避免重复处理 @@ -2363,6 +2622,8 @@ public class LakalaApiServiceImpl implements LakalaApiService { return Pair.of(false, "保存分账记录失败"); } + // 保存 shop_order_lkl 关键字段 + String result = "订单分账已提交处理"; log.info("[分账操作] 结果:订单[{}] {}", orderId, result); return Pair.of(true, result); @@ -2383,7 +2644,6 @@ public class LakalaApiServiceImpl implements LakalaApiService { } } - /** * 拉卡拉分账结果通知处理 *

diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/order/service/impl/ShopOrderLklServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/order/service/impl/ShopOrderLklServiceImpl.java index b9efdbaa..4703d762 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/order/service/impl/ShopOrderLklServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/order/service/impl/ShopOrderLklServiceImpl.java @@ -135,7 +135,7 @@ public class ShopOrderLklServiceImpl extends BaseServiceImpl