增加 确认收货 异步通知接收地址,优化 拉卡拉预支付 日志
This commit is contained in:
parent
d55dd93b05
commit
846cc94c0d
@ -60,22 +60,32 @@ public class ShopOrderLkl implements Serializable {
|
||||
|
||||
private String lkl_log_date;
|
||||
|
||||
private String lkl_split_log_no;
|
||||
private String lkl_sub_log_no;
|
||||
|
||||
private String lkl_trade_no;
|
||||
|
||||
private String lkl_receive_trade_no;
|
||||
|
||||
private String lkl_receive_log_no;
|
||||
|
||||
private String lkl_merchant_no;
|
||||
|
||||
private String lkl_term_no;
|
||||
|
||||
private String notify_url;
|
||||
|
||||
private String receive_notify_url;
|
||||
|
||||
private String lkl_req;
|
||||
|
||||
private String lkl_resp;
|
||||
|
||||
private String lkl_notify_resp;
|
||||
|
||||
private String lkl_receive_notify_resp;
|
||||
|
||||
private Integer receive_status;
|
||||
|
||||
private Integer status;
|
||||
|
||||
private Date created_at;
|
||||
|
||||
@ -182,7 +182,7 @@ public class UniCloudPushServiceImpl implements UniCloudPushService {
|
||||
|
||||
try {
|
||||
JSONObject json = JSONUtil.parseObj(body);
|
||||
log.info("[推送服务] 原始响应: {}", json.toStringPretty());
|
||||
// log.debug("[推送服务] 原始响应: {}", json.toStringPretty());
|
||||
|
||||
// 解析标准响应字段
|
||||
Integer errCode = json.getInt("errCode", -1);
|
||||
|
||||
@ -86,6 +86,7 @@ secure:
|
||||
- "/shop/sf-express/cancel-order/notify"
|
||||
- "/shop/sf-express/rider-order-status/notify"
|
||||
- "/shop/sf-express/order-complete/notify"
|
||||
- "/mobile/shop/lakala/trans/receive/completeNotify"
|
||||
- "/shop/sync/third/**"
|
||||
- "/esProduct/**"
|
||||
- "/admin/oss/upload/**"
|
||||
|
||||
@ -24,44 +24,10 @@ import java.io.IOException;
|
||||
@RestController
|
||||
@RequestMapping("/mobile/pay/lakala")
|
||||
public class LakalaController extends BaseControllerImpl {
|
||||
//
|
||||
// @Resource
|
||||
// private LakalaPayService lakalaPayService;
|
||||
|
||||
@ApiOperation(value = "本地文件转base64", notes = "本地文件转base64")
|
||||
@RequestMapping(value = "/file2base64", method = RequestMethod.POST)
|
||||
public String file2Base64(@RequestParam("file") MultipartFile file) throws IOException {
|
||||
String str = Base64Utils.encodeToString(file.getBytes());
|
||||
return str;
|
||||
}
|
||||
|
||||
// @ApiOperation(value = "商户分账业务开通申请", notes = "商户分账业务开通申请")
|
||||
// @RequestMapping(value = "/ledger/applyLedgerMer", method = RequestMethod.POST)
|
||||
// public CommonResult ledgerApplyLedgerMer(@RequestBody JSONObject paramsJSON) {
|
||||
// return lakalaPayService.applyLedgerMer(paramsJSON);
|
||||
// }
|
||||
//
|
||||
// @ApiOperation(value = "商户分账业务开通申请异步回调回调", notes = "商户分账业务开通申请异步回调回调")
|
||||
// @RequestMapping(value = "/ledger/applyLedgerMerNotify", method = RequestMethod.POST)
|
||||
// public JSONObject ledgerApplyLedgerMerNotify(HttpServletRequest request) {
|
||||
// return lakalaPayService.applyLedgerMerNotify(request);
|
||||
// }
|
||||
//
|
||||
// @ApiOperation(value = "分账接收方创建申请", notes = "分账接收方创建申请")
|
||||
// @RequestMapping(value = "/ledger/applyLedgerReceiver", method = RequestMethod.POST)
|
||||
// public CommonResult applyLedgerReceiver(@RequestBody JSONObject paramsJSON) {
|
||||
// return lakalaPayService.applyLedgerReceiver(paramsJSON);
|
||||
// }
|
||||
//
|
||||
// @ApiOperation(value = "分账关系绑定申请", notes = "分账关系绑定申请")
|
||||
// @RequestMapping(value = "/ledger/applyBind", method = RequestMethod.POST)
|
||||
// public CommonResult applyBind(@RequestBody JSONObject paramsJSON) {
|
||||
// return lakalaPayService.applyLedgerMerReceiverBind(paramsJSON);
|
||||
// }
|
||||
//
|
||||
// @ApiOperation(value = "分账关系绑定申请异步回调通知", notes = "分账关系绑定申请异步回调通知")
|
||||
// @RequestMapping(value = "/ledger/applyBindNotify", method = RequestMethod.POST)
|
||||
// public JSONObject applyBindNotify(HttpServletRequest request) {
|
||||
// return lakalaPayService.applyLedgerMerReceiverBindNotify(request);
|
||||
// }
|
||||
}
|
||||
|
||||
@ -111,7 +111,7 @@ public class LakalaPayServiceImpl implements LakalaPayService {
|
||||
|
||||
|
||||
/**
|
||||
* 拉卡拉预下单
|
||||
* 拉卡拉预下单(废弃)
|
||||
* 参考:https://o.lakala.com/#/home/document/detail?id=110
|
||||
*
|
||||
* @param merchantNo 商户号
|
||||
@ -127,34 +127,38 @@ public class LakalaPayServiceImpl implements LakalaPayService {
|
||||
* @param remark 备注
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public JSONObject lklTransPreOrder(String merchantNo, String termNo, String xcxAppId, String openId, String storeId, String orderId, String subject, String totalAmount, String notifyURL, String requestIP, String remark) {
|
||||
// @Override
|
||||
public JSONObject lklTransPreOrderBak(String merchantNo, String termNo, String xcxAppId, String openId, String storeId, String orderId, String subject, String totalAmount, String notifyURL, String requestIP, String remark) {
|
||||
// 1. 配置初始化
|
||||
initLKLSDK();
|
||||
|
||||
if (StrUtil.isBlank(merchantNo) || StrUtil.isBlank(termNo)) {
|
||||
log.warn("[拉卡拉预下单] 参数校验失败:缺少商户号或终端号, merchantNo={}, termNo={}", merchantNo, termNo);
|
||||
throw new ApiException(I18nUtil._("缺少商户号或终端号!"));
|
||||
}
|
||||
|
||||
log.info("[拉卡拉预下单] 开始处理请求, merchantNo={}, termNo={}, orderId={}", merchantNo, termNo, orderId);
|
||||
|
||||
//2. 装配数据
|
||||
/*** 微信主扫场景示例 */
|
||||
V3LabsTransPreorderRequest v3LabsTransPreorderWechatReq = new V3LabsTransPreorderRequest();
|
||||
v3LabsTransPreorderWechatReq.setMerchantNo(merchantNo);
|
||||
v3LabsTransPreorderWechatReq.setTermNo(termNo);
|
||||
v3LabsTransPreorderWechatReq.setOutTradeNo(orderId);
|
||||
v3LabsTransPreorderWechatReq.setSubject(subject);
|
||||
V3LabsTransPreorderRequest v3LabsTransPreorderRequest = new V3LabsTransPreorderRequest();
|
||||
v3LabsTransPreorderRequest.setMerchantNo(merchantNo);
|
||||
v3LabsTransPreorderRequest.setTermNo(termNo);
|
||||
v3LabsTransPreorderRequest.setOutTradeNo(orderId);
|
||||
v3LabsTransPreorderRequest.setSubject(subject);
|
||||
//微信:WECHAT 支付宝:ALIPAY 银联:UQRCODEPAY 翼支付: BESTPAY 苏宁易付宝: SUNING 拉卡拉支付账户:LKLACC 网联小钱包:NUCSPAY 京东钱包:JD
|
||||
v3LabsTransPreorderWechatReq.setAccountType("WECHAT");
|
||||
v3LabsTransPreorderRequest.setAccountType("WECHAT");
|
||||
// 41:NATIVE((ALIPAY,云闪付支持,京东白条分期)51:JSAPI(微信公众号支付,支付宝服务窗支付,银联JS支付,翼支付JS支付、拉卡拉钱包支付)71:微信小程序支付 61:APP支付(微信APP支付)
|
||||
v3LabsTransPreorderWechatReq.setTransType("51");
|
||||
v3LabsTransPreorderWechatReq.setTotalAmount(totalAmount); // 应支付金额,单位:分
|
||||
v3LabsTransPreorderWechatReq.setSettleType("1"); //“0”或者空,常规结算方式,如需接拉卡拉分账通需传“1”,商户未开通分账之前切记不用上送此参数。;
|
||||
v3LabsTransPreorderWechatReq.setNotifyUrl(notifyURL);
|
||||
v3LabsTransPreorderWechatReq.setRemark(remark);
|
||||
v3LabsTransPreorderRequest.setTransType("51");
|
||||
v3LabsTransPreorderRequest.setTotalAmount(totalAmount); // 应支付金额,单位:分
|
||||
v3LabsTransPreorderRequest.setSettleType("1"); //“0”或者空,常规结算方式,如需接拉卡拉分账通需传“1”,商户未开通分账之前切记不用上送此参数。;
|
||||
v3LabsTransPreorderRequest.setNotifyUrl(notifyURL);
|
||||
v3LabsTransPreorderRequest.setRemark(remark);
|
||||
// v3LabsTransPreorderRequest.setCompleteNotifyUrl("https://mall.gpxscs.cn/api/mobile/shop/lakala/trans/receive/completeNotify");
|
||||
|
||||
//地址位置信息
|
||||
V3LabsTradeLocationInfo v3LabsTradePreorderLocationInfo = new V3LabsTradeLocationInfo(requestIP);
|
||||
v3LabsTransPreorderWechatReq.setLocationInfo(v3LabsTradePreorderLocationInfo);
|
||||
v3LabsTransPreorderRequest.setLocationInfo(v3LabsTradePreorderLocationInfo);
|
||||
|
||||
//微信主扫场景下 acc_busi_fields 域内容
|
||||
V3LabsTradePreorderWechatBus wechatBus = new V3LabsTradePreorderWechatBus();
|
||||
@ -162,35 +166,217 @@ public class LakalaPayServiceImpl implements LakalaPayService {
|
||||
wechatBus.setUserId(openId); // 微信 openId
|
||||
wechatBus.setDeviceInfo("WEB"); // 终端设备号(门店号或收银设备ID),注意:PC网页或JSAPI支付请传”WEB”
|
||||
// wechatBus.setAttach(storeId); // 附加数据,商户自定义数据,在查询交易结果时原样返回。
|
||||
v3LabsTransPreorderWechatReq.setAccBusiFields(wechatBus);
|
||||
v3LabsTransPreorderRequest.setAccBusiFields(wechatBus);
|
||||
|
||||
JSONObject reqParams = JSONUtil.parseObj(v3LabsTransPreorderRequest);
|
||||
reqParams.set("complete_notify_url", "https://mall.gpxscs.cn/api/mobile/shop/lakala/trans/receive/completeNotify");
|
||||
|
||||
try {
|
||||
log.info("拉卡拉预下单请求参数:{}", JSONUtil.toJsonStr(v3LabsTransPreorderWechatReq));
|
||||
log.info("[拉卡拉预下单] 请求参数: {}", JSONUtil.toJsonStr(reqParams));
|
||||
|
||||
//3. 发送请求
|
||||
String responseStr = LKLSDK.httpPost(v3LabsTransPreorderWechatReq);
|
||||
log.info("拉卡拉预下单响应数据:{}", responseStr);
|
||||
String reqUrl = serverUrl + "/api/v3/labs/trans/preorder";
|
||||
log.debug("[拉卡拉预下单] 请求URL: {}", reqUrl);
|
||||
String responseStr = LKLSDK.httpPost(reqUrl, reqParams.toString(), appId);
|
||||
log.info("[拉卡拉预下单] 响应数据: {}", responseStr);
|
||||
if (StrUtil.isBlank(responseStr)) {
|
||||
log.warn("[拉卡拉预下单] 响应为空, orderId={}", orderId);
|
||||
return null;
|
||||
}
|
||||
|
||||
JSONObject lakalaRespJSON = JSONUtil.parseObj(responseStr);
|
||||
|
||||
if (lakalaRespJSON != null && lakalaRespJSON.getStr("code").equals("BBS00000")) {
|
||||
log.debug("[拉卡拉预下单] 支付成功,保存订单记录, orderId={}", orderId);
|
||||
// 新增一个拉卡拉订单记录 shop_order_lkl 表
|
||||
JSONObject lklPayReqAndRespJson = new JSONObject();
|
||||
lklPayReqAndRespJson.put("req", JSONUtil.parseObj(v3LabsTransPreorderWechatReq));
|
||||
lklPayReqAndRespJson.put("req", JSONUtil.parseObj(v3LabsTransPreorderRequest));
|
||||
lklPayReqAndRespJson.put("resp", lakalaRespJSON);
|
||||
shopService.lklPayAddShopOrderLkl(lklPayReqAndRespJson);
|
||||
}
|
||||
//4. 响应
|
||||
log.info("[拉卡拉预下单] 处理完成, orderId={}, responseCode={}", orderId, lakalaRespJSON != null ? lakalaRespJSON.getStr("code") : "NULL");
|
||||
return lakalaRespJSON;
|
||||
} catch (SDKException e) {
|
||||
log.error("拉卡拉支付出错:", e);
|
||||
log.error("[拉卡拉预下单] SDK异常, orderId=" + orderId, e);
|
||||
throw new ApiException(I18nUtil._("支付失败!"), e);
|
||||
} catch (Exception e) {
|
||||
log.error("[拉卡拉预下单] 系统异常, orderId=" + orderId, e);
|
||||
throw new ApiException(I18nUtil._("系统异常!"), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 拉卡拉预下单
|
||||
* 参考:https://o.lakala.com/#/home/document/detail?id=110
|
||||
*
|
||||
* @param merchantNo 商户号
|
||||
* @param termNo 终端号
|
||||
* @param xcxAppId 小程序appid
|
||||
* @param openId openid
|
||||
* @param storeId 店铺号
|
||||
* @param orderId 订单号
|
||||
* @param subject 订单标题
|
||||
* @param totalAmount 订单金额(单位:分)
|
||||
* @param notifyURL 回调地址
|
||||
* @param requestIP 请求IP
|
||||
* @param remark 备注
|
||||
* @return 拉卡拉预下单响应结果
|
||||
*/
|
||||
@Override
|
||||
public JSONObject lklTransPreOrder(String merchantNo, String termNo, String xcxAppId, String openId, String storeId, String orderId, String subject, String totalAmount, String notifyURL, String requestIP, String remark) {
|
||||
// 1. 参数校验
|
||||
if (StrUtil.isBlank(merchantNo)) {
|
||||
log.warn("[拉卡拉预下单] 参数校验失败:商户号不能为空, orderId={}", orderId);
|
||||
throw new ApiException(I18nUtil._("商户号不能为空!"));
|
||||
}
|
||||
|
||||
if (StrUtil.isBlank(termNo)) {
|
||||
log.warn("[拉卡拉预下单] 参数校验失败:终端号不能为空, orderId={}", orderId);
|
||||
throw new ApiException(I18nUtil._("终端号不能为空!"));
|
||||
}
|
||||
|
||||
if (StrUtil.isBlank(orderId)) {
|
||||
log.warn("[拉卡拉预下单] 参数校验失败:订单号不能为空, merchantNo={}", merchantNo);
|
||||
throw new ApiException(I18nUtil._("订单号不能为空!"));
|
||||
}
|
||||
|
||||
if (StrUtil.isBlank(subject)) {
|
||||
log.warn("[拉卡拉预下单] 参数校验失败:订单标题不能为空, orderId={}", orderId);
|
||||
throw new ApiException(I18nUtil._("订单标题不能为空!"));
|
||||
}
|
||||
|
||||
if (StrUtil.isBlank(totalAmount)) {
|
||||
log.warn("[拉卡拉预下单] 参数校验失败:订单金额不能为空, orderId={}", orderId);
|
||||
throw new ApiException(I18nUtil._("订单金额不能为空!"));
|
||||
}
|
||||
|
||||
if (StrUtil.isBlank(notifyURL)) {
|
||||
log.warn("[拉卡拉预下单] 参数校验失败:回调地址不能为空, orderId={}", orderId);
|
||||
throw new ApiException(I18nUtil._("回调地址不能为空!"));
|
||||
}
|
||||
|
||||
if (StrUtil.isBlank(requestIP)) {
|
||||
log.warn("[拉卡拉预下单] 参数校验失败:请求IP不能为空, orderId={}", orderId);
|
||||
throw new ApiException(I18nUtil._("请求IP不能为空!"));
|
||||
}
|
||||
|
||||
log.info("[拉卡拉预下单] 开始处理请求, merchantNo={}, termNo={}, orderId={}", merchantNo, termNo, orderId);
|
||||
|
||||
try {
|
||||
// 2. 装配请求数据
|
||||
JSONObject reqData = new JSONObject();
|
||||
reqData.put("merchant_no", merchantNo);
|
||||
reqData.put("term_no", termNo);
|
||||
reqData.put("out_trade_no", orderId);
|
||||
reqData.put("subject", subject);
|
||||
// 微信:WECHAT 支付宝:ALIPAY 银联:UQRCODEPAY 翼支付: BESTPAY 苏宁易付宝: SUNING 拉卡拉支付账户:LKLACC 网联小钱包:NUCSPAY 京东钱包:JD
|
||||
reqData.put("account_type", "WECHAT");
|
||||
// 41:NATIVE((ALIPAY,云闪付支持,京东白条分期)51:JSAPI(微信公众号支付,支付宝服务窗支付,银联JS支付,翼支付JS支付、拉卡拉钱包支付)71:微信小程序支付 61:APP支付(微信APP支付)
|
||||
reqData.put("trans_type", "51");
|
||||
reqData.put("total_amount", totalAmount); // 应支付金额,单位:分
|
||||
reqData.put("settle_type", "1"); // "0"或者空,常规结算方式,如需接拉卡拉分账通需传"1",商户未开通分账之前切记不用上送此参数。
|
||||
reqData.put("notify_url", notifyURL);
|
||||
reqData.put("remark", remark);
|
||||
reqData.put("complete_notify_url", "https://mall.gpxscs.cn/api/mobile/shop/lakala/trans/receive/completeNotify");
|
||||
|
||||
// 地址位置信息
|
||||
JSONObject locationInfo = new JSONObject();
|
||||
locationInfo.put("request_ip", requestIP);
|
||||
reqData.put("location_info", locationInfo);
|
||||
|
||||
// 微信业务参数
|
||||
if (StrUtil.isNotBlank(xcxAppId) && StrUtil.isNotBlank(openId)) {
|
||||
JSONObject accBusiFields = new JSONObject();
|
||||
accBusiFields.put("sub_appid", xcxAppId); // 小程序appId
|
||||
accBusiFields.put("user_id", openId); // 微信 openId
|
||||
accBusiFields.put("device_info", "WEB"); // 终端设备号(门店号或收银设备ID),注意:PC网页或JSAPI支付请传"WEB"
|
||||
reqData.put("acc_busi_fields", accBusiFields);
|
||||
log.debug("[拉卡拉预下单] 已添加微信业务参数, xcxAppId={}, openId={}", xcxAppId, openId);
|
||||
} else {
|
||||
log.warn("[拉卡拉预下单] 微信业务参数不完整或不需要, xcxAppId={}, openId={}", xcxAppId, openId);
|
||||
}
|
||||
|
||||
// 3. 构造请求体
|
||||
JSONObject reqBody = new JSONObject();
|
||||
reqBody.put("req_time", DateTimeUtils.formatDateTime(LocalDateTime.now(), "yyyyMMddHHmmss"));
|
||||
reqBody.put("version", "3.0");
|
||||
reqBody.put("req_data", reqData);
|
||||
|
||||
log.info("[拉卡拉预下单] 请求参数组装完成, orderId={}", orderId);
|
||||
log.debug("[拉卡拉预下单] 完整请求参数: {}", JSONUtil.toJsonStr(reqBody));
|
||||
|
||||
// 4. 发送请求
|
||||
String reqUrl = serverUrl + "/api/v3/labs/trans/preorder";
|
||||
log.info("[拉卡拉预下单] 准备发送请求, orderId={}, url={}", orderId, reqUrl);
|
||||
|
||||
String authorization = LakalaUtil.genAuthorizationByPath(priKeyPath, appId, serialNo, reqBody.toString());
|
||||
if (StrUtil.isBlank(authorization)) {
|
||||
log.error("[拉卡拉预下单] 生成签名失败, orderId={}", orderId);
|
||||
throw new ApiException("生成请求签名失败!");
|
||||
}
|
||||
|
||||
JSONObject header = new JSONObject();
|
||||
header.put("Authorization", authorization);
|
||||
header.put("Content-Type", "application/json");
|
||||
|
||||
log.debug("[拉卡拉预下单] 请求头信息生成完成, orderId={}", orderId);
|
||||
|
||||
// 使用RestTemplate发送POST请求
|
||||
ResponseEntity<JSONObject> lakalaRespEntity = RestTemplateHttpUtil.sendPostBodyBackEntity(reqUrl, header, reqBody, JSONObject.class);
|
||||
log.info("[拉卡拉预下单] 收到响应, orderId={}, responseStatus={}", orderId, lakalaRespEntity != null ? lakalaRespEntity.getStatusCode() : "NULL");
|
||||
|
||||
// 5. 处理响应结果
|
||||
if (lakalaRespEntity == null) {
|
||||
log.warn("[拉卡拉预下单] 响应为空, orderId={}", orderId);
|
||||
return null;
|
||||
}
|
||||
|
||||
JSONObject respBody = lakalaRespEntity.getBody();
|
||||
log.debug("[拉卡拉预下单] 响应体内容, orderId={}, responseBody={}", orderId, respBody);
|
||||
|
||||
if (respBody == null) {
|
||||
log.warn("[拉卡拉预下单] 响应体为空, orderId={}", orderId);
|
||||
return null;
|
||||
}
|
||||
|
||||
String responseCode = respBody.getStr("code");
|
||||
if (StrUtil.isBlank(responseCode)) {
|
||||
log.warn("[拉卡拉预下单] 响应码为空, orderId={}", orderId);
|
||||
return respBody;
|
||||
}
|
||||
|
||||
// 使用安全的字符串比较方式,避免空指针异常
|
||||
if (!lklPaySuccessCode.equals(responseCode)) {
|
||||
log.warn("[拉卡拉预下单] 响应码异常, orderId={}, code={}, msg={}", orderId, responseCode, respBody.getStr("msg"));
|
||||
return respBody;
|
||||
}
|
||||
|
||||
log.info("[拉卡拉预下单] 支付成功,准备保存订单记录, orderId={}", orderId);
|
||||
// 新增一个拉卡拉订单记录 shop_order_lkl 表
|
||||
JSONObject lklPayReqAndRespJson = new JSONObject();
|
||||
lklPayReqAndRespJson.put("req", reqData);
|
||||
lklPayReqAndRespJson.put("resp", respBody);
|
||||
|
||||
try {
|
||||
shopService.lklPayAddShopOrderLkl(lklPayReqAndRespJson);
|
||||
log.debug("[拉卡拉预下单] 订单记录保存成功, orderId={}", orderId);
|
||||
} catch (Exception e) {
|
||||
log.error("[拉卡拉预下单] 保存订单记录失败, orderId={}", orderId, e);
|
||||
// 不中断主流程,仅记录错误
|
||||
}
|
||||
|
||||
// 6. 返回响应结果
|
||||
log.info("[拉卡拉预下单] 处理完成, orderId={}, responseCode={}", orderId, responseCode);
|
||||
return respBody;
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("[拉卡拉预下单] 系统异常, merchantNo={}, termNo={}, orderId={}", merchantNo, termNo, orderId, e);
|
||||
throw new ApiException("拉卡拉预下单出错:" + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 拉卡拉合单预下单(主要有运费的订单使用合单)
|
||||
* 参考:https://o.lakala.com/#/home/document/detail?id=208
|
||||
@ -204,41 +390,64 @@ public class LakalaPayServiceImpl implements LakalaPayService {
|
||||
* @param storeId 店铺Id
|
||||
* @param orderId 订单号
|
||||
* @param subject 订单标题
|
||||
* @param totalAmount 订单总金额
|
||||
* @param agentAmount 代理商收取金额
|
||||
* @param totalAmount 订单总金额(单位:分)
|
||||
* @param agentAmount 代理商收取金额(单位:分)
|
||||
* @param notifyURL 回调地址
|
||||
* @param requestIP 请求ip
|
||||
* @param requestIP 请求IP
|
||||
* @param remark 备注
|
||||
* @return 拉卡拉合单预下单响应结果
|
||||
**/
|
||||
@Override
|
||||
public JSONObject lklTransMergePreOrder(String merchantNo, String termNo, String agentMerchantNo, String agentTermNo, String xcxAppId, String openId, String storeId, String orderId, String subject, String totalAmount, String agentAmount, String notifyURL, String requestIP, String remark) {
|
||||
// 2. 参数校验
|
||||
log.info("[拉卡拉合单预下单] 开始处理请求, merchantNo={}, termNo={}, agentMerchantNo={}, agentTermNo={}, orderId={}",
|
||||
merchantNo, termNo, agentMerchantNo, agentTermNo, orderId);
|
||||
|
||||
// 1. 参数校验
|
||||
if (StrUtil.isBlank(merchantNo)) {
|
||||
log.warn("[拉卡拉合单预下单] 参数校验失败:商家商户号不能为空, orderId={}", orderId);
|
||||
throw new ApiException("商家商户号不能为空!");
|
||||
}
|
||||
|
||||
if (StrUtil.isBlank(termNo)) {
|
||||
log.warn("[拉卡拉合单预下单] 参数校验失败:终端号不能为空, orderId={}", orderId);
|
||||
throw new ApiException("终端号不能为空!");
|
||||
}
|
||||
|
||||
// 3. 校验其他必要参数
|
||||
if (StrUtil.isBlank(orderId)) {
|
||||
log.warn("[拉卡拉合单预下单] 参数校验失败:订单号不能为空, merchantNo={}, termNo={}", merchantNo, termNo);
|
||||
throw new ApiException("订单号不能为空!");
|
||||
}
|
||||
|
||||
if (StrUtil.isBlank(subject)) {
|
||||
log.warn("[拉卡拉合单预下单] 参数校验失败:订单标题不能为空, orderId={}", orderId);
|
||||
throw new ApiException("订单标题不能为空!");
|
||||
}
|
||||
|
||||
if (StrUtil.isBlank(totalAmount)) {
|
||||
log.warn("[拉卡拉合单预下单] 参数校验失败:订单总金额不能为空, orderId={}", orderId);
|
||||
throw new ApiException("订单总金额不能为空!");
|
||||
}
|
||||
|
||||
if (StrUtil.isBlank(notifyURL)) {
|
||||
log.warn("[拉卡拉合单预下单] 参数校验失败:回调地址不能为空, orderId={}", orderId);
|
||||
throw new ApiException("回调地址不能为空!");
|
||||
}
|
||||
|
||||
if (StrUtil.isBlank(requestIP)) {
|
||||
log.warn("[拉卡拉合单预下单] 参数校验失败:请求IP不能为空, orderId={}", orderId);
|
||||
throw new ApiException("请求IP不能为空!");
|
||||
}
|
||||
|
||||
// 如果不符合合单交易条件,则走聚合主扫单笔交易
|
||||
if (StrUtil.isBlank(agentMerchantNo) || StrUtil.isBlank(agentTermNo) || StrUtil.isBlank(agentAmount) || "0".equals(agentAmount)) {
|
||||
log.info("不符合合单交易条件,转为单笔交易处理。商家商户号:{},代理商商户号:{},代理商终端号:{},代理商金额:{}",
|
||||
log.info("[拉卡拉合单预下单] 不符合合单交易条件,转为单笔交易处理。商家商户号:{},代理商商户号:{},代理商终端号:{},代理商金额:{}",
|
||||
merchantNo, agentMerchantNo, agentTermNo, agentAmount);
|
||||
return lklTransPreOrder(merchantNo, termNo, xcxAppId, openId, storeId, orderId, subject, totalAmount, notifyURL, requestIP, remark);
|
||||
}
|
||||
|
||||
try {
|
||||
// 4. 装配请求数据
|
||||
log.debug("[拉卡拉合单预下单] 开始装配请求数据, orderId={}", orderId);
|
||||
// 2. 装配请求数据
|
||||
JSONObject reqData = new JSONObject();
|
||||
|
||||
// 基本交易信息
|
||||
@ -251,6 +460,7 @@ public class LakalaPayServiceImpl implements LakalaPayService {
|
||||
reqData.put("subject", subject); // 订单标题
|
||||
reqData.put("notify_url", notifyURL); // 异步通知地址
|
||||
reqData.put("remark", remark); // 备注
|
||||
reqData.put("complete_notify_url", "https://mall.gpxscs.cn/api/mobile/shop/lakala/trans/receive/completeNotify"); // 发货类小程序确认收获后通知商户的地址
|
||||
|
||||
// 位置信息
|
||||
JSONObject locationInfo = new JSONObject();
|
||||
@ -258,10 +468,15 @@ public class LakalaPayServiceImpl implements LakalaPayService {
|
||||
reqData.put("location_info", locationInfo);
|
||||
|
||||
// 微信业务参数
|
||||
JSONObject accBusiFields = new JSONObject();
|
||||
accBusiFields.put("sub_appid", xcxAppId); // 小程序appid
|
||||
accBusiFields.put("user_id", openId); // 用户openid
|
||||
reqData.put("acc_busi_fields", accBusiFields);
|
||||
if (StrUtil.isNotBlank(xcxAppId) && StrUtil.isNotBlank(openId)) {
|
||||
JSONObject accBusiFields = new JSONObject();
|
||||
accBusiFields.put("sub_appid", xcxAppId); // 小程序appId
|
||||
accBusiFields.put("user_id", openId); // 用户openid
|
||||
reqData.put("acc_busi_fields", accBusiFields);
|
||||
log.debug("[拉卡拉合单预下单] 已添加微信业务参数, xcxAppId={}, openId={}", xcxAppId, openId);
|
||||
} else {
|
||||
log.warn("[拉卡拉合单预下单] 微信业务参数不完整或不需要, xcxAppId={}, openId={}", xcxAppId, openId);
|
||||
}
|
||||
|
||||
// 重要约定,订单号规则:商品订单:ORD_订单号,运费订单:DF_订单号
|
||||
// 分单信息
|
||||
@ -269,8 +484,20 @@ public class LakalaPayServiceImpl implements LakalaPayService {
|
||||
goodsSplitInfo.put("out_sub_trade_no", CommonConstant.Sep_GoodsFee_Prefix + orderId); // 商品子订单号
|
||||
goodsSplitInfo.put("merchant_no", merchantNo); // 分账商户号
|
||||
goodsSplitInfo.put("term_no", termNo); // 分账终端号
|
||||
int totalAmountInt = Convert.toInt(totalAmount) - Convert.toInt(agentAmount);
|
||||
goodsSplitInfo.put("amount", Convert.toStr(totalAmountInt)); // 分账金额
|
||||
|
||||
// 安全转换金额,避免类型转换异常
|
||||
int totalAmountInt = 0;
|
||||
int agentAmountInt = 0;
|
||||
try {
|
||||
totalAmountInt = Convert.toInt(totalAmount);
|
||||
agentAmountInt = Convert.toInt(agentAmount);
|
||||
} catch (NumberFormatException e) {
|
||||
log.error("[拉卡拉合单预下单] 金额转换异常, totalAmount={}, agentAmount={}, orderId={}", totalAmount, agentAmount, orderId, e);
|
||||
throw new ApiException("金额格式错误!");
|
||||
}
|
||||
|
||||
int goodsAmountInt = totalAmountInt - agentAmountInt;
|
||||
goodsSplitInfo.put("amount", Convert.toStr(goodsAmountInt)); // 分账金额
|
||||
goodsSplitInfo.put("settle_type", "0"); // "0"或者空,常规结算方式
|
||||
goodsSplitInfo.put("sub_remark", "商品订单金额"); // 子单备注信息
|
||||
|
||||
@ -287,50 +514,87 @@ public class LakalaPayServiceImpl implements LakalaPayService {
|
||||
outSplitInfo.add(goodsSplitInfo);
|
||||
reqData.put("out_split_info", outSplitInfo);
|
||||
|
||||
// 5. 构造请求体
|
||||
log.info("[拉卡拉合单预下单] 分单信息组装完成, orderId={}, goodsAmount={}分, deliveryAmount={}分",
|
||||
orderId, goodsAmountInt, agentAmountInt);
|
||||
|
||||
// 3. 构造请求体
|
||||
JSONObject reqBody = new JSONObject();
|
||||
reqBody.put("req_time", DateTimeUtils.formatDateTime(LocalDateTime.now(), "yyyyMMddHHmmss"));
|
||||
reqBody.put("version", "3.0");
|
||||
reqBody.put("req_data", reqData);
|
||||
|
||||
// 6. 发送请求
|
||||
log.info("[拉卡拉合单预下单] 请求参数组装完成, orderId={}", orderId);
|
||||
log.debug("[拉卡拉合单预下单] 完整请求参数: {}", JSONUtil.toJsonStr(reqBody));
|
||||
|
||||
// 4. 发送请求
|
||||
String reqUrl = serverUrl + "/api/v3/labs/trans/merge/preorder";
|
||||
log.info("拉卡拉合单预下单请求参数:{}", reqBody);
|
||||
log.info("[拉卡拉合单预下单] 准备发送请求, orderId={}, url={}", orderId, reqUrl);
|
||||
|
||||
String authorization = LakalaUtil.genAuthorizationByPath(priKeyPath, appId, serialNo, reqBody.toString());
|
||||
if (StrUtil.isBlank(authorization)) {
|
||||
log.error("[拉卡拉合单预下单] 生成签名失败, orderId={}", orderId);
|
||||
return new JSONObject().set("code", "BBS00001").set("msg", "生成请求签名失败").set("resp_data", null);
|
||||
}
|
||||
|
||||
JSONObject header = new JSONObject();
|
||||
header.put("Authorization", authorization);
|
||||
header.put("Content-Type", "application/json");
|
||||
|
||||
// 这里的请求方法,对返回的字段进行了处理,需要注意
|
||||
ResponseEntity<JSONObject> lakalaRespJSON = RestTemplateHttpUtil.sendPostBodyBackEntity(reqUrl, header, reqBody, JSONObject.class);
|
||||
log.info("拉卡拉合单交易响应参数:{}", lakalaRespJSON);
|
||||
log.debug("[拉卡拉合单预下单] 请求头信息生成完成, orderId={}", orderId);
|
||||
|
||||
// 7. 处理响应结果
|
||||
if (lakalaRespJSON == null) {
|
||||
// 发送请求
|
||||
ResponseEntity<JSONObject> lakalaRespEntity = RestTemplateHttpUtil.sendPostBodyBackEntity(reqUrl, header, reqBody, JSONObject.class);
|
||||
log.info("[拉卡拉合单预下单] 收到响应, orderId={}, responseStatus={}", orderId, lakalaRespEntity != null ? lakalaRespEntity.getStatusCode() : "NULL");
|
||||
|
||||
// 5. 处理响应结果
|
||||
if (lakalaRespEntity == null) {
|
||||
log.warn("[拉卡拉合单预下单] 响应为空, orderId={}", orderId);
|
||||
return new JSONObject().set("code", "BBS00001").set("msg", "拉卡拉合单交易无响应值").set("resp_data", null);
|
||||
}
|
||||
|
||||
JSONObject respBody = lakalaRespJSON.getBody();
|
||||
JSONObject respBody = lakalaRespEntity.getBody();
|
||||
log.debug("[拉卡拉合单预下单] 响应体内容, orderId={}, responseBody={}", orderId, respBody);
|
||||
|
||||
// 7. 处理响应结果
|
||||
if (!lklPaySuccessCode.equals(respBody.getStr("code")) || respBody == null) {
|
||||
return new JSONObject().set("code", "BBS00001").set("msg", "拉卡拉合单交易无响应值").set("resp_data", null);
|
||||
// 6. 处理响应结果
|
||||
if (respBody == null) {
|
||||
log.warn("[拉卡拉合单预下单] 响应体为空, orderId={}", orderId);
|
||||
return new JSONObject().set("code", "BBS00001").set("msg", "拉卡拉合单交易响应体为空").set("resp_data", null);
|
||||
}
|
||||
|
||||
String responseCode = respBody.getStr("code");
|
||||
if (StrUtil.isBlank(responseCode)) {
|
||||
log.warn("[拉卡拉合单预下单] 响应码为空, orderId={}", orderId);
|
||||
return new JSONObject().set("code", "BBS00001").set("msg", "拉卡拉合单交易响应码为空").set("resp_data", null);
|
||||
}
|
||||
|
||||
// 使用安全的字符串比较方式,避免空指针异常
|
||||
if (!lklPaySuccessCode.equals(responseCode)) {
|
||||
log.warn("[拉卡拉合单预下单] 响应码异常, orderId={}, code={}, msg={}", orderId, responseCode, respBody.getStr("msg"));
|
||||
return new JSONObject().set("code", "BBS00001").set("msg", "拉卡拉合单交易失败:" + respBody.getStr("msg")).set("resp_data", null);
|
||||
}
|
||||
|
||||
log.info("[拉卡拉合单预下单] 支付成功,准备保存订单记录, orderId={}", orderId);
|
||||
// 新增一个拉卡拉订单记录 shop_order_lkl 表
|
||||
JSONObject lklPayReqAndRespJson = new JSONObject();
|
||||
lklPayReqAndRespJson.put("req", reqData);
|
||||
lklPayReqAndRespJson.put("resp", respBody); // 返回原始响应数据
|
||||
|
||||
// 新增 shopOrderLkl 记录
|
||||
shopService.lklPayAddShopOrderLkl(lklPayReqAndRespJson);
|
||||
try {
|
||||
// 新增 shopOrderLkl 记录
|
||||
shopService.lklPayAddShopOrderLkl(lklPayReqAndRespJson);
|
||||
log.debug("[拉卡拉合单预下单] 订单记录保存成功, orderId={}", orderId);
|
||||
} catch (Exception e) {
|
||||
log.error("[拉卡拉合单预下单] 保存订单记录失败, orderId={}", orderId, e);
|
||||
// 不中断主流程,仅记录错误
|
||||
}
|
||||
|
||||
// 8. 返回响应结果
|
||||
// 7. 返回响应结果
|
||||
log.info("[拉卡拉合单预下单] 处理完成, orderId={}, responseCode={}", orderId, responseCode);
|
||||
return respBody;
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("拉卡拉合单交易出错,订单号:{},错误信息:", orderId, e);
|
||||
throw new ApiException("拉卡拉合单交易出错:" + e.getMessage(), e);
|
||||
log.error("[拉卡拉合单预下单] 系统异常, merchantNo={}, termNo={}, orderId={}", merchantNo, termNo, orderId, e);
|
||||
return new JSONObject().set("code", "BBS00001").set("msg", "系统异常:" + e.getMessage()).set("resp_data", null);
|
||||
}
|
||||
}
|
||||
|
||||
@ -340,7 +604,7 @@ public class LakalaPayServiceImpl implements LakalaPayService {
|
||||
* 参考地址:https://o.lakala.com/#/home/document/detail?id=113
|
||||
*
|
||||
* @param storeId 店铺ID
|
||||
* @param outTradeNo 退货订单号,如: FX-20241214-1
|
||||
* @param outTradeNo 外部交易订单号
|
||||
* @param originTradeNo 原拉卡拉交易流水号
|
||||
* @param refundAmount 退款金额(单位:分)
|
||||
* @param refundReason 退款原因
|
||||
@ -351,33 +615,58 @@ public class LakalaPayServiceImpl implements LakalaPayService {
|
||||
@Override
|
||||
public Pair<Boolean, String> innerLklRefund(Integer storeId, String outTradeNo, String originTradeNo, String refundAmount, String refundReason, String lklMerchantNo, String lklTermNo) {
|
||||
try {
|
||||
log.info("开始执行拉卡拉内部退款,参数: storeId={}, outTradeNo={}, originTradeNo={}, refundAmount={}, refundReason={}",
|
||||
log.info("[拉卡拉退款] 开始执行拉卡拉内部退款,参数: storeId={}, outTradeNo={}, originTradeNo={}, refundAmount={}, refundReason={}",
|
||||
storeId, outTradeNo, originTradeNo, refundAmount, refundReason);
|
||||
|
||||
// 1. 获取请求IP
|
||||
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
|
||||
if (attributes == null) {
|
||||
log.error("无法获取HttpServletRequest,退款失败");
|
||||
log.error("[拉卡拉退款] 无法获取HttpServletRequest,退款失败");
|
||||
return Pair.of(false, I18nUtil._("系统异常,无法获取请求信息!"));
|
||||
}
|
||||
HttpServletRequest request = attributes.getRequest();
|
||||
String requestIp = IpKit.getRealIp(request);
|
||||
|
||||
// 2. 校验参数
|
||||
if (ObjectUtil.isEmpty(storeId) || org.apache.commons.lang3.StringUtils.isAnyBlank(outTradeNo, refundAmount, originTradeNo)) {
|
||||
log.warn("退款请求参数不完整: storeId={}, outTradeNo={}, originTradeNo={}, refundAmount={}, requestIp={}", storeId, outTradeNo, originTradeNo, refundAmount, requestIp);
|
||||
return Pair.of(false, I18nUtil._("缺少必要参数,退款失败!"));
|
||||
if (ObjectUtil.isEmpty(storeId)) {
|
||||
log.warn("[拉卡拉退款] 店铺ID不能为空: storeId={}", storeId);
|
||||
return Pair.of(false, I18nUtil._("店铺ID不能为空,退款失败!"));
|
||||
}
|
||||
|
||||
if (StrUtil.isBlank(outTradeNo)) {
|
||||
log.warn("[拉卡拉退款] 外部交易订单号不能为空: outTradeNo={}", outTradeNo);
|
||||
return Pair.of(false, I18nUtil._("外部交易订单号不能为空,退款失败!"));
|
||||
}
|
||||
|
||||
if (StrUtil.isBlank(originTradeNo)) {
|
||||
log.warn("[拉卡拉退款] 原拉卡拉交易流水号不能为空: originTradeNo={}", originTradeNo);
|
||||
return Pair.of(false, I18nUtil._("原拉卡拉交易流水号不能为空,退款失败!"));
|
||||
}
|
||||
|
||||
if (StrUtil.isBlank(refundAmount)) {
|
||||
log.warn("[拉卡拉退款] 退款金额不能为空: refundAmount={}", refundAmount);
|
||||
return Pair.of(false, I18nUtil._("退款金额不能为空,退款失败!"));
|
||||
}
|
||||
|
||||
// 校验退款金额格式
|
||||
if (!refundAmount.matches("\\d+") || Integer.parseInt(refundAmount) <= 0) {
|
||||
log.warn("退款金额不合法: refundAmount={}", refundAmount);
|
||||
log.warn("[拉卡拉退款] 退款金额不合法: refundAmount={}", refundAmount);
|
||||
return Pair.of(false, I18nUtil._("退款金额不合法!"));
|
||||
}
|
||||
|
||||
// 3. 初始化拉卡拉SDK
|
||||
initLKLSDK();
|
||||
|
||||
// 4. 获取店铺的拉卡拉商户号和终端号
|
||||
ShopStoreBase shopStoreBase = shopService.getLklMerchantNoAndTermNo(storeId);
|
||||
if (shopStoreBase == null || org.apache.commons.lang3.StringUtils.isAnyBlank(shopStoreBase.getLkl_merchant_no(), shopStoreBase.getLkl_term_no())) {
|
||||
log.error("无法获取店铺的拉卡拉商户号或终端号: storeId={}", 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._("缺少商户号参数,退款失败!"));
|
||||
}
|
||||
|
||||
@ -396,37 +685,44 @@ public class LakalaPayServiceImpl implements LakalaPayService {
|
||||
|
||||
refundRequest.setLocationInfo(new V3LabsTradeLocationInfo(requestIp, null, ""));
|
||||
|
||||
log.info("拉卡拉退款请求参数: {}", JSONUtil.toJsonStr(refundRequest));
|
||||
log.info("[拉卡拉退款] 请求参数: {}", JSONUtil.toJsonStr(refundRequest));
|
||||
|
||||
String responseString = LKLSDK.httpPost(refundRequest);
|
||||
// 6. 处理响应
|
||||
if (StrUtil.isBlank(responseString)) {
|
||||
log.error("拉卡拉退款接口无响应");
|
||||
log.error("[拉卡拉退款] 拉卡拉退款接口无响应");
|
||||
return Pair.of(false, I18nUtil._("服务端无返回值,退款失败!"));
|
||||
}
|
||||
|
||||
log.info("拉卡拉退款接口响应: {}", responseString);
|
||||
log.info("[拉卡拉退款] 拉卡拉退款接口响应: {}", responseString);
|
||||
|
||||
JSONObject lakalaResponseJson = JSONUtil.parseObj(responseString);
|
||||
if (lakalaResponseJson == null) {
|
||||
log.error("拉卡拉退款接口返回值解析失败: responseString={}", responseString);
|
||||
log.error("[拉卡拉退款] 拉卡拉退款接口返回值解析失败: responseString={}", responseString);
|
||||
return Pair.of(false, I18nUtil._("返回值解析失败,退款失败!"));
|
||||
}
|
||||
if (!"BBS00000".equals(lakalaResponseJson.getStr("code"))) {
|
||||
|
||||
String responseCode = lakalaResponseJson.getStr("code");
|
||||
if (StrUtil.isBlank(responseCode)) {
|
||||
log.error("[拉卡拉退款] 拉卡拉退款响应码为空: response={}", responseString);
|
||||
return Pair.of(false, I18nUtil._("返回值格式错误,退款失败!"));
|
||||
}
|
||||
|
||||
if (!"BBS00000".equals(responseCode)) {
|
||||
String errorMessage = lakalaResponseJson.getStr("msg", "未知错误");
|
||||
log.error("拉卡拉退款失败, 错误信息: {}", errorMessage);
|
||||
log.error("[拉卡拉退款] 拉卡拉退款失败, 错误信息: {}, 响应码: {}", errorMessage, responseCode);
|
||||
return Pair.of(false, I18nUtil._(errorMessage));
|
||||
}
|
||||
|
||||
JSONObject responseData = lakalaResponseJson.getJSONObject("resp_data");
|
||||
log.info("拉卡拉退款成功: outTradeNo={}", outTradeNo);
|
||||
log.info("[拉卡拉退款] 拉卡拉退款成功: outTradeNo={}", outTradeNo);
|
||||
return Pair.of(true, responseData == null ? "" : responseData.toString());
|
||||
|
||||
} catch (SDKException e) {
|
||||
log.error("拉卡拉退款SDK异常: ", e);
|
||||
log.error("[拉卡拉退款] 拉卡拉退款SDK异常: ", e);
|
||||
return Pair.of(false, I18nUtil._("拉卡拉退款SDK异常,退款失败!") + e.getMessage());
|
||||
} catch (Exception e) {
|
||||
log.error("拉卡拉退款发生未知异常: ", e);
|
||||
log.error("[拉卡拉退款] 拉卡拉退款发生未知异常: ", e);
|
||||
return Pair.of(false, I18nUtil._("拉卡拉退款发生未知异常,退款失败!") + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@ -1434,7 +1434,7 @@ public class PayUserPayServiceImpl extends BaseServiceImpl<PayUserPayMapper, Pay
|
||||
payConsumeDeposit.setUser_id(userId);
|
||||
|
||||
lklNotifyRespJSON.set("out_separate_no", orderId);// 默认非合单主单订单号
|
||||
lklNotifyRespJSON.set("lkl_split_log_no", lklNotifyRespJSON.getStr("log_no")); // 默认非合单主单的流水号
|
||||
lklNotifyRespJSON.set("lkl_sub_log_no", lklNotifyRespJSON.getStr("log_no")); // 默认非合单主单的流水号
|
||||
lklNotifyRespJSON.set("split_amt", lklNotifyRespJSON.getStr("total_amount")); // 默认非合单主单支付金额
|
||||
// 拉卡拉订单合单信息
|
||||
if (StrUtil.isNotBlank(outSplitRspInfos)) {
|
||||
@ -1453,7 +1453,7 @@ public class PayUserPayServiceImpl extends BaseServiceImpl<PayUserPayMapper, Pay
|
||||
cn.hutool.json.JSONObject goodsOrderInfo = payConsumeTradeService.getLklCombineSplitRespInfo(outSplitRspInfos, false);
|
||||
if (goodsOrderInfo != null) {
|
||||
lklNotifyRespJSON.set("out_separate_no", goodsOrderInfo.getStr("out_sub_trade_no"));// 合单子订单号
|
||||
lklNotifyRespJSON.set("lkl_split_log_no", lklNotifyRespJSON.getStr("sub_log_no")); // 合单子商品订单的流水号
|
||||
lklNotifyRespJSON.set("lkl_sub_log_no", lklNotifyRespJSON.getStr("sub_log_no")); // 合单子商品订单的流水号
|
||||
lklNotifyRespJSON.set("split_amt", lklNotifyRespJSON.getStr("amount")); // 合单子商品订单支付金额
|
||||
}
|
||||
}
|
||||
|
||||
@ -131,6 +131,18 @@ public class LakalaController extends BaseControllerImpl {
|
||||
return lakalaPayService.getBankCardBin(paramsJSON.getStr("bankCardNo"));
|
||||
}
|
||||
|
||||
@ApiOperation(value = "发货类交易确认收货通知", notes = "发货类交易确认收货通知 https://o.lakala.com/#/home/document/detail?id=1003")
|
||||
@RequestMapping(value = "/trans/receive/completeNotify", method = RequestMethod.POST)
|
||||
public ResponseEntity<JSONObject> receiveCompleteNotify(HttpServletRequest request) {
|
||||
// 完整地址: https://mall.gpxscs.cn/api/mobile/shop/lakala/trans/receive/completeNotify
|
||||
JSONObject resp = lakalaPayService.receiveCompleteNotify(request);
|
||||
if (resp != null && "SUCCESS".equals(resp.get("code"))) {
|
||||
return ResponseEntity.ok(resp);
|
||||
}
|
||||
|
||||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(resp);
|
||||
}
|
||||
|
||||
@ApiOperation(value = "商户入网电子合同申请回调通知", notes = "商户入网电子合同申请回调通知")
|
||||
@RequestMapping(value = "/ec/applyNotify", method = RequestMethod.POST)
|
||||
public ResponseEntity<JSONObject> ecApplyNotify(HttpServletRequest request) {
|
||||
|
||||
@ -95,6 +95,19 @@ public interface LakalaApiService {
|
||||
*/
|
||||
Pair<Boolean, String> innerApplyLedgerMer(String merCupNo);
|
||||
|
||||
/**
|
||||
* 发货类交易确认收货通知
|
||||
* 参考:https://o.lakala.com/#/home/document/detail?id=1003
|
||||
* 注意:
|
||||
* (1)交易通知接口是交易成功完成后会向 complete_notify_url 这个地址(主扫交易或者主扫合单请求中的complete_notify_url字段)发起交易结果通知。拉卡拉系统通知时,如果商户的应答没有按照以下“响应参考报文”示例返回成功状态时,则系统认为通知失败,系统会通过一定的策略定期重新发起通知。
|
||||
* (2)同样的通知可能会多次发送给商户系统,商户系统必须能够正确处理重复的通知。
|
||||
* (3)在没有收到拉卡拉支付交易通知的情况下,建议商户主动调用【06查询交易】确认交易状态。
|
||||
*
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
JSONObject receiveCompleteNotify(HttpServletRequest request);
|
||||
|
||||
/**
|
||||
* 商户入网电子合同申请回调通知
|
||||
* 参考:https://o.lakala.com/#/home/document/detail?id=289
|
||||
@ -172,6 +185,29 @@ public interface LakalaApiService {
|
||||
*/
|
||||
Pair<Boolean, String> innerDoOrderSeparate(String orderId, String storeId);
|
||||
|
||||
/**
|
||||
* 根据商户号、交易号和收货流水号执行订单分账操作
|
||||
* <p>
|
||||
* 该方法用于处理拉卡拉订单的分账逻辑。在用户确认收货后,系统会根据订单信息执行分账操作,
|
||||
* 将订单金额按照预设比例分配给平台、商家和代理商(如果存在)。
|
||||
* </p>
|
||||
* <p>
|
||||
* 分账操作流程:
|
||||
* 1. 参数校验和订单查询
|
||||
* 2. 检查订单状态(是否已确认收货)
|
||||
* 3. 检查是否已分账,避免重复处理
|
||||
* 4. 计算分账金额
|
||||
* 5. 构建分账请求并发送至拉卡拉
|
||||
* 6. 保存分账结果
|
||||
* </p>
|
||||
*
|
||||
* @param lklMerchantNo 拉卡拉商户号
|
||||
* @param receiveTradeNo 收货交易号(对应拉卡拉的trade_no)
|
||||
* @param receiveLogNo 收货流水号(对应拉卡拉的log_no)
|
||||
* @return Pair<Boolean, String> 处理结果对,first为是否成功,second为结果描述信息
|
||||
*/
|
||||
Pair<Boolean, String> innerDoOrderSeparateByMerchantAndLogNo(String lklMerchantNo, String receiveTradeNo, String receiveLogNo);
|
||||
|
||||
/**
|
||||
* 分账结果通知
|
||||
* 参考:https://o.lakala.com/#/home/document/detail?id=393
|
||||
|
||||
@ -675,6 +675,104 @@ public class LakalaApiServiceImpl implements LakalaApiService {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 发货类交易确认收货通知处理
|
||||
* <p>
|
||||
* 参考文档:https://o.lakala.com/#/home/document/detail?id=1003
|
||||
* </p>
|
||||
* <p>
|
||||
* 注意事项:
|
||||
* (1)交易通知接口是交易成功完成后会向 complete_notify_url 这个地址(主扫交易或者主扫合单请求中的complete_notify_url字段)发起交易结果通知。
|
||||
* 拉卡拉系统通知时,如果商户的应答没有按照以下"响应参考报文"示例返回成功状态时,则系统认为通知失败,系统会通过一定的策略定期重新发起通知。
|
||||
* (2)同样的通知可能会多次发送给商户系统,商户系统必须能够正确处理重复的通知。
|
||||
* (3)在没有收到拉卡拉支付交易通知的情况下,建议商户主动调用【06查询交易】确认交易状态。
|
||||
* </p>
|
||||
*
|
||||
* @param request HTTP请求对象,包含拉卡拉确认收货通知的参数
|
||||
* @return JSONObject 响应结果对象
|
||||
*/
|
||||
@Override
|
||||
public JSONObject receiveCompleteNotify(HttpServletRequest request) {
|
||||
log.info("[确认收货通知] 开始处理发货类交易确认收货通知");
|
||||
|
||||
// 验签
|
||||
Pair<Boolean, String> checkResult = LakalaUtil.chkLklApiNotifySign(request, lklNotifyCerPath, false);
|
||||
if (!checkResult.getFirst()) {
|
||||
log.warn("[确认收货通知] 验签失败: {}", checkResult.getSecond());
|
||||
return JSONUtil.createObj().set("code", "FAIL").set("message", checkResult.getSecond());
|
||||
}
|
||||
|
||||
JSONObject paramsJSON = JSONUtil.parseObj(checkResult.getSecond());
|
||||
if (paramsJSON == null) {
|
||||
log.warn("[确认收货通知] 参数解析失败: 返回数据转换异常");
|
||||
return JSONUtil.createObj().set("code", "FAIL").set("message", "返回数据转换异常!");
|
||||
}
|
||||
|
||||
String logNo = paramsJSON.getStr("log_no");
|
||||
String tradeState = paramsJSON.getStr("trade_state");
|
||||
String merchantNo = paramsJSON.getStr("merchant_no");
|
||||
String originTradeNo = paramsJSON.getStr("origin_trade_no");
|
||||
String originLogNo = paramsJSON.getStr("origin_log_no");
|
||||
|
||||
log.info("[确认收货通知] 接收到通知参数: logNo={}, tradeState={}, merchantNo={}, originTradeNo={}, originLogNo={}",
|
||||
logNo, tradeState, merchantNo, originTradeNo, originLogNo);
|
||||
|
||||
if (StrUtil.isBlank(tradeState) || !"SUCCESS".equals(tradeState)) {
|
||||
log.warn("[确认收货通知] 交易状态未成功,不做任何处理: tradeState={}", tradeState);
|
||||
return JSONUtil.createObj().set("code", "FAIL").set("message", "交易状态未成功,不做任何处理!");
|
||||
}
|
||||
|
||||
if (StrUtil.isBlank(logNo) || StrUtil.isBlank(merchantNo) || StrUtil.isBlank(originTradeNo) || StrUtil.isBlank(originLogNo)) {
|
||||
log.warn("[确认收货通知] 关键参数为空: logNo={}, merchantNo={}, originTradeNo={}, originLogNo={}",
|
||||
logNo, merchantNo, originTradeNo, originLogNo);
|
||||
return JSONUtil.createObj().set("code", "FAIL").set("message", "关键编号返回空值!");
|
||||
}
|
||||
|
||||
ShopOrderLkl shopOrderLkl = shopOrderLklService.getByMerchantNoAndTradeNoAndSubLogNo(merchantNo, originTradeNo, originLogNo);
|
||||
if (shopOrderLkl == null) {
|
||||
log.warn("[确认收货通知] 订单不存在: merchantNo={}, originTradeNo={}, originLogNo={}",
|
||||
merchantNo, originTradeNo, originLogNo);
|
||||
return JSONUtil.createObj().set("code", "FAIL").set("message", "订单不存在!");
|
||||
}
|
||||
|
||||
try {
|
||||
// 更新订单信息
|
||||
shopOrderLkl.setLkl_receive_log_no(logNo);
|
||||
shopOrderLkl.setLkl_receive_trade_no(paramsJSON.getStr("trade_no"));
|
||||
shopOrderLkl.setLkl_receive_notify_resp(checkResult.getSecond());
|
||||
shopOrderLkl.setReceive_status(CommonConstant.Enable);
|
||||
|
||||
log.debug("[确认收货通知] 准备更新订单信息: orderId={}", shopOrderLkl.getOrder_id());
|
||||
Boolean updateResult = shopOrderLklService.addOrUpdateByStoreOrder(shopOrderLkl);
|
||||
if (Boolean.FALSE.equals(updateResult)) {
|
||||
log.error("[确认收货通知] 更新订单信息失败: orderId={}", shopOrderLkl.getOrder_id());
|
||||
return JSONUtil.createObj().set("code", "FAIL").set("message", "更新订单信息失败!");
|
||||
}
|
||||
log.info("[确认收货通知] 订单信息更新成功: orderId={}", shopOrderLkl.getOrder_id());
|
||||
|
||||
// 发起分账指令
|
||||
log.info("[确认收货通知] 开始发起分账指令: merchantNo={}, receiveTradeNo={}, logNo={}",
|
||||
merchantNo, shopOrderLkl.getLkl_receive_trade_no(), logNo);
|
||||
Pair<Boolean, String> separateResult = innerDoOrderSeparateByMerchantAndLogNo(merchantNo, shopOrderLkl.getLkl_receive_trade_no(), logNo);
|
||||
if (!separateResult.getFirst()) {
|
||||
log.error("[确认收货通知] 发起分账指令失败: orderId={}, reason={}", shopOrderLkl.getOrder_id(), separateResult.getSecond());
|
||||
return JSONUtil.createObj().set("code", "FAIL").set("message", "发起分账指令失败:" + separateResult.getSecond());
|
||||
}
|
||||
|
||||
log.info("[确认收货通知] 处理完成: orderId={}, log_no={}", shopOrderLkl.getOrder_id(), shopOrderLkl.getLkl_receive_log_no());
|
||||
JSONObject respData = JSONUtil.createObj();
|
||||
respData.set("code", "SUCCESS");
|
||||
respData.set("message", "操作成功!");
|
||||
return respData;
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("[确认收货通知] 处理过程中发生异常: orderId=" + shopOrderLkl.getOrder_id(), e);
|
||||
return JSONUtil.createObj().set("code", "FAIL").set("message", "系统处理异常:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 商户入网电子合同申请回调通知
|
||||
* 参考:https://o.lakala.com/#/home/document/detail?id=289
|
||||
@ -694,7 +792,7 @@ public class LakalaApiServiceImpl implements LakalaApiService {
|
||||
|
||||
String errMsg = "入网电子合同申请回调:";
|
||||
JSONObject respData = new JSONObject();
|
||||
respData.set("code", "FAIL").set("message", "处理失败!");
|
||||
respData.set("code", "FAIL").set("message", "返回数据转换异常!");
|
||||
|
||||
JSONObject paramsJSON = JSONUtil.parseObj(checkResult.getSecond());
|
||||
if (paramsJSON == null) {
|
||||
@ -1601,7 +1699,7 @@ public class LakalaApiServiceImpl implements LakalaApiService {
|
||||
public Pair<Boolean, String> innerDoOrderSeparate(String orderId, String storeId) {
|
||||
// 1. 输入参数校验
|
||||
if (StrUtil.isBlank(orderId)) {
|
||||
log.warn("分账操作参数校验失败:订单号为空");
|
||||
log.warn("[分账操作] 参数校验失败:订单号为空");
|
||||
return Pair.of(false, "订单号不能为空");
|
||||
}
|
||||
|
||||
@ -1609,10 +1707,10 @@ public class LakalaApiServiceImpl implements LakalaApiService {
|
||||
// TODO 检查可分账余额是否足够?
|
||||
|
||||
// 2. 查询订单信息
|
||||
log.info("开始执行订单[{}]分账操作", orderId);
|
||||
log.info("[分账操作] 开始执行订单[{}]分账操作", orderId);
|
||||
List<ShopOrderLkl> shopOrderLklList = shopOrderLklService.selectByOrderId(orderId, "", storeId);
|
||||
if (CollectionUtil.isEmpty(shopOrderLklList)) {
|
||||
log.warn("分账操作失败:订单[{}]不存在", orderId);
|
||||
log.warn("[分账操作] 失败:订单[{}]不存在", orderId);
|
||||
return Pair.of(false, "订单不存在");
|
||||
}
|
||||
|
||||
@ -1624,21 +1722,26 @@ public class LakalaApiServiceImpl implements LakalaApiService {
|
||||
initLKLSDK();
|
||||
|
||||
// 4. 遍历处理每个店铺订单的分账
|
||||
log.info("订单[{}]包含{}个子订单,开始逐一处理", orderId, totalCount);
|
||||
log.info("[分账操作] 订单[{}]包含{}个子订单,开始逐一处理", orderId, totalCount);
|
||||
for (ShopOrderLkl shopOrderLkl : shopOrderLklList) {
|
||||
log.debug("处理子订单:storeId={}, splitLogNo={}", shopOrderLkl.getStore_id(), shopOrderLkl.getLkl_split_log_no());
|
||||
log.debug("[分账操作] 处理子订单:storeId={}, subLogNo={}, receive_log_no={}", shopOrderLkl.getStore_id(), shopOrderLkl.getLkl_sub_log_no(), shopOrderLkl.getLkl_receive_log_no());
|
||||
|
||||
if (!CommonConstant.Enable.equals(shopOrderLkl.getReceive_status()) || StrUtil.isBlank(shopOrderLkl.getLkl_receive_log_no())) {
|
||||
log.warn("[分账操作] 订单[{}]对账流水号[{}]未被确认收货,跳过处理", orderId, shopOrderLkl.getLkl_receive_log_no());
|
||||
continue;
|
||||
}
|
||||
|
||||
// 5. 检查分账状态,避免重复处理
|
||||
LklOrderSeparate lklOrderSeparateExist = lklOrderSeparateService.getByOutTradeNo(shopOrderLkl.getLkl_split_log_no(), orderId);
|
||||
if (lklOrderSeparateExist != null) {
|
||||
String status = lklOrderSeparateExist.getStatus();
|
||||
LklOrderSeparate existingSeparateRecord = lklOrderSeparateService.getByOutTradeNo(shopOrderLkl.getLkl_sub_log_no(), orderId);
|
||||
if (existingSeparateRecord != null) {
|
||||
String status = existingSeparateRecord.getStatus();
|
||||
if ("SUCCESS".equals(status)) {
|
||||
log.info("订单[{}]子订单[{}]已完成分账,跳过处理", orderId, shopOrderLkl.getLkl_log_no());
|
||||
log.info("[分账操作] 订单[{}]子订单[{}]已完成分账,跳过处理", orderId, shopOrderLkl.getLkl_log_no());
|
||||
successCount++;
|
||||
continue;
|
||||
}
|
||||
if ("PROCESSING".equals(status) || "ACCEPTED".equals(status)) {
|
||||
log.info("订单[{}]子订单[{}]分账处理中或已受理,跳过处理", orderId, shopOrderLkl.getLkl_log_no());
|
||||
log.info("[分账操作] 订单[{}]子订单[{}]分账处理中或已受理,跳过处理", orderId, shopOrderLkl.getLkl_log_no());
|
||||
successCount++;
|
||||
continue;
|
||||
}
|
||||
@ -1653,21 +1756,21 @@ public class LakalaApiServiceImpl implements LakalaApiService {
|
||||
|
||||
// 7. 分账金额校验
|
||||
if (splitAmount < 1) {
|
||||
String errorMsg = String.format("店铺[%s]订单[%s]分账金额[%d]低于1分钱,跳过分账",
|
||||
String errorMsg = String.format("[分账操作] 店铺[%s]订单[%s]分账金额[%d]低于1分钱,跳过分账",
|
||||
shopOrderLkl.getStore_id(), orderId, splitAmount);
|
||||
log.error(errorMsg);
|
||||
errorMessages.append(errorMsg).append("; ");
|
||||
if (lklOrderSeparateExist != null) {
|
||||
lklOrderSeparateService.updateRemark(lklOrderSeparateExist.getId(), errorMsg);
|
||||
if (existingSeparateRecord != null) {
|
||||
lklOrderSeparateService.updateRemark(existingSeparateRecord.getId(), errorMsg);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// 获取分账平台接收方信息
|
||||
LklLedgerMerReceiverBind platform = lklLedgerMerReceiverBindService.getPlatformByMerCupNo(merchantNo);
|
||||
LklLedgerMerReceiverBind platformReceiver = lklLedgerMerReceiverBindService.getPlatformByMerCupNo(merchantNo);
|
||||
|
||||
if (platform == null) {
|
||||
String errorMsg = String.format("店铺[%s]未绑定平台方接收账户,跳过分账", shopOrderLkl.getStore_id());
|
||||
if (platformReceiver == null) {
|
||||
String errorMsg = String.format("[分账操作] 店铺[%s]未绑定平台方接收账户,跳过分账", shopOrderLkl.getStore_id());
|
||||
log.error(errorMsg);
|
||||
errorMessages.append(errorMsg).append("; ");
|
||||
continue;
|
||||
@ -1677,43 +1780,43 @@ public class LakalaApiServiceImpl implements LakalaApiService {
|
||||
List<V3SacsSeparateRecvDatas> recvDatas = new ArrayList<>();
|
||||
|
||||
// 9. 获取商家分账比例并校验
|
||||
BigDecimal splitRatioValMch = shopOrderLkl.getSplit_ratio(); // 如:94 代表94%
|
||||
BigDecimal merchantSplitRatioRaw = shopOrderLkl.getSplit_ratio(); // 如:94 代表94%
|
||||
// 判断商家分账比例是否有效(必须在(0, 100]范围内)
|
||||
boolean canSplitForMch = splitRatioValMch != null
|
||||
&& splitRatioValMch.compareTo(BigDecimal.ZERO) > 0
|
||||
&& splitRatioValMch.compareTo(new BigDecimal(100)) <= 0;
|
||||
if (!canSplitForMch) {
|
||||
String errorMsg = String.format("店铺[%s]商家分账比例[%s]不在(0-100]范围内,无法分账",
|
||||
shopOrderLkl.getStore_id(), splitRatioValMch);
|
||||
boolean canSplitForMerchant = merchantSplitRatioRaw != null
|
||||
&& merchantSplitRatioRaw.compareTo(BigDecimal.ZERO) > 0
|
||||
&& merchantSplitRatioRaw.compareTo(new BigDecimal(100)) <= 0;
|
||||
if (!canSplitForMerchant) {
|
||||
String errorMsg = String.format("[分账操作] 店铺[%s]商家分账比例[%s]不在(0-100]范围内,无法分账",
|
||||
shopOrderLkl.getStore_id(), merchantSplitRatioRaw);
|
||||
log.error(errorMsg);
|
||||
errorMessages.append(errorMsg).append("; ");
|
||||
continue;
|
||||
}
|
||||
// 商家分账
|
||||
BigDecimal mchRatio = splitRatioValMch.divide(new BigDecimal(100)); // 比如:94%
|
||||
BigDecimal merchantSplitRatio = merchantSplitRatioRaw.divide(new BigDecimal(100)); // 比如:94%
|
||||
|
||||
BigDecimal distributorRatio = BigDecimal.ZERO;
|
||||
BigDecimal platformRatio = BigDecimal.ONE;
|
||||
BigDecimal distributorSplitRatio = BigDecimal.ZERO;
|
||||
BigDecimal platformSplitRatio = BigDecimal.ONE;
|
||||
// 分账代理商接收方信息
|
||||
List<LklLedgerMerReceiverBind> distributors = lklLedgerMerReceiverBindService.selectDistributorByMerCupNo(merchantNo);
|
||||
if (distributors != null && distributors.size() > 0) {
|
||||
distributorRatio = new BigDecimal("0.8");
|
||||
platformRatio = new BigDecimal("0.2");
|
||||
List<LklLedgerMerReceiverBind> distributorReceivers = lklLedgerMerReceiverBindService.selectDistributorByMerCupNo(merchantNo);
|
||||
if (distributorReceivers != null && !distributorReceivers.isEmpty()) {
|
||||
distributorSplitRatio = new BigDecimal("0.8");
|
||||
platformSplitRatio = new BigDecimal("0.2");
|
||||
}
|
||||
|
||||
// 记录关键分账参数,便于问题排查
|
||||
log.info("分账参数信息:订单={}, 商户={}, 总金额={}分, 商家比例={}, 平台比例={}, 代理商比例={}, 是否有代理商={}",
|
||||
orderId, merchantNo, splitAmount, mchRatio, platformRatio, distributorRatio,
|
||||
(distributors != null && !distributors.isEmpty()));
|
||||
log.info("[分账操作] 参数信息:订单={}, 商户={}, 总金额={}分, 商家比例={}, 平台比例={}, 代理商比例={}, 是否有代理商={}",
|
||||
orderId, merchantNo, splitAmount, merchantSplitRatio, platformSplitRatio, distributorSplitRatio,
|
||||
(distributorReceivers != null && !distributorReceivers.isEmpty()));
|
||||
|
||||
// 返回值如下:{platformAmount=6, merchantAmount=94, agentAmount=0}
|
||||
Map<String, Integer> splitAmountMap = CommonUtil.calculateProfitSharing(splitAmount, mchRatio, platformRatio, distributorRatio);
|
||||
Map<String, Integer> splitAmountMap = CommonUtil.calculateProfitSharing(splitAmount, merchantSplitRatio, platformSplitRatio, distributorSplitRatio);
|
||||
Integer merchantAmount = splitAmountMap.get("merchantAmount");
|
||||
Integer platformAmount = splitAmountMap.get("platformAmount");
|
||||
Integer agentAmount = splitAmountMap.get("agentAmount");
|
||||
|
||||
// 记录分账结果,便于问题排查
|
||||
log.info("分账金额计算结果:订单={}, 商户={}, 总金额={}分, 商家分得={}分, 平台分得={}分, 代理商分得={}分",
|
||||
log.info("[分账操作] 金额计算结果:订单={}, 商户={}, 总金额={}分, 商家分得={}分, 平台分得={}分, 代理商分得={}分",
|
||||
orderId, merchantNo, splitAmount, merchantAmount, platformAmount, agentAmount);
|
||||
|
||||
if (merchantAmount > 0) {
|
||||
@ -1725,55 +1828,55 @@ public class LakalaApiServiceImpl implements LakalaApiService {
|
||||
|
||||
if (platformAmount > 0) {
|
||||
V3SacsSeparateRecvDatas receiver = new V3SacsSeparateRecvDatas();
|
||||
receiver.setRecvNo(platform.getReceiver_no());
|
||||
receiver.setRecvNo(platformReceiver.getReceiver_no());
|
||||
receiver.setSeparateValue(platformAmount.toString());
|
||||
recvDatas.add(receiver);
|
||||
}
|
||||
|
||||
if (agentAmount > 0 && distributors != null && !distributors.isEmpty()) {
|
||||
if (agentAmount > 0 && distributorReceivers != null && !distributorReceivers.isEmpty()) {
|
||||
V3SacsSeparateRecvDatas receiver = new V3SacsSeparateRecvDatas();
|
||||
receiver.setRecvNo(distributors.get(0).getReceiver_no());
|
||||
receiver.setRecvNo(distributorReceivers.get(0).getReceiver_no());
|
||||
receiver.setSeparateValue(agentAmount.toString());
|
||||
recvDatas.add(receiver);
|
||||
}
|
||||
|
||||
// 14. 构建分账请求对象
|
||||
V3SacsSeparateRequest request = new V3SacsSeparateRequest();
|
||||
request.setMerchantNo(merchantNo);
|
||||
request.setLogNo(shopOrderLkl.getLkl_split_log_no()); // 合单和非合单的流水号保存在此字段
|
||||
request.setLogDate(shopOrderLkl.getLkl_log_date());
|
||||
request.setOutSeparateNo(shopOrderLkl.getOut_separate_no());
|
||||
request.setTotalAmt(splitAmount.toString());
|
||||
request.setLklOrgNo(orgCode);
|
||||
request.setCalType("0"); // 0- 按照指定金额,1- 按照指定比例。默认 0
|
||||
request.setNotifyUrl(projectDomain + "/api/mobile/shop/lakala/sacs/separateNotify");
|
||||
V3SacsSeparateRequest separateRequest = new V3SacsSeparateRequest();
|
||||
separateRequest.setMerchantNo(merchantNo);
|
||||
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
|
||||
separateRequest.setNotifyUrl(projectDomain + "/api/mobile/shop/lakala/sacs/separateNotify");
|
||||
|
||||
// 15. 设置分账接收方列表
|
||||
request.setRecvDatas(recvDatas);
|
||||
log.info("分账请求参数: 订单={}, 商户={}, 金额={}分, 分账接收方数量={}",
|
||||
separateRequest.setRecvDatas(recvDatas);
|
||||
log.info("[分账操作] 请求参数: 订单={}, 商户={}, 金额={}分, 分账接收方数量={}",
|
||||
orderId, merchantNo, splitAmount, recvDatas.size());
|
||||
|
||||
log.debug("分账请求详细参数: {}", JSONUtil.toJsonStr(request));
|
||||
log.debug("[分账操作] 请求详细参数: {}", JSONUtil.toJsonStr(separateRequest));
|
||||
|
||||
// 16. 发送分账请求
|
||||
log.info("向拉卡拉发送分账请求:订单={}, 商户={}, 分账流水号={}",
|
||||
orderId, merchantNo, shopOrderLkl.getLkl_split_log_no());
|
||||
String response = LKLSDK.httpPost(request);
|
||||
log.info("[分账操作] 向拉卡拉发送分账请求:订单={}, 商户={}, 分账流水号={}",
|
||||
orderId, merchantNo, shopOrderLkl.getLkl_sub_log_no());
|
||||
String response = LKLSDK.httpPost(separateRequest);
|
||||
if (StrUtil.isBlank(response)) {
|
||||
String errorMsg = String.format("拉卡拉无响应,订单=%s,商户=%s,分账流水号=%s",
|
||||
orderId, merchantNo, shopOrderLkl.getLkl_split_log_no());
|
||||
String errorMsg = String.format("[分账操作] 拉卡拉无响应,订单=%s,商户=%s,分账流水号=%s",
|
||||
orderId, merchantNo, shopOrderLkl.getLkl_sub_log_no());
|
||||
log.error(errorMsg);
|
||||
errorMessages.append(errorMsg).append("; ");
|
||||
continue;
|
||||
}
|
||||
|
||||
log.debug("分账响应结果: {}", response);
|
||||
log.debug("[分账操作] 响应结果: {}", response);
|
||||
|
||||
// 17. 解析响应结果
|
||||
JSONObject respJson = JSONUtil.parseObj(response);
|
||||
if (respJson == null || !lklSacsSuccessCode.equals(respJson.getStr("code")) || respJson.getJSONObject("resp_data") == null) {
|
||||
String errorMsg = String.format("拉卡拉返回格式异常,订单=%s,商户=%s,分账流水号=%s,响应=%s,respJson=%s",
|
||||
orderId, merchantNo, shopOrderLkl.getLkl_split_log_no(), response, respJson);
|
||||
String errorMsg = String.format("[分账操作] 拉卡拉返回格式异常,订单=%s,商户=%s,分账流水号=%s,响应=%s,respJson=%s",
|
||||
orderId, merchantNo, shopOrderLkl.getLkl_sub_log_no(), response, respJson);
|
||||
log.error(errorMsg);
|
||||
errorMessages.append(errorMsg).append("; ");
|
||||
continue;
|
||||
@ -1781,37 +1884,37 @@ public class LakalaApiServiceImpl implements LakalaApiService {
|
||||
|
||||
// 18. 保存分账记录
|
||||
JSONObject respData = respJson.getJSONObject("resp_data");
|
||||
LklOrderSeparate lklOrderSeparate = new LklOrderSeparate();
|
||||
lklOrderSeparate.setSeparate_no(respData.getStr("separate_no"));
|
||||
lklOrderSeparate.setOut_separate_no(request.getOutSeparateNo());
|
||||
lklOrderSeparate.setMerchant_no(merchantNo);
|
||||
lklOrderSeparate.setLog_no(request.getLogNo());
|
||||
lklOrderSeparate.setLog_date(request.getLogDate());
|
||||
lklOrderSeparate.setOrder_id(shopOrderLkl.getOrder_id());
|
||||
lklOrderSeparate.setTotal_amt(request.getTotalAmt());
|
||||
lklOrderSeparate.setNotify_url(request.getNotifyUrl());
|
||||
lklOrderSeparate.setLkl_org_no(request.getLklOrgNo());
|
||||
lklOrderSeparate.setRecv_datas(JSONUtil.toJsonStr(request.getRecvDatas()));
|
||||
lklOrderSeparate.setStatus(respData.getStr("status"));
|
||||
lklOrderSeparate.setTotal_separate_value(platformAmount + agentAmount);
|
||||
LklOrderSeparate separateRecord = new LklOrderSeparate();
|
||||
separateRecord.setSeparate_no(respData.getStr("separate_no"));
|
||||
separateRecord.setOut_separate_no(separateRequest.getOutSeparateNo());
|
||||
separateRecord.setMerchant_no(merchantNo);
|
||||
separateRecord.setLog_no(separateRequest.getLogNo()); // 发货完成交易流水号后14位 。分账商户用该流水号发起分账
|
||||
separateRecord.setLog_date(separateRequest.getLogDate());
|
||||
separateRecord.setOrder_id(shopOrderLkl.getOrder_id());
|
||||
separateRecord.setTotal_amt(separateRequest.getTotalAmt());
|
||||
separateRecord.setNotify_url(separateRequest.getNotifyUrl());
|
||||
separateRecord.setLkl_org_no(separateRequest.getLklOrgNo());
|
||||
separateRecord.setRecv_datas(JSONUtil.toJsonStr(separateRequest.getRecvDatas()));
|
||||
separateRecord.setStatus(respData.getStr("status"));
|
||||
separateRecord.setTotal_separate_value(platformAmount + agentAmount);
|
||||
|
||||
try {
|
||||
if (lklOrderSeparateService.addOrUpdateByReceiverNo(lklOrderSeparate)) {
|
||||
log.info("分账记录保存成功:订单={}, 分账单号={}, 状态={}, 分账流水号={}",
|
||||
orderId, lklOrderSeparate.getSeparate_no(), lklOrderSeparate.getStatus(), lklOrderSeparate.getLog_no());
|
||||
if (lklOrderSeparateService.addOrUpdateByReceiverNo(separateRecord)) {
|
||||
log.info("[分账操作] 记录保存成功:订单={}, 分账单号={}, 状态={}, 分账流水号={}",
|
||||
orderId, separateRecord.getSeparate_no(), separateRecord.getStatus(), separateRecord.getLog_no());
|
||||
successCount++;
|
||||
} else {
|
||||
String errorMsg = String.format("保存分账记录失败,订单=%s,分账单号=%s,分账流水号=%s",
|
||||
orderId, lklOrderSeparate.getSeparate_no(), lklOrderSeparate.getLog_no());
|
||||
String errorMsg = String.format("[分账操作] 保存分账记录失败,订单=%s,分账单号=%s,分账流水号=%s",
|
||||
orderId, separateRecord.getSeparate_no(), separateRecord.getLog_no());
|
||||
log.error(errorMsg);
|
||||
lklOrderSeparateService.updateRemark(lklOrderSeparate.getLog_no(), lklOrderSeparate.getSeparate_no(), errorMsg);
|
||||
lklOrderSeparateService.updateRemark(separateRecord.getLog_no(), separateRecord.getSeparate_no(), errorMsg);
|
||||
errorMessages.append(errorMsg).append("; ");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
String errorMsg = String.format("保存分账记录异常,订单=%s,分账单号=%s,流水号=%s,错误=%s",
|
||||
String errorMsg = String.format("[分账操作] 保存分账记录异常,订单=%s,分账单号=%s,流水号=%s,错误=%s",
|
||||
orderId,
|
||||
lklOrderSeparate.getSeparate_no(),
|
||||
lklOrderSeparate.getLog_no(),
|
||||
separateRecord.getSeparate_no(),
|
||||
separateRecord.getLog_no(),
|
||||
e.getMessage());
|
||||
log.error(errorMsg, e);
|
||||
errorMessages.append(errorMsg).append("; ");
|
||||
@ -1819,27 +1922,284 @@ public class LakalaApiServiceImpl implements LakalaApiService {
|
||||
}
|
||||
|
||||
// 19. 返回最终处理结果
|
||||
log.info("订单[{}]分账处理完成:总订单数={},成功处理数={}", orderId, totalCount, successCount);
|
||||
log.info("[分账操作] 处理完成:总订单数={},成功处理数={}", orderId, totalCount, successCount);
|
||||
if (successCount == 0) {
|
||||
String result = "分账全部失败: " + errorMessages;
|
||||
log.warn("订单[{}]分账结果:{}", orderId, result);
|
||||
log.warn("[分账操作] 结果:订单[{}] {}", orderId, result);
|
||||
return Pair.of(false, result);
|
||||
} else if (successCount < totalCount) {
|
||||
String result = "部分分账成功,处理中: " + errorMessages;
|
||||
log.info("订单[{}]分账结果:{}", orderId, result);
|
||||
log.info("[分账操作] 结果:订单[{}] {}", orderId, result);
|
||||
return Pair.of(true, result);
|
||||
} else {
|
||||
String result = "全部订单分账已提交处理";
|
||||
log.info("订单[{}]分账结果:{}", orderId, result);
|
||||
log.info("[分账操作] 结果:订单[{}] {}", orderId, result);
|
||||
return Pair.of(true, result);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
String errorMsg = String.format("分账系统异常,订单=%s,错误=%s", orderId, e.getMessage());
|
||||
String errorMsg = String.format("[分账操作] 系统异常,订单=%s,错误=%s", orderId, e.getMessage());
|
||||
log.error(errorMsg, e);
|
||||
return Pair.of(false, "系统异常,请稍后重试");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据商户号、交易号和收货流水号执行订单分账操作
|
||||
* <p>
|
||||
* 该方法用于处理拉卡拉订单的分账逻辑。在用户确认收货后,系统会根据订单信息执行分账操作,
|
||||
* 将订单金额按照预设比例分配给平台、商家和代理商(如果存在)。
|
||||
* </p>
|
||||
* <p>
|
||||
* 分账操作流程:
|
||||
* 1. 参数校验和订单查询
|
||||
* 2. 检查订单状态(是否已确认收货)
|
||||
* 3. 检查是否已分账,避免重复处理
|
||||
* 4. 计算分账金额
|
||||
* 5. 构建分账请求并发送至拉卡拉
|
||||
* 6. 保存分账结果
|
||||
* </p>
|
||||
*
|
||||
* @param lklMerchantNo 拉卡拉商户号
|
||||
* @param receiveTradeNo 收货交易号(对应拉卡拉的trade_no)
|
||||
* @param receiveLogNo 收货流水号(对应拉卡拉的log_no)
|
||||
* @return Pair<Boolean, String> 处理结果对,first为是否成功,second为结果描述信息
|
||||
*/
|
||||
@Transactional
|
||||
@Override
|
||||
public Pair<Boolean, String> innerDoOrderSeparateByMerchantAndLogNo(String lklMerchantNo, String receiveTradeNo, String receiveLogNo) {
|
||||
// 1. 输入参数校验
|
||||
if (StrUtil.isBlank(lklMerchantNo) || StrUtil.isBlank(receiveTradeNo) || StrUtil.isBlank(receiveLogNo)) {
|
||||
log.warn("[分账操作] 参数校验失败:缺少必要参数, merchantNo={}, tradeNo={}, logNo={}",
|
||||
lklMerchantNo, receiveTradeNo, receiveLogNo);
|
||||
return Pair.of(false, "缺少必要参数");
|
||||
}
|
||||
|
||||
try {
|
||||
log.info("[分账操作] 开始处理分账请求, merchantNo={}, tradeNo={}, logNo={}",
|
||||
lklMerchantNo, receiveTradeNo, receiveLogNo);
|
||||
|
||||
// TODO 检查可分账余额是否足够?
|
||||
|
||||
// 2. 查询订单信息
|
||||
ShopOrderLkl shopOrderLkl = shopOrderLklService.getByMerchantNoAndTradeNoAndSubLogNo(lklMerchantNo, receiveTradeNo, receiveLogNo);
|
||||
if (shopOrderLkl == null) {
|
||||
log.warn("[分账操作] 失败:对账流水号[{}]不存在", receiveLogNo);
|
||||
return Pair.of(false, "订单不存在");
|
||||
}
|
||||
|
||||
String orderId = shopOrderLkl.getOrder_id();
|
||||
log.info("[分账操作] 开始处理订单[{}]的分账", orderId);
|
||||
|
||||
log.debug("[分账操作] 处理子订单:storeId={}, receive_log_no={}", shopOrderLkl.getStore_id(), shopOrderLkl.getLkl_receive_log_no());
|
||||
|
||||
// 3. 检查是否已确认收货
|
||||
if (!CommonConstant.Enable.equals(shopOrderLkl.getReceive_status()) || StrUtil.isBlank(shopOrderLkl.getLkl_receive_log_no())) {
|
||||
log.warn("[分账操作] 订单[{}]对账流水号[{}]未被确认收货,跳过处理", orderId, shopOrderLkl.getLkl_receive_log_no());
|
||||
return Pair.of(false, "订单未确认收货");
|
||||
}
|
||||
|
||||
// 4. 检查分账状态,避免重复处理
|
||||
LklOrderSeparate existingSeparateRecord = lklOrderSeparateService.getByOutTradeNo(shopOrderLkl.getLkl_sub_log_no(), shopOrderLkl.getOut_separate_no());
|
||||
if (existingSeparateRecord != null) {
|
||||
String status = existingSeparateRecord.getStatus();
|
||||
if ("SUCCESS".equals(status)) {
|
||||
log.info("[分账操作] 订单[{}]子订单[{}]已完成分账,跳过处理", orderId, shopOrderLkl.getLkl_log_no());
|
||||
return Pair.of(true, "订单已处理");
|
||||
}
|
||||
if ("PROCESSING".equals(status) || "ACCEPTED".equals(status)) {
|
||||
log.info("[分账操作] 订单[{}]子订单[{}]分账处理中或已受理,跳过处理", orderId, shopOrderLkl.getLkl_log_no());
|
||||
return Pair.of(true, "订单已处理中或已受理");
|
||||
}
|
||||
}
|
||||
|
||||
// 5. 获取订单分账相关参数
|
||||
String merchantNo = shopOrderLkl.getLkl_merchant_no();
|
||||
|
||||
// 分账金额 = 应付总金额-运费(支付时已计算好)
|
||||
Integer splitAmount = shopOrderLkl.getSplit_amt();
|
||||
splitAmount = CheckUtil.isEmpty(splitAmount) ? 0 : splitAmount;
|
||||
|
||||
// 6. 分账金额校验
|
||||
if (splitAmount < 1) {
|
||||
String errorMsg = String.format("[分账操作] 店铺[%s]订单[%s]分账金额[%d]低于1分钱,跳过分账",
|
||||
shopOrderLkl.getStore_id(), orderId, splitAmount);
|
||||
log.error(errorMsg);
|
||||
if (existingSeparateRecord != null) {
|
||||
lklOrderSeparateService.updateRemark(existingSeparateRecord.getId(), errorMsg);
|
||||
}
|
||||
return Pair.of(false, "订单分账金额低于1分钱");
|
||||
}
|
||||
|
||||
// 7. 获取分账平台接收方信息
|
||||
LklLedgerMerReceiverBind platformReceiver = lklLedgerMerReceiverBindService.getPlatformByMerCupNo(merchantNo);
|
||||
if (platformReceiver == null) {
|
||||
String errorMsg = String.format("[分账操作] 店铺[%s]未绑定平台方接收账户,跳过分账", shopOrderLkl.getStore_id());
|
||||
log.error(errorMsg);
|
||||
return Pair.of(false, "平台方未绑定账户");
|
||||
}
|
||||
|
||||
// 8. 构建分账接收方列表
|
||||
List<V3SacsSeparateRecvDatas> recvDatas = new ArrayList<>();
|
||||
|
||||
// 9. 获取商家分账比例并校验
|
||||
BigDecimal merchantSplitRatioRaw = shopOrderLkl.getSplit_ratio();
|
||||
// 判断商家分账比例是否有效(必须在(0, 100]范围内)
|
||||
boolean canSplitForMerchant = merchantSplitRatioRaw != null
|
||||
&& merchantSplitRatioRaw.compareTo(BigDecimal.ZERO) > 0
|
||||
&& merchantSplitRatioRaw.compareTo(new BigDecimal(100)) <= 0;
|
||||
if (!canSplitForMerchant) {
|
||||
String errorMsg = String.format("[分账操作] 店铺[%s]商家分账比例[%s]不在(0-100]范围内,无法分账",
|
||||
shopOrderLkl.getStore_id(), merchantSplitRatioRaw);
|
||||
log.error(errorMsg);
|
||||
return Pair.of(false, "商家分账比例无效");
|
||||
}
|
||||
|
||||
// 10. 计算商家分账比例(转换为小数)
|
||||
BigDecimal merchantSplitRatio = merchantSplitRatioRaw.divide(new BigDecimal(100));
|
||||
|
||||
// 11. 获取代理商分账信息
|
||||
BigDecimal distributorSplitRatio = BigDecimal.ZERO;
|
||||
BigDecimal platformSplitRatio = BigDecimal.ONE;
|
||||
List<LklLedgerMerReceiverBind> distributorReceivers = lklLedgerMerReceiverBindService.selectDistributorByMerCupNo(merchantNo);
|
||||
if (distributorReceivers != null && !distributorReceivers.isEmpty()) {
|
||||
distributorSplitRatio = new BigDecimal("0.8");
|
||||
platformSplitRatio = new BigDecimal("0.2");
|
||||
log.debug("[分账操作] 检测到代理商存在,调整分账比例: 代理商比例={}, 平台比例={}", distributorSplitRatio, platformSplitRatio);
|
||||
}
|
||||
|
||||
// 12. 记录关键分账参数,便于问题排查
|
||||
log.info("[分账操作] 参数信息:订单={}, 商户={}, 总金额={}分, 商家比例={}, 平台比例={}, 代理商比例={}, 是否有代理商={}",
|
||||
orderId, merchantNo, splitAmount, merchantSplitRatio, platformSplitRatio, distributorSplitRatio,
|
||||
(distributorReceivers != null && !distributorReceivers.isEmpty()));
|
||||
|
||||
// 13. 计算各参与方分账金额
|
||||
Map<String, Integer> splitAmountMap = CommonUtil.calculateProfitSharing(splitAmount, merchantSplitRatio, platformSplitRatio, distributorSplitRatio);
|
||||
Integer merchantAmount = splitAmountMap.get("merchantAmount");
|
||||
Integer platformAmount = splitAmountMap.get("platformAmount");
|
||||
Integer agentAmount = splitAmountMap.get("agentAmount");
|
||||
|
||||
// 14. 记录分账结果,便于问题排查
|
||||
log.info("[分账操作] 金额计算结果:订单={}, 商户={}, 总金额={}分, 商家分得={}分, 平台分得={}分, 代理商分得={}分",
|
||||
orderId, merchantNo, splitAmount, merchantAmount, platformAmount, agentAmount);
|
||||
|
||||
// 15. 构建分账接收方列表
|
||||
if (merchantAmount > 0) {
|
||||
V3SacsSeparateRecvDatas receiver = new V3SacsSeparateRecvDatas();
|
||||
receiver.setRecvMerchantNo(merchantNo);
|
||||
receiver.setSeparateValue(merchantAmount.toString());
|
||||
recvDatas.add(receiver);
|
||||
log.debug("[分账操作] 添加商家接收方: merchantNo={}, amount={}", merchantNo, merchantAmount);
|
||||
}
|
||||
|
||||
if (platformAmount > 0) {
|
||||
V3SacsSeparateRecvDatas receiver = new V3SacsSeparateRecvDatas();
|
||||
receiver.setRecvNo(platformReceiver.getReceiver_no());
|
||||
receiver.setSeparateValue(platformAmount.toString());
|
||||
recvDatas.add(receiver);
|
||||
log.debug("[分账操作] 添加平台接收方: receiverNo={}, amount={}", platformReceiver.getReceiver_no(), platformAmount);
|
||||
}
|
||||
|
||||
if (agentAmount > 0 && distributorReceivers != null && !distributorReceivers.isEmpty()) {
|
||||
V3SacsSeparateRecvDatas receiver = new V3SacsSeparateRecvDatas();
|
||||
receiver.setRecvNo(distributorReceivers.get(0).getReceiver_no());
|
||||
receiver.setSeparateValue(agentAmount.toString());
|
||||
recvDatas.add(receiver);
|
||||
log.debug("[分账操作] 添加代理商接收方: receiverNo={}, amount={}", distributorReceivers.get(0).getReceiver_no(), agentAmount);
|
||||
}
|
||||
|
||||
// 16. 初始化拉卡拉SDK
|
||||
log.debug("[分账操作] 初始化拉卡拉SDK");
|
||||
initLKLSDK();
|
||||
|
||||
// 17. 构建分账请求对象
|
||||
V3SacsSeparateRequest separateRequest = new V3SacsSeparateRequest();
|
||||
separateRequest.setMerchantNo(merchantNo);
|
||||
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
|
||||
separateRequest.setNotifyUrl(projectDomain + "/api/mobile/shop/lakala/sacs/separateNotify");
|
||||
|
||||
// 18. 设置分账接收方列表
|
||||
separateRequest.setRecvDatas(recvDatas);
|
||||
log.info("[分账操作] 请求参数: 订单={}, 商户={}, 金额={}分, 分账接收方数量={}",
|
||||
orderId, merchantNo, splitAmount, recvDatas.size());
|
||||
|
||||
log.debug("[分账操作] 请求详细参数: {}", JSONUtil.toJsonStr(separateRequest));
|
||||
|
||||
// 19. 发送分账请求
|
||||
log.info("[分账操作] 向拉卡拉发送分账请求:订单={}, 商户={}, 分账流水号={}",
|
||||
orderId, merchantNo, shopOrderLkl.getLkl_receive_log_no());
|
||||
String response = LKLSDK.httpPost(separateRequest);
|
||||
if (StrUtil.isBlank(response)) {
|
||||
String errorMsg = String.format("[分账操作] 拉卡拉无响应,订单=%s,商户=%s,分账流水号=%s",
|
||||
orderId, merchantNo, shopOrderLkl.getLkl_receive_log_no());
|
||||
log.error(errorMsg);
|
||||
return Pair.of(false, "拉卡拉无响应");
|
||||
}
|
||||
|
||||
log.debug("[分账操作] 响应结果: {}", response);
|
||||
|
||||
// 20. 解析响应结果
|
||||
JSONObject respJson = JSONUtil.parseObj(response);
|
||||
if (respJson == null || !lklSacsSuccessCode.equals(respJson.getStr("code")) || respJson.getJSONObject("resp_data") == null) {
|
||||
String errorMsg = String.format("[分账操作] 拉卡拉返回格式异常,订单=%s,商户=%s,分账流水号=%s,响应=%s,respJson=%s",
|
||||
orderId, merchantNo, shopOrderLkl.getLkl_receive_log_no(), response, respJson);
|
||||
log.error(errorMsg);
|
||||
return Pair.of(false, "拉卡拉返回格式异常");
|
||||
}
|
||||
|
||||
// 21. 保存分账记录
|
||||
JSONObject respData = respJson.getJSONObject("resp_data");
|
||||
LklOrderSeparate separateRecord = new LklOrderSeparate();
|
||||
separateRecord.setSeparate_no(respData.getStr("separate_no"));
|
||||
separateRecord.setOut_separate_no(separateRequest.getOutSeparateNo());
|
||||
separateRecord.setMerchant_no(merchantNo);
|
||||
separateRecord.setLog_no(separateRequest.getLogNo());
|
||||
separateRecord.setLog_date(separateRequest.getLogDate());
|
||||
separateRecord.setOrder_id(shopOrderLkl.getOrder_id());
|
||||
separateRecord.setTotal_amt(separateRequest.getTotalAmt());
|
||||
separateRecord.setNotify_url(separateRequest.getNotifyUrl());
|
||||
separateRecord.setLkl_org_no(separateRequest.getLklOrgNo());
|
||||
separateRecord.setRecv_datas(JSONUtil.toJsonStr(separateRequest.getRecvDatas()));
|
||||
separateRecord.setStatus(respData.getStr("status"));
|
||||
separateRecord.setTotal_separate_value(platformAmount + agentAmount);
|
||||
|
||||
try {
|
||||
if (lklOrderSeparateService.addOrUpdateByReceiverNo(separateRecord)) {
|
||||
log.info("[分账操作] 记录保存成功:订单={}, 分账单号={}, 状态={}, 分账流水号={}",
|
||||
orderId, separateRecord.getSeparate_no(), separateRecord.getStatus(), separateRecord.getLog_no());
|
||||
} else {
|
||||
String errorMsg = String.format("[分账操作] 保存分账记录失败,订单=%s,分账单号=%s,分账流水号=%s",
|
||||
orderId, separateRecord.getSeparate_no(), separateRecord.getLog_no());
|
||||
log.error(errorMsg);
|
||||
lklOrderSeparateService.updateRemark(separateRecord.getLog_no(), separateRecord.getSeparate_no(), errorMsg);
|
||||
return Pair.of(false, "保存分账记录失败");
|
||||
}
|
||||
|
||||
String result = "订单分账已提交处理";
|
||||
log.info("[分账操作] 结果:订单[{}] {}", orderId, result);
|
||||
return Pair.of(true, result);
|
||||
} catch (Exception e) {
|
||||
String errorMsg = String.format("[分账操作] 保存分账记录异常,订单=%s,分账单号=%s,流水号=%s,错误=%s",
|
||||
orderId,
|
||||
separateRecord.getSeparate_no(),
|
||||
separateRecord.getLog_no(),
|
||||
e.getMessage());
|
||||
log.error(errorMsg, e);
|
||||
return Pair.of(false, "保存分账记录异常");
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
String errorMsg = String.format("[分账操作] 系统异常,分账对账流水号=%s,错误=%s", receiveLogNo, e.getMessage());
|
||||
log.error(errorMsg, e);
|
||||
return Pair.of(false, "系统异常,请稍后重试");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 拉卡拉分账结果通知处理
|
||||
* <p>
|
||||
|
||||
@ -63,4 +63,14 @@ public interface ShopOrderLklService extends IBaseService<ShopOrderLkl> {
|
||||
* @return
|
||||
*/
|
||||
List<ShopOrderLkl> selectByOrderId(String orderId, String lklLogNo, String storeId);
|
||||
|
||||
/**
|
||||
* 根据商户号、商户订单号、子商户订单号查询一条记录
|
||||
*
|
||||
* @param lklMerchantNo
|
||||
* @param lklTradeNo
|
||||
* @param lklSubLogNo
|
||||
* @return
|
||||
*/
|
||||
ShopOrderLkl getByMerchantNoAndTradeNoAndSubLogNo(String lklMerchantNo, String lklTradeNo, String lklSubLogNo);
|
||||
}
|
||||
|
||||
@ -4961,10 +4961,10 @@ public class ShopOrderBaseServiceImpl extends BaseServiceImpl<ShopOrderBaseMappe
|
||||
}
|
||||
|
||||
// 重要;拉卡拉给平台和代理商分账
|
||||
Pair<Boolean, String> retOrderSeparateRet = lakalaApiService.innerDoOrderSeparate(order_row.getOrder_id(), Convert.toStr(order_row.getStore_id()));
|
||||
if (!retOrderSeparateRet.getFirst()) {
|
||||
throw new ApiException(I18nUtil._("平台或代理商分账失败: " + retOrderSeparateRet.getSecond()));
|
||||
}
|
||||
// Pair<Boolean, String> retOrderSeparateRet = lakalaApiService.innerDoOrderSeparate(order_row.getOrder_id(), Convert.toStr(order_row.getStore_id()));
|
||||
// if (!retOrderSeparateRet.getFirst()) {
|
||||
// throw new ApiException(I18nUtil._("平台或代理商分账失败: " + retOrderSeparateRet.getSecond()));
|
||||
// }
|
||||
|
||||
// 统计总营业额
|
||||
ShopStoreAnalytics analytics_row = shopStoreAnalyticsService.get(store_id);
|
||||
|
||||
@ -183,6 +183,7 @@ public class ShopOrderLklServiceImpl extends BaseServiceImpl<ShopOrderLklMapper,
|
||||
record.setAccount_type(JsonUtil.getJsonValueSmart(reqDataJson, "accountType"));
|
||||
record.setTrans_type(JsonUtil.getJsonValueSmart(reqDataJson, "transType"));
|
||||
record.setNotify_url(JsonUtil.getJsonValueSmart(reqDataJson, "notifyUrl"));
|
||||
record.setReceive_notify_url(JsonUtil.getJsonValueSmart(reqDataJson, "complete_notify_url"));
|
||||
record.setLkl_merchant_no(JsonUtil.getJsonValueSmart(reqDataJson, "merchantNo"));
|
||||
record.setLkl_term_no(JsonUtil.getJsonValueSmart(reqDataJson, "termNo"));
|
||||
record.setLkl_req(JSONUtil.toJsonStr(reqDataJson));
|
||||
@ -235,10 +236,10 @@ public class ShopOrderLklServiceImpl extends BaseServiceImpl<ShopOrderLklMapper,
|
||||
record.setLkl_trade_no(lklPayNotifyDataJson.getStr("trade_no"));
|
||||
record.setTrade_status(lklPayNotifyDataJson.getStr("trade_status"));
|
||||
|
||||
// 新增的订单字段,lkl_split_log_no,out_separate_no,split_amt 三字段无值,就给主单的值
|
||||
record.setLkl_split_log_no(JsonUtil.getJsonValueSmart(lklPayNotifyDataJson, "split_log_no"));
|
||||
if (CheckUtil.isEmpty(record.getLkl_split_log_no())) {
|
||||
record.setLkl_split_log_no(logNo);
|
||||
// 新增的订单字段,lkl_sub_log_no,out_separate_no,split_amt 三字段无值,就给主单的值
|
||||
record.setLkl_sub_log_no(JsonUtil.getJsonValueSmart(lklPayNotifyDataJson, "split_log_no"));
|
||||
if (CheckUtil.isEmpty(record.getLkl_sub_log_no())) {
|
||||
record.setLkl_sub_log_no(logNo);
|
||||
}
|
||||
|
||||
record.setOut_separate_no(JsonUtil.getJsonValueSmart(lklPayNotifyDataJson, "out_separate_no"));
|
||||
@ -292,4 +293,56 @@ public class ShopOrderLklServiceImpl extends BaseServiceImpl<ShopOrderLklMapper,
|
||||
return CollectionUtil.newArrayList();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据商户号、商户订单号、子商户订单号查询一条记录
|
||||
*
|
||||
* @param lklMerchantNo 拉卡拉商户号
|
||||
* @param lklTradeNo 拉卡拉交易号
|
||||
* @param lklSubLogNo 拉卡拉子订单流水号
|
||||
* @return ShopOrderLkl 拉卡拉订单记录
|
||||
*/
|
||||
@Override
|
||||
public ShopOrderLkl getByMerchantNoAndTradeNoAndSubLogNo(String lklMerchantNo, String lklTradeNo, String lklSubLogNo) {
|
||||
// 检查参数是否全部为空
|
||||
if (StringUtils.isAllBlank(lklMerchantNo, lklTradeNo, lklSubLogNo)) {
|
||||
log.warn("[拉卡拉订单查询] 参数校验失败:所有查询条件均为空");
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
log.debug("[拉卡拉订单查询] 开始查询, merchantNo={}, tradeNo={}, subLogNo={}",
|
||||
lklMerchantNo, lklTradeNo, lklSubLogNo);
|
||||
|
||||
QueryWrapper<ShopOrderLkl> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.orderByAsc("id");
|
||||
|
||||
// 根据非空参数构建查询条件
|
||||
if (StrUtil.isNotBlank(lklMerchantNo)) {
|
||||
queryWrapper.eq("lkl_merchant_no", lklMerchantNo);
|
||||
log.debug("[拉卡拉订单查询] 添加商户号查询条件: {}", lklMerchantNo);
|
||||
}
|
||||
|
||||
if (StrUtil.isNotBlank(lklTradeNo)) {
|
||||
queryWrapper.eq("lkl_trade_no", lklTradeNo);
|
||||
log.debug("[拉卡拉订单查询] 添加交易号查询条件: {}", lklTradeNo);
|
||||
}
|
||||
|
||||
if (StrUtil.isNotBlank(lklSubLogNo)) {
|
||||
queryWrapper.eq("lkl_sub_log_no", lklSubLogNo);
|
||||
log.debug("[拉卡拉订单查询] 添加子订单流水号查询条件: {}", lklSubLogNo);
|
||||
}
|
||||
|
||||
ShopOrderLkl result = findOne(queryWrapper);
|
||||
|
||||
log.debug("[拉卡拉订单查询] 查询完成, merchantNo={}, tradeNo={}, subLogNo={}, found={}",
|
||||
lklMerchantNo, lklTradeNo, lklSubLogNo, result != null);
|
||||
|
||||
return result;
|
||||
} catch (Exception e) {
|
||||
log.error("[拉卡拉订单查询] 系统异常, merchantNo={}, tradeNo={}, subLogNo={}",
|
||||
lklMerchantNo, lklTradeNo, lklSubLogNo, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1011,9 +1011,9 @@ public class SFExpressApiServiceImpl implements SFExpressApiService {
|
||||
return new ThirdApiRes().fail(-1, "返回数据转换失败!");
|
||||
}
|
||||
|
||||
String orderId = shopStoreSfOrder.getShop_order_id();
|
||||
|
||||
ShopStoreSfOrder order = shopStoreSfOrderService.getBySfOrderId(orderId);
|
||||
String sfOrderId = shopStoreSfOrder.getSf_order_id();
|
||||
ShopStoreSfOrder order = shopStoreSfOrderService.getBySfOrderId(sfOrderId);
|
||||
if (order == null) {
|
||||
return new ThirdApiRes().fail(-1, "订单不存在!");
|
||||
}
|
||||
@ -1067,6 +1067,8 @@ public class SFExpressApiServiceImpl implements SFExpressApiService {
|
||||
// 订单确认收货
|
||||
shopOrderBaseService.receive(shopStoreSfOrder.getShop_order_id(), null);
|
||||
|
||||
String orderId = shopStoreSfOrder.getShop_order_id();
|
||||
|
||||
// 消息推送
|
||||
JSONObject payload = new JSONObject();
|
||||
payload.put("category", CommonConstant.PUSH_MSG_CATE_MCH_ORDER_DETAIL);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user