优化入驻流程,增加补偿机制

This commit is contained in:
Jack 2025-09-25 03:23:34 +08:00
parent 5efd10b87a
commit 4343379f4c
6 changed files with 361 additions and 22 deletions

View File

@ -116,7 +116,9 @@ public class LakalaController extends BaseControllerImpl {
// return sfExpressApiService.createSfExpressShop(66, "能辉超市", "桂平市", "广西壮族自治区贵港市桂平市广佰汇超市(桂平店)", "谢能坤", "17777525395", "110.07165452271", "23.369069486251");
return lakalaApiService.sacsQuery("8226330541100GU", "20250918770188017227140800").toString();
// return lakalaApiService.sacsQuery("8226330541100GU", "20250918770188017227140800").toString();
return lakalaApiService.queryLedgerMer("8226330541100HA");
}
@ApiOperation(value = "批量发送推送消息 - 测试案例", notes = "批量发送推送消息 - 测试案例")

View File

@ -10,6 +10,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 org.springframework.data.util.Pair;
import javax.servlet.http.HttpServletRequest;
@ -268,6 +269,18 @@ public interface LakalaApiService {
*/
JSONObject sacsQuery(String merchantNo, String separateNo);
/**
* 商户分账业务信息查询
* 参考https://o.lakala.com/#/home/document/detail?id=381
*
* @param merCupNo 银联商户号
* @return 分账业务信息查询失败时返回null
* <p>
* 返回{"merInnerNo":"4002025092404043540","merCupNo":"8226330541100HA","splitLowestRatio":20.0,"orgId":"980688","orgName":"桂平发发","splitStatus":"VALID","splitStatusText":"启用","splitRange":"ALL","sepFundSource":"TR","bindRelations":[{"merInnerNo":"4002025092404043540","merCupNo":"8226330541100HA","receiverNo":"SR2024000129789","receiverName":"桂平发发网络有限公司"}],"platformId":null,"splitLaunchMode":"MANUAL","splitRuleSource":null,"eleContractNo":"QY20250924613672961"}
*/
JSONObject queryLedgerMer(String merCupNo);
/**
* 订单分账撤销
* 参考https://o.lakala.com/#/home/document/detail?id=390
@ -288,4 +301,13 @@ public interface LakalaApiService {
*/
Integer fixedUnSuccessSeparateStatusJob();
/**
* 检测修复补全商户的商户分账业务信息及分账接收方绑定关系分账业务申请异步通知的补偿机制
*
* @param shopMchEntry 商户入驻信息实例
* @return
*/
Boolean checkAndFixLedgerMerApplyAndBindRelations(ShopMchEntry shopMchEntry);
}

View File

@ -50,8 +50,9 @@ public interface LklLedgerMemberService extends IBaseService<LklLedgerMember> {
* @param auditStatus
* @param auditStatusText
* @param remark
* @param notifyResp
* @return
*/
Boolean updateAuditResult(String applyId, String merInnerNo, String merCupNo, String entrustFileName, String entrustFilePath, String auditStatus, String auditStatusText, String remark);
Boolean updateAuditResult(String applyId, String merInnerNo, String merCupNo, String entrustFileName, String entrustFilePath, String auditStatus, String auditStatusText, String remark, String notifyResp);
}

View File

@ -1266,7 +1266,7 @@ public class LakalaApiServiceImpl implements LakalaApiService {
try {
Boolean updateSuccess = lklLedgerMemberService.updateAuditResult(
applyId, merInnerNo, merCupNo, entrustFileName, entrustFilePath,
auditStatus, auditStatusText, remark
auditStatus, auditStatusText, remark, checkResult.getSecond()
);
if (!updateSuccess) {
@ -2070,6 +2070,80 @@ public class LakalaApiServiceImpl implements LakalaApiService {
}
}
/**
* 商户分账业务信息查询
* 参考https://o.lakala.com/#/home/document/detail?id=381
*
* @param merCupNo 银联商户号
* @return 分账业务信息查询失败时返回null
* <p>
* 返回{"merInnerNo":"4002025092404043540","merCupNo":"8226330541100HA","splitLowestRatio":20.0,"orgId":"980688","orgName":"桂平发发","splitStatus":"VALID","splitStatusText":"启用","splitRange":"ALL","sepFundSource":"TR","bindRelations":[{"merInnerNo":"4002025092404043540","merCupNo":"8226330541100HA","receiverNo":"SR2024000129789","receiverName":"桂平发发网络有限公司"}],"platformId":null,"splitLaunchMode":"MANUAL","splitRuleSource":null,"eleContractNo":"QY20250924613672961"}
*/
@Override
public JSONObject queryLedgerMer(String merCupNo) {
// 1. 参数校验
if (StrUtil.isBlank(merCupNo)) {
log.warn("[分账商户查询] 参数校验失败:银联商户号为空");
return null;
}
// 2. 初始化拉卡拉SDK配置
initLKLSDK();
try {
// 3. 构造请求参数
String orderNo = StringUtils.genLklOrderNo(8);
V2MmsOpenApiLedgerQueryLedgerMerRequest request = new V2MmsOpenApiLedgerQueryLedgerMerRequest();
request.setVersion("1.0");
request.setOrderNo(orderNo);
request.setOrgCode(orgCode);
request.setMerCupNo(merCupNo);
log.debug("[分账商户查询] 开始查询商户分账信息,商户号: {}", merCupNo);
// 4. 发送HTTP请求到拉卡拉服务器
String responseStr = LKLSDK.httpPost(request);
// 5. 检查响应结果
if (StrUtil.isBlank(responseStr)) {
log.warn("[分账商户查询] 服务器无返回值,商户号: {}", merCupNo);
return null;
}
// 6. 解析响应JSON
JSONObject lakalaRespJSON = JSONUtil.parseObj(responseStr);
if (lakalaRespJSON == null) {
log.warn("[分账商户查询] 响应数据解析失败,商户号: {},响应内容: {}", merCupNo, responseStr);
return null;
}
// 7. 检查业务状态码
String code = lakalaRespJSON.getStr("retCode");
if (!"000000".equals(code)) {
log.warn("[分账商户查询] 业务处理失败,商户号: {},错误码: {},错误信息: {}",
merCupNo, code, lakalaRespJSON.getStr("retMsg"));
return null;
}
// 8. 检查响应数据
JSONObject respData = lakalaRespJSON.getJSONObject("respData");
if (respData == null) {
log.warn("[分账商户查询] 响应数据为空,商户号: {},完整响应: {}", merCupNo, responseStr);
return null;
}
log.info("[分账商户查询] 查询成功,商户号: {}", merCupNo);
return respData;
} catch (SDKException e) {
log.error("[分账商户查询] SDK调用异常商户号: {}", merCupNo, e);
return null;
} catch (Exception e) {
log.error("[分账商户查询] 查询过程中发生未知异常,商户号: {}", merCupNo, e);
return null;
}
}
/**
* 执行拉卡拉订单分账操作
@ -2950,4 +3024,229 @@ public class LakalaApiServiceImpl implements LakalaApiService {
return totalSuccessCount;
}
/**
* 检测修复补全商户的商户分账业务信息及分账接收方绑定关系分账业务申请异步通知的补偿机制
*
* @param shopMchEntry 商户入驻信息实例
* @return 是否处理成功
*/
@Override
public Boolean checkAndFixLedgerMerApplyAndBindRelations(ShopMchEntry shopMchEntry) {
// 1. 输入参数校验
if (shopMchEntry == null) {
log.warn("[分账业务补偿机制] 商户入驻信息为空");
return false;
}
String merCupNo = shopMchEntry.getLkl_mer_cup_no();
if (CheckUtil.isEmpty(merCupNo)) {
log.warn("[分账业务补偿机制] 商户未进件成功停止执行mchId: {}", shopMchEntry.getId());
return false;
}
// 2. 查询商户分账业务信息
JSONObject ledgerMerInfo;
try {
ledgerMerInfo = queryLedgerMer(merCupNo);
} catch (Exception e) {
log.error("[分账业务补偿机制] 查询商户分账业务信息异常merCupNo: {}", merCupNo, e);
return false;
}
// 检查返回结果是否为空
if (ObjectUtil.isEmpty(ledgerMerInfo)) {
log.warn("[分账业务补偿机制] 查询商户分账业务信息返回空merCupNo: {}", merCupNo);
return false;
}
String splitStatus = ledgerMerInfo.getStr("splitStatus");
if (StrUtil.isBlank(splitStatus)) {
splitStatus = "";
}
if (!"VALID".equals(splitStatus)) {
log.warn("[分账业务补偿机制] 商户分账业务未通过或未申请停止执行merCupNo: {}, splitStatus: {}", merCupNo, splitStatus);
return false;
}
log.info("[分账业务补偿机制] 开始处理商户分账信息修复merCupNo: {}", merCupNo);
// 3. 处理分账业务申请记录
Long mchId = shopMchEntry.getId();
String merInnerNo = ledgerMerInfo.getStr("merInnerNo");
String orderNo = StringUtils.genLklOrderNo(8);
boolean memberUpdated = false;
LklLedgerMember ledgerMember = lklLedgerMemberService.getByMerCupNo(merCupNo);
try {
if (ObjectUtil.isEmpty(ledgerMember)) {
// 情况1: 分账业务申请记录不存在创建新记录
log.debug("[分账业务补偿机制] 分账业务申请记录不存在创建新记录merCupNo: {}", merCupNo);
ledgerMember = new LklLedgerMember();
ledgerMember.setOrg_code(ledgerMerInfo.getStr("orgId", orgCode));
ledgerMember.setOrder_no(orderNo);
ledgerMember.setMer_cup_no(merCupNo);
ledgerMember.setMer_inner_no(StrUtil.blankToDefault(merInnerNo, ""));
ledgerMember.setContact_mobile(shopMchEntry.getLogin_mobile());
ledgerMember.setSplit_lowest_ratio(ledgerMerInfo.getStr("splitLowestRatio", splitLowestRatio));
ledgerMember.setSplit_entrust_file_name("商家分账授权委托书.pdf");
ledgerMember.setSplit_entrust_file_path(StrUtil.blankToDefault(shopMchEntry.getLkl_ec_file_path(), ""));
ledgerMember.setSplit_range(ledgerMerInfo.getStr("splitRange", "ALL"));
ledgerMember.setEle_contract_no(ledgerMerInfo.getStr("eleContractNo", StrUtil.blankToDefault(shopMchEntry.getLkl_ec_no(), "")));
ledgerMember.setSep_fund_source(ledgerMerInfo.getStr("sepFundSource", "TR"));
ledgerMember.setSplit_launch_mode(ledgerMerInfo.getStr("splitLaunchMode", "MANUAL"));
ledgerMember.setSettle_type("01");
ledgerMember.setSplit_rule_source("");
ledgerMember.setRet_url(projectDomain + "/api/mobile/shop/lakala/ledger/applyLedgerMerNotify");
ledgerMember.setApply_id(orderNo);
ledgerMember.setAudit_status(CommonConstant.Enable);
ledgerMember.setAudit_status_text("审核通过");
ledgerMember.setAudit_resp(ledgerMerInfo.toString());
ledgerMember.setRemark("审核通过(补偿机制)");
ledgerMember.setMch_id(mchId);
ledgerMember.setVersion("1.0");
memberUpdated = lklLedgerMemberService.addOrUpdateByMerCupNo(ledgerMember);
if (memberUpdated) {
log.info("[分账业务补偿机制] 成功创建分账业务申请记录merCupNo: {}", merCupNo);
} else {
log.error("[分账业务补偿机制] 创建分账业务申请记录失败merCupNo: {}", merCupNo);
return false;
}
} else if (!CommonConstant.Enable.equals(ledgerMember.getAudit_status())) {
// 情况2: 分账业务申请记录存在但未审核通过更新状态
log.debug("[分账业务补偿机制] 分账业务申请记录存在但未审核通过更新状态merCupNo: {}", merCupNo);
ledgerMember.setAudit_status(CommonConstant.Enable);
ledgerMember.setAudit_status_text("审核通过");
ledgerMember.setAudit_resp(ledgerMerInfo.toString());
ledgerMember.setRemark("审核通过(补偿机制)");
ledgerMember.setMch_id(mchId); // 确保mch_id设置正确
memberUpdated = lklLedgerMemberService.addOrUpdateByMerCupNo(ledgerMember);
if (memberUpdated) {
log.info("[分账业务补偿机制] 成功更新分账业务申请记录状态merCupNo: {}", merCupNo);
} else {
log.error("[分账业务补偿机制] 更新分账业务申请记录状态失败merCupNo: {}", merCupNo);
return false;
}
} else {
// 情况3: 分账业务申请记录已审核通过
log.debug("[分账业务补偿机制] 分账业务申请记录已审核通过merCupNo: {}", merCupNo);
memberUpdated = true;
}
} catch (Exception e) {
log.error("[分账业务补偿机制] 处理分账业务申请记录异常merCupNo: {}", merCupNo, e);
return false;
}
// 4. 更新商户分账申请状态
if (memberUpdated && !CommonConstant.Enable.equals(shopMchEntry.getHas_apply_split())) {
boolean updateResult = shopMchEntryService.updateMulStatus(mchId, merCupNo, 0, 0, 0, 1, 0, 0, CommonConstant.MCH_APPR_STA_LKL_PADDING);
if (updateResult) {
shopMchEntry.setHas_apply_split(CommonConstant.Enable);
log.info("[分账业务补偿机制] 成功更新商户分账申请状态mchId: {}", mchId);
} else {
log.warn("[分账业务补偿机制] 更新商户分账申请状态失败mchId: {}", mchId);
// 不返回false因为这不影响主要流程
}
}
// 5. 处理分账接收方绑定关系
int bindSuccessCount = 0;
JSONArray ledgerReceivers = ledgerMerInfo.getJSONArray("bindRelations");
if (CollUtil.isNotEmpty(ledgerReceivers)) {
log.debug("[分账业务补偿机制] 开始处理分账接收方绑定关系,绑定数量: {}", ledgerReceivers.size());
for (Object obj : ledgerReceivers) {
if (!(obj instanceof JSONObject)) {
continue;
}
JSONObject ledgerReceiver = (JSONObject) obj;
if (ledgerReceiver == null) {
continue;
}
String receiverMerCupNo = ledgerReceiver.getStr("merCupNo");
String receiverNo = ledgerReceiver.getStr("receiverNo");
if (StrUtil.hasBlank(receiverMerCupNo, receiverNo)) {
log.warn("[分账业务补偿机制] 接收方信息不完整跳过处理receiverMerCupNo: {}, receiverNo: {}", receiverMerCupNo, receiverNo);
continue;
}
LklLedgerMerReceiverBind ledgerMerReceiverBind = lklLedgerMerReceiverBindService.getByCondition(receiverMerCupNo, receiverNo);
boolean bindUpdated = false;
try {
if (ObjectUtil.isEmpty(ledgerMerReceiverBind)) {
// 情况1: 绑定关系不存在创建新记录
log.debug("[分账业务补偿机制] 绑定关系不存在创建新记录merCupNo: {}, receiverNo: {}", receiverMerCupNo, receiverNo);
ledgerMerReceiverBind = new LklLedgerMerReceiverBind();
ledgerMerReceiverBind.setOrder_no(orderNo);
ledgerMerReceiverBind.setOrg_code(ledgerMerInfo.getStr("orgId", orgCode));
ledgerMerReceiverBind.setMer_inner_no(ledgerReceiver.getStr("merInnerNo", ""));
ledgerMerReceiverBind.setMer_cup_no(receiverMerCupNo);
ledgerMerReceiverBind.setEntrust_file_name("小发同城合作协议书.pdf");
ledgerMerReceiverBind.setEntrust_file_path(StrUtil.blankToDefault(shopMchEntry.getLkl_ec_file_path(), ""));
ledgerMerReceiverBind.setRet_url(projectDomain + "/api/mobile/shop/lakala/ledger/applyLedgerMerReceiverBindNotify");
ledgerMerReceiverBind.setApply_id(orderNo);
ledgerMerReceiverBind.setPlatform_id(0L);
ledgerMerReceiverBind.setMch_id(mchId);
ledgerMerReceiverBind.setAudit_status("1");
ledgerMerReceiverBind.setAudit_status_text("审核通过");
ledgerMerReceiverBind.setRemark("审核通过(补偿机制)");
ledgerMerReceiverBind.setVersion("1.0");
bindUpdated = lklLedgerMerReceiverBindService.addOrUpdateByMerCupNoReceiverNo(ledgerMerReceiverBind);
} else if (!"1".equals(ledgerMerReceiverBind.getAudit_status())) {
// 情况2: 绑定关系存在但未审核通过更新状态
log.debug("[分账业务补偿机制] 绑定关系存在但未审核通过更新状态merCupNo: {}, receiverNo: {}", receiverMerCupNo, receiverNo);
ledgerMerReceiverBind.setMch_id(mchId);
ledgerMerReceiverBind.setAudit_status("1");
ledgerMerReceiverBind.setAudit_status_text("审核通过");
ledgerMerReceiverBind.setRemark("审核通过(补偿机制)");
bindUpdated = lklLedgerMerReceiverBindService.addOrUpdateByMerCupNoReceiverNo(ledgerMerReceiverBind);
} else {
// 情况3: 绑定关系已审核通过
log.debug("[分账业务补偿机制] 绑定关系已审核通过merCupNo: {}, receiverNo: {}", receiverMerCupNo, receiverNo);
bindUpdated = true;
}
if (bindUpdated) {
bindSuccessCount++;
}
} catch (Exception e) {
log.error("[分账业务补偿机制] 处理分账接收方绑定关系异常merCupNo: {}, receiverNo: {}", receiverMerCupNo, receiverNo, e);
// 继续处理其他绑定关系
}
}
}
// 6. 更新商户分账接收方绑定状态
if (bindSuccessCount > 0 && !CommonConstant.Enable.equals(shopMchEntry.getHas_bind_receiver())) {
boolean updateResult = shopMchEntryService.updateMulStatus(mchId, merCupNo, 0, 0, 0, 0, 0, 1, CommonConstant.MCH_APPR_STA_LKL_PADDING);
if (updateResult) {
shopMchEntry.setHas_bind_receiver(CommonConstant.Enable);
log.info("[分账业务补偿机制] 成功更新商户分账接收方绑定状态mchId: {}, 成功处理数量: {}", mchId, bindSuccessCount);
} else {
log.warn("[分账业务补偿机制] 更新商户分账接收方绑定状态失败mchId: {}", mchId);
// 不返回false因为这不影响主要流程
}
}
log.info("[分账业务补偿机制] 处理完成merCupNo: {}, memberUpdated: {}, bindSuccessCount: {}", merCupNo, memberUpdated, bindSuccessCount);
return true;
}
}

View File

@ -101,10 +101,11 @@ public class LklLedgerMemberServiceImpl extends BaseServiceImpl<LklLedgerMemberM
* @param auditStatus
* @param auditStatusText
* @param remark
* @param notifyResp
* @return
*/
@Override
public Boolean updateAuditResult(String applyId, String merInnerNo, String merCupNo, String entrustFileName, String entrustFilePath, String auditStatus, String auditStatusText, String remark) {
public Boolean updateAuditResult(String applyId, String merInnerNo, String merCupNo, String entrustFileName, String entrustFilePath, String auditStatus, String auditStatusText, String remark, String notifyResp) {
if (StrUtil.isBlank(applyId) || StrUtil.isBlank(merCupNo) || StrUtil.isBlank(auditStatus)) {
log.error("缺少参数applyId={}, merCupNo={}, auditStatus={}", applyId, merCupNo, auditStatus);
return false;
@ -119,6 +120,7 @@ public class LklLedgerMemberServiceImpl extends BaseServiceImpl<LklLedgerMemberM
updateWrapper.set("audit_status", auditStatus);
updateWrapper.set("audit_status_text", auditStatusText);
updateWrapper.set("remark", remark);
updateWrapper.set("audit_resp", notifyResp);
return update(updateWrapper);
}

View File

@ -793,6 +793,20 @@ public class ShopMchEntryServiceImpl extends BaseServiceImpl<ShopMchEntryMapper,
}
try {
// 6. 获取当前商户用户信息
UserDto currentUser = getCurrentUser();
if (currentUser == null || CheckUtil.isEmpty(currentUser.getId())) {
log.warn("当前用户未登录入驻ID: {}", mchId);
return false;
}
// 7. 获取用户基础信息
AccountUserBase userBase = accountService.getUserBase(currentUser.getId());
if (userBase == null) {
log.warn("商户用户基础信息不存在用户ID: {}", currentUser.getId());
return false;
}
// 2. 查询商户入驻记录
ShopMchEntry shopMchEntry = get(mchId);
if (shopMchEntry == null) {
@ -800,7 +814,10 @@ public class ShopMchEntryServiceImpl extends BaseServiceImpl<ShopMchEntryMapper,
return false;
}
// 3. 检查入驻状态
// 3. 检测修复补全商户的商户分账业务信息及分账接收方绑定关系分账业务申请异步通知的补偿机制
lakalaApiService.checkAndFixLedgerMerApplyAndBindRelations(shopMchEntry);
// 5. 检查入驻状态
boolean isValidStatus = CommonConstant.Enable.equals(shopMchEntry.getHas_ec_signed())
&& CommonConstant.Enable.equals(shopMchEntry.getHas_apply_mer())
&& CommonConstant.Enable.equals(shopMchEntry.getHas_apply_split())
@ -812,27 +829,14 @@ public class ShopMchEntryServiceImpl extends BaseServiceImpl<ShopMchEntryMapper,
return false;
}
// 4. 获取当前商户用户信息
UserDto currentUser = getCurrentUser();
if (currentUser == null || CheckUtil.isEmpty(currentUser.getId())) {
log.warn("当前用户未登录入驻ID: {}", mchId);
return false;
}
// 5. 获取用户基础信息
AccountUserBase userBase = accountService.getUserBase(currentUser.getId());
if (userBase == null) {
log.warn("商户用户基础信息不存在用户ID: {}", currentUser.getId());
return false;
}
// 6. 检查店铺关联关系
// 8. 检查店铺关联关系
boolean hasStoreRelation = false;
if (StrUtil.isNotBlank(shopMchEntry.getStore_id()) && StrUtil.isNotBlank(userBase.getStore_ids())) {
hasStoreRelation = userBase.getStore_ids().contains(shopMchEntry.getStore_id());
}
// 7. 获取店铺员工信息
// 9. 获取店铺员工信息
ShopStoreEmployee storeEmployee = null;
if (StrUtil.isNotBlank(shopMchEntry.getStore_id())) {
Integer storeId = Convert.toInt(shopMchEntry.getStore_id());
@ -844,15 +848,20 @@ public class ShopMchEntryServiceImpl extends BaseServiceImpl<ShopMchEntryMapper,
}
}
// 8. 检查权限组信息
// 10. 检查权限组信息
boolean hasRoles = storeEmployee != null && StrUtil.isNotBlank(storeEmployee.getRights_group_id());
// 10. 当满足创建店铺条件且存在信息缺失时需要进行修复
// 11. 当满足创建店铺条件且存在信息缺失时需要进行修复
if (storeEmployee == null || !hasRoles || !hasStoreRelation) {
log.info("开始修复商户信息入驻ID: {}, storeEmployee为空: {}, 缺少角色: {}, 缺少店铺关联: {}",
mchId, storeEmployee == null, !hasRoles, !hasStoreRelation);
// 补偿创建初始化店铺部分赋值
Pair<Integer, String> result = shopStoreBaseService.covMerchEntryInfo2StoreInfo(mchId, false);
if (result != null && result.getFirst() > 0) {
log.info("商户信息修复成功入驻ID: {}", mchId);
// 修复成功后检查商户绑定状态是否完成更改总的审核状态
checkMerchEntryFinished(mchId);
return true;
} else {
log.error("商户信息修复失败入驻ID: {}, 错误信息:{}", mchId, result != null ? result.getSecond() : "未知错误");
@ -860,6 +869,10 @@ public class ShopMchEntryServiceImpl extends BaseServiceImpl<ShopMchEntryMapper,
}
}
// 12. 如果信息完整检查商户绑定状态是否完成更改总的审核状态
log.debug("商户信息完整检查是否需要更新审核状态入驻ID: {}", mchId);
checkMerchEntryFinished(mchId);
return true;
} catch (Exception e) {
log.error("商户信息修复异常mchId: {}", mchId, e);