diff --git a/mall-common/src/main/java/com/suisung/mall/common/modules/lakala/LklOrderSeparate.java b/mall-common/src/main/java/com/suisung/mall/common/modules/lakala/LklOrderSeparate.java new file mode 100644 index 00000000..d0562013 --- /dev/null +++ b/mall-common/src/main/java/com/suisung/mall/common/modules/lakala/LklOrderSeparate.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.suisung.mall.common.modules.lakala; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +import java.util.Date; + + +@Data +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("lkl_order_separate") +@ApiModel(value = "拉卡拉分账接收方", description = "拉卡拉分账接收方表") +public class LklOrderSeparate { + + @TableId(value = "id", type = IdType.INPUT) + @ApiModelProperty(value = "自增Id", example = "1") + private Long id; + + @ApiModelProperty(value = "拉卡拉外部商户号") + private String merchant_no; + + @ApiModelProperty(value = "拉卡拉对账单流水号 posp流水号,查清结算用") + private String log_no; + + @ApiModelProperty(value = "交易日期,yyyyMMdd,查清结算用") + private String log_date; + + @ApiModelProperty(value = "商户分账指令流水号,每个商户号下唯一,否则会校验失败") + private String out_separate_no; + + @ApiModelProperty(value = "分账指令流水号,分账系统生成唯一流水") + private String separate_no; + + @ApiModelProperty(value = "分账总金额,单位:分") + private String total_amt; + + @ApiModelProperty(value = "分账计算类型:0- 按照指定金额,1- 按照指定比例。默认 0") + private String cal_type; + + @ApiModelProperty(value = "指令类型 SEPARATE-分账, CANCEL-分账撤销,FALLBACK-分账回退") + private String cmd_type; + + @ApiModelProperty(value = "分账接收类型:0-全部分账到商户本身。1-分账到多方,默认 1") + private String separate_type; + + @ApiModelProperty(value = "分账日期 yyyyMMdd") + private String separate_date; + + @ApiModelProperty(value = "完成日期 yyyyMMdd") + private String finish_date; + + @ApiModelProperty(value = "拉卡拉异步通知回调地址") + private String notify_url; + + @ApiModelProperty(value = "分账接收数据对象,JSON 格式") + private String recv_datas; + + @ApiModelProperty(value = "最终分账明细,JSON 格式") + private String detail_datas; + + @ApiModelProperty(value = "拉卡拉机构编号") + private String lkl_org_no; + + @ApiModelProperty(value = "分账状态:PROCESSING-处理中, ACCEPTED-已受理, SUCCESS-成功, FAIL-失败") + private String status; + + @ApiModelProperty(value = "处理状态:ACCEPTED-已受理, PROCESSING-处理中, FAIL-失败, SUCCESS-成功") + private String final_status; + + @ApiModelProperty(value = "新建时间") + private Date created_at; + + @ApiModelProperty(value = "更新时间") + private Date updated_at; +} \ No newline at end of file diff --git a/mall-common/src/main/java/com/suisung/mall/common/modules/store/ShopMchEntry.java b/mall-common/src/main/java/com/suisung/mall/common/modules/store/ShopMchEntry.java index 831bcedc..87a1645d 100644 --- a/mall-common/src/main/java/com/suisung/mall/common/modules/store/ShopMchEntry.java +++ b/mall-common/src/main/java/com/suisung/mall/common/modules/store/ShopMchEntry.java @@ -81,7 +81,6 @@ public class ShopMchEntry implements Serializable { @ApiModelProperty(value = "邮箱") private String email; - @ApiModelProperty(value = "店铺地区编号,省份code/城市code/区code") private String store_district; @@ -211,6 +210,9 @@ public class ShopMchEntry implements Serializable { @ApiModelProperty(value = "拉卡拉银联商户号(唯一)") private String lkl_mer_cup_no; + @ApiModelProperty(value = "拉卡拉分配的业务终端号") + private String lkl_term_no; + @ApiModelProperty(value = "拉卡拉审核状态:1-已通过;2-未通过") private Integer lkl_tk_audit_status; diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/mapper/LklOrderSeparateMapper.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/mapper/LklOrderSeparateMapper.java new file mode 100644 index 00000000..0cc63266 --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/mapper/LklOrderSeparateMapper.java @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.suisung.mall.shop.lakala.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.suisung.mall.common.modules.lakala.LklOrderSeparate; +import org.springframework.stereotype.Repository; + + +@Repository +public interface LklOrderSeparateMapper extends BaseMapper { + +} 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 0e1fea84..e7339007 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 @@ -9,6 +9,7 @@ package com.suisung.mall.shop.lakala.service; import cn.hutool.json.JSONObject; +import com.lkl.laop.sdk.request.V3SacsSeparateRequest; import com.suisung.mall.common.api.CommonResult; import org.springframework.data.util.Pair; @@ -181,13 +182,31 @@ public interface LakalaApiService { */ JSONObject getBankCardBin(String bankCardNo); + /** - * @param imgURL - * @param imgType 法人身份证正面图:FR_ID_CARD_FRONT;法人身份证反面:FR_ID_CARD_BEHIND; - * 身份证正面:ID_CARD_FRONT;身份证反面:ID_CARD_BEHIND; - * 营业执照:BUSINESS_LICENSE;银行卡:BANK_CARD + * 查询拉卡拉商户可分账的金额 + * 参考:https://o.lakala.com/#/home/document/detail?id=394 + * + * @param merchantNo 拉卡拉外部商户号 + * @param logNo 拉卡拉对账单流水号 + * @param logDate 拉卡拉对账单交易日期 yyyyMMdd + * @return 响应结果 { + * "merchant_no": "82229005943096D", + * "total_separate_amt": "9900", + * "can_separate_amt": "0", + * "log_date": "20221220", + * "log_no": "66210306990190" + * } + */ + JSONObject queryMchCanSplitAmt(String merchantNo, String logNo, String logDate); + + /** + * 拉卡拉订单分账,用户下单成功之后,进行分账 + * 说明:分账指令是异步处理模式,响应报文成功时,指令状态是”status”: “PROCESSING”,需要等待分账结果通知,或者主动发起查询,建议主动发起查询与分账指令动作之间间隔15秒以上。 + * 参考:https://o.lakala.com/#/home/document/detail?id=389 + * + * @param v3SacsSeparateRequest * @return */ - - + Pair innerDoOrderSeparate(V3SacsSeparateRequest v3SacsSeparateRequest); } 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 16610002..627de726 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 @@ -62,6 +62,7 @@ import java.util.List; public class LakalaApiServiceImpl implements LakalaApiService { private static final boolean init = false; private static final String lklSuccessCode = "000000"; + private static final String lklSacsSuccessCode = "SACS0000"; // 可选的两个参数,不同的店铺商家,可以数据库里配置不同的商户号和终端号 @Value("${lakala.merchant_no}") public String merchantNo; // 拉卡拉分配的商户号 @@ -1165,7 +1166,7 @@ public class LakalaApiServiceImpl implements LakalaApiService { // 判断分账接收方记录是否存在,存在就不再新建了 LklLedgerReceiver lklLedgerReceiverOld = lklLedgerReceiverService.getByCondition(paramsJSON.getStr("licenseNo"), paramsJSON.getStr("contactMobile"), paramsJSON.getLong("platformId")); if (lklLedgerReceiverOld != null) { - return CommonResult.success(lklLedgerReceiverOld, "分账接收方已创建过!"); + return CommonResult.success(lklLedgerReceiverOld, "该接收方已创建过!"); } // 1. 配置初始化 @@ -1232,7 +1233,7 @@ public class LakalaApiServiceImpl implements LakalaApiService { String responseStr = LKLSDK.httpPost(req); JSONObject lakalaRespJSON = JSONUtil.parseObj(responseStr); if (StrUtil.isBlank(responseStr) || lakalaRespJSON == null) { - return CommonResult.failed(I18nUtil._("创建分账接收方无响应!")); + return CommonResult.failed(I18nUtil._("创建分账接收方响应数据无效!")); // throw new ApiException(I18nUtil._("创建分账接收方无响应!")); } @@ -1609,5 +1610,95 @@ public class LakalaApiServiceImpl implements LakalaApiService { return null; } + /** + * 查询拉卡拉商户可分账的金额 + * 参考:https://o.lakala.com/#/home/document/detail?id=394 + * + * @param merchantNo 拉卡拉外部商户号 + * @param logNo 拉卡拉对账单流水号 + * @param logDate 拉卡拉对账单交易日期 yyyyMMdd + * @return 响应结果 { + * "merchant_no": "82229005943096D", + * "total_separate_amt": "9900", + * "can_separate_amt": "0", + * "log_date": "20221220", + * "log_no": "66210306990190" + * } + */ + @Override + public JSONObject queryMchCanSplitAmt(String merchantNo, String logNo, String logDate) { + if (StrUtil.isBlank(merchantNo) || (StrUtil.isBlank(logNo) && StrUtil.isBlank(logDate))) { + return null; + } + + // 1. 配置初始化 + initLKLSDK(); + + //2. 装配数据 + V3SacsQueryAmtRequest req = new V3SacsQueryAmtRequest(); + req.setMerchantNo(merchantNo); + req.setLogNo(logNo); + req.setLogDate(logDate); + + try { + //3. 发送请求 + String responseStr = LKLSDK.httpPost(req); + if (StrUtil.isBlank(responseStr)) { + log.error(I18nUtil._("服务器无返回值!")); + return null; + } + + JSONObject lklRespJSON = JSONUtil.parseObj(responseStr); + if (lklRespJSON == null || !lklSacsSuccessCode.equals(lklRespJSON.getStr("code")) || lklRespJSON.get("resp_data") == null) { + log.error(I18nUtil._("返回值有误!")); + return null; + } + + return (JSONObject) lklRespJSON.get("resp_data"); + } catch (SDKException e) { + log.error("账户余额查询失败:", e); + return null; + } + } + + /** + * 拉卡拉订单分账,用户下单成功之后,进行分账 + * 说明:分账指令是异步处理模式,响应报文成功时,指令状态是”status”: “PROCESSING”,需要等待分账结果通知,或者主动发起查询,建议主动发起查询与分账指令动作之间间隔15秒以上。 + * 参考:https://o.lakala.com/#/home/document/detail?id=389 + * + * @param v3SacsSeparateRequest + * @return + */ + @Override + public Pair innerDoOrderSeparate(V3SacsSeparateRequest v3SacsSeparateRequest) { + if (v3SacsSeparateRequest == null) { + return Pair.of(false, "分账参数不能为空"); + } + + // 1. 配置初始化 + initLKLSDK(); + + try { + log.debug("分账执行请求参数:{}", JSONUtil.toJsonStr(v3SacsSeparateRequest)); + + //3. 发送请求 + String responseStr = LKLSDK.httpPost(v3SacsSeparateRequest); + if (StrUtil.isBlank(responseStr)) { + return Pair.of(false, "服务器无返回值!"); + } + + JSONObject lklRespJSON = JSONUtil.parseObj(responseStr); + if (lklRespJSON == null || !lklSacsSuccessCode.equals(lklRespJSON.getStr("code")) || lklRespJSON.get("resp_data") == null) { + log.error("返回值有误!"); + return Pair.of(false, "返回值有误!"); + } + + return Pair.of(true, "分账成功执行,处理中"); + } catch (SDKException e) { + log.error("账户余额查询失败:", e); + return Pair.of(false, "分账发生错误"); + } + } + } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklTkServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklTkServiceImpl.java index f303e458..ddc879ea 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklTkServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklTkServiceImpl.java @@ -578,13 +578,18 @@ public class LklTkServiceImpl { // 给商家入驻表增加拉卡拉的商户号和拉卡拉返回的数据 String merCupNo = dataJSON.getStr("externalCustomerNo"); //拉卡拉外部商户号 String merInnerNo = dataJSON.getStr("customerNo"); //拉卡拉内部商户号 + String termNos = dataJSON.getStr("termNos"); //拉卡拉分配的业务终端号 + if (StrUtil.isBlank(merInnerNo) || StrUtil.isBlank(merCupNo)) { + return new JSONObject().set("code", "FAIL").set("message", "返回数据有误"); + } + ShopMchEntry shopMchEntry = shopMchEntryService.getShopMerchEntryByMerInnerNo(merInnerNo); if (ObjectUtil.isEmpty(shopMchEntry)) { logger.error("拉卡拉进件异步通知:返回的内部商户号:{} 入驻信息不存在!", merInnerNo); return new JSONObject().put("code", "FAIL").put("message", "内部商户号:" + merInnerNo + " 入驻信息不存在"); } - Boolean success = shopMchEntryService.updateMerchEntryLklAuditStatusByLklMerCupNo(merInnerNo, merCupNo, CommonConstant.Enable, null, data); + Boolean success = shopMchEntryService.updateMerchEntryLklAuditStatusByLklMerCupNo(merInnerNo, merCupNo, termNos, CommonConstant.Enable, null, data); if (!success) { return new JSONObject().set("code", "FAIL").set("message", "更新商户号失败"); // throw new ApiException("更新商户号失败"); @@ -610,29 +615,27 @@ public class LklTkServiceImpl { // 1、(电子合同)给商家申请分账功能使用;务必检查是否申请过?申请过忽略 // 下一步等待拉卡拉审核通过,再绑定接收方和商家的关系 Pair retPair = lakalaApiService.innerApplyLedgerMer(merCupNo); + + // 2:新增一个接收方记录,起码要一个平台方,代理商根据入驻信息新增 + Boolean genSuccess = lklLedgerReceiverService.innerApplyLedgerReceiver(merCupNo, shopMchEntry.getDistributor_id()); + + if (retPair.getFirst() && genSuccess) { + return new JSONObject().put("code", "SUCCESS").put("message", "处理成功"); + } + if (!retPair.getFirst()) { String message = "商家申请分账功能失败:" + retPair.getSecond(); logger.error(message); return new JSONObject().set("code", "FAIL").set("message", message); -// throw new ApiException(message); } - // 2:新增一个接收方记录,起码要一个平台方,代理商根据入驻信息新增 - Boolean genSuccess = lklLedgerReceiverService.innerApplyLedgerReceiver(merCupNo, shopMchEntry.getDistributor_id()); if (!genSuccess) { logger.error("申请分账接收方失败"); return new JSONObject().set("code", "FAIL").set("message", "申请分账接收方失败"); -// throw new ApiException("申请分账接收方失败"); } - - // 更新商家的hasEsigned状态=1 -// lklLedgerMemberService.updateMulStatus("", shopMchEntry.getLogin_mobile(), 1, 0, 0, 0); - - return new JSONObject().put("code", "SUCCESS").put("message", "处理成功"); } return new JSONObject().set("code", "FAIL").set("message", "进件回调处理失败"); -// throw new ApiException("进件回调处理失败"); } /** diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/ShopMchEntryService.java b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/ShopMchEntryService.java index 800bfe32..e170a2dd 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/ShopMchEntryService.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/ShopMchEntryService.java @@ -158,16 +158,17 @@ public interface ShopMchEntryService { Boolean updateMerchEntryLklMerCupNo(String loginMobile, Integer lklAuditStatus, String lklMerCupNo, String lklMerInnerNo, String lklTkRegParams, String lklTkRegResp); /** - * 更新商家入驻申请的拉卡拉审核状态和响应数据 + * 根据拉卡拉内部商户号更新商家入驻申请的拉卡拉审核状态和响应数据 * - * @param lklMerCupNo 拉卡拉银联商户号 - * @param lklInnerMerNo 拉卡拉内部商户号 - * @param lklAuditStatus 拉卡拉审核状态 - * @param approvalStatus 审批状态 - * @param lklTkRegResp 进件返回的数据 + * @param lklInnerMerNo 拉卡拉内部商户号 + * @param lklMerCupNo 拉卡拉外部商户号 + * @param termNos 拉卡拉分配的业务终端号 + * @param lklAuditStatus 拉卡拉审核状态 + * @param approvalStatus 入驻材料审核状态 + * @param lklTkRegNotifyReq lklTkRegResp 异步请求参数 * @return */ - Boolean updateMerchEntryLklAuditStatusByLklMerCupNo(String lklMerCupNo, String lklInnerMerNo, Integer lklAuditStatus, Integer approvalStatus, String lklTkRegResp); + Boolean updateMerchEntryLklAuditStatusByLklMerCupNo(String lklMerCupNo, String lklInnerMerNo, String termNos, Integer lklAuditStatus, Integer approvalStatus, String lklTkRegNotifyReq); /** diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopMchEntryServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopMchEntryServiceImpl.java index 17a0a73f..548fda62 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopMchEntryServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopMchEntryServiceImpl.java @@ -800,14 +800,16 @@ public class ShopMchEntryServiceImpl extends BaseServiceImpl + + + + + * + +