diff --git a/mall-common/src/main/java/com/suisung/mall/common/modules/order/ShopOrderLkl.java b/mall-common/src/main/java/com/suisung/mall/common/modules/order/ShopOrderLkl.java index c18b7fff..9399741e 100644 --- a/mall-common/src/main/java/com/suisung/mall/common/modules/order/ShopOrderLkl.java +++ b/mall-common/src/main/java/com/suisung/mall/common/modules/order/ShopOrderLkl.java @@ -56,13 +56,15 @@ public class ShopOrderLkl implements Serializable { private String trade_status; + private String lkl_trade_no; + private String lkl_log_no; private String lkl_log_date; - private String lkl_sub_log_no; + private String lkl_sub_trade_no; - private String lkl_trade_no; + private String lkl_sub_log_no; private String lkl_receive_trade_no; diff --git a/mall-common/src/main/java/com/suisung/mall/common/modules/store/ShopStoreBase.java b/mall-common/src/main/java/com/suisung/mall/common/modules/store/ShopStoreBase.java index 0c195c77..e8149916 100644 --- a/mall-common/src/main/java/com/suisung/mall/common/modules/store/ShopStoreBase.java +++ b/mall-common/src/main/java/com/suisung/mall/common/modules/store/ShopStoreBase.java @@ -78,6 +78,9 @@ public class ShopStoreBase implements Serializable { @ApiModelProperty(value = "店铺状态(ENUM):0-关闭; 1-运营中, 商品是否可用,需要判断该商品店铺状态") private Integer store_is_open; + @ApiModelProperty(value = "店铃声开关:1-开启;2-关闭;") + private Integer ringtone_is_enable; + @ApiModelProperty(value = "店铺营业状态:1-营业中;2-已打烊;") private Integer store_biz_state; diff --git a/mall-common/src/main/java/com/suisung/mall/common/service/impl/CommonService.java b/mall-common/src/main/java/com/suisung/mall/common/service/impl/CommonService.java index 8df7da18..00ffece4 100644 --- a/mall-common/src/main/java/com/suisung/mall/common/service/impl/CommonService.java +++ b/mall-common/src/main/java/com/suisung/mall/common/service/impl/CommonService.java @@ -8,7 +8,12 @@ package com.suisung.mall.common.service.impl; +import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONArray; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; import com.suisung.mall.common.api.StateCode; +import com.suisung.mall.common.constant.CommonConstant; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -140,6 +145,116 @@ public class CommonService { } public static void main(String[] args) { - System.out.println(isValidInput("", "+8618924071446")); + System.out.println(getLklCombineSplitRespInfo("8226330541100GU", "[{\"sub_trade_no\":\"20250911110110000066202050017882\",\"sub_log_no\":\"66202050017882\",\"origin_sub_trade_no\":\"20250911110113130266250044162421\",\"origin_sub_log_no\":\"66250044162421\",\"merchant_no\":\"822584059990FYP\",\"term_no\":\"N5811590\",\"amount\":\"1\"},{\"sub_trade_no\":\"20250911110110000066202050152097\",\"sub_log_no\":\"66202050152097\",\"origin_sub_trade_no\":\"20250911110113130266250044162422\",\"origin_sub_log_no\":\"66250044162422\",\"merchant_no\":\"8226330541100GU\",\"term_no\":\"N5817779\",\"amount\":\"1\"}]", false)); } + + /** + * 从拉卡拉分账响应信息中提取合单运费或商品订单信息 + *

该方法用于处理合单支付场景,从拉卡拉返回的分账信息中筛选出运费子单或商品子单信息

+ * + * @param merchantNo 商家商户号 + * @param outSplitRspInfos 拉卡拉分账响应信息,格式为JSON数组字符串: + * [ + * { + * "sub_trade_no":"20250830110113130266250034401288", // 子交易流水号 + * "merchant_no":"822584059990FYP", // 商户号 + * "amount":"1", // 分账金额 + * "settle_type":"0", // 结算类型 + * "sub_log_no":"66250034401288", // 子流水号 + * "out_sub_trade_no":"DF-DD-20250830-21", // 外部子交易订单号(DF开头为运费订单) + * "term_no":"N5811590" // 终端设备号 + * }, + * { + * "sub_trade_no":"20250830110113130266250034401289", // 子交易流水号 + * "merchant_no":"8226330541100GU", // 商户号 + * "amount":"1", // 分账金额 + * "settle_type":"0", // 结算类型 + * "sub_log_no":"66250034401289", // 子流水号 + * "out_sub_trade_no":"ORD-DD-20250830-21", // 外部子交易订单号(ORD开头为商品订单) + * "term_no":"N5817779" // 终端设备号 + * } + * ] + * @param isDeliveryFee true: 提取运费子单信息, false: 提取商品子单信息 + * @return JSONObject 返回匹配的子单信息,格式如下: + * { + * "sub_trade_no":"20250830110113130266250034401288", + * "merchant_no":"822584059990FYP", + * "amount":"1", + * "settle_type":"0", + * "sub_log_no":"66250034401288", + * "out_sub_trade_no":"DF-DD-20250830-21", + * "term_no":"N5811590" + * } + */ + public static JSONObject getLklCombineSplitRespInfo(String merchantNo, String outSplitRspInfos, boolean isDeliveryFee) { + log.debug("[拉卡拉合单数据拆分] 开始获取合单数据: merchantNo={} isDeliveryFee={} outSplitRspInfos长度={}", + merchantNo, isDeliveryFee, outSplitRspInfos != null ? outSplitRspInfos.length() : 0); + + // 输入参数校验:检查分账信息是否为空 + if (StrUtil.isBlank(outSplitRspInfos)) { + log.warn("[拉卡拉合单数据拆分] 合单数据为空"); + return null; + } + + // 解析JSON数组:将字符串转换为JSONArray对象 + JSONArray outSplitRspInfoArray; + try { + outSplitRspInfoArray = JSONUtil.parseArray(outSplitRspInfos); + log.debug("[拉卡拉合单数据拆分] JSON解析完成,数组大小={}", outSplitRspInfoArray.size()); + } catch (Exception e) { + log.error("[拉卡拉合单数据拆分] JSON解析失败:{}", outSplitRspInfos, e); + return null; + } + + // 检查解析后的数组是否为空 + if (outSplitRspInfoArray.isEmpty()) { + log.warn("[拉卡拉合单数据拆分] 拆分合单数据失败:分账信息数组为空"); + return null; + } + + // 遍历JSON数组查找匹配的子单 (合单订单通常只有两个子单:一个运费单,一个商品单) + final String deliveryPrefix = CommonConstant.Sep_DeliveryFee_Prefix; + final String goodsPrefix = CommonConstant.Sep_GoodsFee_Prefix; + log.debug("[拉卡拉合单数据拆分] 开始遍历数组查找匹配子单: deliveryPrefix={} goodsPrefix={}", deliveryPrefix, goodsPrefix); + + for (int i = 0; i < outSplitRspInfoArray.size(); i++) { + JSONObject item = outSplitRspInfoArray.getJSONObject(i); + + if (item == null) { + log.debug("[拉卡拉合单数据拆分] 数组第{}项为空,跳过", i); + continue; + } + + // 获取外部子交易订单号字段和商户号 + String subMerchantNo = item.getStr("merchant_no"); + String outSubTradeNo = item.getStr("out_sub_trade_no"); + log.debug("[拉卡拉合单数据拆分] 检查第{}项: outSubTradeNo={} subMerchantNo={}", i, outSubTradeNo, subMerchantNo); + + // 根据isDeliveryFee参数和商户号筛选对应的子单信息 + if (isDeliveryFee && StrUtil.isNotBlank(merchantNo) && !merchantNo.equals(subMerchantNo)) { + log.debug("[拉卡拉合单数据拆分] 找到运费子单(通过商户号匹配): outSubTradeNo={} subMerchantNo={}", outSubTradeNo, subMerchantNo); + return item; + } else if (!isDeliveryFee && StrUtil.isNotBlank(merchantNo) && merchantNo.equals(subMerchantNo)) { + log.debug("[拉卡拉合单数据拆分] 找到商品子单(通过商户号匹配): outSubTradeNo={} subMerchantNo={}", outSubTradeNo, subMerchantNo); + return item; + } else { + // 如果商户号匹配失败,则通过订单号前缀匹配 + if (isDeliveryFee && StrUtil.isNotBlank(outSubTradeNo) && outSubTradeNo.startsWith(deliveryPrefix)) { + log.debug("[拉卡拉合单数据拆分] 找到运费子单(通过前缀匹配): outSubTradeNo={}", outSubTradeNo); + return item; + } else if (!isDeliveryFee && StrUtil.isNotBlank(outSubTradeNo) && outSubTradeNo.startsWith(goodsPrefix)) { + log.debug("[拉卡拉合单数据拆分] 找到商品子单(通过前缀匹配): outSubTradeNo={}", outSubTradeNo); + return item; + } else { + log.debug("[拉卡拉合单数据拆分] 第{}项不匹配条件: isDeliveryFee={} merchantNo={} subMerchantNo={} outSubTradeNo={}", + i, isDeliveryFee, merchantNo, subMerchantNo, outSubTradeNo); + } + } + } + + // 未找到匹配的子单信息 + log.warn("[拉卡拉合单数据拆分] 未找到匹配的子单信息: merchantNo={} isDeliveryFee={}", merchantNo, isDeliveryFee); + return null; + } + } diff --git a/mall-pay/src/main/java/com/suisung/mall/pay/service/PayConsumeTradeService.java b/mall-pay/src/main/java/com/suisung/mall/pay/service/PayConsumeTradeService.java index 7a1f02be..05691e94 100644 --- a/mall-pay/src/main/java/com/suisung/mall/pay/service/PayConsumeTradeService.java +++ b/mall-pay/src/main/java/com/suisung/mall/pay/service/PayConsumeTradeService.java @@ -1,6 +1,5 @@ package com.suisung.mall.pay.service; -import cn.hutool.json.JSONObject; import com.suisung.mall.common.api.CommonResult; import com.suisung.mall.common.modules.order.ShopOrderReturn; import com.suisung.mall.common.modules.pay.PayConsumeTrade; @@ -62,44 +61,4 @@ public interface PayConsumeTradeService extends IBaseService { */ Boolean updateTradeByPrimaryKey(PayConsumeTrade payConsumeTrade); - - /** - * 从拉卡拉分账响应信息中提取合单运费或商品订单信息 - *

该方法用于处理合单支付场景,从拉卡拉返回的分账信息中筛选出运费子单或商品子单信息

- * - * @param outSplitRspInfos 拉卡拉分账响应信息,格式为JSON数组字符串: - * [ - * { - * "sub_trade_no":"20250830110113130266250034401288", // 子交易流水号 - * "merchant_no":"822584059990FYP", // 商户号 - * "amount":"1", // 分账金额 - * "settle_type":"0", // 结算类型 - * "sub_log_no":"66250034401288", // 子流水号 - * "out_sub_trade_no":"DF_DD_20250830_21", // 外部子交易订单号(DF开头为运费订单) - * "term_no":"N5811590" // 终端设备号 - * }, - * { - * "sub_trade_no":"20250830110113130266250034401289", // 子交易流水号 - * "merchant_no":"8226330541100GU", // 商户号 - * "amount":"1", // 分账金额 - * "settle_type":"0", // 结算类型 - * "sub_log_no":"66250034401289", // 子流水号 - * "out_sub_trade_no":"ORD_DD_20250830_21", // 外部子交易订单号(ORD开头为商品订单) - * "term_no":"N5817779" // 终端设备号 - * } - * ] - * @param isDeliveryFee true: 提取运费子单信息, false: 提取商品子单信息 - * @return JSONObject 返回匹配的子单信息,格式如下: - * { - * "sub_trade_no":"20250830110113130266250034401288", - * "merchant_no":"822584059990FYP", - * "amount":"1", - * "settle_type":"0", - * "sub_log_no":"66250034401288", - * "out_sub_trade_no":"DF-DD-20250830-21", - * "term_no":"N5811590" - * } - */ - JSONObject getLklCombineSplitRespInfo(String outSplitRspInfos, boolean isDeliveryFee); - } 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 d6335e51..bbc342af 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 @@ -381,7 +381,7 @@ public class LakalaPayServiceImpl implements LakalaPayService { } // 重要约定,订单号规则:商品订单:ORD_订单号,运费订单:DF_订单号 - // 分单信息 + // 商品子单信息 JSONObject goodsSplitInfo = new JSONObject(); goodsSplitInfo.put("out_sub_trade_no", CommonConstant.Sep_GoodsFee_Prefix + orderId); // 商品子订单号 goodsSplitInfo.put("merchant_no", merchantNo); // 分账商户号 @@ -400,9 +400,10 @@ public class LakalaPayServiceImpl implements LakalaPayService { int goodsAmountInt = totalAmountInt - agentAmountInt; goodsSplitInfo.put("amount", Convert.toStr(goodsAmountInt)); // 分账金额 - goodsSplitInfo.put("settle_type", "0"); // "0"或者空,常规结算方式 + goodsSplitInfo.put("settle_type", "1"); // "0"或者空,常规结算方式 goodsSplitInfo.put("sub_remark", "商品订单金额"); // 子单备注信息 + // 运费子单信息 JSONObject deliverySplitInfo = new JSONObject(); deliverySplitInfo.put("out_sub_trade_no", CommonConstant.Sep_DeliveryFee_Prefix + orderId); // 运费子订单号 deliverySplitInfo.put("merchant_no", agentMerchantNo); // 分账商户号 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 4760554d..873fc809 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 @@ -7,9 +7,7 @@ import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.NumberUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; -import cn.hutool.json.JSONArray; import cn.hutool.json.JSONObject; -import cn.hutool.json.JSONUtil; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; @@ -22,6 +20,7 @@ import com.suisung.mall.common.feignService.AccountService; import com.suisung.mall.common.feignService.ShopService; import com.suisung.mall.common.modules.order.*; import com.suisung.mall.common.modules.pay.*; +import com.suisung.mall.common.service.impl.CommonService; import com.suisung.mall.common.utils.CheckUtil; import com.suisung.mall.common.utils.I18nUtil; import com.suisung.mall.core.web.service.impl.BaseServiceImpl; @@ -189,7 +188,7 @@ public class PayConsumeTradeServiceImpl extends BaseServiceImpl该方法用于处理合单支付场景,从拉卡拉返回的分账信息中筛选出运费子单或商品子单信息

- * - * @param outSplitRspInfos 拉卡拉分账响应信息,格式为JSON数组字符串: - * [ - * { - * "sub_trade_no":"20250830110113130266250034401288", // 子交易流水号 - * "merchant_no":"822584059990FYP", // 商户号 - * "amount":"1", // 分账金额 - * "settle_type":"0", // 结算类型 - * "sub_log_no":"66250034401288", // 子流水号 - * "out_sub_trade_no":"DF-DD-20250830-21", // 外部子交易订单号(DF开头为运费订单) - * "term_no":"N5811590" // 终端设备号 - * }, - * { - * "sub_trade_no":"20250830110113130266250034401289", // 子交易流水号 - * "merchant_no":"8226330541100GU", // 商户号 - * "amount":"1", // 分账金额 - * "settle_type":"0", // 结算类型 - * "sub_log_no":"66250034401289", // 子流水号 - * "out_sub_trade_no":"ORD-DD-20250830-21", // 外部子交易订单号(ORD开头为商品订单) - * "term_no":"N5817779" // 终端设备号 - * } - * ] - * @param isDeliveryFee true: 提取运费子单信息, false: 提取商品子单信息 - * @return JSONObject 返回匹配的子单信息,格式如下: - * { - * "sub_trade_no":"20250830110113130266250034401288", - * "merchant_no":"822584059990FYP", - * "amount":"1", - * "settle_type":"0", - * "sub_log_no":"66250034401288", - * "out_sub_trade_no":"DF-DD-20250830-21", - * "term_no":"N5811590" - * } - */ - @Override - public JSONObject getLklCombineSplitRespInfo(String outSplitRspInfos, boolean isDeliveryFee) { - // 输入参数校验:检查分账信息是否为空 - if (StrUtil.isBlank(outSplitRspInfos)) { - logger.warn("获取子流水号失败:输入的分账信息为空"); - return null; - } - - // 解析JSON数组:将字符串转换为JSONArray对象 - JSONArray outSplitRspInfoArray; - try { - outSplitRspInfoArray = JSONUtil.parseArray(outSplitRspInfos); - } catch (Exception e) { - logger.error("JSON解析失败:{}", outSplitRspInfos, e); - return null; - } - - // 检查解析后的数组是否为空 - if (outSplitRspInfoArray.isEmpty()) { - logger.warn("获取子流水号失败:分账信息数组为空"); - return null; - } - - // 遍历JSON数组查找匹配的子单 (合单订单通常只有两个子单:一个运费单,一个商品单) - final String deliveryPrefix = CommonConstant.Sep_DeliveryFee_Prefix; - final String goodsPrefix = CommonConstant.Sep_GoodsFee_Prefix; - - for (int i = 0; i < outSplitRspInfoArray.size(); i++) { - JSONObject item = outSplitRspInfoArray.getJSONObject(i); - if (item == null) { - continue; - } - - // 获取外部子交易订单号字段 - String outSubTradeNo = item.getStr("out_sub_trade_no"); - if (StrUtil.isBlank(outSubTradeNo)) { - continue; - } - - // 根据isDeliveryFee参数筛选对应的子单信息 - if (isDeliveryFee && outSubTradeNo.startsWith(deliveryPrefix)) { - // 运费子单:订单号以DF开头 - return item; - } else if (!isDeliveryFee && !outSubTradeNo.startsWith(goodsPrefix)) { - // 商品子单:订单号不以ORD开头 - return item; - } - } - - // 未找到匹配的子单信息 - return null; - } - } 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 52e2aa33..894cc5ea 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 @@ -52,6 +52,7 @@ import com.suisung.mall.common.modules.pay.*; import com.suisung.mall.common.modules.pay.dto.ItemActivityInfoDTO; import com.suisung.mall.common.modules.store.ShopStoreBase; import com.suisung.mall.common.pojo.res.ThirdApiRes; +import com.suisung.mall.common.service.impl.CommonService; import com.suisung.mall.common.utils.CheckUtil; import com.suisung.mall.common.utils.I18nUtil; import com.suisung.mall.common.utils.LogUtil; @@ -1344,59 +1345,69 @@ public class PayUserPayServiceImpl extends BaseServiceImpl params; try { + logger.info("[拉卡拉支付通知] 开始处理拉卡拉支付异步通知"); + + // 初始化拉卡拉SDK lakalaPayService.initLKLSDK(); + log.debug("[拉卡拉支付通知] 拉卡拉SDK初始化完成"); // 读取请求体并验签 String body = LKLSDK.notificationHandle(request); String authorization = request.getHeader("Authorization"); + logger.debug("[拉卡拉支付通知] 接收到通知数据,body长度={},authorization长度={}", + body != null ? body.length() : 0, + authorization != null ? authorization.length() : 0); if (StrUtil.isBlank(body)) { + log.warn("[拉卡拉支付通知] 验签失败,请求体为空"); return lklNotifyMsg(false, "验签失败!"); } // 敏感头信息脱敏打印 - logger.info("拉卡拉支付异步通知回调 body:{} \n authorization: {}", body, authorization); - // 非合单返回的数据异步通知返回的 body json数据:{"out_trade_no":"202203151637334864280014","trade_no":"2022031566210203291925","log_no":"66210203291925", - // "acc_trade_no":"2022031522001483661454130929 ","trade_status":"SUCCESS","trade_state":"SUCCESS","total_amount":"1", - // "payer_amount":"1","acc_settle_amount":"1","trade_time":"20220315163808","user_id1":"app***@163.com", - // "user_id2":"2088432881453660","notify_url":"https://www.baidu.com","account_type":"ALIPAY","card_type":"99"} - - // 合单返回的数据异步通知返回的 body json数据:{"out_trade_no":"DD-20250830-10","trade_no":"20250830110113130266250034160499","log_no":"66250034160499", - // "acc_trade_no":"4200002826202508306761393882","trade_status":"SUCCESS","trade_state":"SUCCESS","total_amount":"2","payer_amount":"2","acc_settle_amount":"2", - // "acc_mdiscount_amount":"0","acc_discount_amount":"0","trade_time":"20250830180435","user_id1":"oDVKR7T0qxg6O8tqIL9SgY6LXqqQ", - // "user_id2":"oVxsc1QRAqDRv_gAmXuLZwSVSL18","notify_url":"https://mall.gpxscs.cn/mobile/pay/index/lkl_wxPay_notify_url","account_type":"WECHAT", - // "bank_type":"OTHERS","card_type":"02","merchant_no":"8226330541100GU","remark":"","sub_mch_id":"803819329", - // "out_split_rsp_infos":[{"sub_trade_no":"20250830110113130266250034112794","sub_log_no":"66250034112794","out_sub_trade_no":"ORD-DD-20250830-10", - // "merchant_no":"8226330541100GU","term_no":"N5817779","amount":"1","settle_type":"0"},{"sub_trade_no":"20250830110113130266250034160498","sub_log_no":"66250034160498", - // "out_sub_trade_no":"DF-DD-20250830-10","merchant_no":"822584059990FYP","term_no":"N5811590","amount":"1","settle_type":"0"}],"trade_req_date":"20250830","gb_amount":"", - // "qb_amount":""} + logger.info("[拉卡拉支付通知] 拉卡拉支付异步通知回调 body:{} \n authorization: {}", + body, authorization != null ? "***" : "null"); // 解析JSON格式响应 cn.hutool.json.JSONObject lklNotifyRespJSON = JSONUtil.parseObj(body); + logger.debug("[拉卡拉支付通知] 解析JSON完成: keys={}", lklNotifyRespJSON.keySet()); + params = Convert.toMap(String.class, String.class, lklNotifyRespJSON); String orderId = params.getOrDefault("out_trade_no", ""); - String accTradeNo = params.getOrDefault("acc_trade_no", ""); // 需要跟拉卡拉确认这个字段是原支付交易对应的微信订单号吗? - String outSplitRspInfos = params.getOrDefault("out_split_rsp_infos", ""); // 拉卡拉合单订单信息 + String tradeStatus = params.getOrDefault("trade_status", ""); + String accTradeNo = params.getOrDefault("acc_trade_no", ""); + String outSplitRspInfos = params.getOrDefault("out_split_rsp_infos", ""); + + logger.info("[拉卡拉支付通知] 核心参数 - 订单号:{} 状态:{} 是否合单:{}", + orderId, tradeStatus, StrUtil.isNotBlank(outSplitRspInfos) ? "是" : "否"); // 提取授权签名信息 Map authMap = LakalaUtil.getLakalaAuthorizationMap(authorization); if (authMap != null && authMap.containsKey("signature")) { params.put("sign", authMap.get("signature")); + logger.debug("[拉卡拉支付通知] 签名信息提取成功"); } else { - logger.error("缺少签名信息"); + logger.error("[拉卡拉支付通知] 缺少签名信息,authMap={}", authMap); return lklNotifyMsg(false, "缺少签名信息"); } if (StrUtil.isBlank(orderId)) { - logger.error("缺少out_trade_no字段"); + logger.error("[拉卡拉支付通知] 缺少out_trade_no字段,body={}", body); return lklNotifyMsg(false, "缺少out_trade_no字段"); } // 查询交易信息 + logger.debug("[拉卡拉支付通知] 查询交易信息: orderId={}", orderId); QueryWrapper tradeQueryWrapper = new QueryWrapper<>(); tradeQueryWrapper.eq("order_id", orderId); PayConsumeTrade trade_row_tmp = payConsumeTradeService.findOne(tradeQueryWrapper); @@ -1405,25 +1416,32 @@ public class PayUserPayServiceImpl extends BaseServiceImpl channelQueryWrapper = new QueryWrapper<>(); channelQueryWrapper.eq("payment_channel_code", "lakala"); PayPaymentChannel payPaymentChannel = payPaymentChannelService.findOne(channelQueryWrapper); if (payPaymentChannel == null) { - logger.error("支付渠道不存在"); + logger.error("[拉卡拉支付通知] 支付渠道不存在: channelCode=lakala"); return lklNotifyMsg(false, "支付渠道不存在"); } Integer payment_channel_id = payPaymentChannel.getPayment_channel_id(); + logger.debug("[拉卡拉支付通知] 支付渠道查询完成: channelId={}", payment_channel_id); // 插入充值记录 + logger.debug("[拉卡拉支付通知] 创建充值记录"); PayConsumeDeposit payConsumeDeposit = createNotify(params, payPaymentChannel); payConsumeDeposit.setOrder_id(orderId); payConsumeDeposit.setStore_id(payment_store_id); // 所属店铺 @@ -1433,11 +1451,22 @@ public class PayUserPayServiceImpl extends BaseServiceImpl * @param outSeparateNo * @return */ - LklOrderSeparate getByOutTradeNo(String logNo, String outSeparateNo); + LklOrderSeparate getByLogNoAndOutTradeNo(String logNo, String outSeparateNo); /** * 根据商户号和平台订单号查询记录 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 99411a50..36dfdc63 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,6 +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.service.impl.CommonService; import com.suisung.mall.common.utils.*; import com.suisung.mall.shop.lakala.service.*; import com.suisung.mall.shop.lakala.utils.LakalaUtil; @@ -604,10 +605,11 @@ public class LakalaApiServiceImpl implements LakalaApiService { req.setOrgCode(orgCode); req.setMerCupNo(shopMchEntry.getLkl_mer_cup_no()); // 从进件申请返回的商户号(不要传入内部商户号,传银联商户号才有效) req.setContactMobile(shopMchEntry.getLogin_mobile()); // 商户入驻注册的手机号 - // 分账比例为了考虑低价订单的运费占比高,分账比例暂时定70%分账给商户,30%分账给平台 + // 分账比例默认 94% req.setSplitLowestRatio(new BigDecimal(splitLowestRatio)); req.setEleContractNo(shopMchEntry.getLkl_ec_no()); - String fileName = "商家分账授权委托书.pdf";//paramsJSON.getStr("splitEntrustFileName"); + req.setSplitRange("ALL"); // ALL:全部交易分账 (商户所有交易默认待分账) MARK:标记交易分账(只有带分账标识交易待分账,其余交易正常结算) 默认:MARK + String fileName = "商家分账授权委托书.pdf"; req.setSplitEntrustFileName(fileName); // TODO 分账结算委托书文件上传到拉卡拉服务器 @@ -714,15 +716,52 @@ public class LakalaApiServiceImpl implements LakalaApiService { return JSONUtil.createObj().set("code", "FAIL").set("message", "返回数据转换异常!"); } - String logNo = paramsJSON.getStr("log_no"); - String tradeState = paramsJSON.getStr("trade_state"); + // 订单是否为合单 + boolean isCombine = paramsJSON.containsKey("out_split_rsp_infos"); + log.debug("[确认收货通知] 检查是否为合单订单: isCombine={}", isCombine); + String merchantNo = paramsJSON.getStr("merchant_no"); + log.debug("[确认收货通知] 获取商户号: merchantNo={}", merchantNo); + + // 分账用途 + String logNo = paramsJSON.getStr("log_no"); + String tradeNo = paramsJSON.getStr("trade_no"); + log.debug("[确认收货通知] 获取基础交易信息: logNo={} tradeNo={}", logNo, tradeNo); + + // 查询用途 String originTradeNo = paramsJSON.getStr("origin_trade_no"); String originLogNo = paramsJSON.getStr("origin_log_no"); + log.debug("[确认收货通知] 获取原始交易信息: originTradeNo={} originLogNo={}", originTradeNo, originLogNo); + + String tradeState = paramsJSON.getStr("trade_state"); + log.debug("[确认收货通知] 获取交易状态: tradeState={}", tradeState); log.info("[确认收货通知] 接收到通知参数: logNo={}, tradeState={}, merchantNo={}, originTradeNo={}, originLogNo={}", logNo, tradeState, merchantNo, originTradeNo, originLogNo); + if (isCombine) { + log.debug("[确认收货通知] 处理合单订单,开始获取子单信息"); + // 合单的时候获取子单信息 + JSONObject goodsOrderInfo = CommonService.getLklCombineSplitRespInfo(merchantNo, paramsJSON.getStr("out_split_rsp_infos"), false); + if (goodsOrderInfo != null) { + log.debug("[确认收货通知] 成功获取商品子单信息: {}", goodsOrderInfo); + // 分账用途 + tradeNo = goodsOrderInfo.getStr("sub_trade_no"); + logNo = goodsOrderInfo.getStr("sub_log_no"); + log.debug("[确认收货通知] 从子单信息中获取交易号: tradeNo={} logNo={}", tradeNo, logNo); + + // 查询用途 + originTradeNo = goodsOrderInfo.getStr("origin_sub_trade_no"); + originLogNo = goodsOrderInfo.getStr("origin_sub_log_no"); + log.debug("[确认收货通知] 从子单信息中获取原始交易号: originTradeNo={} originLogNo={}", originTradeNo, originLogNo); + } else { + log.warn("[确认收货通知] 未能获取到商品子单信息,使用原始参数进行处理"); + } + } else { + log.debug("[确认收货通知] 非合单订单,使用原始参数进行处理"); + } + + if (StrUtil.isBlank(tradeState) || !"SUCCESS".equals(tradeState)) { log.warn("[确认收货通知] 交易状态未成功,不做任何处理: tradeState={}", tradeState); return JSONUtil.createObj().set("code", "FAIL").set("message", "交易状态未成功,不做任何处理!"); @@ -734,7 +773,7 @@ public class LakalaApiServiceImpl implements LakalaApiService { return JSONUtil.createObj().set("code", "FAIL").set("message", "关键编号返回空值!"); } - ShopOrderLkl shopOrderLkl = shopOrderLklService.getByLklMchNoAndTradeNoAndSubLogNo(merchantNo, originTradeNo, originLogNo); + ShopOrderLkl shopOrderLkl = shopOrderLklService.getByLklMchNoAndSubTradeNoAndSubLogNo(merchantNo, originTradeNo, originLogNo); if (shopOrderLkl == null) { log.warn("[确认收货通知] 订单不存在: merchantNo={}, originTradeNo={}, originLogNo={}", merchantNo, originTradeNo, originLogNo); @@ -744,7 +783,7 @@ public class LakalaApiServiceImpl implements LakalaApiService { try { // 更新订单信息 shopOrderLkl.setLkl_receive_log_no(logNo); - shopOrderLkl.setLkl_receive_trade_no(paramsJSON.getStr("trade_no")); + shopOrderLkl.setLkl_receive_trade_no(tradeNo); shopOrderLkl.setLkl_receive_notify_resp(checkResult.getSecond()); shopOrderLkl.setReceive_status(CommonConstant.Enable); @@ -759,7 +798,7 @@ public class LakalaApiServiceImpl implements LakalaApiService { // 发起分账指令 log.info("[确认收货通知] 开始发起分账指令: merchantNo={}, receiveTradeNo={}, logNo={}", merchantNo, shopOrderLkl.getLkl_receive_trade_no(), logNo); - Pair separateResult = innerDoOrderSeparateByMerchantAndLogNo(merchantNo, shopOrderLkl.getLkl_receive_trade_no(), logNo); + Pair separateResult = innerDoOrderSeparateByMerchantAndLogNo(merchantNo, shopOrderLkl.getLkl_receive_trade_no(), shopOrderLkl.getLkl_receive_log_no()); if (!separateResult.getFirst()) { log.error("[确认收货通知] 发起分账指令失败: orderId={}, reason={}", shopOrderLkl.getOrder_id(), separateResult.getSecond()); return JSONUtil.createObj().set("code", "FAIL").set("message", "发起分账指令失败:" + separateResult.getSecond()); @@ -767,7 +806,7 @@ public class LakalaApiServiceImpl implements LakalaApiService { // 调用内部的确认收货 shopOrderBaseService.receive(shopOrderLkl.getOrder_id(), null); - + log.info("[确认收货通知] 处理完成: orderId={}, log_no={}", shopOrderLkl.getOrder_id(), shopOrderLkl.getLkl_receive_log_no()); JSONObject respData = JSONUtil.createObj(); respData.set("code", "SUCCESS"); @@ -1740,7 +1779,7 @@ public class LakalaApiServiceImpl implements LakalaApiService { } // 5. 检查分账状态,避免重复处理 - LklOrderSeparate existingSeparateRecord = lklOrderSeparateService.getByOutTradeNo(shopOrderLkl.getLkl_sub_log_no(), orderId); + LklOrderSeparate existingSeparateRecord = lklOrderSeparateService.getByLogNoAndOutTradeNo(shopOrderLkl.getLkl_sub_log_no(), orderId); if (existingSeparateRecord != null) { String status = existingSeparateRecord.getStatus(); if ("SUCCESS".equals(status)) { @@ -2005,7 +2044,7 @@ public class LakalaApiServiceImpl implements LakalaApiService { } // 4. 检查分账状态,避免重复处理 - LklOrderSeparate existingSeparateRecord = lklOrderSeparateService.getByOutTradeNo(shopOrderLkl.getLkl_sub_log_no(), shopOrderLkl.getOut_separate_no()); + LklOrderSeparate existingSeparateRecord = lklOrderSeparateService.getByLogNoAndOutTradeNo(shopOrderLkl.getLkl_receive_log_no(), shopOrderLkl.getOut_separate_no()); if (existingSeparateRecord != null) { String status = existingSeparateRecord.getStatus(); if ("SUCCESS".equals(status)) { @@ -2120,9 +2159,9 @@ public class LakalaApiServiceImpl implements LakalaApiService { // 17. 构建分账请求对象 V3SacsSeparateRequest separateRequest = new V3SacsSeparateRequest(); separateRequest.setMerchantNo(merchantNo); + separateRequest.setOutSeparateNo(shopOrderLkl.getOut_separate_no()); separateRequest.setLogNo(shopOrderLkl.getLkl_receive_log_no()); // 使用收货流水号作为分账流水号 separateRequest.setLogDate(shopOrderLkl.getLkl_log_date()); - separateRequest.setOutSeparateNo(shopOrderLkl.getOut_separate_no()); separateRequest.setTotalAmt(splitAmount.toString()); separateRequest.setLklOrgNo(orgCode); separateRequest.setCalType("0"); // 0- 按照指定金额,1- 按照指定比例。默认 0 @@ -2154,7 +2193,7 @@ public class LakalaApiServiceImpl implements LakalaApiService { String errorMsg = String.format("[分账操作] 拉卡拉返回格式异常,订单=%s,商户=%s,分账流水号=%s,响应=%s,respJson=%s", orderId, merchantNo, shopOrderLkl.getLkl_receive_log_no(), response, respJson); log.error(errorMsg); - return Pair.of(false, "拉卡拉返回格式异常"); + return Pair.of(false, "拉卡拉分账异常:[" + respJson.getStr("code") + "]" + respJson.getStr("msg")); } // 21. 保存分账记录 @@ -2271,7 +2310,7 @@ public class LakalaApiServiceImpl implements LakalaApiService { .put("message", errorMsg); } - LklOrderSeparate lklOrderSeparateExist = lklOrderSeparateService.getByOutTradeNo(logNo, outSeparateNo); + LklOrderSeparate lklOrderSeparateExist = lklOrderSeparateService.getByLogNoAndOutTradeNo(logNo, outSeparateNo); if (lklOrderSeparateExist == null) { String errorMsg = "未找到对应的分账记录"; log.error(errorMsg + ", 外部分账单号={}, 分账单号={}, 参数详情: {}", outSeparateNo, separateNo, paramsJson); @@ -2288,6 +2327,14 @@ public class LakalaApiServiceImpl implements LakalaApiService { .put("message", "分账已处理成功,请不要重复通知"); } + if (!"FAIL".equals(lklOrderSeparateExist.getFinal_status())) { + String errorMsg = "已受理或处理中,成功后再通知"; + log.warn(errorMsg + ", 订单号={}, 外部分账单号={}, 参数详情: {}", logNo, outSeparateNo, paramsJson); + return JSONUtil.createObj() + .put("code", "FAIL") + .put("message", "已受理或处理中,成功后再通知"); + } + // 4. 记录关键参数信息,便于问题排查 log.info("接收到分账通知,分账单号={}, 外部分账单号={}, 状态={}, 最终状态={}", separateNo, outSeparateNo, status, finalStatus); @@ -2302,6 +2349,9 @@ public class LakalaApiServiceImpl implements LakalaApiService { lklOrderSeparate.setCal_type(paramsJson.getStr("cal_type")); lklOrderSeparate.setSeparate_type(paramsJson.getStr("separate_type")); lklOrderSeparate.setSeparate_date(paramsJson.getStr("separate_date")); + lklOrderSeparate.setTotal_separate_value(paramsJson.getInt("total_amt")); + lklOrderSeparate.setRemark("分账已完成"); + lklOrderSeparate.setFinish_date(paramsJson.getStr("finish_date")); // 处理detail_datas(避免空指针) JSONArray detailDatas = paramsJson.getJSONArray("detail_datas"); diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklOrderSeparateServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklOrderSeparateServiceImpl.java index af7168b8..6c6f99b8 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklOrderSeparateServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklOrderSeparateServiceImpl.java @@ -54,30 +54,30 @@ public class LklOrderSeparateServiceImpl extends BaseServiceImpl list = list(new QueryWrapper() - .eq("log_no", splitLogNo) + .eq("log_no", logNo) .eq("out_separate_no", outSeparateNo)); if (CollUtil.isEmpty(list)) { - log.info("未找到记录:logNo={}, outSeparateNo={}", splitLogNo, outSeparateNo); + log.info("未找到记录:logNo={}, outSeparateNo={}", logNo, outSeparateNo); return null; } return list.get(0); } catch (Exception e) { - log.error("查询记录时发生异常:logNo={}, outSeparateNo={}, 异常信息={}", splitLogNo, outSeparateNo, e.getMessage(), e); + log.error("查询记录时发生异常:logNo={}, outSeparateNo={}, 异常信息={}", logNo, outSeparateNo, e.getMessage(), e); return null; } } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/order/service/ShopOrderLklService.java b/mall-shop/src/main/java/com/suisung/mall/shop/order/service/ShopOrderLklService.java index 95c203ae..6c521927 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/order/service/ShopOrderLklService.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/order/service/ShopOrderLklService.java @@ -82,7 +82,7 @@ public interface ShopOrderLklService extends IBaseService { * @param lklSubLogNo * @return */ - ShopOrderLkl getByLklMchNoAndTradeNoAndSubLogNo(String lklMerchantNo, String lklTradeNo, String lklSubLogNo); + ShopOrderLkl getByLklMchNoAndSubTradeNoAndSubLogNo(String lklMerchantNo, String lklTradeNo, String lklSubLogNo); /** 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 a659b445..47932f7e 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 @@ -763,9 +763,9 @@ public class ShopOrderBaseServiceImpl extends BaseServiceImpl store_row_Opl = store_rows.stream().filter(s -> ObjectUtil.equal(store_id, Convert.toInt(s.get("store_id")))).findFirst(); 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 3a2148af..bdf9c142 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 @@ -123,100 +123,149 @@ public class ShopOrderLklServiceImpl extends BaseServiceImpl queryWrapper = new QueryWrapper<>(); queryWrapper.orderByAsc("id"); @@ -351,25 +427,25 @@ public class ShopOrderLklServiceImpl extends BaseServiceImpl())); + return CommonResult.success(shopStoreBaseService.getStoreList(page, rows, new HashMap<>())); } @ApiOperation(value = "列出店铺分类", notes = "列出店铺分类") @@ -314,26 +314,4 @@ public class StoreController extends BaseControllerImpl { } } - -// /** -// * 列表查询 -// * @return -// */ -// @ApiOperation(value = "店铺分类表-分类强调区别, 类型强调共性-分页列表查询", notes = "店铺分类表-分类强调区别, 类型强调共性-分页列表查询") -// @RequestMapping(value = "/categoryTree", method = RequestMethod.GET) -// public CommonResult categoryTree(ShopBaseStoreCategory category) { -// QueryWrapper queryWrapper = new QueryWrapper<>(); -// if (category.getStore_category_parent_id() != null) -// queryWrapper.eq("store_category_parent_id", category.getStore_category_parent_id()); -// -// return CommonResult.success(shopBaseStoreCategoryService.getMobileCategoryTree(queryWrapper)); -// } - -// @ApiOperation(value = "根据分类查询店铺", notes = "列表数据") -// @RequestMapping(value = "/listStores", method = RequestMethod.GET) -// public Page listStores(@RequestParam(name = "page", defaultValue = "1") Integer page, -// @RequestParam(name = "rows", defaultValue = "10") Integer rows) { -// return shopStoreBaseService.getMobileStoreList(page, rows); -// } - } \ No newline at end of file diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopStoreBaseServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopStoreBaseServiceImpl.java index 15364599..5a4a8066 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopStoreBaseServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopStoreBaseServiceImpl.java @@ -2383,6 +2383,11 @@ public class ShopStoreBaseServiceImpl extends BaseServiceImpl 0) { return CommonResult.failed("打包费请控制在0到10元范围"); } @@ -2734,6 +2744,14 @@ public class ShopStoreBaseServiceImpl extends BaseServiceImpl store_id , user_id, store_name, store_grade_id, store_logo, store_slogan, store_domain, store_area, store_district_id, - store_address, store_latitude, store_longitude, store_is_selfsupport, store_type, store_is_open, store_biz_state, shop_parent_id, + store_address, store_latitude, store_longitude, store_is_selfsupport, store_type, store_is_open, store_biz_state, + ringtone_is_enable, shop_parent_id, store_category_id, store_state_id, store_time, store_end_time, product_category_ids, store_o2o_tags, store_o2o_flag, store_o2o_merchant_id, store_circle, subsite_id, lkl_merchant_no, lkl_term_no, wx_qrcode, split_ratio, packing_fee, created_at, updated_at