From 13ec66d045cc98687667258f3182e31da11dca2d Mon Sep 17 00:00:00 2001 From: liyj <1617420630@qq.com> Date: Sat, 11 Oct 2025 15:50:12 +0800 Subject: [PATCH 1/8] =?UTF-8?q?=E6=B6=88=E6=81=AF=E6=8E=A8=E9=80=81?= =?UTF-8?q?=E6=A0=B9=E6=8D=AE=E5=BE=AE=E4=BF=A1=E5=8F=B7=E5=8E=BB=E9=87=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../message/service/impl/ShopMessageTemplateServiceImpl.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/message/service/impl/ShopMessageTemplateServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/message/service/impl/ShopMessageTemplateServiceImpl.java index fff857fb..65ac9764 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/message/service/impl/ShopMessageTemplateServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/message/service/impl/ShopMessageTemplateServiceImpl.java @@ -762,7 +762,9 @@ public class ShopMessageTemplateServiceImpl extends BaseServiceImpl> futures = new ArrayList<>(); for (int i = 1; i <= pages; i++) { - List finalList = accountService.getAllBindPage(CommonConstant.BIND_SUB_TMPL_SKILL, i, BATCH_SIZE); + List finalList = accountService.getAllBindPage(CommonConstant.BIND_SUB_TMPL_SKILL, i, BATCH_SIZE) + .stream().filter(com.suisung.mall.common.utils.CommonUtil.distinctByKey(AccountUserBindConnect::getBind_openid)) + .collect(Collectors.toList()); int finalI = i; futures.add(executor.submit(() -> { finalList.forEach(accountUserBindConnect -> { From 97e20776c5e3866f142f40fe1a839265e7a99cfe Mon Sep 17 00:00:00 2001 From: Jack <46790855@qq.com> Date: Sat, 11 Oct 2025 20:55:40 +0800 Subject: [PATCH 2/8] =?UTF-8?q?=E6=94=AF=E4=BB=98=E5=90=88=E5=8D=95?= =?UTF-8?q?=E5=8F=98=E6=88=90=E9=9D=9E=E5=90=88=E5=8D=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/modules/order/ShopOrderData.java | 3 ++ .../modules/order/dto/MchOrderInfoDTO.java | 2 + .../service/impl/LakalaPayServiceImpl.java | 35 +++++++------- .../impl/PayConsumeTradeServiceImpl.java | 27 ++++++----- .../service/impl/PayUserPayServiceImpl.java | 46 +++++++++---------- .../impl/ShopOrderBaseServiceImpl.java | 4 ++ .../impl/ShopOrderReturnServiceImpl.java | 30 +++++++----- .../service/impl/SFExpressApiServiceImpl.java | 26 ++++++----- .../mapper/order/ShopOrderBaseMapper.xml | 8 ++-- 9 files changed, 103 insertions(+), 78 deletions(-) diff --git a/mall-common/src/main/java/com/suisung/mall/common/modules/order/ShopOrderData.java b/mall-common/src/main/java/com/suisung/mall/common/modules/order/ShopOrderData.java index 152a1839..ff480e84 100644 --- a/mall-common/src/main/java/com/suisung/mall/common/modules/order/ShopOrderData.java +++ b/mall-common/src/main/java/com/suisung/mall/common/modules/order/ShopOrderData.java @@ -101,6 +101,9 @@ public class ShopOrderData implements Serializable { @ApiModelProperty(value = "平台费(分给平台或代理商的费用),根据不同的店铺分类,从商品原价中扣除相应的费用。") private BigDecimal platform_fee; + @ApiModelProperty(value = "拉卡拉手续费") + private BigDecimal lkl_fee; + @ApiModelProperty(value = "店铺统一设置的打包费") private BigDecimal packing_fee; diff --git a/mall-common/src/main/java/com/suisung/mall/common/modules/order/dto/MchOrderInfoDTO.java b/mall-common/src/main/java/com/suisung/mall/common/modules/order/dto/MchOrderInfoDTO.java index 002a4a4b..23378173 100644 --- a/mall-common/src/main/java/com/suisung/mall/common/modules/order/dto/MchOrderInfoDTO.java +++ b/mall-common/src/main/java/com/suisung/mall/common/modules/order/dto/MchOrderInfoDTO.java @@ -74,6 +74,8 @@ public class MchOrderInfoDTO implements Serializable { private BigDecimal order_shipping_fee; @ApiModelProperty(value = "平台内部配送费") private BigDecimal order_shipping_fee_inner; + @ApiModelProperty(value = "拉卡拉手续费") + private BigDecimal lkl_fee; @ApiModelProperty(value = "平台费") private BigDecimal platform_fee; @ApiModelProperty(value = "店铺统一设置的打包费") 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 5044240d..14cace25 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 @@ -558,25 +558,27 @@ public class LakalaPayServiceImpl implements LakalaPayService { log.warn("[拉卡拉退款] 退款金额不合法: refundAmount={}", refundAmount); return Pair.of(false, I18nUtil._("退款金额不合法!")); } + + if (StrUtil.hasBlank(lklMerchantNo, lklTermNo)) { + // 4. 获取店铺的拉卡拉商户号和终端号 + ShopStoreBase shopStoreBase = shopService.getLklMerchantNoAndTermNo(storeId); + if (shopStoreBase == null) { + log.error("[拉卡拉退款] 无法获取店铺信息: storeId={}", storeId); + return Pair.of(false, I18nUtil._("无法获取店铺信息,退款失败!")); + } - // 3. 初始化拉卡拉SDK - initLKLSDK(); + if (StrUtil.isBlank(shopStoreBase.getLkl_merchant_no()) || StrUtil.isBlank(shopStoreBase.getLkl_term_no())) { + log.error("[拉卡拉退款] 无法获取店铺的拉卡拉商户号或终端号: storeId={}, merchantNo={}, termNo={}", + storeId, shopStoreBase.getLkl_merchant_no(), shopStoreBase.getLkl_term_no()); + return Pair.of(false, I18nUtil._("缺少商户号参数,退款失败!")); + } - // 4. 获取店铺的拉卡拉商户号和终端号 - ShopStoreBase shopStoreBase = shopService.getLklMerchantNoAndTermNo(storeId); - if (shopStoreBase == null) { - log.error("[拉卡拉退款] 无法获取店铺信息: storeId={}", storeId); - return Pair.of(false, I18nUtil._("无法获取店铺信息,退款失败!")); - } - - if (StrUtil.isBlank(shopStoreBase.getLkl_merchant_no()) || StrUtil.isBlank(shopStoreBase.getLkl_term_no())) { - log.error("[拉卡拉退款] 无法获取店铺的拉卡拉商户号或终端号: storeId={}, merchantNo={}, termNo={}", - storeId, shopStoreBase.getLkl_merchant_no(), shopStoreBase.getLkl_term_no()); - return Pair.of(false, I18nUtil._("缺少商户号参数,退款失败!")); + // 如果商户号和终端号是空的, + lklMerchantNo = StrUtil.isBlank(lklMerchantNo) ? shopStoreBase.getLkl_merchant_no() : lklMerchantNo; + lklTermNo = StrUtil.isBlank(lklTermNo) ? shopStoreBase.getLkl_term_no() : lklTermNo; } // TODO 重要的逻辑,获取是否已经分账?已分账:分账退回;查商家账户余额够不够退回?够就执行退回 - if (StrUtil.isBlank(refundReason)) { refundReason = "商家与买方协商退款"; } @@ -585,17 +587,16 @@ public class LakalaPayServiceImpl implements LakalaPayService { V3LabsRelationRefundRequest refundRequest = new V3LabsRelationRefundRequest(); refundRequest.setOutTradeNo(outTradeNo); refundRequest.setOriginTradeNo(originTradeNo); - lklMerchantNo = StrUtil.isBlank(lklMerchantNo) ? shopStoreBase.getLkl_merchant_no() : lklMerchantNo; - lklTermNo = StrUtil.isBlank(lklTermNo) ? shopStoreBase.getLkl_term_no() : lklTermNo; refundRequest.setMerchantNo(lklMerchantNo); refundRequest.setTermNo(lklTermNo); refundRequest.setRefundAmount(refundAmount); refundRequest.setRefundReason(refundReason); - refundRequest.setLocationInfo(new V3LabsTradeLocationInfo(requestIp, null, "")); log.info("[拉卡拉退款] 请求参数: {}", JSONUtil.toJsonStr(refundRequest)); + // 3. 初始化拉卡拉SDK + initLKLSDK(); String responseString = LKLSDK.httpPost(refundRequest); // 6. 处理响应 if (StrUtil.isBlank(responseString)) { diff --git a/mall-pay/src/main/java/com/suisung/mall/pay/service/impl/PayConsumeTradeServiceImpl.java b/mall-pay/src/main/java/com/suisung/mall/pay/service/impl/PayConsumeTradeServiceImpl.java index a8678096..3cc53738 100644 --- a/mall-pay/src/main/java/com/suisung/mall/pay/service/impl/PayConsumeTradeServiceImpl.java +++ b/mall-pay/src/main/java/com/suisung/mall/pay/service/impl/PayConsumeTradeServiceImpl.java @@ -188,7 +188,7 @@ public class PayConsumeTradeServiceImpl extends BaseServiceImpl 0) { + // 注意:商家配置的配送费 if (order_data_row != null && - order_data_row.getOrder_shipping_fee_inner() != null && - order_data_row.getOrder_shipping_fee_inner().compareTo(BigDecimal.ZERO) > 0) { + order_data_row.getOrder_shipping_fee() != null && + order_data_row.getOrder_shipping_fee().compareTo(BigDecimal.ZERO) > 0) { // 运费大于0的, 执行退运费操作, 有两种方案,1、生成退运费售后服务单; 2、直接执行退款 // 1、生成独立退运费售后服务单,需注意运费是退给运费代理商的,需要获取代理商的交易单号 @@ -1631,13 +1636,16 @@ public class ShopOrderReturnServiceImpl extends BaseServiceImpl + @@ -782,13 +783,14 @@ oi.payment_time, od.order_shipping_fee, IFNULL(od.order_shipping_fee_inner, 0) as order_shipping_fee_inner, + IFNULL(od.lkl_fee, 0) as lkl_fee, (od.order_discount_amount + od.voucher_price + od.order_points_fee + od.order_adjust_fee) as total_discount_amount, - - (ob.order_product_amount-od.order_discount_amount-od.voucher_price-od.order_points_fee-od.order_adjust_fee-od.platform_fee-order_shipping_fee_inner+od.packing_fee) + + (ob.order_product_amount-od.order_discount_amount-od.voucher_price-od.order_points_fee-od.order_adjust_fee-od.platform_fee-order_shipping_fee_inner-lkl_fee+od.packing_fee) as order_income_amount, - od.platform_fee, + (od.platform_fee+lkl_fee) as platform_fee, od.packing_fee, od.order_message, sb.store_id, From 2758b5ac622b4d9e5baef8ec653af7d91aa8b594 Mon Sep 17 00:00:00 2001 From: liyj <1617420630@qq.com> Date: Mon, 13 Oct 2025 14:48:43 +0800 Subject: [PATCH 3/8] =?UTF-8?q?=E6=80=9D=E8=BF=85=E6=89=B9=E9=87=8F?= =?UTF-8?q?=E5=AF=B9=E6=8E=A5=E6=AC=A1=E6=97=A5=E6=9B=B4=E6=96=B0=E5=BA=93?= =?UTF-8?q?=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../shop/sync/service/impl/SyncBaseThirdSxAbstract.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/sync/service/impl/SyncBaseThirdSxAbstract.java b/mall-shop/src/main/java/com/suisung/mall/shop/sync/service/impl/SyncBaseThirdSxAbstract.java index e1fc6441..8b0450ee 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/sync/service/impl/SyncBaseThirdSxAbstract.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/sync/service/impl/SyncBaseThirdSxAbstract.java @@ -811,6 +811,7 @@ public abstract class SyncBaseThirdSxAbstract{ shopProductBase.setProduct_add_time(currentDate.getTime()); shopProductBase.setProduct_unit_price(BigDecimal.valueOf(jsonObj.getDouble("retail_price"))); String isSpecial=jsonObj.getStr("isSpecial",DicEnum.YESORNO_0.getCode()); + String is_open_automatic=DicEnum.YESORNO_0.getCode(); if(ObjectUtil.equals(isSpecial,DicEnum.YESORNO_0.getCode())||ObjectUtil.equals(isSpecial,DicEnum.YESORNO_1.getCode())){ shopProductBase.setIs_special(isSpecial);//是否特价商品 特价商品需要手动上架 todo 是否要开发定时上架功能 }else { @@ -830,6 +831,7 @@ public abstract class SyncBaseThirdSxAbstract{ shopProductBase.setUnit_name(jsonObj.getStr("unit")); shopProductBase.setProduct_state_id(StateCode.PRODUCT_STATE_OFF_THE_SHELF_UNCHECK); shopProductBase.setUnit_price(BigDecimal.valueOf(jsonObj.getDouble("retail_price"))); + is_open_automatic=DicEnum.YESORNO_1.getCode(); }else { shopProductBase.setShop_weight(stock); if(null!= jsonObj.getJSONArray("product_spec")){ @@ -944,6 +946,10 @@ public abstract class SyncBaseThirdSxAbstract{ shopProductItem.setItem_is_default(1); shopProductItem.setItem_enable(StateCode.PRODUCT_STATE_NORMAL); + shopProductItem.setIs_open_automatic(is_open_automatic); + if(is_open_automatic.equals(DicEnum.YESORNO_1.getCode())){ + shopProductItem.setAutomatic(stock.intValue()); + } //shopProductImage ShopProductImage shopProductImage = new ShopProductImage(); shopProductImage.setStore_id(storeIdInt); From 375e2b52ac306f6a692be4b7ed46240ce2a9ef72 Mon Sep 17 00:00:00 2001 From: Jack <46790855@qq.com> Date: Mon, 13 Oct 2025 17:12:12 +0800 Subject: [PATCH 4/8] =?UTF-8?q?=E5=88=86=E8=B4=A6=E9=87=91=E9=A2=9D?= =?UTF-8?q?=E7=9A=84=E8=AE=A1=E7=AE=97=E9=80=BB=E8=BE=91=E6=9B=B4=E6=94=B9?= =?UTF-8?q?=EF=BC=8C=E6=94=AF=E4=BB=98=E3=80=81=E5=88=86=E8=B4=A6=E9=80=BB?= =?UTF-8?q?=E8=BE=91=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../modules/esign/EsignPlatformInfo.java | 13 + .../common/modules/order/ShopOrderData.java | 2 +- .../dto/LklSeparateWithTotalAmountDTO.java | 413 ++++++++++++++++++ .../shop/lakala/service/LakalaApiService.java | 18 +- .../service/impl/LakalaApiServiceImpl.java | 141 +++--- .../impl/ShopOrderBaseServiceImpl.java | 7 +- 6 files changed, 511 insertions(+), 83 deletions(-) create mode 100644 mall-common/src/main/java/com/suisung/mall/common/pojo/dto/LklSeparateWithTotalAmountDTO.java diff --git a/mall-common/src/main/java/com/suisung/mall/common/modules/esign/EsignPlatformInfo.java b/mall-common/src/main/java/com/suisung/mall/common/modules/esign/EsignPlatformInfo.java index ea3e155d..65fe2e04 100644 --- a/mall-common/src/main/java/com/suisung/mall/common/modules/esign/EsignPlatformInfo.java +++ b/mall-common/src/main/java/com/suisung/mall/common/modules/esign/EsignPlatformInfo.java @@ -18,6 +18,7 @@ import lombok.EqualsAndHashCode; import lombok.experimental.Accessors; import java.io.Serializable; +import java.math.BigDecimal; import java.util.Date; @Data @@ -32,6 +33,9 @@ public class EsignPlatformInfo implements Serializable { @ApiModelProperty(value = "自增ID") private Long id; + @ApiModelProperty(value = "父代理商 Id(省级代理商Id)") + private Long parent_id; + @ApiModelProperty(value = "公司邮箱") private String email; @@ -110,6 +114,15 @@ public class EsignPlatformInfo implements Serializable { @ApiModelProperty(value = "邀请码,后期跟收益有关") private String invite_code; + @ApiModelProperty(value = "县级市代理商设定的配送费(单位:分)") + private Integer shipping_fee; + + @ApiModelProperty(value = "顺丰商家Id (用于县级代理商创建店铺的商家Id)") + private String supplier_id; + + @ApiModelProperty(value = "分账比例值,取值范围:[0.01,1.00]") + private BigDecimal split_ratio; + @ApiModelProperty(value = "记录状态:1-有效;2-无效;") private Integer status; diff --git a/mall-common/src/main/java/com/suisung/mall/common/modules/order/ShopOrderData.java b/mall-common/src/main/java/com/suisung/mall/common/modules/order/ShopOrderData.java index ff480e84..a52716fe 100644 --- a/mall-common/src/main/java/com/suisung/mall/common/modules/order/ShopOrderData.java +++ b/mall-common/src/main/java/com/suisung/mall/common/modules/order/ShopOrderData.java @@ -101,7 +101,7 @@ public class ShopOrderData implements Serializable { @ApiModelProperty(value = "平台费(分给平台或代理商的费用),根据不同的店铺分类,从商品原价中扣除相应的费用。") private BigDecimal platform_fee; - @ApiModelProperty(value = "拉卡拉手续费") + @ApiModelProperty(value = "拉卡拉手续费,单位:元") private BigDecimal lkl_fee; @ApiModelProperty(value = "店铺统一设置的打包费") diff --git a/mall-common/src/main/java/com/suisung/mall/common/pojo/dto/LklSeparateWithTotalAmountDTO.java b/mall-common/src/main/java/com/suisung/mall/common/pojo/dto/LklSeparateWithTotalAmountDTO.java new file mode 100644 index 00000000..c99bc491 --- /dev/null +++ b/mall-common/src/main/java/com/suisung/mall/common/pojo/dto/LklSeparateWithTotalAmountDTO.java @@ -0,0 +1,413 @@ +package com.suisung.mall.common.pojo.dto; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.springframework.data.util.Pair; + +import java.math.BigDecimal; +import java.math.RoundingMode; + +/** + * 拉卡拉订单基于总金额分账信息处理类 + * 实现基于总金额的分账算法,支持平台、代理商和商家的多级分账,类里涉及的金额单位:分 + *

+ * 分账计算逻辑: + * 1、totalSeparateAmount,是必填参数,订单的总金额,必须大于0;lklRatio 是必填参数,拉卡拉的分账比例,如 0.0025 + * 先减去拉卡拉配送费=lklRatio*totalSeparateAmount(结果四舍五入,保留整数,以下计算结果一律四舍五入),余额得到可分账金额(分) canSeparateAmount + * 2、refCanSeparateAmount 是可选参数,如果有效(非空且大于0),往下计算分账基准依据此参数计算(实际的可分账金额A),而不是以 canSeparateAmount 为基准。 + * 3、shippingFee 是可选参数,如果有效(非空且大于0),往下实际的可分账金额B = 实际的可分账金额A -shippingFee。 + * 4、实际的可分账金额B 就是平台、一级代理商、二级代理商、商家的可分账金额,按照以下规则进行分账给四个对象。 + * 5、四个对象之前,需要知道他们的准则: + * 6、平台一定参加分账的,如果 platRatio 无效(空值或小于等于0),默认0.01,优先分账,凭条分账金额 =totalSeparateAmount* platRatio。 + * 7、平台和商家一定参加分账的,一级代理商和二级代理商,如果对应的比例agent1stRatio,agent2ndRatio 有效(非空且大于0)就参与分账,否则不参与。 + * 8、mchRatio 可以根据分账金额,动态调整到实际比例 + * 9、所有参与分账的主体,其分账金额都不能为负数,否则将抛出异常。 + * 10、分账顺序按照优先级:拉卡拉 -> 平台 -> 二级代理商 -> 一级代理商 -> 商家,商家获得剩余的所有金额。 + * 11、五方分账金额之和不能超过 totalSeparateAmount + * 12、分账计算完成后,会计算出 mchRatio 的实际比例 + * 13、如果商家实际分账比例低于0.2阈值,会抛出异常:商家分账低于阈值 + */ +@Data +@EqualsAndHashCode(callSuper = false) +public class LklSeparateWithTotalAmountDTO { + + // 常量定义 + private static final BigDecimal MCH_RATIO_THRESHOLD = new BigDecimal("0.2"); + + // 基础金额属性 + private Integer totalSeparateAmount; // 分账总金额(分) + private Integer canSeparateAmount; // 可分账金额(分) + private Integer refCanSeparateAmount; // 拉卡拉可分账金额参考(分) + private Integer shippingFee; // 配送费(分) + + // 分账比例属性 + 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%) + + // 分账金额结果属性 + private Integer lklAmount; // 拉卡拉分账金额(分) + private Integer mchAmount; // 商户分账金额(分) + private Integer platAmount; // 平台分账金额(分) + private Integer agent1stAmount; // 一级代理商分账金额(分) + private Integer agent2ndAmount; // 二级代理商分账金额(分) + + /** + * 测试方法 + * 包含多个测试用例,验证分账计算逻辑的正确性和异常处理机制 + */ + public static void main(String[] args) { + // 测试用例1: 所有参与方都参与分账(符合比例要求) + System.out.println("=== 测试用例1: 所有参与方都参与分账 ==="); + LklSeparateWithTotalAmountDTO dto1 = new LklSeparateWithTotalAmountDTO(); + dto1.setTotalSeparateAmount(1500); // 总金额100元(10000分) + dto1.setShippingFee(600); +// dto1.setRefCanSeparateAmount(1496); + dto1.setLklRatio(new BigDecimal("0.0025")); // 拉卡拉分账比例0.25% + dto1.setMchRatio(new BigDecimal("0.95")); // 商家分账比例94.75% + dto1.setPlatRatio(new BigDecimal("0.01")); // 平台分账比例1% +// dto1.setAgent2ndRatio(new BigDecimal("0.04")); // 二级代理商分账比例4% +// dto1.setAgent1stRatio(new BigDecimal("0.01")); // 一级代理商分账比例1% + + Pair result = dto1.calculateSeparateAmount(); + if (result.getFirst()) { + System.out.println("分账计算成功:"); + System.out.println(result.getSecond()); + System.out.println("JSON格式输出:"); + System.out.println(result.getSecond().toJSON()); + } else { + System.out.println("分账计算失败"); + if (result.getSecond() != null) { + System.out.println("部分结果:"); + System.out.println(result.getSecond()); + } + } + } + + /** + * 执行分账计算逻辑 + * + * @return Pair Boolean表示是否成功,LklSeparateWithTotalAmountDTO为分账结果 + */ + public Pair calculateSeparateAmount() { + try { + // 参数校验 + validateInputs(); + + // 1. 计算拉卡拉分账金额和可分账金额 + calculateLklAmountAndCanSeparateAmount(); + + // 2. 确定实际可分账金额 + int actualCanSeparateAmount = determineActualCanSeparateAmount(); + + // 3. 计算各参与方分账比例 + calculateDefaultRatios(); + + // 4. 根据优先级顺序计算各参与方分账金额 + calculateAmountsInPriorityOrder(actualCanSeparateAmount); + + // 5. 校验分账金额总和不能超过总金额 + validateSeparateAmountTotal(); + + // 6. 计算商家实际分账比例 + calculateActualMchRatio(); + + return Pair.of(true, this); + } catch (IllegalArgumentException e) { + // 参数校验异常,返回false和当前对象 + System.err.println("分账计算参数异常: " + e.getMessage()); + return Pair.of(false, this); + } catch (Exception e) { + // 其他异常,返回false和null + System.err.println("分账计算异常: " + e.getMessage()); + return Pair.of(false, null); + } + } + + /** + * 校验必要参数 + * + * @throws IllegalArgumentException 当参数不合法时抛出异常 + */ + private void validateInputs() { + // 校验totalSeparateAmount必须为有效值且大于0 + if (totalSeparateAmount == null || totalSeparateAmount <= 0) { + throw new IllegalArgumentException("分账计算缺少必要参数或参数不合法"); + } + + // 校验必要参数 + if (lklRatio == null || mchRatio == null) { + throw new IllegalArgumentException("分账计算缺少必要参数"); + } + + // 校验shippingFee不能大于等于totalSeparateAmount + if (shippingFee != null && shippingFee >= totalSeparateAmount) { + throw new IllegalArgumentException("配送费不能大于等于总金额"); + } + } + + /** + * 计算拉卡拉分账金额和初始可分账金额 + * 拉卡拉分账金额 = 总金额 * 拉卡拉分账比例(四舍五入) + * 可分账金额 = 总金额 - 拉卡拉分账金额 + * + * @throws IllegalArgumentException 当计算出的分账金额为负数时抛出异常 + */ + private void calculateLklAmountAndCanSeparateAmount() { + // 拉卡拉分账金额 = 总金额 * 拉卡拉分账比例(四舍五入) + lklAmount = lklRatio.multiply(new BigDecimal(totalSeparateAmount)) + .setScale(0, RoundingMode.HALF_UP) + .intValue(); + + // 校验拉卡拉分账金额不能为负数 + if (lklAmount < 0) { + // 记录详细日志 + System.err.println("拉卡拉分账金额计算结果为负数: " + lklAmount); + throw new IllegalArgumentException("拉卡拉分账金额计算异常"); + } + + // 可分账金额 = 总金额 - 拉卡拉分账金额 + canSeparateAmount = totalSeparateAmount - lklAmount; + + // 校验可分账金额不能为负数 + if (canSeparateAmount < 0) { + // 记录详细日志 + System.err.println("可分账金额计算结果为负数: " + canSeparateAmount); + throw new IllegalArgumentException("可分账金额计算异常"); + } + } + + /** + * 确定实际可分账金额 + * 实际可分账金额A: 如果refCanSeparateAmount有效则使用,否则使用canSeparateAmount + * 实际可分账金额B = 实际可分账金额A - 配送费(如果配送费有效) + * + * @return 实际可分账金额 + * @throws IllegalArgumentException 当实际可分账金额为负数时抛出异常 + */ + private int determineActualCanSeparateAmount() { + // 实际可分账金额A: 如果refCanSeparateAmount有效则使用,否则使用canSeparateAmount + int actualCanSeparateAmountA = (refCanSeparateAmount != null && refCanSeparateAmount > 0) + ? refCanSeparateAmount : canSeparateAmount; + + // 实际可分账金额B = 实际可分账金额A - 配送费(如果配送费有效) + int actualCanSeparateAmountB = actualCanSeparateAmountA; + if (shippingFee != null && shippingFee > 0) { + actualCanSeparateAmountB = actualCanSeparateAmountA - shippingFee; + } + + // 校验实际可分账金额不能为负数 + if (actualCanSeparateAmountB < 0) { + // 记录详细日志 + System.err.println("实际可分账金额计算结果为负数: " + actualCanSeparateAmountB); + throw new IllegalArgumentException("实际可分账金额计算异常"); + } + + return actualCanSeparateAmountB; + } + + /** + * 计算各参与方分账比例 + * 如果平台比例无效,设置默认值0.01 + */ + private void calculateDefaultRatios() { + // 如果平台比例无效,设置默认值0.01 + if (platRatio == null || platRatio.compareTo(BigDecimal.ZERO) <= 0) { + platRatio = new BigDecimal("0.01"); + } + } + + /** + * 根据优先级顺序计算各参与方分账金额 + * 分账顺序:拉卡拉 -> 平台 -> 二级代理商 -> 一级代理商 -> 商家 + * 商家获得所有剩余金额 + * + * @param actualCanSeparateAmount 实际可分账金额 + * @throws IllegalArgumentException 当计算出的分账金额为负数或分账金额超过可用金额时抛出异常 + */ + private void calculateAmountsInPriorityOrder(int actualCanSeparateAmount) { + // 重置所有分账金额 + platAmount = 0; + agent1stAmount = 0; + agent2ndAmount = 0; + mchAmount = 0; + + // 1. 计算拉卡拉分账金额(拉卡拉一定参与分账) + lklAmount = lklRatio.multiply(new BigDecimal(totalSeparateAmount)) + .setScale(0, RoundingMode.HALF_UP) + .intValue(); + + // 校验拉卡拉分账金额不能为负数 + if (lklAmount < 0) { + throw new IllegalArgumentException("拉卡拉分账金额计算异常"); + } + + // 2. 校验实际可分账金额不能小于0 + if (actualCanSeparateAmount < 0) { + throw new IllegalArgumentException("实际可分账金额不能为负数"); + } + + // 3. 初始化剩余金额为实际可分账金额 + int remainingAmount = actualCanSeparateAmount; + + // 4. 计算平台分账金额(平台一定参与分账) + platAmount = platRatio.multiply(new BigDecimal(totalSeparateAmount)) + .setScale(0, RoundingMode.HALF_UP) + .intValue(); + + // 校验平台分账金额不能为负数 + if (platAmount < 0) { + throw new IllegalArgumentException("平台分账金额计算异常"); + } + + // 确保不超过剩余金额 + if (platAmount > remainingAmount) { + platAmount = remainingAmount; + } + + // 更新剩余金额 + remainingAmount -= platAmount; + + // 5. 判断代理商是否参与分账 + boolean isAgent2ndParticipate = agent2ndRatio != null && agent2ndRatio.compareTo(BigDecimal.ZERO) > 0; + boolean isAgent1stParticipate = agent1stRatio != null && agent1stRatio.compareTo(BigDecimal.ZERO) > 0; + + // 6. 按优先级顺序计算代理商分账金额 + // 优先级:平台 -> 二级代理商 -> 一级代理商 + if (isAgent2ndParticipate) { + // 计算二级代理商分账金额 + agent2ndAmount = agent2ndRatio.multiply(new BigDecimal(totalSeparateAmount)) + .setScale(0, RoundingMode.HALF_UP) + .intValue(); + + // 校验二级代理商分账金额不能为负数 + if (agent2ndAmount < 0) { + throw new IllegalArgumentException("二级代理商分账金额计算异常"); + } + + // 确保不超过剩余金额 + if (agent2ndAmount > remainingAmount) { + agent2ndAmount = remainingAmount; + } + remainingAmount -= agent2ndAmount; + } + + if (isAgent1stParticipate) { + // 计算一级代理商分账金额 + agent1stAmount = agent1stRatio.multiply(new BigDecimal(totalSeparateAmount)) + .setScale(0, RoundingMode.HALF_UP) + .intValue(); + + // 校验一级代理商分账金额不能为负数 + if (agent1stAmount < 0) { + throw new IllegalArgumentException("一级代理商分账金额计算异常"); + } + + // 确保不超过剩余金额 + if (agent1stAmount > remainingAmount) { + agent1stAmount = remainingAmount; + } + remainingAmount -= agent1stAmount; + } + + // 7. 最后计算商家分账金额(使用剩余所有金额) + mchAmount = remainingAmount; + + // 校验商家分账金额不能为负数 + if (mchAmount < 0) { + throw new IllegalArgumentException("商家分账金额计算异常"); + } + } + + + /** + * 计算商家实际分账比例 + * + * @throws IllegalArgumentException 当商家实际分账比例低于阈值时抛出异常 + */ + private void calculateActualMchRatio() { + if (totalSeparateAmount != null && totalSeparateAmount > 0 && mchAmount != null) { + // 计算实际比例,保留6位小数 + mchRatio = new BigDecimal(mchAmount) + .divide(new BigDecimal(totalSeparateAmount), 6, RoundingMode.HALF_UP); + + // 如果计算出的实际比例低于阈值,打印日志并抛出异常 + if (mchRatio.compareTo(MCH_RATIO_THRESHOLD) < 0) { + System.err.println("警告: 商家实际分账比例低于阈值,当前比例: " + mchRatio + ",阈值: " + MCH_RATIO_THRESHOLD); + throw new IllegalArgumentException("商家分账低于阈值"); + } + } + } + + /** + * 校验分账金额总和不能超过总金额 + * + * @throws IllegalArgumentException 当分账金额总和超过总金额时抛出异常 + */ + private void validateSeparateAmountTotal() { + int totalAmount = 0; + totalAmount += (lklAmount != null ? lklAmount : 0); + totalAmount += (platAmount != null ? platAmount : 0); + totalAmount += (agent2ndAmount != null ? agent2ndAmount : 0); + totalAmount += (agent1stAmount != null ? agent1stAmount : 0); + totalAmount += (mchAmount != null ? mchAmount : 0); + + if (totalAmount > totalSeparateAmount) { + // 记录详细日志 + System.err.println("分账金额总和超过总金额,分账金额总和: " + totalAmount + ",总金额: " + totalSeparateAmount); + throw new IllegalArgumentException("分账金额总和超过总金额"); + } + } + + /** + * 生成对象的字符串表示 + * + * @return 对象的字符串表示 + */ + @Override + public String toString() { + return "分账计算结果{" + + "总分账金额(分) totalSeparateAmount=" + totalSeparateAmount + + ", 可分账金额(分) canSeparateAmount=" + canSeparateAmount + + ", 拉卡拉可分账金额参考(分) refCanSeparateAmount=" + refCanSeparateAmount + + ", 配送费(分) shippingFee=" + shippingFee + + ", 拉卡拉分账比例 lklRatio=" + lklRatio + + ", 商户分账比例 mchRatio=" + mchRatio + + ", 平台分账比例 platRatio=" + platRatio + + ", 一级代理商分账比例 agent1stRatio=" + agent1stRatio + + ", 二级代理商分账比例 agent2ndRatio=" + agent2ndRatio + + ", 拉卡拉分账金额(分) lklAmount=" + lklAmount + + ", 商户分账金额(分) mchAmount=" + mchAmount + + ", 平台分账金额(分) platAmount=" + platAmount + + ", 一级代理商分账金额(分) agent1stAmount=" + agent1stAmount + + ", 二级代理商分账金额(分) agent2ndAmount=" + agent2ndAmount + + '}'; + } + + /** + * 将对象转换为JSON格式字符串 + * + * @return JSON格式字符串 + */ + public String toJSON() { + String sb = "{" + + "\"totalSeparateAmount\":" + totalSeparateAmount + "," + + "\"canSeparateAmount\":" + canSeparateAmount + "," + + "\"refCanSeparateAmount\":" + refCanSeparateAmount + "," + + "\"shippingFee\":" + shippingFee + "," + + "\"lklRatio\":" + (lklRatio != null ? "\"" + lklRatio + "\"" : "null") + "," + + "\"mchRatio\":" + (mchRatio != null ? "\"" + mchRatio + "\"" : "null") + "," + + "\"platRatio\":" + (platRatio != null ? "\"" + platRatio + "\"" : "null") + "," + + "\"agent1stRatio\":" + (agent1stRatio != null ? "\"" + agent1stRatio + "\"" : "null") + "," + + "\"agent2ndRatio\":" + (agent2ndRatio != null ? "\"" + agent2ndRatio + "\"" : "null") + "," + + "\"lklAmount\":" + lklAmount + "," + + "\"mchAmount\":" + mchAmount + "," + + "\"platAmount\":" + platAmount + "," + + "\"agent1stAmount\":" + agent1stAmount + "," + + "\"agent2ndAmount\":" + agent2ndAmount + + "}"; + return sb; + } +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LakalaApiService.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LakalaApiService.java index 43fdabd5..f4c12f23 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LakalaApiService.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LakalaApiService.java @@ -11,7 +11,7 @@ package com.suisung.mall.shop.lakala.service; import cn.hutool.json.JSONObject; import com.suisung.mall.common.api.CommonResult; import com.suisung.mall.common.modules.store.ShopMchEntry; -import com.suisung.mall.common.pojo.dto.LklSeparateDTO; +import com.suisung.mall.common.pojo.dto.LklSeparateWithTotalAmountDTO; import org.springframework.data.util.Pair; import javax.servlet.http.HttpServletRequest; @@ -355,7 +355,6 @@ public interface LakalaApiService { /** * 商户分账参数计算及评估 * - * @param splitMode 分账模式:1-总金额为基准分账,2-可分账金额基准分账,必填参数 * @param orderPayAmount 订单支付总金额(单位:分)必填参数 * @param shippingFeeInner 平台内部配送费(单位:分)必填参数 * @param mchSplitRatioRaw 商户分账比例值(分子值,如10表示10%)必填参数 @@ -365,13 +364,12 @@ public interface LakalaApiService { * @param refCanSeparateAmt 参考可分金额(单位:分) 可选参数 * @return Pair 分账参数评估结果,第一个元素表示是否成功,第二个元素为分账参数对象 */ - Pair calculateAndEvaluateSharingParams(int splitMode, - Integer orderPayAmount, - Integer shippingFeeInner, - BigDecimal mchSplitRatioRaw, - BigDecimal platSplitRatio, - BigDecimal agent1stRatio, - BigDecimal agent2ndRatio, - Integer refCanSeparateAmt); + Pair calculateAndEvaluateSharingParams(Integer orderPayAmount, + Integer shippingFeeInner, + BigDecimal mchSplitRatioRaw, + BigDecimal platSplitRatio, + BigDecimal agent1stRatio, + BigDecimal agent2ndRatio, + Integer refCanSeparateAmt); } 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 b72c8235..7b8b7135 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 @@ -30,7 +30,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.LklSeparateWithTotalAmountDTO; import com.suisung.mall.common.service.impl.CommonService; import com.suisung.mall.common.utils.*; import com.suisung.mall.core.web.service.RedisService; @@ -860,7 +860,7 @@ public class LakalaApiServiceImpl implements LakalaApiService { return JSONUtil.createObj().set("code", "FAIL").set("message", "交易状态未成功,不做任何处理!"); } - if (StrUtil.isBlank(logNo) || StrUtil.isBlank(merchantNo) || StrUtil.isBlank(originTradeNo) || StrUtil.isBlank(originLogNo)) { + if (StrUtil.hasBlank(logNo, merchantNo, originTradeNo, originLogNo)) { log.warn("[确认收货通知] 关键参数为空: logNo={}, merchantNo={}, originTradeNo={}, originLogNo={}", logNo, merchantNo, originTradeNo, originLogNo); return JSONUtil.createObj().set("code", "FAIL").set("message", "关键编号返回空值!"); @@ -888,7 +888,7 @@ public class LakalaApiServiceImpl implements LakalaApiService { } log.info("[确认收货通知] 订单信息更新成功: orderId={}", shopOrderLkl.getOrder_id()); - // 发起分账指令 + // 准备发起分账指令 log.info("[确认收货通知] 开始发起分账指令: merchantNo={}, receiveTradeNo={}, logNo={}", merchantNo, shopOrderLkl.getLkl_receive_trade_no(), logNo); Pair separateResult = innerDoOrderSeparateByMerchantAndLogNo(merchantNo, shopOrderLkl.getLkl_receive_trade_no(), shopOrderLkl.getLkl_receive_log_no()); @@ -2510,34 +2510,36 @@ public class LakalaApiServiceImpl implements LakalaApiService { } // 获取代理商分账信息 - BigDecimal platformSplitRatio = BigDecimal.valueOf(0.01); - BigDecimal distributorSplitRatio = BigDecimal.ZERO; - List distributorReceivers = lklLedgerMerReceiverBindService.selectDistributorByMerCupNo(merchantNo); - if (CollUtil.isNotEmpty(distributorReceivers)) { - distributorSplitRatio = BigDecimal.valueOf(1).subtract(mchSplitRatio).subtract(platformSplitRatio); - log.debug("[分账操作] 检测到代理商存在,调整分账比例: 代理商比例={}, 平台比例={}", distributorSplitRatio, platformSplitRatio); + BigDecimal platformSplitRatio = BigDecimal.valueOf(0.01); // 默认平台比例 1% + BigDecimal agent2ndSplitRatio = null; + + // 代理商绑定列表 + List lklLedgerMerReceiverBindList = lklLedgerMerReceiverBindService.selectDistributorByMerCupNo(merchantNo); + if (CollUtil.isNotEmpty(lklLedgerMerReceiverBindList)) { + // 县级代理商比例值 = 1-商家比例值-平台比例值 + agent2ndSplitRatio = BigDecimal.ONE.subtract(mchSplitRatio).subtract(platformSplitRatio); + log.debug("[分账操作] 检测到代理商存在,调整分账比例: 代理商比例={}, 平台比例={}", agent2ndSplitRatio, platformSplitRatio); } else { - platformSplitRatio = BigDecimal.valueOf(1).subtract(mchSplitRatio); - distributorSplitRatio = null; + // 平台比例值 = 1-商家比例值 + platformSplitRatio = BigDecimal.ONE.subtract(mchSplitRatio); } - // 内部配送费 + // 内部配送费(单位:分) Integer shoppingFeeInner = CheckUtil.isEmpty(shopOrderLkl.getShopping_fee_inner()) ? 0 : shopOrderLkl.getShopping_fee_inner(); // 计算拉卡拉手续费、商家分账金额、平台和代理商的分账金额 - Pair calcResult = calculateAndEvaluateSharingParams( - CommonConstant.SeparateCalcMode_CanSeparateAmt, + Pair calcResult = calculateAndEvaluateSharingParams( shopOrderLkl.getTotal_amt(), shoppingFeeInner, mchSplitRatio, platformSplitRatio, - null, distributorSplitRatio, refCanSeparateAmt); + null, agent2ndSplitRatio, refCanSeparateAmt); if (calcResult == null || !calcResult.getFirst() || calcResult.getSecond() == null) { log.error("[分账操作] 分账参数评估,结果无法分账"); return Pair.of(false, "分账数据评估,结果无法分账"); } - LklSeparateDTO lklSeparateDTO = calcResult.getSecond(); + LklSeparateWithTotalAmountDTO lklSeparateDTO = calcResult.getSecond(); log.debug("[分账操作] 分账参数计算结果:{}", lklSeparateDTO); @@ -2550,57 +2552,71 @@ public class LakalaApiServiceImpl implements LakalaApiService { shopOrderLkl.setSplit_amt_ref(refCanSeparateAmt); } - // 分账金额校验 + // 可分账金额校验 if (CheckUtil.isEmpty(refCanSeparateAmt)) { - String errorMsg = String.format("[分账操作] 店铺[%s]订单[%s]分账金额[%d]低于1分钱,跳过分账", + String errorMsg = String.format("[分账操作] 店铺[%s]订单[%s]可分账金额[%d]低于1分钱,跳过分账", shopOrderLkl.getStore_id(), orderId, refCanSeparateAmt); log.error(errorMsg); if (existingSeparateRecord != null) { lklOrderSeparateService.updateRemark(existingSeparateRecord.getId(), errorMsg); } - return Pair.of(false, "订单分账金额低于1分钱"); + return Pair.of(false, "订单可分账金额低于1分钱"); } - // 构建分账接收方列表 - List recvDatas = new ArrayList<>(); Integer merchantAmount = lklSeparateDTO.getMchAmount(); Integer platformAmount = lklSeparateDTO.getPlatAmount(); - Integer agentAmount = lklSeparateDTO.getAgent2ndAmount(); + Integer agent2ndAmount = lklSeparateDTO.getAgent2ndAmount(); - log.info("[分账操作] 金额计算结果:订单={}, 商户={}, 总金额={}分, 可分金额={}分, 商家比例={}, 商家分得={}分, 平台比例={}, 平台分得={}分, 代理商比例={}, 代理商分得={}分", + log.info("[分账操作] 金额计算结果:订单={}, 商户={}, 总金额={}分, 可分金额={}分, 商家比例={}, 商家分得={}分, 平台比例={}, 平台分得={}分, 县级代理商比例={}, 县级代理商分得={}分", orderId, merchantNo, shopOrderLkl.getTotal_amt(), refCanSeparateAmt, mchSplitRatio, merchantAmount, - platformSplitRatio, platformAmount, distributorSplitRatio, agentAmount); + platformSplitRatio, platformAmount, agent2ndSplitRatio, agent2ndAmount); - // 构建分账接收方分账参数 + // 构建分账接收方分账列表参数 + List recvDatas = new ArrayList<>(); // 商家分账参数 - if (merchantAmount != null && merchantAmount > 0) { + if (CheckUtil.isNotEmpty(merchantAmount)) { V3SacsSeparateRecvDatas receiver = new V3SacsSeparateRecvDatas(); receiver.setRecvMerchantNo(merchantNo); receiver.setSeparateValue(merchantAmount.toString()); recvDatas.add(receiver); + log.debug("[分账操作] 添加商家接收方: merchantNo={}, amount={}", merchantNo, merchantAmount); } // 平台分账参数 - if (platformAmount != null && platformAmount > 0) { + if (CheckUtil.isNotEmpty(platformAmount)) { 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 != null && agentAmount > 0 && CollUtil.isNotEmpty(distributorReceivers)) { - LklLedgerMerReceiverBind distributorReceiver = distributorReceivers.get(0); - if (distributorReceiver != null && StrUtil.isNotBlank(distributorReceiver.getReceiver_no())) { + // 县级代理商分账参数 + if (CollUtil.isNotEmpty(lklLedgerMerReceiverBindList) && CheckUtil.isNotEmpty(agent2ndAmount)) { + LklLedgerMerReceiverBind agent2ndReceiver = lklLedgerMerReceiverBindList.get(0); + if (agent2ndReceiver != null && StrUtil.isNotBlank(agent2ndReceiver.getReceiver_no())) { V3SacsSeparateRecvDatas receiver = new V3SacsSeparateRecvDatas(); - receiver.setRecvNo(distributorReceiver.getReceiver_no()); - receiver.setSeparateValue(agentAmount.toString()); + receiver.setRecvNo(agent2ndReceiver.getReceiver_no()); + receiver.setSeparateValue(Convert.toStr(agent2ndAmount)); recvDatas.add(receiver); - log.debug("[分账操作] 添加代理商接收方: receiverNo={}, amount={}", distributorReceiver.getReceiver_no(), agentAmount); + + log.debug("[分账操作] 添加县级代理商接收方: receiverNo={}, amount={}", agent2ndReceiver.getReceiver_no(), agent2ndAmount); + + // 平台内部配送费,由县级代理商代收 add 2025-10-11 + V3SacsSeparateRecvDatas shippingFeeReceiver = new V3SacsSeparateRecvDatas(); + shippingFeeReceiver.setRecvNo(agent2ndReceiver.getReceiver_no()); + shippingFeeReceiver.setSeparateValue(Convert.toStr(shoppingFeeInner)); + recvDatas.add(shippingFeeReceiver); } + } else { + // 没有县级代理商的时候,配送费暂由平台代收 add 2025-10-11 + V3SacsSeparateRecvDatas shippingFeeReceiver = new V3SacsSeparateRecvDatas(); + shippingFeeReceiver.setRecvNo(platformReceiver.getReceiver_no()); + shippingFeeReceiver.setSeparateValue(Convert.toStr(shoppingFeeInner)); + recvDatas.add(shippingFeeReceiver); } // 初始化拉卡拉SDK @@ -2619,8 +2635,7 @@ public class LakalaApiServiceImpl implements LakalaApiService { separateRequest.setNotifyUrl(projectDomain + "/api/mobile/shop/lakala/sacs/separateNotify"); separateRequest.setRecvDatas(recvDatas); - log.info("[分账操作] 分账接收方数量={}", recvDatas.size()); - log.debug("[分账操作] 请求详细参数: {}", JSONUtil.toJsonStr(separateRequest)); + log.debug("[分账操作] 分账接收方数量={},请求详细参数: {}", recvDatas.size(), JSONUtil.toJsonStr(separateRequest)); // 发送分账请求 log.info("[分账操作] 向拉卡拉发送分账请求:订单={}, 商户={}, 分账流水号={}", @@ -3617,7 +3632,6 @@ public class LakalaApiServiceImpl implements LakalaApiService { /** * 商户分账参数计算及评估 * - * @param splitMode 分账模式:1-总金额为基准分账,2-可分账金额基准分账,必填参数 * @param orderPayAmount 订单支付总金额(单位:分)必填参数 * @param shippingFeeInner 平台内部配送费(单位:分)必填参数 * @param mchSplitRatioRaw 商户分账比例值(分子值,如10表示10%)必填参数 @@ -3628,17 +3642,17 @@ public class LakalaApiServiceImpl implements LakalaApiService { * @return Pair 分账参数评估结果,第一个元素表示是否成功,第二个元素为分账参数对象 */ @Override - public Pair calculateAndEvaluateSharingParams(int splitMode, - Integer orderPayAmount, - Integer shippingFeeInner, - BigDecimal mchSplitRatioRaw, - BigDecimal platSplitRatio, - BigDecimal agent1stRatio, - BigDecimal agent2ndRatio, - Integer refCanSeparateAmt) { - log.debug("[分账参数计算] 开始计算分账参数: splitMode={}, orderPayAmount={}, shippingFeeInner={}, " + + public Pair calculateAndEvaluateSharingParams( + Integer orderPayAmount, + Integer shippingFeeInner, + BigDecimal mchSplitRatioRaw, + BigDecimal platSplitRatio, + BigDecimal agent1stRatio, + BigDecimal agent2ndRatio, + Integer refCanSeparateAmt) { + log.debug("[分账参数计算] 开始计算分账参数: orderPayAmount={}, shippingFeeInner={}, " + "mchSplitRatioRaw={}, platSplitRatio={}, agent1stRatio={}, agent2ndRatio={}, refCanSeparateAmt={}", - splitMode, orderPayAmount, shippingFeeInner, mchSplitRatioRaw, platSplitRatio, + orderPayAmount, shippingFeeInner, mchSplitRatioRaw, platSplitRatio, agent1stRatio, agent2ndRatio, refCanSeparateAmt); // 参数校验 @@ -3652,10 +3666,6 @@ public class LakalaApiServiceImpl implements LakalaApiService { return Pair.of(false, null); } - if (splitMode != 1 && splitMode != 2) { - log.warn("[分账参数计算] 分账模式参数错误: splitMode={}", splitMode); - return Pair.of(false, null); - } // 计算商家分账比例(转换为小数) BigDecimal mchSplitRatio = mchSplitRatioRaw.divide(new BigDecimal(100)); @@ -3674,7 +3684,7 @@ public class LakalaApiServiceImpl implements LakalaApiService { log.debug("[分账参数计算] 配送费: {}, 拉卡拉费率: {}", actualShippingFeeInner, wxFeeRatio); // 构建分账参数对象 - LklSeparateDTO lklSeparateDTO = new LklSeparateDTO(); + LklSeparateWithTotalAmountDTO lklSeparateDTO = new LklSeparateWithTotalAmountDTO(); lklSeparateDTO.setTotalSeparateAmount(orderPayAmount); lklSeparateDTO.setShippingFee(actualShippingFeeInner); lklSeparateDTO.setLklRatio(wxFeeRatio); // 拉卡拉给的微信分账比例 0.0025 千分之2.5 @@ -3698,25 +3708,20 @@ public class LakalaApiServiceImpl implements LakalaApiService { log.debug("[分账参数计算] 设置参考可分账金额: {}", refCanSeparateAmt); } - // 根据分账模式执行不同的分账计算 - LklSeparateDTO.SharingResult canSeparateAmtResult; - if (splitMode == 1) { - // 总金额为基准分账 - log.debug("[分账参数计算] 使用总金额为基准分账模式"); - canSeparateAmtResult = lklSeparateDTO.sharingOnTotalAmount(); - } else { - // 可分金额基准分账 - log.debug("[分账参数计算] 使用可分账金额基准分账模式"); - canSeparateAmtResult = lklSeparateDTO.sharingOnCanSeparateAmount(); - } + try { + // 根据分账模式执行不同的分账计算 + Pair canSeparateAmtResult = lklSeparateDTO.calculateSeparateAmount(); + if (!canSeparateAmtResult.getFirst()) { + log.warn("[分账参数计算] 分账参数有误,分账估算失败"); + return Pair.of(false, lklSeparateDTO); + } - if (!canSeparateAmtResult.isSuccess()) { - log.warn("[分账参数计算] 分账参数评估失败: {}", canSeparateAmtResult.getErrorMessage()); + log.info("[分账参数计算] 分账估算成功, result={}", lklSeparateDTO); + return Pair.of(true, lklSeparateDTO); + } catch (Exception e) { + log.error("[分账参数计算] 分账参数有误,分账估算失败", e); return Pair.of(false, lklSeparateDTO); } - - log.info("[分账参数计算] 分账参数计算评估成功, result={}", lklSeparateDTO); - return Pair.of(true, lklSeparateDTO); } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/order/service/impl/ShopOrderBaseServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/order/service/impl/ShopOrderBaseServiceImpl.java index 26ddc3fe..1b47effe 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/order/service/impl/ShopOrderBaseServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/order/service/impl/ShopOrderBaseServiceImpl.java @@ -56,7 +56,7 @@ import com.suisung.mall.common.modules.product.ShopProductItem; import com.suisung.mall.common.modules.product.ShopProductValidPeriod; import com.suisung.mall.common.modules.store.*; import com.suisung.mall.common.modules.user.*; -import com.suisung.mall.common.pojo.dto.LklSeparateDTO; +import com.suisung.mall.common.pojo.dto.LklSeparateWithTotalAmountDTO; import com.suisung.mall.common.pojo.dto.StandardAddressDTO; import com.suisung.mall.common.pojo.dto.WxOrderBaseInfoDTO; import com.suisung.mall.common.pojo.req.*; @@ -7679,8 +7679,7 @@ public class ShopOrderBaseServiceImpl extends BaseServiceImpl calcResult = lakalaApiService.calculateAndEvaluateSharingParams( - CommonConstant.SeparateCalcMode_CanSeparateAmt, + Pair calcResult = lakalaApiService.calculateAndEvaluateSharingParams( Convert.toInt(order_payment_amount.multiply(BigDecimal.valueOf(100))), innerMinDeliverFee, storeSplitRatio, @@ -7690,7 +7689,7 @@ public class ShopOrderBaseServiceImpl extends BaseServiceImpl Date: Mon, 13 Oct 2025 23:52:03 +0800 Subject: [PATCH 5/8] =?UTF-8?q?=E5=88=86=E8=B4=A6=E9=87=91=E9=A2=9D?= =?UTF-8?q?=E7=9A=84=E8=AE=A1=E7=AE=97=E9=80=BB=E8=BE=91=E6=9B=B4=E6=94=B9?= =?UTF-8?q?=EF=BC=8C=E5=88=86=E8=B4=A6=E6=8E=A5=E6=94=B6=E6=96=B9=E5=92=8C?= =?UTF-8?q?=E4=BB=A3=E7=90=86=E5=95=86=E7=9A=84=E5=85=B3=E7=B3=BB=E6=9B=B4?= =?UTF-8?q?=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mall/common/constant/CommonConstant.java | 6 ++ .../lakala/LklLedgerMerReceiverBind.java | 4 + .../modules/lakala/LklLedgerReceiver.java | 4 + .../LklLedgerMerReceiverBindService.java | 32 ++++-- .../service/impl/LakalaApiServiceImpl.java | 80 ++++++++------- .../LklLedgerMerReceiverBindServiceImpl.java | 99 +++++++++++++------ .../impl/ShopOrderReturnServiceImpl.java | 4 +- 7 files changed, 154 insertions(+), 75 deletions(-) diff --git a/mall-common/src/main/java/com/suisung/mall/common/constant/CommonConstant.java b/mall-common/src/main/java/com/suisung/mall/common/constant/CommonConstant.java index 5837be79..7a3b6e19 100644 --- a/mall-common/src/main/java/com/suisung/mall/common/constant/CommonConstant.java +++ b/mall-common/src/main/java/com/suisung/mall/common/constant/CommonConstant.java @@ -115,4 +115,10 @@ public class CommonConstant { public static final int SeparateCalcMode_CanSeparateAmt = 2; + // 代理商等级:0-平台方;1-一级代理;2-二级代理; + public static final Integer Agent_Level_Plat = 0; + public static final Integer Agent_Level_1st = 1; + public static final Integer Agent_Level_2nd = 2; + + } diff --git a/mall-common/src/main/java/com/suisung/mall/common/modules/lakala/LklLedgerMerReceiverBind.java b/mall-common/src/main/java/com/suisung/mall/common/modules/lakala/LklLedgerMerReceiverBind.java index 3a913973..12a86ea8 100644 --- a/mall-common/src/main/java/com/suisung/mall/common/modules/lakala/LklLedgerMerReceiverBind.java +++ b/mall-common/src/main/java/com/suisung/mall/common/modules/lakala/LklLedgerMerReceiverBind.java @@ -18,6 +18,7 @@ import lombok.EqualsAndHashCode; import lombok.experimental.Accessors; import java.io.Serializable; +import java.math.BigDecimal; import java.util.Date; @Data @@ -45,6 +46,9 @@ public class LklLedgerMerReceiverBind implements Serializable { private String audit_status; private String audit_status_text; private String remark; + private Integer level; + private BigDecimal split_ratio; + private Integer shipping_fee; private String version; private Date created_at; private Date updated_at; diff --git a/mall-common/src/main/java/com/suisung/mall/common/modules/lakala/LklLedgerReceiver.java b/mall-common/src/main/java/com/suisung/mall/common/modules/lakala/LklLedgerReceiver.java index 1c13fce2..1beb64f3 100644 --- a/mall-common/src/main/java/com/suisung/mall/common/modules/lakala/LklLedgerReceiver.java +++ b/mall-common/src/main/java/com/suisung/mall/common/modules/lakala/LklLedgerReceiver.java @@ -18,6 +18,7 @@ import lombok.EqualsAndHashCode; import lombok.experimental.Accessors; import java.io.Serializable; +import java.math.BigDecimal; import java.util.Date; @Data @@ -54,6 +55,9 @@ public class LklLedgerReceiver implements Serializable { private String attach_list; private String settle_type; private Long platform_id; + private Integer level; + private BigDecimal split_ratio; + private Integer shipping_fee; private String version; private Integer status; private Date created_at; diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklLedgerMerReceiverBindService.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklLedgerMerReceiverBindService.java index 43a17ef5..779b333a 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklLedgerMerReceiverBindService.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklLedgerMerReceiverBindService.java @@ -51,6 +51,30 @@ public interface LklLedgerMerReceiverBindService extends IBaseService selectAgentByMerCupNo(String merCupNo); + + /** + * 根据商户编号查询商户的一级代理商绑定记录 + * + * @param merCupNo + * @return + */ + LklLedgerMerReceiverBind getAgent1stByMerCupNo(String merCupNo); + + /** + * 根据商户编号查询商户的二级代理商绑定记录 + * + * @param merCupNo + * @return + */ + LklLedgerMerReceiverBind getAgent2ndByMerCupNo(String merCupNo); + /** * 根据申请编号查询一条平台绑定记录 * @@ -59,14 +83,6 @@ public interface LklLedgerMerReceiverBindService extends IBaseService selectDistributorByMerCupNo(String merCupNo); - /** * 判断商户是否已经绑定了分账接收方 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 7b8b7135..d7de65a8 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 @@ -2274,7 +2274,7 @@ public class LakalaApiServiceImpl implements LakalaApiService { BigDecimal distributorSplitRatio = BigDecimal.ZERO; BigDecimal platformSplitRatio = BigDecimal.ONE; // 分账代理商接收方信息 - List distributorReceivers = lklLedgerMerReceiverBindService.selectDistributorByMerCupNo(merchantNo); + List distributorReceivers = lklLedgerMerReceiverBindService.selectAgentByMerCupNo(merchantNo); if (distributorReceivers != null && !distributorReceivers.isEmpty()) { distributorSplitRatio = new BigDecimal("0.8"); platformSplitRatio = new BigDecimal("0.2"); @@ -2478,7 +2478,7 @@ public class LakalaApiServiceImpl implements LakalaApiService { log.info("[分账操作] 查询拉卡拉可分账余额接口:lklMerchantNo={} logDate={} receiveLogNo={} 结果:{}", lklMerchantNo, shopOrderLkl.getLkl_log_date(), receiveLogNo, mchCanSplitAmt); - // 可分账金额 + // 拉卡拉返回的实际可分账金额 refCanSeparateAmt = Convert.toInt(mchCanSplitAmt.getSecond()); if (CheckUtil.isEmpty(refCanSeparateAmt)) { log.warn("[分账操作] lklMerchantNo={} receiveTradeNo={} receiveLogNo={} 拉卡拉可分账金额无值或0,系统将自动计算可分账金额", @@ -2509,19 +2509,21 @@ public class LakalaApiServiceImpl implements LakalaApiService { return Pair.of(false, "平台方未绑定账户"); } - // 获取代理商分账信息 - BigDecimal platformSplitRatio = BigDecimal.valueOf(0.01); // 默认平台比例 1% - BigDecimal agent2ndSplitRatio = null; - // 代理商绑定列表 - List lklLedgerMerReceiverBindList = lklLedgerMerReceiverBindService.selectDistributorByMerCupNo(merchantNo); - if (CollUtil.isNotEmpty(lklLedgerMerReceiverBindList)) { - // 县级代理商比例值 = 1-商家比例值-平台比例值 - agent2ndSplitRatio = BigDecimal.ONE.subtract(mchSplitRatio).subtract(platformSplitRatio); - log.debug("[分账操作] 检测到代理商存在,调整分账比例: 代理商比例={}, 平台比例={}", agent2ndSplitRatio, platformSplitRatio); - } else { - // 平台比例值 = 1-商家比例值 - platformSplitRatio = BigDecimal.ONE.subtract(mchSplitRatio); + // 获取代理商分账信息 + BigDecimal platformSplitRatio = CheckUtil.isEmpty(platformReceiver.getSplit_ratio()) ? BigDecimal.valueOf(0.01) : platformReceiver.getSplit_ratio(); // 默认平台比例 1% + + LklLedgerMerReceiverBind agent1stReceiver = lklLedgerMerReceiverBindService.getAgent1stByMerCupNo(merchantNo); + LklLedgerMerReceiverBind agent2ndReceiver = lklLedgerMerReceiverBindService.getAgent2ndByMerCupNo(merchantNo); + + BigDecimal agent1stSplitRatio = null; + BigDecimal agent2ndSplitRatio = null; + if (agent1stReceiver != null) { + agent1stSplitRatio = CheckUtil.isEmpty(agent1stReceiver.getSplit_ratio()) ? BigDecimal.ZERO : agent1stReceiver.getSplit_ratio(); // 默认省级比例 + } + + if (agent2ndReceiver != null) { + agent2ndSplitRatio = CheckUtil.isEmpty(agent2ndReceiver.getSplit_ratio()) ? BigDecimal.ZERO : agent2ndReceiver.getSplit_ratio(); // 默认市级比例 } // 内部配送费(单位:分) @@ -2533,7 +2535,7 @@ public class LakalaApiServiceImpl implements LakalaApiService { shoppingFeeInner, mchSplitRatio, platformSplitRatio, - null, agent2ndSplitRatio, refCanSeparateAmt); + agent1stSplitRatio, agent2ndSplitRatio, refCanSeparateAmt); if (calcResult == null || !calcResult.getFirst() || calcResult.getSecond() == null) { log.error("[分账操作] 分账参数评估,结果无法分账"); @@ -2562,15 +2564,15 @@ public class LakalaApiServiceImpl implements LakalaApiService { } return Pair.of(false, "订单可分账金额低于1分钱"); } - - + Integer merchantAmount = lklSeparateDTO.getMchAmount(); Integer platformAmount = lklSeparateDTO.getPlatAmount(); + Integer agent1stAmount = lklSeparateDTO.getAgent1stAmount(); Integer agent2ndAmount = lklSeparateDTO.getAgent2ndAmount(); - log.info("[分账操作] 金额计算结果:订单={}, 商户={}, 总金额={}分, 可分金额={}分, 商家比例={}, 商家分得={}分, 平台比例={}, 平台分得={}分, 县级代理商比例={}, 县级代理商分得={}分", + log.info("[分账操作] 金额计算结果:订单={}, 商户={}, 总金额={}分, 可分金额={}分, 商家比例={}, 商家分得={}分, 平台比例={}, 平台分得={}分, 省级代理商比例={}, 省级代理商分得={}分, 县级代理商比例={}, 县级代理商分得={}分", orderId, merchantNo, shopOrderLkl.getTotal_amt(), refCanSeparateAmt, mchSplitRatio, merchantAmount, - platformSplitRatio, platformAmount, agent2ndSplitRatio, agent2ndAmount); + platformSplitRatio, platformAmount, agent1stSplitRatio, agent1stAmount, agent2ndSplitRatio, agent2ndAmount); // 构建分账接收方分账列表参数 List recvDatas = new ArrayList<>(); @@ -2578,7 +2580,7 @@ public class LakalaApiServiceImpl implements LakalaApiService { if (CheckUtil.isNotEmpty(merchantAmount)) { V3SacsSeparateRecvDatas receiver = new V3SacsSeparateRecvDatas(); receiver.setRecvMerchantNo(merchantNo); - receiver.setSeparateValue(merchantAmount.toString()); + receiver.setSeparateValue(Convert.toStr(merchantAmount)); recvDatas.add(receiver); log.debug("[分账操作] 添加商家接收方: merchantNo={}, amount={}", merchantNo, merchantAmount); @@ -2588,29 +2590,37 @@ public class LakalaApiServiceImpl implements LakalaApiService { if (CheckUtil.isNotEmpty(platformAmount)) { V3SacsSeparateRecvDatas receiver = new V3SacsSeparateRecvDatas(); receiver.setRecvNo(platformReceiver.getReceiver_no()); - receiver.setSeparateValue(platformAmount.toString()); + receiver.setSeparateValue(Convert.toStr(platformAmount)); recvDatas.add(receiver); log.debug("[分账操作] 添加平台接收方: receiverNo={}, amount={}", platformReceiver.getReceiver_no(), platformAmount); } + // 省级代理商分账参数 + if (agent1stReceiver != null && StrUtil.isNotBlank(agent1stReceiver.getReceiver_no()) && CheckUtil.isNotEmpty(agent1stAmount)) { + V3SacsSeparateRecvDatas receiver = new V3SacsSeparateRecvDatas(); + receiver.setRecvNo(agent1stReceiver.getReceiver_no()); + receiver.setSeparateValue(Convert.toStr(agent1stAmount)); + recvDatas.add(receiver); + + log.debug("[分账操作] 添加省级代理商接收方: receiverNo={}, amount={}", agent1stReceiver.getReceiver_no(), agent1stAmount); + } + // 县级代理商分账参数 - if (CollUtil.isNotEmpty(lklLedgerMerReceiverBindList) && CheckUtil.isNotEmpty(agent2ndAmount)) { - LklLedgerMerReceiverBind agent2ndReceiver = lklLedgerMerReceiverBindList.get(0); - if (agent2ndReceiver != null && StrUtil.isNotBlank(agent2ndReceiver.getReceiver_no())) { - V3SacsSeparateRecvDatas receiver = new V3SacsSeparateRecvDatas(); - receiver.setRecvNo(agent2ndReceiver.getReceiver_no()); - receiver.setSeparateValue(Convert.toStr(agent2ndAmount)); - recvDatas.add(receiver); + if (agent2ndReceiver != null && StrUtil.isNotBlank(agent2ndReceiver.getReceiver_no()) && CheckUtil.isNotEmpty(agent2ndAmount)) { + V3SacsSeparateRecvDatas receiver = new V3SacsSeparateRecvDatas(); + receiver.setRecvNo(agent2ndReceiver.getReceiver_no()); + receiver.setSeparateValue(Convert.toStr(agent2ndAmount)); + recvDatas.add(receiver); - log.debug("[分账操作] 添加县级代理商接收方: receiverNo={}, amount={}", agent2ndReceiver.getReceiver_no(), agent2ndAmount); + log.debug("[分账操作] 添加县级代理商接收方: receiverNo={}, amount={}", agent2ndReceiver.getReceiver_no(), agent2ndAmount); + + // 有县级代理商的时候,配送费暂由它代收 add 2025-10-11 + V3SacsSeparateRecvDatas shippingFeeReceiver = new V3SacsSeparateRecvDatas(); + shippingFeeReceiver.setRecvNo(agent2ndReceiver.getReceiver_no()); + shippingFeeReceiver.setSeparateValue(Convert.toStr(shoppingFeeInner)); + recvDatas.add(shippingFeeReceiver); - // 平台内部配送费,由县级代理商代收 add 2025-10-11 - V3SacsSeparateRecvDatas shippingFeeReceiver = new V3SacsSeparateRecvDatas(); - shippingFeeReceiver.setRecvNo(agent2ndReceiver.getReceiver_no()); - shippingFeeReceiver.setSeparateValue(Convert.toStr(shoppingFeeInner)); - recvDatas.add(shippingFeeReceiver); - } } else { // 没有县级代理商的时候,配送费暂由平台代收 add 2025-10-11 V3SacsSeparateRecvDatas shippingFeeReceiver = new V3SacsSeparateRecvDatas(); diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerMerReceiverBindServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerMerReceiverBindServiceImpl.java index 7c5a0f37..9f38b7c5 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerMerReceiverBindServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerMerReceiverBindServiceImpl.java @@ -112,44 +112,98 @@ public class LklLedgerMerReceiverBindServiceImpl extends BaseServiceImpl selectListByMerCupNo(String merCupNo, Boolean isPlatform) { if (StrUtil.isBlank(merCupNo)) { - return null; + return Collections.emptyList(); } QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.eq("mer_cup_no", merCupNo) - .eq("audit_status", CommonConstant.Enable); - if (isPlatform != null && isPlatform) { - queryWrapper.eq("platform_id", 0); - } else if (isPlatform != null && !isPlatform) { - queryWrapper.gt("platform_id", 0); + .eq("audit_status", CommonConstant.Enable) + .orderByAsc("id"); + + if (isPlatform != null) { + if (isPlatform) { + queryWrapper.eq("platform_id", 0); + } else { + queryWrapper.gt("platform_id", 0) + .in("level", CommonConstant.Agent_Level_1st, CommonConstant.Agent_Level_2nd); + } } - queryWrapper.orderByAsc("id"); - return list(queryWrapper); } /** * 根据商户编号查询一条平台绑定记录 * - * @param merCupNo - * @return + * @param merCupNo 商户银联编号 + * @return 平台绑定记录,不存在时返回null */ @Override public LklLedgerMerReceiverBind getPlatformByMerCupNo(String merCupNo) { List list = selectListByMerCupNo(merCupNo, true); - if (CollectionUtil.isEmpty(list)) { + return CollectionUtil.isEmpty(list) ? null : list.get(0); + } + + /** + * 根据商户编号查询代理商绑定记录列表 + * + * @param merCupNo 商户银联编号 + * @return 代理商绑定记录列表,不存在时返回空列表 + */ + @Override + public List selectAgentByMerCupNo(String merCupNo) { + return selectListByMerCupNo(merCupNo, false); + } + + /** + * 根据商户编号查询一级代理商绑定记录 + * + * @param merCupNo 商户银联编号 + * @return 一级代理商绑定记录,不存在时返回null + */ + @Override + public LklLedgerMerReceiverBind getAgent1stByMerCupNo(String merCupNo) { + if (StrUtil.isBlank(merCupNo)) { return null; } - return list.get(0); + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("mer_cup_no", merCupNo) + .eq("audit_status", CommonConstant.Enable) + .gt("platform_id", 0) + .eq("level", CommonConstant.Agent_Level_1st) + .orderByAsc("id"); + + return findOne(queryWrapper); + } + + /** + * 根据商户编号查询二级代理商绑定记录 + * + * @param merCupNo 商户银联编号 + * @return 二级代理商绑定记录,不存在时返回null + */ + @Override + public LklLedgerMerReceiverBind getAgent2ndByMerCupNo(String merCupNo) { + if (StrUtil.isBlank(merCupNo)) { + return null; + } + + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("mer_cup_no", merCupNo) + .eq("audit_status", CommonConstant.Enable) + .gt("platform_id", 0) + .eq("level", CommonConstant.Agent_Level_2nd) + .orderByAsc("id"); + + return findOne(queryWrapper); } /** @@ -170,21 +224,6 @@ public class LklLedgerMerReceiverBindServiceImpl extends BaseServiceImpl selectDistributorByMerCupNo(String merCupNo) { - List list = selectListByMerCupNo(merCupNo, false); - if (CollectionUtil.isEmpty(list)) { - return null; - } - - return list; - } /** * 判断商户是否已经绑定了分账接收方 diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/order/service/impl/ShopOrderReturnServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/order/service/impl/ShopOrderReturnServiceImpl.java index 7ecccde9..3a396142 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/order/service/impl/ShopOrderReturnServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/order/service/impl/ShopOrderReturnServiceImpl.java @@ -1741,12 +1741,12 @@ public class ShopOrderReturnServiceImpl extends BaseServiceImpl Date: Tue, 14 Oct 2025 02:11:00 +0800 Subject: [PATCH 6/8] =?UTF-8?q?=E5=A4=9A=E4=B8=AA=E4=BB=A3=E7=90=86?= =?UTF-8?q?=E5=95=86=E5=85=A5=E9=A9=BB=E9=80=BB=E8=BE=91=20=E6=96=B0?= =?UTF-8?q?=E5=A2=9E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/EsignPlatformInfoService.java | 22 ++- .../impl/EsignPlatformInfoServiceImpl.java | 154 ++++++++++++++++-- .../service/LklLedgerReceiverService.java | 7 +- .../service/impl/LakalaApiServiceImpl.java | 16 +- .../impl/LklLedgerReceiverServiceImpl.java | 21 +-- .../lakala/service/impl/LklTkServiceImpl.java | 2 +- 6 files changed, 181 insertions(+), 41 deletions(-) diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/EsignPlatformInfoService.java b/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/EsignPlatformInfoService.java index 80582157..dc2e0217 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/EsignPlatformInfoService.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/EsignPlatformInfoService.java @@ -27,12 +27,12 @@ public interface EsignPlatformInfoService { EsignPlatformInfo getDistributorInfoById(Long id); /** - * 根据ID获取代理商信息 + * 根据入驻编号获取平台和代理商信息 * - * @param ids + * @param mchId * @return */ - List getDistributorAndPlatformByIds(Long... ids); + List getDistributorAndPlatformByIds(Long mchId); /** * 根据分类和营业执照号获取平台方信息 @@ -57,4 +57,20 @@ public interface EsignPlatformInfoService { * @return */ Pair getEsignPlatformMobileAndLicenseNumber(); + + /** + * 根据入驻编号获取商户的二级代理 + * + * @param mchId + * @return + */ + EsignPlatformInfo getMch2ndAgent(Long mchId); + + /** + * 根据入驻编号获取商户的二级代理(收运费的代理商) + * + * @param mchId + * @return + */ + EsignPlatformInfo getMch2ndAgentWithShippingFee(Long mchId); } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/impl/EsignPlatformInfoServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/impl/EsignPlatformInfoServiceImpl.java index 9aeed464..8c259542 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/impl/EsignPlatformInfoServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/impl/EsignPlatformInfoServiceImpl.java @@ -13,18 +13,30 @@ import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.suisung.mall.common.constant.CommonConstant; import com.suisung.mall.common.modules.esign.EsignPlatformInfo; +import com.suisung.mall.common.modules.store.ShopMchEntry; +import com.suisung.mall.common.utils.CheckUtil; import com.suisung.mall.common.utils.phone.PhoneNumberUtils; import com.suisung.mall.core.web.service.impl.BaseServiceImpl; import com.suisung.mall.shop.esign.mapper.EsignPlatformInfoMapper; import com.suisung.mall.shop.esign.service.EsignPlatformInfoService; +import com.suisung.mall.shop.store.service.ShopMchEntryService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Lazy; import org.springframework.data.util.Pair; import org.springframework.stereotype.Service; import org.springframework.util.ObjectUtils; +import javax.annotation.Resource; import java.util.List; +@Slf4j @Service public class EsignPlatformInfoServiceImpl extends BaseServiceImpl implements EsignPlatformInfoService { + + @Lazy + @Resource + private ShopMchEntryService shopMchEntryService; + /** * 根据ID获取代理商信息 * @@ -51,34 +63,52 @@ public class EsignPlatformInfoServiceImpl extends BaseServiceImpl 平台方和代理商信息列表 */ @Override - public List getDistributorAndPlatformByIds(Long... ids) { + public List getDistributorAndPlatformByIds(Long mchId) { + // 获取平台方记录 QueryWrapper queryWrapper = new QueryWrapper<>(); - queryWrapper.eq("status", CommonConstant.Enable).orderByAsc("level"); - if (ids != null && ids.length > 0) { - queryWrapper.and(wrapper -> { - wrapper.in("id", ids).gt("level", 0); - wrapper.or(wrapperOr -> { - wrapperOr.eq("level", 0); - }); - }); - } else { - queryWrapper.eq("level", 0); - } + queryWrapper.eq("level", 0) + .eq("status", CommonConstant.Enable) + .orderByAsc("level"); List esignPlatformInfos = list(queryWrapper); if (CollectionUtil.isEmpty(esignPlatformInfos)) { + log.error("[获取平台和代理商信息] 未找到平台方记录"); return null; } + // 获取商户的二级代理 + EsignPlatformInfo agent2nd = getMch2ndAgent(mchId); + if (agent2nd == null) { + return esignPlatformInfos; + } + + esignPlatformInfos.add(agent2nd); + + // 获取一级代理(如果存在) + if (CheckUtil.isEmpty(agent2nd.getParent_id())) { + return esignPlatformInfos; + } + + try { + EsignPlatformInfo agent1st = get(agent2nd.getParent_id()); + if (agent1st != null) { + esignPlatformInfos.add(agent1st); + } + } catch (Exception e) { + log.error("[获取平台和代理商信息] 获取一级代理商时发生异常,parent_id: {}", agent2nd.getParent_id(), e); + } + return esignPlatformInfos; } + /** * 根据分类和营业执照号获取平台方信息 * @@ -148,4 +178,98 @@ public class EsignPlatformInfoServiceImpl extends BaseServiceImpl queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("level", CommonConstant.Agent_Level_2nd) + .eq("status", CommonConstant.Enable) + .orderByAsc("id"); + + // 优先使用指定的分销商ID查询,否则使用区域信息查询 + if (CheckUtil.isNotEmpty(shopMchEntry.getDistributor_id())) { + queryWrapper.eq("id", shopMchEntry.getDistributor_id()); + log.debug("[获取二级代理] 使用指定分销商ID查询,distributorId={}", shopMchEntry.getDistributor_id()); + } + + EsignPlatformInfo result = findOne(queryWrapper); + if (result == null) { + if (StrUtil.isNotBlank(shopMchEntry.getStore_district())) { + // 运费代理商 + queryWrapper.clear(); + queryWrapper.eq("level", CommonConstant.Agent_Level_2nd) + .eq("status", CommonConstant.Enable) + .eq("license_district_id", shopMchEntry.getStore_district()) + .gt("shipping_fee", 0).ne("supplier_id", "") + .orderByAsc("id"); + log.debug("[获取二级代理] 使用区域信息查询,districtId={}", shopMchEntry.getStore_district()); + + result = findOne(queryWrapper); + } + } + + if (result == null) { + log.info("[获取二级代理] 未找到匹配的二级代理信息,mchId={}", mchId); + } else { + log.debug("[获取二级代理] 成功获取二级代理信息,mchId={}, agentId={}", mchId, result.getId()); + } + + return result; + + } catch (Exception e) { + log.error("[获取二级代理] 查询过程中发生异常,mchId={}", mchId, e); + return null; + } + } + + /** + * 根据入驻编号获取商户的二级代理(收运费的代理商) + * + * @param mchId 商户入驻编号 + * @return EsignPlatformInfo 收运费的二级代理信息,未找到或不满足条件时返回null + */ + @Override + public EsignPlatformInfo getMch2ndAgentWithShippingFee(Long mchId) { + // 获取商户的二级代理信息 + EsignPlatformInfo esignPlatformInfo = getMch2ndAgent(mchId); + if (esignPlatformInfo == null) { + return null; + } + + // 检查该代理是否具备收取运费的条件:设置了运费且有供应商ID + if (CheckUtil.isNotEmpty(esignPlatformInfo.getShipping_fee()) && + StrUtil.isNotBlank(esignPlatformInfo.getSupplier_id())) { + return esignPlatformInfo; + } + + return null; + } + } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklLedgerReceiverService.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklLedgerReceiverService.java index c7e6d88a..61ec9d94 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklLedgerReceiverService.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklLedgerReceiverService.java @@ -43,20 +43,19 @@ public interface LklLedgerReceiverService extends IBaseServicedistributor_id) + if (esignPlatformInfoService.getMch2ndAgent(shopMchEntry.getId()) != null) { ecParams.put("E1", platformName + "和代理商"); ecParams.put("E2", "《平台商户入驻服务框架协议》和《小发同城服务费结算》"); } else { @@ -1189,7 +1193,7 @@ public class LakalaApiServiceImpl implements LakalaApiService { Long receiverCnt = lklLedgerReceiverService.countByCondition("", "", shopMchEntry.getDistributor_id()); if (receiverCnt <= 0) { // 1:新增一个接收方记录,起码要一个平台方,代理商根据入驻信息新增 - Boolean success = lklLedgerReceiverService.innerApplyLedgerReceiver(shopMchEntry.getId(), merCupNo, shopMchEntry.getDistributor_id()); + Boolean success = lklLedgerReceiverService.innerApplyLedgerReceiver(shopMchEntry.getId(), merCupNo); if (!success) { return CommonResult.failed("申请分账接收方失败"); } @@ -2564,7 +2568,7 @@ public class LakalaApiServiceImpl implements LakalaApiService { } return Pair.of(false, "订单可分账金额低于1分钱"); } - + Integer merchantAmount = lklSeparateDTO.getMchAmount(); Integer platformAmount = lklSeparateDTO.getPlatAmount(); Integer agent1stAmount = lklSeparateDTO.getAgent1stAmount(); diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerReceiverServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerReceiverServiceImpl.java index 0fe18ce6..2832b90a 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerReceiverServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerReceiverServiceImpl.java @@ -32,7 +32,6 @@ import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import javax.annotation.Resource; -import java.util.ArrayList; import java.util.List; @Slf4j @@ -137,21 +136,19 @@ public class LklLedgerReceiverServiceImpl extends BaseServiceImpl ids = new ArrayList<>(); - if (distributorId != null && distributorId > 0) { - ids.add(distributorId); - } + public JSONArray buildApplyLedgerReceiverReqParams(Long mchId) { + // 获取平台记录和代理商记录 - List esignPlatformInfoList = esignPlatformInfoService.getDistributorAndPlatformByIds(ids.toArray(new Long[0])); + List esignPlatformInfoList = esignPlatformInfoService.getDistributorAndPlatformByIds(mchId); if (CollectionUtil.isEmpty(esignPlatformInfoList)) { return null; } + JSONArray reqParams = new JSONArray(); for (EsignPlatformInfo esignPlatformInfo : esignPlatformInfoList) { JSONObject reqParam = new JSONObject(); @@ -216,14 +213,14 @@ public class LklLedgerReceiverServiceImpl extends BaseServiceImpl Date: Tue, 14 Oct 2025 12:05:10 +0800 Subject: [PATCH 7/8] =?UTF-8?q?fix=20=E8=AE=A2=E5=8D=95=E6=A0=87=E9=A2=98?= =?UTF-8?q?=E8=BF=87=E9=95=BF=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pay/controller/admin/PayController.java | 22 ++++++++++++++----- .../impl/ShopOrderBaseServiceImpl.java | 22 ++++++++++++++----- 2 files changed, 34 insertions(+), 10 deletions(-) diff --git a/mall-pay/src/main/java/com/suisung/mall/pay/controller/admin/PayController.java b/mall-pay/src/main/java/com/suisung/mall/pay/controller/admin/PayController.java index fa853514..8ade5abc 100644 --- a/mall-pay/src/main/java/com/suisung/mall/pay/controller/admin/PayController.java +++ b/mall-pay/src/main/java/com/suisung/mall/pay/controller/admin/PayController.java @@ -139,15 +139,27 @@ public class PayController { @RequestMapping(value = "/saveOrUpdatePayConsumeTrade", method = RequestMethod.POST) public boolean saveOrUpdatePayConsumeTrade(@RequestBody PayConsumeTrade payConsumeTrade) { - boolean flag = false; - try { - flag = payConsumeTradeService.saveOrUpdate(payConsumeTrade); - } catch (Exception e) { + // 参数校验 + if (payConsumeTrade == null) { + logger.warn("[保存或更新交易记录] 参数校验失败:payConsumeTrade 为空"); + return false; + } + + try { + boolean flag = payConsumeTradeService.saveOrUpdate(payConsumeTrade); + if (flag) { + logger.debug("[保存或更新交易记录] 操作成功,tradeId: {}", payConsumeTrade.getConsume_trade_id()); + } else { + logger.warn("[保存或更新交易记录] 操作失败,tradeId: {}", payConsumeTrade.getConsume_trade_id()); + } + return flag; + } catch (Exception e) { + logger.error("[保存或更新交易记录] 系统异常,tradeId: {}", payConsumeTrade.getConsume_trade_id(), e); return false; } - return flag; } + @RequestMapping(value = "/saveOrUpdatePayUserResource", method = RequestMethod.POST) public boolean saveOrUpdatePayUserResource(@RequestBody PayUserResource payUserResource) { boolean flag; diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/order/service/impl/ShopOrderBaseServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/order/service/impl/ShopOrderBaseServiceImpl.java index f70101f7..1c596304 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/order/service/impl/ShopOrderBaseServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/order/service/impl/ShopOrderBaseServiceImpl.java @@ -3303,7 +3303,7 @@ public class ShopOrderBaseServiceImpl extends BaseServiceImpl stockDeltaMap = new HashMap<>(); - stockDeltaMap.put(item_src_id+"_"+order_item_row.getOrder_id(), -order_item_quantity); + stockDeltaMap.put(item_src_id + "_" + order_item_row.getOrder_id(), -order_item_quantity); syncThirdDataService.incrProductStockToRedis(stockDeltaMap); } } @@ -4226,7 +4226,7 @@ public class ShopOrderBaseServiceImpl extends BaseServiceImpl stockDeltaMap = new HashMap<>(); - stockDeltaMap.put(shopProductItem.getItem_src_id()+"_"+order_item_row.getOrder_id(), order_item_quantity); + stockDeltaMap.put(shopProductItem.getItem_src_id() + "_" + order_item_row.getOrder_id(), order_item_quantity); syncThirdDataService.incrProductStockToRedis(stockDeltaMap); } } @@ -6523,7 +6523,20 @@ public class ShopOrderBaseServiceImpl extends BaseServiceImpl Convert.toStr(s.get("product_item_name"))).collect(Collectors.joining("|")); + // 订单商品标题 + // String product_item_name = item_items.stream().map(s -> Convert.toStr(s.get("product_item_name"))).collect(Collectors.joining("|")); + String product_item_name = ""; + if (CollUtil.isNotEmpty(item_items)) { + String firstProductName = Convert.toStr(item_items.get(0).get("product_item_name")); + if (StrUtil.isNotBlank(firstProductName)) { + // 限制长度,防止超出字段限制 + if (firstProductName.length() > 100) { + firstProductName = firstProductName.substring(0, 100); + } + product_item_name = firstProductName + "等商品"; + } + } + Integer subsite_id = (Integer) store_item.get("subsite_id"); Integer store_is_selfsupport = (Integer) store_item.get("store_is_selfsupport"); Integer payment_type_id = (Integer) checkout_row.get("payment_type_id"); @@ -7244,7 +7257,7 @@ public class ShopOrderBaseServiceImpl extends BaseServiceImpl stockDeltaMap = new HashMap<>(); - stockDeltaMap.put(item_src_id+"_"+order_id, -cart_quantity); + stockDeltaMap.put(item_src_id + "_" + order_id, -cart_quantity); syncThirdDataService.incrProductStockToRedis(stockDeltaMap); } @@ -7877,7 +7890,6 @@ public class ShopOrderBaseServiceImpl extends BaseServiceImpl Date: Tue, 14 Oct 2025 17:06:24 +0800 Subject: [PATCH 8/8] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=95=86=E5=93=81?= =?UTF-8?q?=E5=88=86=E7=B1=BBdiy=E6=9F=A5=E8=AF=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../impl/ShopBaseProductCategoryServiceImpl.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/base/service/impl/ShopBaseProductCategoryServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/base/service/impl/ShopBaseProductCategoryServiceImpl.java index fefd23e3..8342d4b6 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/base/service/impl/ShopBaseProductCategoryServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/base/service/impl/ShopBaseProductCategoryServiceImpl.java @@ -485,13 +485,21 @@ public class ShopBaseProductCategoryServiceImpl extends BaseServiceImpl voucher_item_ids = productSearchDTO.getVoucher_item_id(); if (CollUtil.isNotEmpty(voucher_item_ids)) { List itemList = shopProductItemService.find(new QueryWrapper().in("item_id", voucher_item_ids)); - if (CollUtil.isNotEmpty(itemList)) { product_id_row = CommonUtil.column(itemList, ShopProductItem::getProduct_id); productSearchDTO.setProduct_ids(product_id_row); } } // end + //根据itemid查询 + List itemIdList = productSearchDTO.getItem_ids(); + if (CollUtil.isNotEmpty(itemIdList)) { + List itemList = shopProductItemService.find(new QueryWrapper().in("item_id", itemIdList)); + if (CollUtil.isNotEmpty(itemList)) { + product_id_row = CommonUtil.column(itemList, ShopProductItem::getProduct_id); + productSearchDTO.setProduct_ids(product_id_row); + } + } String show_type = accountBaseConfigService.getProductShowType(); productSearchDTO.setShow_type(show_type);