修正顺丰退款的问题,全部退款或退部分款必须可用。

This commit is contained in:
Jack 2025-09-13 21:31:35 +08:00
parent 52e5f24913
commit 5da423e50b
12 changed files with 497 additions and 297 deletions

View File

@ -74,6 +74,8 @@ public class ShopOrderLkl implements Serializable {
private String lkl_term_no;
private String wx_transaction_id; // 微信用户交易单号, 确认收货时使用
private String notify_url;
private String receive_notify_url;

View File

@ -473,10 +473,12 @@
<includeSystemScope>true</includeSystemScope>
</configuration>
</plugin>
<plugin>
<groupId>com.spotify</groupId>
<artifactId>docker-maven-plugin</artifactId>
</plugin>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.1.0</version>

View File

@ -569,36 +569,47 @@ public class LakalaApiServiceImpl implements LakalaApiService {
/**
* 商户分账业务开通申请
*
* @param merCupNo
* @return
* <p>向拉卡拉提交商户分账业务开通申请包括上传分账授权委托书等必要文件
*
* @param merCupNo 拉卡拉商户号银联商户号
* @return Pair对象第一个元素表示操作是否成功第二个元素为操作结果信息
*/
@Override
public Pair<Boolean, String> innerApplyLedgerMer(String merCupNo) {
log.debug("商户分账业务申请开始");
log.info("开始执行商户分账业务申请流程,商户号: {}", merCupNo);
// 参数校验
if (StringUtils.isBlank(merCupNo)) {
log.warn("商户分账业务申请失败:商户号不能为空");
return Pair.of(false, I18nUtil._("商户号不能为空!"));
}
// 获取商户入驻记录
log.debug("开始查询商户入驻信息,商户号: {}", merCupNo);
ShopMchEntry shopMchEntry = shopMchEntryService.getShopMerchEntryByMerCupNo(merCupNo);
if (shopMchEntry == null) {
log.warn("商户分账业务申请失败:商家入驻信息不存在,商户号: {}", merCupNo);
return Pair.of(false, I18nUtil._("商家入驻信息不存在!"));
}
// 判断是否已经申请过
log.debug("检查商户是否已申请过分账业务,商户号: {}", merCupNo);
LklLedgerMember lklLedgerMember = lklLedgerMemberService.getByMerCupNo(merCupNo);
if (lklLedgerMember != null && lklLedgerMember.getAudit_status() == 1) {
if (lklLedgerMember != null && Integer.valueOf(1).equals(lklLedgerMember.getAudit_status())) {
log.info("商户已申请过分账业务,无需重复申请,商户号: {}", merCupNo);
return Pair.of(true, I18nUtil._("商家已经申请过了!"));
}
// 检查更新店铺初始化状态
log.debug("检查并更新店铺初始化状态商户ID: {}", shopMchEntry.getId());
shopMchEntryService.checkMchEntryStoreStatus(shopMchEntry.getId(), shopMchEntry);
// 1. 配置初始化
log.debug("初始化拉卡拉SDK");
initLKLSDK();
//2. 装配数据
log.debug("装配分账业务申请请求参数");
V2MmsOpenApiLedgerApplyLedgerMerRequest req = new V2MmsOpenApiLedgerApplyLedgerMerRequest();
req.setVersion("2.0");
req.setOrderNo(StringUtils.genLklOrderNo(8));// 14位年月日时24小时制分秒+8位的随机数
@ -624,26 +635,32 @@ public class LakalaApiServiceImpl implements LakalaApiService {
String retUrl = domain + "/mobile/shop/lakala/ledger/applyLedgerMerNotify";
req.setRetUrl(retUrl);
log.debug("商户分账业务申请请求参数:{}", JSONUtil.toJsonStr(req));
log.debug("商户分账业务申请请求参数: {}", JSONUtil.toJsonStr(req));
try {
//3. 发送请求
log.info("开始向拉卡拉提交分账业务申请,订单号: {}", req.getOrderNo());
String responseStr = LKLSDK.httpPost(req);
if (StrUtil.isBlank(responseStr)) {
log.error("申请拉卡拉分账业务无返回值,订单号: {}", req.getOrderNo());
return Pair.of(false, I18nUtil._("申请拉卡拉分账业务无返回值!"));
}
log.debug("商户分账业务申请响应数据:{}", responseStr);
log.debug("商户分账业务申请响应数据: {}", responseStr);
// 成功返回示例{'retCode':'000000','retMsg':'申请已受理请等待审核结果','respData':{'version':'1.0','orderNo':'KFPT20230223181025407788734','orgCode':'1','applyId':681201215598657536}}
JSONObject lakalaRespJSON = JSONUtil.parseObj(responseStr);
if (lakalaRespJSON == null) {
log.error("申请拉卡拉分账业务返回值异常,订单号: {}", req.getOrderNo());
return Pair.of(false, I18nUtil._("申请拉卡拉分账业务返回值异常!"));
}
Object applyId = lakalaRespJSON.getByPath("respData.applyId");
if (!lakalaRespJSON.getStr("retCode").equals(lklSuccessCode) || applyId == null) {
return Pair.of(false, lakalaRespJSON.getStr("retMsg"));
if (!lklSuccessCode.equals(lakalaRespJSON.getStr("retCode")) || applyId == null) {
String retMsg = lakalaRespJSON.getStr("retMsg");
log.warn("拉卡拉分账业务申请被拒绝,订单号: {},返回码: {},返回信息: {}",
req.getOrderNo(), lakalaRespJSON.getStr("retCode"), retMsg);
return Pair.of(false, retMsg);
}
JSONObject paramsJSON = new JSONObject();
@ -670,15 +687,21 @@ public class LakalaApiServiceImpl implements LakalaApiService {
// 新增数据
// JSON 对象的键名转换为下划线命名
log.debug("准备保存分账业务申请记录");
LklLedgerMember lklLedgerMemberNew = JSONUtil.toBean(StringUtils.convertCamelToSnake(paramsJSON.toString()), LklLedgerMember.class);
if (!lklLedgerMemberService.addOrUpdateByMerCupNo(lklLedgerMemberNew)) {
log.error("新增或更改拉卡拉分账业务申请信息失败,订单号: {}", req.getOrderNo());
return Pair.of(false, I18nUtil._("新增或更改拉卡拉分账业务申请信息失败!"));
}
log.info("商户分账业务申请提交成功,等待审核,订单号: {}申请ID: {}", req.getOrderNo(), applyId);
return Pair.of(true, I18nUtil._("商户申请拉卡拉分账业务,提交成功,待审核中!"));
} catch (SDKException e) {
log.error("申请拉卡拉分账业务出错", e);
log.error("申请拉卡拉分账业务出错,订单号: {}", req.getOrderNo(), e);
return Pair.of(false, I18nUtil._("申请拉卡拉分账业务出错!"));
} catch (Exception e) {
log.error("申请拉卡拉分账业务出现未预期异常,订单号: {}", req.getOrderNo(), e);
return Pair.of(false, I18nUtil._("申请拉卡拉分账业务出现未预期异常!"));
}
}
@ -1359,49 +1382,56 @@ public class LakalaApiServiceImpl implements LakalaApiService {
/**
* 内部调用分账关系绑定申请优化版
* 参考https://o.lakala.com/#/home/document/detail?id=386
*
* @param paramsJSON 包含绑定参数的JSON对象 {merCupNo}
* @return 操作结果及提示信息
*/
/**
* 内部调用分账关系绑定申请优化版
* 参考https://o.lakala.com/#/home/document/detail?id=386
* <p>参考https://o.lakala.com/#/home/document/detail?id=386
* 为商户绑定分账接收方包括平台方和代理商如有
*
* @param paramsJSON 包含绑定参数的JSON对象 {merCupNo}
* @return 操作结果及提示信息
* @return Pair对象第一个元素表示操作是否成功第二个元素为操作结果信息
*/
public Pair<Boolean, String> innerApplyLedgerMerReceiverBind(JSONObject paramsJSON) {
log.debug("商家绑定分账接收方申请开始:{}", paramsJSON);
log.info("开始执行商家绑定分账接收方申请");
// 1. 参数校验提前失败
if (paramsJSON == null) {
log.warn("商家绑定分账接收方申请失败:绑定参数为空");
return Pair.of(false, I18nUtil._("绑定参数为空"));
}
String merCupNo = paramsJSON.getStr("merCupNo");
if (StrUtil.isBlank(merCupNo)) {
log.warn("商家绑定分账接收方申请失败商户号merCupNo为空");
return Pair.of(false, I18nUtil._("商户号merCupNo为空"));
}
log.debug("商家绑定分账接收方申请参数:{}", paramsJSON);
// 2. 基础数据查询提前失败
log.debug("开始查询商户入驻信息,商户号: {}", merCupNo);
ShopMchEntry shopMchEntry = shopMchEntryService.getShopMerchEntryByMerCupNo(merCupNo);
if (shopMchEntry == null) {
log.warn("商家绑定分账接收方申请失败:商户入驻记录不存在,商户号: {}", merCupNo);
return Pair.of(false, I18nUtil._("商户入驻记录不存在"));
}
// 进件记录
log.debug("开始查询分账业务申请记录,商户号: {}", merCupNo);
LklLedgerMember lklLedgerMember = lklLedgerMemberService.getByMerCupNo(merCupNo);
if (lklLedgerMember == null || !CommonConstant.Enable.equals(lklLedgerMember.getAudit_status())) {
log.warn("商家绑定分账接收方申请失败:商家尚未申请分账业务或审核未通过,商户号: {}", merCupNo);
return Pair.of(false, I18nUtil._("商家尚未申请分账业务"));
}
// 分账接收方列表
log.debug("开始查询分账接收方列表");
List<LklLedgerReceiver> receiverList = lklLedgerReceiverService.selectPlatformAnDistributorList();
if (CollectionUtil.isEmpty(receiverList)) {
log.warn("商家绑定分账接收方申请失败:分账接收方信息为空");
return Pair.of(false, I18nUtil._("分账接收方信息为空"));
}
log.info("获取到 {} 个分账接收方,开始处理绑定申请", receiverList.size());
// 3. 公共参数准备避免循环内重复计算
// 正式上线的时候调整 api 地址
String domain = projectDomain;
@ -1418,19 +1448,26 @@ public class LakalaApiServiceImpl implements LakalaApiService {
int totalCount = receiverList.size();
// 5. 初始化SDK建议移至类初始化或统一配置
log.debug("初始化拉卡拉SDK");
initLKLSDK();
// 4. 循环处理接收方绑定
for (LklLedgerReceiver receiver : receiverList) {
try {
log.debug("开始处理分账接收方绑定,接收方编号: {}", receiver.getReceiver_no());
// 跳过已存在的绑定关系
if (lklLedgerMerReceiverBindService.getByCondition(merCupNo, receiver.getReceiver_no()) != null) {
log.warn("分账绑定关系已存在merCupNo={}, receiverNo={}", merCupNo, receiver.getReceiver_no());
LklLedgerMerReceiverBind existingBind = lklLedgerMerReceiverBindService.getByCondition(merCupNo, receiver.getReceiver_no());
if (existingBind != null) {
log.info("分账绑定关系已存在跳过处理merCupNo={}, receiverNo={}", merCupNo, receiver.getReceiver_no());
successCount++; // 已存在的绑定视为成功
continue;
}
// 6. 构建请求参数
String orderNo = StringUtils.genLklOrderNo(8);
log.debug("生成订单号: {}", orderNo);
V2MmsOpenApiLedgerApplyBindRequest request = new V2MmsOpenApiLedgerApplyBindRequest();
request.setOrderNo(orderNo);
request.setOrgCode(orgCode);
@ -1443,17 +1480,23 @@ public class LakalaApiServiceImpl implements LakalaApiService {
request.setRetUrl(retUrl);
// 7. 记录请求参数
log.debug("商家绑定分账接收方参数:{}", JSONUtil.toJsonStr(request));
log.debug("商家绑定分账接收方请求参数:{}", JSONUtil.toJsonStr(request));
// 8. 发送请求并处理响应
log.info("向拉卡拉提交分账接收方绑定申请,订单号: {},商户号: {},接收方: {}",
orderNo, merCupNo, receiver.getReceiver_no());
String responseStr = LKLSDK.httpPost(request);
JSONObject respJson = JSONUtil.parseObj(responseStr);
if (respJson == null || !lklSuccessCode.equals(respJson.getStr("retCode"))) {
log.error("绑定接收方拉卡拉响应失败:{}", respJson != null ? respJson.getStr("retMsg") : "无响应数据");
String errorMsg = respJson != null ? respJson.getStr("retMsg") : "无响应数据";
log.error("绑定接收方拉卡拉响应失败,订单号: {},错误信息: {}", orderNo, errorMsg);
continue; // 单个失败不影响其他接收方处理
}
log.info("拉卡拉分账接收方绑定申请提交成功,订单号: {}申请ID: {}",
orderNo, respJson.getByPath("respData.applyId"));
// 9. 更新参数并保存记录
paramsJSON.set("orderNo", orderNo);
paramsJSON.set("apply_id", respJson.getByPath("respData.applyId"));
@ -1468,20 +1511,25 @@ public class LakalaApiServiceImpl implements LakalaApiService {
String snakeJson = StringUtils.convertCamelToSnake(paramsJSON.toString());
LklLedgerMerReceiverBind bindRecord = JSONUtil.toBean(snakeJson, LklLedgerMerReceiverBind.class);
log.debug("准备保存分账绑定记录");
if (lklLedgerMerReceiverBindService.addOrUpdateByMerCupNoReceiverNo(bindRecord)) {
successCount++;
log.info("分账绑定记录保存成功,订单号: {}", orderNo);
} else {
log.warn("绑定记录保存失败merCupNo={}, receiverNo={}", merCupNo, receiver.getReceiver_no());
log.warn("分账绑定记录保存失败,订单号: {},商户号: {},接收方: {}",
orderNo, merCupNo, receiver.getReceiver_no());
}
} catch (Exception e) {
log.error("处理分账绑定失败merCupNo={}, receiverNo={}", merCupNo, receiver.getReceiver_no(), e);
log.error("处理分账绑定异常,商户号: {},接收方: {}", merCupNo, receiver.getReceiver_no(), e);
// 单个接收方处理失败继续处理其他接收方
}
}
// 10. 返回结果
log.info("分账接收方绑定处理完成,成功: {},总数: {}", successCount, totalCount);
if (successCount == 0) {
log.error("商家绑定分账接收方全部失败");
if (lklLedgerMember != null) {
shopMchEntryService.updateMerchEntryApprovalByMchId(
lklLedgerMember.getMch_id(), CommonConstant.MCH_APPR_STA_NOPASS, "商家绑定分账接收方失败"
@ -1489,9 +1537,13 @@ public class LakalaApiServiceImpl implements LakalaApiService {
}
return Pair.of(false, "商家绑定分账接收方失败");
} else if (successCount < totalCount) {
return Pair.of(true, "商家绑定分账接收方,部分提交成功(" + successCount + "/" + totalCount + "),待审核通知");
String message = "商家绑定分账接收方,部分提交成功(" + successCount + "/" + totalCount + "),待审核通知";
log.info(message);
return Pair.of(true, message);
} else {
return Pair.of(true, "商家绑定分账接收方,全部提交成功,待审核通知");
String message = "商家绑定分账接收方,全部提交成功,待审核通知";
log.info(message);
return Pair.of(true, message);
}
}

View File

@ -318,44 +318,54 @@ public class LklTkServiceImpl {
}
/**
* (重要) 请求拉卡拉进件
* TODO 已经进件过了一般不涉及更改企业小微的信息可以不要重新进件了
* <p>
* 参考拉卡拉给的独立文档2拓客SAAS商户管理接口().docx
* (重要) 请求拉卡拉进件
*
* @param mchId 入驻商家自增Id
* @return
* <p>此方法用于向拉卡拉提交商户进件申请包括完整的商户信息和相关附件
* 已经进件过的商户一般不涉及更改企业小微的信息可以不要重新进件
*
* <p>参考拉卡拉给的独立文档2拓客SAAS商户管理接口().docx
*
* @param mchId 入驻商家自增Id不能为空
* @return Pair对象第一个元素表示操作是否成功第二个元素为操作结果信息
*/
public Pair<Boolean, String> registrationMerchant(Long mchId) {
logger.info("开始执行拉卡拉商户进件流程商户ID: {}", mchId);
// 参数校验
if (ObjectUtil.isEmpty(mchId)) {
logger.warn("商户进件失败入驻商户Id不能为空");
return Pair.of(false, "入驻商户Id不能为空");
}
String authorization = getLklTkAuthorization();
if (StrUtil.isBlank(authorization)) {
logger.error("商户进件失败获取拉卡拉token失败");
return Pair.of(false, "获取拉卡拉token失败");
}
JSONObject header = new JSONObject();
header.put("Authorization", getLklTkAuthorization());
header.put("Authorization", authorization);
// 获取商家入驻信息组成请求参数
ShopMchEntry shopMchEntry = shopMchEntryService.shopMerchEntryById(mchId);
if (ObjectUtil.isEmpty(shopMchEntry)) {
logger.warn("商户进件失败商家入驻信息不存在商户ID: {}", mchId);
return Pair.of(false, "商家入驻信息不存在");
}
if (!CommonConstant.Enable.equals(shopMchEntry.getHas_ec_signed())
|| StrUtil.isBlank(shopMchEntry.getContract_download_url())) {
logger.warn("商户进件失败商家未签署合同商户ID: {}", mchId);
return Pair.of(false, "商家先签署合同,再来进件!");
}
// 判断是否已经进件过进件过执行下一步操作进件异步通知的相关操作
//密集操作进件审核通过之后要下一步流程操作申请分账业务创建分账接收方
if (CommonConstant.Enable.equals(shopMchEntry.getHas_apply_mer()) && CheckUtil.isNotEmpty(shopMchEntry.getDistributor_id())
// 密集操作进件审核通过之后要下一步流程操作申请分账业务创建分账接收方
if (CommonConstant.Enable.equals(shopMchEntry.getHas_apply_mer())
&& CheckUtil.isNotEmpty(shopMchEntry.getDistributor_id())
&& StrUtil.isAllNotBlank(shopMchEntry.getLkl_mer_cup_no(), shopMchEntry.getLkl_term_no())) {
// 已经进件过了执行下一步操作
logger.info("商户已进件执行后续操作商户ID: {}", mchId);
registrationMerchantAfterHook(mchId, shopMchEntry.getLkl_mer_cup_no(), shopMchEntry.getDistributor_id());
return Pair.of(true, "请勿重复提交,拉卡拉已进件成功了,准备提交分账业务申请!");
}
@ -475,60 +485,87 @@ public class LklTkServiceImpl {
reqJsonBody.put("bizContent", bizContent);
// 附件文件相关开始
logger.debug("开始处理商户附件文件商户ID: {}", mchId);
JSONArray attachments = new JSONArray();
if (isQy) {
if (Boolean.TRUE.equals(isQy)) {
JSONObject SETTLE_ID_CARD_FRONT = updatePhoto(shopMchEntry.getLegal_person_id_images(), "FR_ID_CARD_FRONT", false);
if (SETTLE_ID_CARD_FRONT != null) {
attachments.put(SETTLE_ID_CARD_FRONT); // 法人身份证正面
logger.debug("成功添加法人身份证正面图片");
} else {
logger.warn("法人身份证正面图片添加失败");
}
JSONObject SETTLE_ID_CARD_BEHIND = updatePhoto(shopMchEntry.getLegal_person_id_images2(), "FR_ID_CARD_BEHIND", false);
if (SETTLE_ID_CARD_BEHIND != null) {
attachments.put(SETTLE_ID_CARD_BEHIND); // 法人身份证国徽面
logger.debug("成功添加法人身份证国徽面图片");
} else {
logger.warn("法人身份证国徽面图片添加失败");
}
JSONObject BUSINESS_LICENCE = updatePhoto(shopMchEntry.getBiz_license_image(), "BUSINESS_LICENCE", false);
if (BUSINESS_LICENCE != null) {
attachments.put(BUSINESS_LICENCE); // 营业执照
logger.debug("成功添加营业执照图片");
} else {
logger.warn("营业执照图片添加失败");
}
} else {
JSONObject ID_CARD_FRONT = updatePhoto(shopMchEntry.getIndividual_id_images(), "ID_CARD_FRONT", false);
if (ID_CARD_FRONT != null) {
attachments.put(ID_CARD_FRONT); // 身份证正面
logger.debug("成功添加身份证正面图片");
} else {
logger.warn("身份证正面图片添加失败");
}
JSONObject ID_CARD_BEHIND = updatePhoto(shopMchEntry.getIndividual_id_images2(), "ID_CARD_BEHIND", false);
if (ID_CARD_BEHIND != null) {
attachments.put(ID_CARD_BEHIND); // 身份证国徽面
logger.debug("成功添加身份证国徽面图片");
} else {
logger.warn("身份证国徽面图片添加失败");
}
}
JSONObject SHOP_OUTSIDE_IMG = updatePhoto(shopMchEntry.getFront_facade_image(), "SHOP_OUTSIDE_IMG", false);
if (SHOP_OUTSIDE_IMG != null) {
attachments.put(SHOP_OUTSIDE_IMG); // 门店门面图片
logger.debug("成功添加门店门面图片");
} else {
logger.warn("门店门面图片添加失败");
}
JSONObject SHOP_INSIDE_IMG = updatePhoto(shopMchEntry.getEnvironment_image(), "SHOP_INSIDE_IMG", false);
if (SHOP_INSIDE_IMG != null) {
attachments.put(SHOP_INSIDE_IMG); // 门店内部图片
logger.debug("成功添加门店内部图片");
} else {
logger.warn("门店内部图片添加失败");
}
JSONObject BANK_CARD = updatePhoto(shopMchEntry.getBank_image(), "BANK_CARD", false);
if (BANK_CARD != null) {
attachments.put(BANK_CARD); // 银行卡图片
logger.debug("成功添加银行卡图片");
} else {
logger.warn("银行卡图片添加失败");
}
reqJsonBody.put("attchments", attachments);
logger.debug("商户附件文件处理完成,共添加 {} 个附件", attachments.size());
// 附件文件相关结束
String urlPath = "/sit/htkregistration/merchant";
if (isLklProd) {
if (Boolean.TRUE.equals(isLklProd)) {
// 生产环境启用
urlPath = "/registration/merchant";
}
try {
logger.info("进件请求参数:{}", JSONUtil.toJsonStr(reqJsonBody));
logger.info("准备提交拉卡拉进件请求商户ID: {}", mchId);
logger.debug("进件请求参数:{}", JSONUtil.toJsonStr(reqJsonBody));
JSONObject response = RestTemplateHttpUtil.sendLklPost(buildLklTkUrl(urlPath), header, reqJsonBody, JSONObject.class);
logger.debug("拉卡拉进件响应参数:{}", response);
@ -538,6 +575,7 @@ public class LklTkServiceImpl {
|| !"000000".equals(response.getStr("retCode"))) {
String errMsg = response.getStr("retMsg") == null ? "提交拉卡拉进件,出现未知错误" : response.getStr("retMsg");
logger.error("拉卡拉进件失败商户ID: {},错误信息: {}", mchId, errMsg);
shopMchEntryService.updateMerchEntryApprovalByMchId(shopMchEntry.getId(), CommonConstant.MCH_APPR_STA_LKL_NOPASS, "提交拉卡拉进件失败:" + errMsg);
return Pair.of(false, "提交拉卡拉进件失败:" + errMsg);
@ -546,19 +584,24 @@ public class LklTkServiceImpl {
// {"merchantNo": "100132349","status": "WAIT_AUDI","state": "1"}
JSONObject rawData = response.getJSONObject("rawData"); // 进件这个接口比较特殊不按照常规返回数据
String lklMerInnerNo = rawData.getStr("merchantNo"); //拉卡拉内部商户号
logger.info("拉卡拉进件成功商户ID: {},拉卡拉商户号: {}", mchId, lklMerInnerNo);
// 表中的内部外部商户号暂时都传同一个内部商户号以便异步通知更改记录
Boolean success = shopMchEntryService.updateMerchEntryLklMerCupNo(mchId, CommonConstant.Disable2, lklMerInnerNo, lklMerInnerNo, reqJsonBody.toString(), rawData.toString());
if (!success) {
if (!Boolean.TRUE.equals(success)) {
logger.error("进件成功但更新商户号失败商户ID: {}", mchId);
shopMchEntryService.updateMerchEntryApprovalByMchId(shopMchEntry.getId(), CommonConstant.MCH_APPR_STA_LKL_NOPASS, "进件成功,但更新商户号失败!");
return Pair.of(false, "提交进件成功,但更新商户号失败!");
}
} catch (Exception e) {
logger.error("拉卡拉进件异常{}", e.getMessage());
logger.error("拉卡拉进件异常商户ID: {}", mchId, e);
shopMchEntryService.updateMerchEntryApprovalByMchId(shopMchEntry.getId(), CommonConstant.MCH_APPR_STA_LKL_NOPASS, "进件失败:" + e.getMessage());
return Pair.of(false, "提交拉卡拉进件失败:" + e.getMessage());
}
logger.info("拉卡拉进件提交成功等待审核商户ID: {}", mchId);
shopMchEntryService.updateMerchEntryApprovalByMchId(shopMchEntry.getId(), CommonConstant.MCH_APPR_STA_LKL_PADDING, "提交拉卡拉进件成功,正进一步审核!");
return Pair.of(true, "提交拉卡拉进件成功,正进一步审核!");
}
@ -566,91 +609,117 @@ public class LklTkServiceImpl {
/**
* 重要拉卡拉进件异步通知
*
* @param request
* @return
* <p>处理拉卡拉平台发送的商户进件结果异步通知包括解密通知数据更新商户状态等操作
*
* @param request HTTP请求对象包含拉卡拉发送的异步通知数据
* @return JSONObject 响应结果包含处理状态码和消息
*/
// @Transactional
public JSONObject registrationMerchantNotify(HttpServletRequest request) {
logger.debug("拉卡拉进件异步通知开始");
logger.info("开始处理拉卡拉进件异步通知");
// 解密请求参数
String requestBody = LakalaUtil.getBody(request);
logger.debug("拉卡拉进件异步通知返回参数:{}", requestBody);
try {
// 解密请求参数
String requestBody = LakalaUtil.getBody(request);
logger.debug("拉卡拉进件异步通知原始参数:{}", requestBody);
if (StrUtil.isBlank(requestBody)) {
return new JSONObject().set("code", "400").set("message", "返回参数为空");
if (StrUtil.isBlank(requestBody)) {
logger.warn("拉卡拉进件异步通知参数为空");
return new JSONObject().set("code", "400").set("message", "返回参数为空");
}
JSONObject reqBodyJSON = JSONUtil.parseObj(requestBody);
if (reqBodyJSON.isEmpty() || reqBodyJSON.get("data") == null) {
logger.warn("拉卡拉进件异步通知参数格式有误,无法解析: {}", requestBody);
return new JSONObject().set("code", "400").set("message", "参数格式有误,无法解析");
}
String srcData = reqBodyJSON.getStr("data");
if (StrUtil.isBlank(srcData)) {
logger.warn("拉卡拉进件异步通知关键参数为空值");
return new JSONObject().set("code", "400").set("message", "关键参数为空值");
}
// 公钥解密出来的数据
logger.debug("开始解密拉卡拉通知数据");
String notifyPubKey = LakalaUtil.getResourceFile(notifyPubKeyPath, false, false);
String data = LakalaUtil.decryptNotifyData(notifyPubKey, srcData);
if (StrUtil.isBlank(data)) {
logger.error("拉卡拉进件异步通知数据解密失败");
return new JSONObject().set("code", "400").set("message", "数据解密出错!");
}
logger.info("拉卡拉进件异步通知数据解密成功,开始处理业务逻辑");
// 逻辑处理
JSONObject dataJSON = JSONUtil.parseObj(data);
String auditStatus = dataJSON.getStr("status");
String merCupNo = dataJSON.getStr("externalCustomerNo"); //拉卡拉外部商户号
String merInnerNo = dataJSON.getStr("customerNo"); //拉卡拉内部商户号
String termNos = dataJSON.getStr("termNos"); //拉卡拉分配的业务终端号
logger.debug("解析通知数据完成 - 审核状态: {},外部商户号: {},内部商户号: {},终端号: {}",
auditStatus, merCupNo, merInnerNo, termNos);
// 合并参数校验
if (dataJSON.isEmpty() ||
StrUtil.isBlank(auditStatus) ||
StrUtil.isBlank(merCupNo) ||
StrUtil.isBlank(merInnerNo)) {
logger.warn("拉卡拉进件异步通知参数解析出错,数据: {}", data);
return new JSONObject().set("code", "500").set("message", "参数解析出错");
}
// 给商家入驻表增加拉卡拉的商户号和拉卡拉返回的数据
logger.debug("开始查询商户入驻信息,内部商户号: {}", merInnerNo);
ShopMchEntry shopMchEntry = shopMchEntryService.getShopMerchEntryByMerInnerNo(merInnerNo);
if (shopMchEntry == null) {
logger.error("拉卡拉进件异步通知:{}内部商户号入驻信息不存在!", merInnerNo);
return new JSONObject().put("code", "500").put("message", merInnerNo + "内部商户号入驻信息不存在");
}
Long mchId = shopMchEntry.getId();
logger.info("找到商户入驻信息商户ID: {}", mchId);
// 校验审核状态
logger.debug("校验审核状态: {}", auditStatus);
if (!"SUCCESS".equals(auditStatus) && !"REVIEW_PASS".equals(auditStatus)) {
String remark = dataJSON.getStr("remark");
logger.warn("拉卡拉进件审核未通过,审核状态: {},备注: {}", auditStatus, remark);
shopMchEntryService.updateMerchEntryApprovalByMchId(mchId, CommonConstant.MCH_APPR_STA_LKL_NOPASS, "进件失败:" + remark);
return new JSONObject().set("code", "FAIL").set("message", "返回审核状态有误");
}
logger.info("拉卡拉进件审核通过商户ID: {},开始更新商户信息", mchId);
// RMK 拉卡拉进价提交成功,边处理周边的数据边等待审核异步通知
// 更新已进件成功的商户号和设备号
logger.debug("开始更新商户拉卡拉审核状态");
Boolean success = shopMchEntryService.updateMerchEntryLklAuditStatusByLklMerCupNo(
merInnerNo, merCupNo, termNos, CommonConstant.Enable, null, data);
if (!Boolean.TRUE.equals(success)) {
logger.error("拉卡拉进件审核通过但更新商户号失败商户ID: {}", mchId);
shopMchEntryService.updateMerchEntryApprovalByMchId(mchId, CommonConstant.MCH_APPR_STA_LKL_NOPASS, "进件时更新商户号失败");
return new JSONObject().set("code", "500").set("message", "更新商户号失败");
}
logger.info("商户拉卡拉审核状态更新成功商户ID: {}", mchId);
shopMchEntryService.updateMerchEntryApprovalByMchId(shopMchEntry.getId(), CommonConstant.MCH_APPR_STA_LKL_PADDING,
"进件、申请分账业务、创建分账接收方均已成功,等待拉卡拉审核分账业务请求!");
//密集操作进件审核通过之后要下一步流程操作申请分账业务创建分账接收方
logger.info("开始执行进件后续操作商户ID: {},拉卡拉商户号: {}", mchId, merCupNo);
registrationMerchantAfterHook(mchId, merCupNo, shopMchEntry.getDistributor_id());
logger.info("拉卡拉进件异步通知处理完成商户ID: {}", mchId);
return new JSONObject().set("code", "200").set("message", "处理成功");
} catch (Exception e) {
logger.error("处理拉卡拉进件异步通知异常", e);
return new JSONObject().set("code", "500").set("message", "处理异常:" + e.getMessage());
}
JSONObject reqBodyJSON = JSONUtil.parseObj(requestBody);
if (reqBodyJSON.isEmpty() || reqBodyJSON.get("data") == null) {
return new JSONObject().set("code", "400").set("message", "参数格式有误,无法解析");
}
String srcData = reqBodyJSON.getStr("data");
if (StrUtil.isBlank(srcData)) {
return new JSONObject().set("code", "400").set("message", "关键参数为空值");
}
// 公钥解密出来的数据
String notifyPubKey = LakalaUtil.getResourceFile(notifyPubKeyPath, false, false);
String data = LakalaUtil.decryptNotifyData(notifyPubKey, srcData);
if (StrUtil.isBlank(data)) {
return new JSONObject().set("code", "400").set("message", "数据解密出错!");
}
logger.debug("拉卡拉进件异步通知data解密成功开始处理逻辑");
// 逻辑处理
JSONObject dataJSON = JSONUtil.parseObj(data);
String auditStatus = dataJSON.getStr("status");
String merCupNo = dataJSON.getStr("externalCustomerNo"); //拉卡拉外部商户号
String merInnerNo = dataJSON.getStr("customerNo"); //拉卡拉内部商户号
String termNos = dataJSON.getStr("termNos"); //拉卡拉分配的业务终端号
// 合并参数校验
if (dataJSON.isEmpty() ||
StrUtil.isBlank(auditStatus) ||
StrUtil.isBlank(merCupNo) ||
StrUtil.isBlank(merInnerNo)) {
return new JSONObject().set("code", "500").set("message", "参数解析出错");
}
// 给商家入驻表增加拉卡拉的商户号和拉卡拉返回的数据
ShopMchEntry shopMchEntry = shopMchEntryService.getShopMerchEntryByMerInnerNo(merInnerNo);
if (shopMchEntry == null) {
logger.error("拉卡拉进件异步通知:{}内部商户号入驻信息不存在!", merInnerNo);
return new JSONObject().put("code", "500").put("message", merInnerNo + "内部商户号入驻信息不存在");
}
Long mchId = shopMchEntry.getId();
// 校验审核状态
if (!"SUCCESS".equals(auditStatus) && !"REVIEW_PASS".equals(auditStatus)) {
logger.debug("返回的审核状态:{}", auditStatus);
shopMchEntryService.updateMerchEntryApprovalByMchId(mchId, CommonConstant.MCH_APPR_STA_LKL_NOPASS, "进件失败:" + dataJSON.getStr("remark"));
return new JSONObject().set("code", "FAIL").set("message", "返回审核状态有误");
}
// RMK 拉卡拉进价提交成功,边处理周边的数据边等待审核异步通知
// 更新已进件成功的商户号和设备号
Boolean success = shopMchEntryService.updateMerchEntryLklAuditStatusByLklMerCupNo(
merInnerNo, merCupNo, termNos, CommonConstant.Enable, null, data);
if (!success) {
shopMchEntryService.updateMerchEntryApprovalByMchId(mchId, CommonConstant.MCH_APPR_STA_LKL_NOPASS, "进件时更新商户号失败");
return new JSONObject().set("code", "500").set("message", "更新商户号失败");
}
shopMchEntryService.updateMerchEntryApprovalByMchId(shopMchEntry.getId(), CommonConstant.MCH_APPR_STA_LKL_PADDING,
"进件、申请分账业务、创建分账接收方均已成功,等待拉卡拉审核分账业务请求!");
//密集操作进件审核通过之后要下一步流程操作申请分账业务创建分账接收方
registrationMerchantAfterHook(mchId, merCupNo, shopMchEntry.getDistributor_id());
return new JSONObject().set("code", "200").set("message", "处理成功");
}
/**

View File

@ -211,7 +211,7 @@ public class ShopOrderReturnController extends BaseControllerImpl {
* {"order_id":"DD-20250701-1","reason":"商家协商退款","order_return_vo":{"order_id":"DD-20250701-1","return_items":[{"order_item_id":1,"return_item_num":1,"return_refund_amount":"0.01"}]}}
* @return CommonResult 处理结果
*/
@ApiOperation(value = "商家退货退", notes = "商家退货退款,支持整单或个别商品退货")
@ApiOperation(value = "商家退", notes = "商家退款,支持整单或个别商品退货")
@RequestMapping(value = "/mch/order/doRefund", method = RequestMethod.POST)
public CommonResult doRefundForMch(@RequestBody JSONObject params) {
return shopOrderReturnService.doRefundForMch(params);

View File

@ -764,7 +764,7 @@ public class ShopOrderBaseServiceImpl extends BaseServiceImpl<ShopOrderBaseMappe
ShopOrderLkl shopOrderLkl = shopOrderLklService.getByStoreIdAndOrderId(shopOrderInfo.getStore_id(), order_id);
if (shopOrderLkl != null) {
base_row.put("lkl_merchant_no", shopOrderLkl.getLkl_merchant_no());
base_row.put("lkl_trade_no", shopOrderLkl.getLkl_sub_trade_no());
base_row.put("lkl_trade_no", shopOrderLkl.getWx_transaction_id());
base_row.put("lkl_log_no", shopOrderLkl.getLkl_sub_log_no());
}
@ -8092,7 +8092,7 @@ public class ShopOrderBaseServiceImpl extends BaseServiceImpl<ShopOrderBaseMappe
ShopOrderLkl shopOrderLkl = shopOrderLklService.getByStoreIdAndOrderId(store_id, order_id);
if (shopOrderLkl != null) {
order_info_row.put("lkl_merchant_no", shopOrderLkl.getLkl_merchant_no());
order_info_row.put("lkl_trade_no", shopOrderLkl.getLkl_sub_trade_no());
order_info_row.put("lkl_trade_no", shopOrderLkl.getWx_transaction_id());
order_info_row.put("lkl_log_no", shopOrderLkl.getLkl_sub_log_no());
}

View File

@ -51,7 +51,6 @@ public class ShopOrderLklServiceImpl extends BaseServiceImpl<ShopOrderLklMapper,
@Resource
private ShopOrderDataService shopOrderDataService;
@Override
public Boolean addOrUpdateByStoreOrder(ShopOrderLkl record) {
if (record == null
@ -244,7 +243,7 @@ public class ShopOrderLklServiceImpl extends BaseServiceImpl<ShopOrderLklMapper,
}
/**
* 根据拉卡拉支付通知数据保存或更新拉卡拉订单记录
* 根据拉卡拉支付异步回调通知数据保存或更新拉卡拉订单记录
* 该方法用于处理拉卡拉支付平台发送的支付通知将通知中的数据保存到shop_order_lkl表中
*
* @param lklPayNotifyDataJson 拉卡拉支付通知的JSON数据
@ -287,9 +286,11 @@ public class ShopOrderLklServiceImpl extends BaseServiceImpl<ShopOrderLklMapper,
// 设置可选字段
String tradeNo = lklPayNotifyDataJson.getStr("trade_no");
String tradeStatus = lklPayNotifyDataJson.getStr("trade_status");
String accTradeNo = lklPayNotifyDataJson.getStr("acc_trade_no");
record.setLkl_trade_no(tradeNo);
record.setTrade_status(tradeStatus);
log.debug("[拉卡拉订单更新] 设置可选字段: tradeNo={} tradeStatus={}", tradeNo, tradeStatus);
record.setWx_transaction_id(accTradeNo); //账户端交易订单号 对应微信的用户交易单号
log.debug("[拉卡拉订单更新] 设置可选字段: tradeNo={} accTradeNo={} tradeStatus={}", tradeNo,accTradeNo, tradeStatus);
// 新增的订单字段,lkl_sub_log_no,out_separate_no,split_amt 四个字段无值就给主单的值
String outSeparateNo = JsonUtil.getJsonValueSmart(lklPayNotifyDataJson, "out_separate_no");

View File

@ -58,7 +58,10 @@ import com.suisung.mall.shop.sfexpress.service.SFExpressApiService;
import com.suisung.mall.shop.store.service.ShopStoreBaseService;
import com.suisung.mall.shop.store.service.ShopStoreConfigService;
import com.suisung.mall.shop.store.service.ShopStoreShippingAddressService;
import io.seata.core.context.RootContext;
import io.seata.core.exception.TransactionException;
import io.seata.spring.annotation.GlobalTransactional;
import io.seata.tm.api.GlobalTransactionContext;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -418,15 +421,16 @@ public class ShopOrderReturnServiceImpl extends BaseServiceImpl<ShopOrderReturnM
/**
* 添加退款退货-发货退货,卖家也可以决定不退货退款买家申请退款不支持卖家可以主动退款
*
* @param orderReturnInputVo
* @param needSendMsg 是否需要发站内 消息
* @return
* @param orderReturnInputVo 退款申请输入参数
* @param needSendMsg 是否需要发送消息通知
* @return CommonResult 退款申请结果
*/
@Override
@Transactional
public CommonResult addItem(OrderReturnInputVo orderReturnInputVo, Boolean needSendMsg) {
Map data = new HashMap();
// 获取用户ID
Integer user_id = orderReturnInputVo.getUser_id();
if (CheckUtil.isEmpty(user_id)) {
UserDto user = getCurrentUser();
@ -436,30 +440,36 @@ public class ShopOrderReturnServiceImpl extends BaseServiceImpl<ShopOrderReturnM
user_id = user.getId();
}
//是否有店铺
// 获取买家店铺ID如果有
Integer buyer_store_id = shopStoreBaseService.getStoreId(user_id);
// 获取订单信息
String order_id = orderReturnInputVo.getOrder_id();
List<Long> order_item_ids = orderReturnInputVo.getReturn_items().stream().map(OrderReturnItemInputVo::getOrder_item_id).distinct().collect(Collectors.toList());
ShopOrderInfo shopOrderInfo = shopOrderInfoService.get(order_id);
List<Long> order_item_ids = orderReturnInputVo.getReturn_items().stream()
.map(OrderReturnItemInputVo::getOrder_item_id)
.distinct()
.collect(Collectors.toList());
ShopOrderInfo shopOrderInfo = shopOrderInfoService.get(order_id);
if (shopOrderInfo == null) {
throw new ApiException(I18nUtil._("此订单信息数据有误!"));
}
ShopOrderBase orderBase = shopOrderBaseService.get(order_id);
if (orderBase == null) {
throw new ApiException(I18nUtil._("此订单详细信息数据有误!"));
}
// 判断此订单商品是否有正在审核的退款单
// 判断此订单商品是否有正在审核的退款单
QueryWrapper<ShopOrderReturn> returnQueryWrapper = new QueryWrapper<>();
returnQueryWrapper.eq("order_id", order_id).eq("return_state_id", StateCode.RETURN_PROCESS_CHECK);
returnQueryWrapper.eq("order_id", order_id)
.eq("return_state_id", StateCode.RETURN_PROCESS_CHECK);
List<ShopOrderReturn> order_return_rows = find(returnQueryWrapper);
if (CollUtil.isNotEmpty(order_return_rows)) {
List<String> return_ids = order_return_rows.stream().map(ShopOrderReturn::getReturn_id).collect(Collectors.toList());
List<String> return_ids = order_return_rows.stream()
.map(ShopOrderReturn::getReturn_id)
.collect(Collectors.toList());
QueryWrapper<ShopOrderReturnItem> returnItemQueryWrapper = new QueryWrapper<>();
returnItemQueryWrapper.in("order_item_id", order_item_ids)
@ -471,13 +481,14 @@ public class ShopOrderReturnServiceImpl extends BaseServiceImpl<ShopOrderReturnM
}
}
// todo 检测该订单使用的优惠券等情况
// 检查数据权限
if (!CheckUtil.checkDataRights(user_id, orderBase, ShopOrderBase::getBuyer_user_id)) {
throw new ApiException(ResultCode.FORBIDDEN);
}
// 获取退款申请参数
String return_id = orderReturnInputVo.getReturn_id();
Integer return_reason_id = orderReturnInputVo.getReturn_reason_id();
Integer return_reason_id = orderReturnInputVo.getReturn_reason_id() == null ? 0 : orderReturnInputVo.getReturn_reason_id();
String return_buyer_message = orderReturnInputVo.getReturn_buyer_message();
Integer store_id = Convert.toInt(orderBase.getStore_id());
String return_tel = orderReturnInputVo.getReturn_tel();
@ -489,8 +500,8 @@ public class ShopOrderReturnServiceImpl extends BaseServiceImpl<ShopOrderReturnM
Date curTime = new Date();
// 构建退款单主表信息
ShopOrderReturn orderReturn = new ShopOrderReturn();
orderReturn.setReturn_id(return_id);
orderReturn.setOrder_id(order_id);
orderReturn.setBuyer_user_id(user_id);
@ -505,29 +516,34 @@ public class ShopOrderReturnServiceImpl extends BaseServiceImpl<ShopOrderReturnM
orderReturn.setReturn_year(DateUtil.year(curTime)); // 退单年份-索引查询
orderReturn.setReturn_month(DateUtil.month(curTime) + 1); // 退单月份-索引查询
orderReturn.setReturn_day(DateUtil.dayOfMonth(curTime)); // 退单日-索引查询
orderReturn.setReturn_reason_id(0);
orderReturn.setReturn_reason_id(0); // 注意这里覆盖了前面设置的return_reason_id
orderReturn.setReturn_store_user_id(0);
orderReturn.setReturn_mobile(0L);
orderReturn.setReturn_telephone("");
orderReturn.setSubsite_id(shopOrderInfo.getSubsite_id());
// 构建退款单明细信息
List<ShopOrderReturnItem> shopOrderReturnItems = new ArrayList<>();
for (OrderReturnItemInputVo returnItemInputVo : orderReturnInputVo.getReturn_items()) {
// 获取订单商品信息
ShopOrderItem shopOrderItem = shopOrderItemService.get(returnItemInputVo.getOrder_item_id());
if (shopOrderItem == null) {
throw new ApiException(I18nUtil._("此订单商品订单数据有误!"));
}
ShopProductIndex shopProductIndex = shopProductIndexService.get(shopOrderItem.getProduct_id());
// 获取商品索引信息
ShopProductIndex shopProductIndex = shopProductIndexService.get(shopOrderItem.getProduct_id());
if (shopProductIndex == null) {
throw new ApiException(I18nUtil._("此订单商品数据有误!"));
}
// 检查是否允许退货
boolean is_denyreturn = ifDenyReturn(shopOrderInfo, shopOrderItem, shopProductIndex);
if (is_denyreturn) {
throw new ApiException(I18nUtil._("此商品不允许退货!"));
}
// 构建退款单明细
ShopOrderReturnItem orderReturnItem = new ShopOrderReturnItem();
Integer return_item_num = returnItemInputVo.getReturn_item_num();
@ -536,61 +552,43 @@ public class ShopOrderReturnServiceImpl extends BaseServiceImpl<ShopOrderReturnM
}
BigDecimal return_refund_amount = returnItemInputVo.getReturn_refund_amount();
String return_item_image = ObjectUtil.defaultIfBlank(orderReturnInputVo.getRefund_pic(), orderReturnInputVo.getUpload_img());
String return_item_image = ObjectUtil.defaultIfBlank(
orderReturnInputVo.getRefund_pic(),
orderReturnInputVo.getUpload_img());
orderReturnItem.setOrder_item_id(returnItemInputVo.getOrder_item_id()); // 退货商品编号(DOT):0为退款
orderReturnItem.setOrder_id(order_id); // 订单编号
orderReturnItem.setReturn_item_num(return_item_num); // 退货商品编号(DOT):0为退款
orderReturnItem.setReturn_item_subtotal(return_refund_amount); // 退款金额 = goods_payment_amount/goods_quantity, 因为涉及到折扣等等 或者为订单中 order_payment_amount
orderReturnItem.setReturn_reason_id(return_reason_id); // 退款理由id
orderReturnItem.setReturn_item_note(return_buyer_message); // 买家退货备注
orderReturnItem.setOrder_item_id(returnItemInputVo.getOrder_item_id());
orderReturnItem.setOrder_id(order_id);
orderReturnItem.setReturn_item_num(return_item_num);
orderReturnItem.setReturn_item_subtotal(return_refund_amount);
orderReturnItem.setReturn_reason_id(return_reason_id);
orderReturnItem.setReturn_item_note(return_buyer_message);
orderReturnItem.setReturn_item_image(return_item_image);
orderReturnItem.setReturn_state_id(StateCode.RETURN_PROCESS_CHECK);
orderReturnItem.setReturn_reason_id(0);
shopOrderReturnItems.add(orderReturnItem);
}
// 保存退款单
if (!addReturnByItem(orderReturn, shopOrderReturnItems)) {
throw new ApiException(ResultCode.FAILED);
}
data.put("return", orderReturn);
data.put("items", shopOrderReturnItems);
//暂时注释
// 七天无理由自动退货
/*if (contractTypeIds.contains(StateCode.CONTRACT_TYPE_7_RETURN) && shopOrderInfo.getOrder_is_out().equals(StateCode.ORDER_PICKING_STATE_NO)) {
ShopOrderReturn shopOrderReturn = new ShopOrderReturn();
shopOrderReturn.setReturn_id(orderReturn.getReturn_id());
shopOrderReturn.setReturn_flag(0);
shopOrderReturn.setReturn_store_message(I18nUtil._("七天无理由自动退货"));
shopOrderReturn.setStore_id(store_id);
// 退单审核
shopOrderReturnService.review(shopOrderReturn, 0);
}*/
if (needSendMsg) {
// 发送消息通知
if (needSendMsg != null && needSendMsg) {
// 退款提醒商家
// 退货单提交成功对商家进行提醒
// String message_id = "return-reminder";
// Map args = new HashMap();
// args.put("order_id", return_id);
// args.put("id", order_id);
// args.put("return_id", return_id);
// args.put("order_item", String.format(("退货商品编号:[%s]"), order_item_id));
// messageService.sendNoticeMsg(0, store_id, message_id, args);
String message_id = "refund-reminder";
Map args = new HashMap();
args.put("order_id", orderReturn.getReturn_id());
messageService.sendNoticeMsg(0, store_id, message_id, args);
// 发送unipush 消息
// 发送unipush消息
String title = "您有一个退款的订单,请及时前往后台审核!";
String content = String.format("订单号:%s 退单号:[%s],时间:%s请及时前往后台审核", order_id, orderReturn.getReturn_id(), DateTimeUtils.formatDateTime(LocalDateTime.now(), "yyyy-MM-dd HH:mm:ss"));
String content = String.format("订单号:%s 退单号:[%s],时间:%s请及时前往后台审核",
order_id, orderReturn.getReturn_id(),
DateTimeUtils.formatDateTime(LocalDateTime.now(), "yyyy-MM-dd HH:mm:ss"));
JSONObject payload = new JSONObject();
payload.put("category", CommonConstant.PUSH_MSG_CATE_MCH_RETURN_ORDER_LIST);
payload.put("orderId", order_id);
@ -598,9 +596,7 @@ public class ShopOrderReturnServiceImpl extends BaseServiceImpl<ShopOrderReturnM
pushMessageService.noticeMerchantEmployeeOrderAction(store_id, order_id, title, content, payload);
}
data.put("order_item_ids", order_item_ids);
return CommonResult.success(data);
}
@ -945,7 +941,7 @@ public class ShopOrderReturnServiceImpl extends BaseServiceImpl<ShopOrderReturnM
String remark = "同城配送异常自动退款!";
// 先整单退货申请
CommonResult commonResult = addWholeItems(shopOrderId, true, remark);
CommonResult commonResult = addRemainingItems(shopOrderId, true, remark);
commonResult.checkFenResult();
logger.debug("[顺丰超时自动退款] 整单退货申请创建成功: shopOrderId={}", shopOrderId);
@ -974,6 +970,12 @@ public class ShopOrderReturnServiceImpl extends BaseServiceImpl<ShopOrderReturnM
return result;
} catch (Exception e) {
logger.error("[顺丰超时自动退款] 处理过程中发生异常: shopOrderId={}", shopOrderId, e);
// 手动触发Seata事务回滚
try {
GlobalTransactionContext.reload(RootContext.getXID()).rollback();
} catch (TransactionException transactionException) {
logger.error("[顺丰超时自动退款] Seata事务回滚异常: shopOrderId={}", shopOrderId, transactionException);
}
throw e;
}
}
@ -1241,6 +1243,7 @@ public class ShopOrderReturnServiceImpl extends BaseServiceImpl<ShopOrderReturnM
// 2. 根据退货标志处理不同流程
if (ObjectUtil.equal(shopOrderReturn.getReturn_flag(), 0)) {
// 2.1 无需退货流程
if (!edit(shopOrderReturn)) {
throw new ApiException(I18nUtil._("修改订单信息失败!"));
@ -1248,6 +1251,7 @@ public class ShopOrderReturnServiceImpl extends BaseServiceImpl<ShopOrderReturnM
if (!processReviewList(return_ids, orderReturns, StateCode.RETURN_PROCESS_CHECK, StateCode.RETURN_PROCESS_FINISH)) {
throw new ApiException(I18nUtil._("审核失败!"));
}
} else {
// 2.2 需要退货流程
ShopStoreShippingAddress address = shopStoreShippingAddressService.get(receiving_address);
@ -1278,6 +1282,7 @@ public class ShopOrderReturnServiceImpl extends BaseServiceImpl<ShopOrderReturnM
}});
return true;
} catch (Exception e) {
logger.error("退货单审核处理异常", e);
throw e instanceof ApiException ? (ApiException) e :
@ -1409,7 +1414,7 @@ public class ShopOrderReturnServiceImpl extends BaseServiceImpl<ShopOrderReturnM
* RETURN_PROCESS_CANCEL = 3135; //-买家取消退款
* @param return_rows 退货订单列表
* @param return_next_state_id 下一个退单状态
* @return
* @return boolean 处理结果
*/
@GlobalTransactional
private boolean editNextState(List<String> return_ids, Integer store_id, Integer return_state_id, List<ShopOrderReturn> return_rows, Integer return_next_state_id) {
@ -1434,15 +1439,17 @@ public class ShopOrderReturnServiceImpl extends BaseServiceImpl<ShopOrderReturnM
ShopOrderInfo shopOrderInfo = shopOrderInfoService.get(order_id);
if (shopOrderInfo == null) {
logger.error("该订单详情信息不存在订单ID: {}", order_id);
throw new ApiException(I18nUtil._("该订单详情信息不存在!"));
}
// 查询订单表是否出库
if (shopOrderInfo.getOrder_is_out().equals(StateCode.ORDER_PICKING_STATE_YES)) {
if (ObjectUtil.equal(shopOrderInfo.getOrder_is_out(), StateCode.ORDER_PICKING_STATE_YES)) {
Long orderItemId = returnItem.getOrder_item_id();
ShopOrderItem shopOrderItem = shopOrderItemService.get(orderItemId);
if (shopOrderItem == null) {
logger.error("该订单商品表信息不存在订单项ID: {}", orderItemId);
throw new ApiException(I18nUtil._("该订单商品表信息不存在!"));
}
@ -1451,15 +1458,22 @@ public class ShopOrderReturnServiceImpl extends BaseServiceImpl<ShopOrderReturnM
ShopProductItem productItem = shopProductItemService.get(itemId);
if (productItem == null) {
logger.error("该订单商品表-SKU表信息不存在商品项ID: {}", itemId);
throw new ApiException(I18nUtil._("该订单商品表-SKU表信息不存在"));
}
productItem.setItem_quantity(productItem.getItem_quantity() + returnItem.getReturn_item_num());
if (!shopProductItemService.edit(productItem)) {
throw new ApiException(I18nUtil._("增加库存失败!"));
// 增加库存
Integer returnNum = returnItem.getReturn_item_num();
if (returnNum != null) {
productItem.setItem_quantity(productItem.getItem_quantity() + returnNum);
if (!shopProductItemService.edit(productItem)) {
logger.error("增加库存失败商品项ID: {}", itemId);
throw new ApiException(I18nUtil._("增加库存失败!"));
}
logger.debug("成功增加商品库存商品项ID: {}, 增加数量: {}", itemId, returnNum);
} else {
logger.warn("退货数量为空无法增加库存订单项ID: {}", orderItemId);
}
}
}
}
@ -1486,55 +1500,92 @@ public class ShopOrderReturnServiceImpl extends BaseServiceImpl<ShopOrderReturnM
//退货类型(BOOL): 0-退款单;1-退运费单
Integer return_is_shipping_fee = return_row.getReturn_is_shipping_fee();
if (CheckUtil.isEmpty(return_is_shipping_fee)) {
// 处理非退运费单的情况
if (CheckUtil.isEmpty(return_is_shipping_fee) || return_is_shipping_fee != 1) {
// 所有单品退款额度
QueryWrapper<ShopOrderItem> orderItemQueryWrapper = new QueryWrapper<>();
orderItemQueryWrapper.eq("order_id", order_id);
List<ShopOrderItem> orderItemList = shopOrderItemService.find(orderItemQueryWrapper);
// 累计订单项支付总金额
BigDecimal order_item_payment_amount = orderItemList.stream().map(s -> s.getOrder_item_payment_amount()).reduce(BigDecimal::add).get();
BigDecimal order_item_payment_amount = BigDecimal.ZERO;
if (CollUtil.isNotEmpty(orderItemList)) {
order_item_payment_amount = orderItemList.stream()
.map(ShopOrderItem::getOrder_item_payment_amount)
.filter(Objects::nonNull)
.reduce(BigDecimal.ZERO, BigDecimal::add);
}
// 当前已经同意退款额度 = 所有单品退款额度
QueryWrapper<ShopOrderReturnItem> returnItemQueryWrapper = new QueryWrapper<>();
returnItemQueryWrapper.eq("order_id", order_id).in("return_state_id", StateCode.RETURN_PROCESS_RECEIVED, StateCode.RETURN_PROCESS_REFUND, StateCode.RETURN_PROCESS_RECEIPT_CONFIRMATION, StateCode.RETURN_PROCESS_FINISH);
returnItemQueryWrapper.eq("order_id", order_id)
.in("return_state_id", Arrays.asList(
StateCode.RETURN_PROCESS_RECEIVED,
StateCode.RETURN_PROCESS_REFUND,
StateCode.RETURN_PROCESS_RECEIPT_CONFIRMATION,
StateCode.RETURN_PROCESS_FINISH));
List<ShopOrderReturnItem> returnItemList = orderReturnItemService.find(returnItemQueryWrapper);
BigDecimal return_item_subtotal = returnItemList.stream().map(s -> s.getReturn_item_subtotal()).reduce(BigDecimal::add).get();
BigDecimal return_item_subtotal = BigDecimal.ZERO;
if (CollUtil.isNotEmpty(returnItemList)) {
return_item_subtotal = returnItemList.stream()
.map(ShopOrderReturnItem::getReturn_item_subtotal)
.filter(Objects::nonNull)
.reduce(BigDecimal.ZERO, BigDecimal::add);
}
// 订单所有商品退款的情况
if (ObjectUtil.compare(order_item_payment_amount, return_item_subtotal) == 0) {
if (order_item_payment_amount.compareTo(return_item_subtotal) == 0) {
logger.debug("订单所有商品均已退款订单ID: {}", order_id);
ShopOrderData shopOrderData = new ShopOrderData();
shopOrderData.setOrder_id(order_id);
shopOrderData.setOrder_refund_status(2); //退款状态:0-是无退款;1-是部分退款;2-是全部退款
if (!shopOrderDataService.edit(shopOrderData)) {
logger.error("修改订单退款状态失败订单ID: {}", order_id);
throw new ApiException(ResultCode.FAILED);
}
// 取消订单
ShopOrderInfo info_row = shopOrderInfoService.get(order_id);
if (info_row == null) {
logger.error("获取订单信息失败订单ID: {}", order_id);
throw new ApiException(I18nUtil._("订单信息不存在!"));
}
// 当前订单状态
Integer order_state_id = info_row.getOrder_state_id();
// 没有发货没有完成订单之前允许取消订单和退运费
if (!Arrays.asList(StateCode.ORDER_STATE_SHIPPED, StateCode.ORDER_STATE_RECEIVED, StateCode.ORDER_STATE_FINISH).contains(order_state_id)) {
List<Integer> forbiddenStates = Arrays.asList(
StateCode.ORDER_STATE_SHIPPED,
StateCode.ORDER_STATE_RECEIVED,
StateCode.ORDER_STATE_FINISH);
if (order_state_id != null && !forbiddenStates.contains(order_state_id)) {
// 取消订单,更改订单的状态为已取消
shopOrderBaseService.cancel(order_id, info_row, false);
// logger.info("全部退款完成,取消订单:{}", order_id);
logger.info("全部退款完成,订单已取消:{}", order_id);
// 未发货退运费 - 判断运费是否存在
ShopOrderData order_data_row = shopOrderDataService.get(order_id);
// 如果有打包费最后的退款订单的退款金额加上 打包费
if (order_data_row != null && order_data_row.getPacking_fee().compareTo(BigDecimal.ZERO) > 0) {
if (order_data_row != null &&
order_data_row.getPacking_fee() != null &&
order_data_row.getPacking_fee().compareTo(BigDecimal.ZERO) > 0) {
// 退款金额+打包费
BigDecimal order_refund_amount_add_fee = NumberUtil.add(order_data_row.getOrder_refund_amount(), order_data_row.getPacking_fee());
BigDecimal order_refund_amount_add_fee = NumberUtil.add(
order_data_row.getOrder_refund_amount(),
order_data_row.getPacking_fee());
// 最后一个退款订单如果有打包费加上打包费
return_row.setReturn_refund_amount(order_refund_amount_add_fee);
logger.debug("已添加打包费到退款金额订单ID: {}", order_id);
}
// 有运费的订单
if (order_data_row != null && order_data_row.getOrder_shipping_fee().compareTo(BigDecimal.ZERO) > 0) {
if (order_data_row != null &&
order_data_row.getOrder_shipping_fee() != null &&
order_data_row.getOrder_shipping_fee().compareTo(BigDecimal.ZERO) > 0) {
// 运费大于0的 执行退运费操作, 有两种方案1生成退运费售后服务单 2直接执行退款
// 1生成独立退运费售后服务单需注意运费是退给运费代理商的需要获取代理商的交易单号
@ -1544,8 +1595,8 @@ public class ShopOrderReturnServiceImpl extends BaseServiceImpl<ShopOrderReturnM
Integer storeId = info_row.getStore_id();
// 订单运费
BigDecimal order_shipping_fee = order_data_row.getOrder_shipping_fee();
BigDecimal order_points_fee = order_data_row.getOrder_points_fee();
BigDecimal order_refund_agree_points = order_data_row.getOrder_refund_agree_points();
BigDecimal order_points_fee = ObjectUtil.defaultIfNull(order_data_row.getOrder_points_fee(), BigDecimal.ZERO);
BigDecimal order_refund_agree_points = ObjectUtil.defaultIfNull(order_data_row.getOrder_refund_agree_points(), BigDecimal.ZERO);
BigDecimal return_refund_point = NumberUtil.round(NumberUtil.sub(order_points_fee, order_refund_agree_points), 2);
return_order_shipping_fee_row.setOrder_id(order_id); // 订单编号
@ -1559,7 +1610,7 @@ public class ShopOrderReturnServiceImpl extends BaseServiceImpl<ShopOrderReturnM
return_order_shipping_fee_row.setReturn_add_time(now); // 添加时间
return_order_shipping_fee_row.setReturn_tel("");
// 店铺审核操作员
Integer storeUserId = user == null ? 0 : user.getId();
Integer storeUserId = user != null ? user.getId() : 0;
return_order_shipping_fee_row.setReturn_store_user_id(storeUserId);
return_order_shipping_fee_row.setReturn_telephone("");
return_order_shipping_fee_row.setSubsite_id(info_row.getSubsite_id());
@ -1581,11 +1632,14 @@ public class ShopOrderReturnServiceImpl extends BaseServiceImpl<ShopOrderReturnM
String type_code = stateCodeService.getCode(StateCode.ORDER_TYPE_FX, "state_code_code");
String return_id = shopNumberSeqService.createNextSeq(type_code);
return_order_shipping_fee_row.setReturn_id(return_id);
// 运费独立加一条退单记录
if (!add(return_order_shipping_fee_row)) {
logger.error("生成退运费订单失败订单ID: {}", order_id);
// 1生成退运费售后服务单
throw new ApiException(I18nUtil._("生成退运费订单失败!"));
}
logger.info("成功生成退运费订单,退单号: {}", return_id);
// 重要加上单条运费退货单
// return_rows.add(return_order_shipping_fee_row);
@ -1603,17 +1657,16 @@ public class ShopOrderReturnServiceImpl extends BaseServiceImpl<ShopOrderReturnM
// // 最后一个退款订单如果有运费加上运费
// return_row.setReturn_refund_amount(order_refund_amount_add_fee);
}
}
} else {
// 退款一部分商品
logger.debug("订单部分商品退款订单ID: {}", order_id);
ShopOrderData orderData = new ShopOrderData();
orderData.setOrder_id(order_id);
orderData.setOrder_refund_status(CommonConstant.Enable);
if (!shopOrderDataService.edit(orderData)) {
logger.error("部分退款失败订单ID: {}", order_id);
throw new ApiException(I18nUtil._("部分退款失败!"));
}
}
@ -1623,6 +1676,7 @@ public class ShopOrderReturnServiceImpl extends BaseServiceImpl<ShopOrderReturnM
orderInfo.setOrder_id(order_id);
orderInfo.setOrder_is_sync(0); // 订单同步状态
if (!shopOrderInfoService.edit(orderInfo)) {
logger.error("修改订单同步状态失败订单ID: {}", order_id);
throw new ApiException(I18nUtil._("修改订单同步状态失败!"));
}
}
@ -1634,18 +1688,37 @@ public class ShopOrderReturnServiceImpl extends BaseServiceImpl<ShopOrderReturnM
// 执行真正退款逻辑
// 卖家账户扣款买家账户增加
// 佣金问题
shopOrderReturn.setReturn_is_paid(1); // 0-退货未完成1-退货完成
shopOrderReturn.setReturn_finish_time(now);
List<ShopOrderReturn> returnOrder = new ArrayList<>();
returnOrder.addAll(return_rows);
if (return_rows != null) {
returnOrder.addAll(return_rows);
}
if (return_order_shipping_fee_row != null) {
returnOrder.add(return_order_shipping_fee_row);
}
// 重要执行退款操作
if (!payService.doRefund(returnOrder)) {
logger.error("执行退款操作失败!退单列表: {}", return_ids);
throw new ApiException(ResultCode.FAILED);
}
logger.info("退款操作执行成功,退单列表: {}", return_ids);
// 更新退货单的退款完成状态和完成时间
ShopOrderReturn updateRefundStatus = new ShopOrderReturn();
updateRefundStatus.setReturn_is_paid(1); // 0-退货未完成1-退货完成
updateRefundStatus.setReturn_finish_time(now);
QueryWrapper<ShopOrderReturn> updateWrapper = new QueryWrapper<>();
updateWrapper.in("return_id", return_ids);
if (!edit(updateRefundStatus, updateWrapper)) {
logger.error("更新退货单退款状态失败!退货单列表: {}", return_ids);
throw new ApiException(ResultCode.FAILED);
}
}
return true;
@ -2195,7 +2268,7 @@ public class ShopOrderReturnServiceImpl extends BaseServiceImpl<ShopOrderReturnM
}
/**
* 对已存在部分退款的订单进行剩余商品的全部退款
* 对已存在部分退款的订单进行剩余商品的全部退款(前提是未发货之前)
* 该方法用于处理订单中部分商品已经申请退款后对剩余商品进行整单退款的场景
*
* @param orderId 订单ID
@ -2204,18 +2277,31 @@ public class ShopOrderReturnServiceImpl extends BaseServiceImpl<ShopOrderReturnM
* @return CommonResult 退款申请结果
*/
@Override
@Transactional
public CommonResult addRemainingItems(String orderId, Boolean isSystemOpt, String remark) {
ShopOrderInfo orderInfo = shopOrderInfoService.get(orderId);
logger.info("开始处理订单剩余商品退款申请订单ID: {}", orderId);
// 参数校验
if (StrUtil.isBlank(orderId)) {
logger.warn("订单剩余商品退款申请失败订单ID为空");
throw new ApiException(I18nUtil._("订单ID不能为空"));
}
// 获取订单信息
ShopOrderInfo orderInfo = shopOrderInfoService.get(orderId);
if (orderInfo == null) {
logger.warn("订单剩余商品退款申请失败订单信息不存在订单ID: {}", orderId);
throw new ApiException(I18nUtil._("此订单信息为空!"));
}
if (orderInfo.getOrder_is_paid().equals(StateCode.ORDER_PAID_STATE_NO)) {
logger.debug("获取订单信息成功订单ID: {},订单状态: {}", orderId, orderInfo.getOrder_is_paid());
// 检查订单支付状态
if (orderInfo.getOrder_is_paid() != null && StateCode.ORDER_PAID_STATE_NO == orderInfo.getOrder_is_paid().intValue()) {
logger.warn("订单剩余商品退款申请失败订单未付款订单ID: {}", orderId);
throw new ApiException(I18nUtil._("该订单未付款,无法申请!"));
}
// 处理系统操作标识和备注信息
if (isSystemOpt == null) {
isSystemOpt = false;
}
@ -2225,27 +2311,38 @@ public class ShopOrderReturnServiceImpl extends BaseServiceImpl<ShopOrderReturnM
}
// 获取订单中所有商品
logger.debug("开始查询订单商品列表订单ID: {}", orderId);
QueryWrapper<ShopOrderItem> itemQueryWrapper = new QueryWrapper<>();
itemQueryWrapper.eq("order_id", orderId);
List<ShopOrderItem> allOrderItems = shopOrderItemService.find(itemQueryWrapper);
if (CollectionUtil.isEmpty(allOrderItems)) {
logger.warn("订单剩余商品退款申请失败订单商品表为空订单ID: {}", orderId);
throw new ApiException(I18nUtil._("订单商品表为空!"));
}
logger.info("获取订单商品列表成功,共 {} 个商品订单ID: {}", allOrderItems.size(), orderId);
// 获取已申请退款的商品ID列表
Set<Long> refundedItemIds = getRefundedItemIds(orderId);
logger.debug("开始查询已退款商品ID列表订单ID: {}", orderId);
Set<Long> refundedItemIds = getRefundFinishedItemIds(orderId);
logger.debug("已退款商品数量: {}订单ID: {}", refundedItemIds.size(), orderId);
// 筛选出尚未申请退款的商品
logger.debug("筛选未退款商品订单ID: {}", orderId);
List<ShopOrderItem> remainingItems = allOrderItems.stream()
.filter(item -> !refundedItemIds.contains(item.getOrder_item_id()))
.collect(Collectors.toList());
if (CollectionUtil.isEmpty(remainingItems)) {
logger.warn("订单剩余商品退款申请失败订单中所有商品均已申请退款订单ID: {}", orderId);
throw new ApiException(I18nUtil._("订单中所有商品均已申请退款!"));
}
logger.info("筛选出未退款商品 {} 个准备创建退款申请订单ID: {}", remainingItems.size(), orderId);
// 生成退款单
logger.debug("构建退款申请参数订单ID: {}", orderId);
OrderReturnInputVo orderReturnInputVo = new OrderReturnInputVo();
orderReturnInputVo.setOrder_id(orderId);
orderReturnInputVo.setReturn_tel("");
@ -2254,6 +2351,7 @@ public class ShopOrderReturnServiceImpl extends BaseServiceImpl<ShopOrderReturnM
orderReturnInputVo.setSystem_opear(isSystemOpt);
// 为剩余商品创建退款申请
logger.debug("为 {} 个未退款商品创建退款明细订单ID: {}", remainingItems.size(), orderId);
for (ShopOrderItem orderItem : remainingItems) {
OrderReturnItemInputVo returnItemInputVo = new OrderReturnItemInputVo();
returnItemInputVo.setOrder_item_id(orderItem.getOrder_item_id());
@ -2261,24 +2359,32 @@ public class ShopOrderReturnServiceImpl extends BaseServiceImpl<ShopOrderReturnM
returnItemInputVo.setReturn_refund_amount(orderItem.getOrder_item_payment_amount());
orderReturnInputVo.getReturn_items().add(returnItemInputVo);
logger.debug("添加退款商品明细商品ID: {},数量: {},金额: {}",
orderItem.getOrder_item_id(),
orderItem.getOrder_item_quantity(),
orderItem.getOrder_item_payment_amount());
}
return addItem(orderReturnInputVo, true);
logger.info("退款申请参数构建完成开始提交退款申请订单ID: {}addItem 请求参数:{}", orderId, JSONUtil.toJsonStr(orderReturnInputVo));
CommonResult result = addItem(orderReturnInputVo, true);
logger.info("订单剩余商品退款申请处理完成订单ID: {},处理结果: {}", orderId, JSONUtil.toJsonStr(result));
return result;
}
/**
* 获取订单中已申请退款的商品ID列表
* 获取订单中已完成退款的商品ID列表
*
* @param orderId 订单ID
* @return Set<Long> 已申请退款的商品ID集合
*/
private Set<Long> getRefundedItemIds(String orderId) {
private Set<Long> getRefundFinishedItemIds(String orderId) {
Set<Long> refundedItemIds = new HashSet<>();
// 查询该订单所有未取消的退款单
QueryWrapper<ShopOrderReturn> returnQueryWrapper = new QueryWrapper<>();
returnQueryWrapper.eq("order_id", orderId)
.ne("return_state_id", StateCode.RETURN_PROCESS_CANCEL);
.eq("return_state_id", StateCode.RETURN_PROCESS_FINISH);
List<ShopOrderReturn> shopOrderReturns = find(returnQueryWrapper);
if (CollectionUtil.isNotEmpty(shopOrderReturns)) {

View File

@ -826,37 +826,37 @@ public class SFExpressApiServiceImpl implements SFExpressApiService {
public ThirdApiRes receiveCancelOrderNotify(String jsonData, String sign) {
// 参数校验
if (StrUtil.isBlank(jsonData) || StrUtil.isBlank(sign)) {
logger.warn("[顺丰订单取消回调] 缺少必要参数: jsonData或sign为空");
logger.warn("[顺丰订单取消回调通知] 缺少必要参数: jsonData或sign为空");
return new ThirdApiRes().fail(1003, "缺少必要参数!");
}
// 签名校验
if (!checkOpenSign(sign, jsonData)) {
logger.warn("[顺丰订单取消回调] 请求签名sign校验失败");
logger.warn("[顺丰订单取消回调通知] 请求签名sign校验失败");
return new ThirdApiRes().fail(2002, "请求签名sign校验失败");
}
logger.info("[顺丰订单取消回调] 接收回调数据: {}", jsonData);
logger.info("[顺丰订单取消回调通知] 接收回调数据: {}", jsonData);
try {
// 解析并更新顺丰同城订单状态
ShopStoreSfOrder shopStoreSfOrder = toShopStoreSfOrder(jsonData);
if (shopStoreSfOrder == null) {
logger.error("[顺丰订单取消回调] 解析订单数据失败: jsonData={}", jsonData);
logger.error("[顺丰订单取消回调通知] 解析订单数据失败: jsonData={}", jsonData);
return new ThirdApiRes().fail(-1, "订单数据解析失败!");
}
String shopOrderId = shopStoreSfOrder.getShop_order_id();
String sfOrderId = shopStoreSfOrder.getSf_order_id();
logger.info("[顺丰订单取消回调] 处理订单取消: shopOrderId={} sfOrderId={}", shopOrderId, sfOrderId);
logger.info("[顺丰订单取消回调通知] 处理订单取消: shopOrderId={} sfOrderId={}", shopOrderId, sfOrderId);
// 判断订单的状态是否已经取消了已取消不再执行
ShopStoreSfOrder shopStoreSfOrderExist = shopStoreSfOrderService.getBySfOrderId(sfOrderId);
if (shopStoreSfOrderExist != null && shopStoreSfOrderExist.getOrder_status() != null
&& (ObjectUtil.equal(shopStoreSfOrderExist.getOrder_status(), StateCode.SF_ORDER_STATUS_CANCELED) ||
ObjectUtil.equal(shopStoreSfOrderExist.getOrder_status(), StateCode.SF_ORDER_STATUS_CANCELING))) {
logger.info("[顺丰订单取消回调] 订单已处于取消状态,无需重复处理: sfOrderId={} status={}",
logger.info("[顺丰订单取消回调通知] 订单已处于取消状态,无需重复处理: sfOrderId={} status={}",
sfOrderId, shopStoreSfOrderExist.getOrder_status());
return new ThirdApiRes().success("success");
}
@ -864,18 +864,18 @@ public class SFExpressApiServiceImpl implements SFExpressApiService {
// 更新顺丰订单状态
Boolean success = shopStoreSfOrderService.updateShopStoreSfOrderStatus(shopStoreSfOrder);
if (!success) {
logger.error("[顺丰订单取消回调] 更新顺丰订单状态失败: sfOrderId={}", sfOrderId);
logger.error("[顺丰订单取消回调通知] 更新顺丰订单状态失败: sfOrderId={}", sfOrderId);
return new ThirdApiRes().fail(-1, "状态处理失败!");
}
logger.debug("[顺丰订单取消回调] 顺丰订单状态更新成功: sfOrderId={}", sfOrderId);
logger.debug("[顺丰订单取消回调通知] 顺丰订单状态更新成功: sfOrderId={}", sfOrderId);
// 重要更改商城订单状态为已取消注意事务问题
success = shopOrderReturnService.sfExpressExpiredForceRefund(shopOrderId);
if (!success) {
logger.error("[顺丰订单取消回调] 取消商城订单业务处理失败: shopOrderId={}", shopOrderId);
logger.error("[顺丰订单取消回调通知] 取消商城订单业务处理失败: shopOrderId={}", shopOrderId);
return new ThirdApiRes().fail(-1, "取消订单业务处理失败!");
}
logger.debug("[顺丰订单取消回调] 商城订单取消处理成功: shopOrderId={}", shopOrderId);
logger.debug("[顺丰订单取消回调通知] 商城订单取消处理成功: shopOrderId={}", shopOrderId);
// 获取顺丰同城的物流轨迹
Map<String, Object> params = new HashMap<>();
@ -885,7 +885,7 @@ public class SFExpressApiServiceImpl implements SFExpressApiService {
JSONObject result = JSONUtil.parseObj(feedRes.getResult());
if (result != null && result.get("feed") != null) {
shopStoreSfOrder.setFeed(JSONUtil.toJsonStr(result.get("feed")));
logger.debug("[顺丰订单取消回调] 获取物流轨迹成功: sfOrderId={}", sfOrderId);
logger.debug("[顺丰订单取消回调通知] 获取物流轨迹成功: sfOrderId={}", sfOrderId);
}
}
@ -894,12 +894,11 @@ public class SFExpressApiServiceImpl implements SFExpressApiService {
payload.put("category", CommonConstant.PUSH_MSG_CATE_MCH_ORDER_DETAIL);
payload.put("orderId", shopOrderId);
pushMessageService.noticeMerchantEmployeeOrderAction(null, shopOrderId, "您有一笔取消订单", "您有一笔取消订单[" + shopOrderId + "],请及时处理。", payload);
logger.info("[顺丰订单取消回调] 推送消息完成: shopOrderId={}", shopOrderId);
logger.info("[顺丰订单取消回调] 处理完成: shopOrderId={} sfOrderId={}", shopOrderId, sfOrderId);
logger.info("[顺丰订单取消回调通知] 处理完成: shopOrderId={} sfOrderId={}", shopOrderId, sfOrderId);
return new ThirdApiRes().success("success");
} catch (Exception e) {
logger.error("[顺丰订单取消回调] 处理过程中发生异常", e);
logger.error("[顺丰订单取消回调通知] 处理过程中发生异常", e);
return new ThirdApiRes().fail(-1, "系统处理异常: " + e.getMessage());
}
}

View File

@ -2375,7 +2375,7 @@ public class ShopStoreBaseServiceImpl extends BaseServiceImpl<ShopStoreBaseMappe
// 打包费
BigDecimal packingFee = Convert.toBigDecimal(getParameter("packing_fee"));
if (packingFee == null || packingFee.compareTo(BigDecimal.ZERO) <= 0) {
base.setPacking_fee(BigDecimal.ZERO);
packingFee = BigDecimal.ZERO;
}
if (packingFee.compareTo(new BigDecimal("10")) > 0) {
@ -2385,9 +2385,11 @@ public class ShopStoreBaseServiceImpl extends BaseServiceImpl<ShopStoreBaseMappe
Integer ringtoneIsEnable = Convert.toInt(getParameter("ringtone_is_enable"));
if (ringtoneIsEnable == null || ringtoneIsEnable <= 0) {
base.setRingtone_is_enable(CommonConstant.Enable);
ringtoneIsEnable = CommonConstant.Enable;
}
base.setRingtone_is_enable(ringtoneIsEnable);
// 百度坐标系BD09经纬度 转出 火星坐标系GCJ02经纬度 因为数据库保存的经纬度统一是GCJ02经纬度所以需要转换
base = bd09ToGcj02Gps(base);
@ -2543,12 +2545,7 @@ public class ShopStoreBaseServiceImpl extends BaseServiceImpl<ShopStoreBaseMappe
// 打包费
BigDecimal packingFee = Convert.toBigDecimal(getParameter("packing_fee"));
if (packingFee == null || packingFee.compareTo(BigDecimal.ZERO) <= 0) {
base.setPacking_fee(BigDecimal.ZERO);
}
Integer ringtoneIsEnable = Convert.toInt(getParameter("ringtone_is_enable"));
if (ringtoneIsEnable == null || ringtoneIsEnable <= 0) {
base.setRingtone_is_enable(CommonConstant.Enable);
packingFee = BigDecimal.ZERO;
}
if (packingFee.compareTo(new BigDecimal("10")) > 0) {
@ -2556,6 +2553,13 @@ public class ShopStoreBaseServiceImpl extends BaseServiceImpl<ShopStoreBaseMappe
}
base.setPacking_fee(packingFee);
Integer ringtoneIsEnable = Convert.toInt(getParameter("ringtone_is_enable"));
if (ringtoneIsEnable == null || ringtoneIsEnable <= 0) {
ringtoneIsEnable = CommonConstant.Enable;
}
base.setRingtone_is_enable(ringtoneIsEnable);
// 百度坐标系BD09经纬度 转出 火星坐标系GCJ02经纬度 因为数据库保存的经纬度统一是GCJ02经纬度所以需要转换
base = bd09ToGcj02Gps(base);

View File

@ -45,7 +45,6 @@ import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.*;
//import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@ -75,8 +74,8 @@ public class SnsUserMessageServiceImpl extends BaseServiceImpl<SnsUserMessageMap
private SnsUserFriendService snsUserFriendService;
@Autowired
private ImService imService;
@Autowired
private RedisTemplate<String, Object> redisTemplate;
// @Autowired
// private RedisTemplate<String, Object> redisTemplate;
@Override
public Map getMsgCount() {
@ -88,30 +87,22 @@ public class SnsUserMessageServiceImpl extends BaseServiceImpl<SnsUserMessageMap
}
Integer userId = user.getId();
String cacheKey = "sns:user:message:unread:" + userId;
String counterKey = "sns:user:message:unread:counter:" + userId;
// String cacheKey = "sns:user:message:unread:" + userId;
// 尝试从Redis缓存中获取数据
Map cachedResult = (Map) redisTemplate.opsForValue().get(cacheKey);
if (cachedResult != null) {
return cachedResult;
}
// // 尝试从Redis缓存中获取数据
// Map cachedResult = (Map) redisTemplate.opsForValue().get(cacheKey);
// if (cachedResult != null) {
// return cachedResult;
// }
// 使用计数器方式提高性能避免每次都count数据库
Long unreadCount = redisTemplate.opsForValue().increment(counterKey, 0);
if (unreadCount == null) {
// 如果计数器不存在则从数据库查询并初始化计数器
QueryWrapper<SnsUserMessage> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("user_id", userId).eq("message_kind", 2).eq("message_is_read", 0);
unreadCount = count(queryWrapper);
// 设置计数器过期时间1小时
redisTemplate.opsForValue().set(counterKey, unreadCount, 3600, TimeUnit.SECONDS);
}
QueryWrapper<SnsUserMessage> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("user_id", userId).eq("message_kind", 2).eq("message_is_read", 0);
long num = count(queryWrapper);
rs.put("num", unreadCount);
rs.put("num", num);
// 构造最后一个用户聊天网址
if (unreadCount > 0) {
if (num > 0) {
QueryWrapper<SnsUserMessage> messageQuery = new QueryWrapper<>();
messageQuery.orderByAsc("message_is_read").orderByDesc("message_time")
.eq("user_id", userId).eq("message_is_read", 0).eq("message_kind", 2);
@ -132,8 +123,8 @@ public class SnsUserMessageServiceImpl extends BaseServiceImpl<SnsUserMessageMap
}
}
// 将结果缓存到Redis缓存5秒以提高高并发下的性能
redisTemplate.opsForValue().set(cacheKey, rs, 5, TimeUnit.SECONDS);
// // 将结果缓存到Redis缓存10秒
// redisTemplate.opsForValue().set(cacheKey, rs, 45, TimeUnit.SECONDS);
return rs;
}
@ -329,10 +320,13 @@ public class SnsUserMessageServiceImpl extends BaseServiceImpl<SnsUserMessageMap
}
/**
* 重写setRead方法在设置消息为已读时更新未读计数器
* 设置为已读
*
* @return
*/
@Override
public boolean setRead() {
// 权限判断
UserDto user = ContextUtil.getCurrentUser();
if (user == null) {
@ -352,29 +346,10 @@ public class SnsUserMessageServiceImpl extends BaseServiceImpl<SnsUserMessageMap
if (CheckUtil.isNotEmpty(user_other_id)) {
queryWrapper.eq("user_other_id", user_other_id);
}
// 查询需要更新的消息数量
List<SnsUserMessage> messagesToUpdate = find(queryWrapper);
long unreadToUpdate = messagesToUpdate.stream()
.filter(m -> m.getMessage_is_read() == 0)
.count();
SnsUserMessage userMessage = new SnsUserMessage();
userMessage.setMessage_is_read(1);
boolean result = saveOrUpdate(userMessage, queryWrapper);
// 更新未读计数器和缓存
if (result && unreadToUpdate > 0) {
String counterKey = "sns:user:message:unread:counter:" + user_id;
String cacheKey = "sns:user:message:unread:" + user_id;
// 减少计数器
redisTemplate.opsForValue().increment(counterKey, -unreadToUpdate);
// 删除缓存下次请求会重新生成
redisTemplate.delete(cacheKey);
}
return result;
saveOrUpdate(userMessage, queryWrapper);
return true;
}
@Override
@ -737,11 +712,14 @@ public class SnsUserMessageServiceImpl extends BaseServiceImpl<SnsUserMessageMap
}
/**
* 重写addMessage方法在添加新消息时更新未读计数器
* 添加短消息
*
* @return
*/
@Override
@Transactional
public Map addMessage() {
UserDto user = ContextUtil.getCurrentUser();
if (user == null) {
throw new ApiException(ResultCode.NEED_LOGIN);
@ -840,18 +818,8 @@ public class SnsUserMessageServiceImpl extends BaseServiceImpl<SnsUserMessageMap
if (!saveOrUpdate(other)) {
throw new ApiException(I18nUtil._("保存收件箱失败data=") + other);
}
result.put("message_id", data.getMessage_id());
result.put("message_other_id", other.getMessage_id());
// 新消息添加后更新接收者的未读计数器和缓存
String counterKey = "sns:user:message:unread:counter:" + user_other_row.getUser_id();
String cacheKey = "sns:user:message:unread:" + user_other_row.getUser_id();
// 增加计数器
redisTemplate.opsForValue().increment(counterKey, 1);
// 删除缓存下次请求会重新生成
redisTemplate.delete(cacheKey);
}
return result;
}

View File

@ -560,9 +560,6 @@
<baseImage>openjdk:8-jre</baseImage>
<!--定义容器启动命令,注意不能换行-->
<!-- <entryPoint>["java", "-jar", "-Xms256m", "-Xmx512m", "-XX:MetaspaceSize=256m", "-XX:MaxMetaspaceSize=256m", "-XX:+UseContainerSupport", "-XX:MaxRAMPercentage=60.0", "-XX:+UseSerialGC", "-XX:MinHeapFreeRatio=40", "-XX:MaxHeapFreeRatio=60", "-XX:+PrintGCDetails", "-XX:+PrintGCDateStamps", "-Xloggc:./gc.log", "-XX:+UseGCLogFileRotation", "-XX:NumberOfGCLogFiles=5", "-XX:GCLogFileSize=10M", "-Dspring.profiles.active=${spring.profile}", "-Duser.timezone=Asia/Shanghai", "/${project.build.finalName}.jar"]-->
<!-- </entryPoint>-->
<!--定义容器启动命令,注意不能换行-->
<entryPoint>["sh", "-c", "mkdir -p /tmp /app/temp /root/nacos/naming/public &amp;&amp; chmod -R 777 /tmp /app/temp /root/nacos &amp;&amp; java -Djava.io.tmpdir=/app/temp -Dnacos.naming.cache.dir=/root/nacos/naming -jar -Xms256m -Xmx512m -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=256m -XX:+UseContainerSupport -XX:MaxRAMPercentage=60.0 -XX:+UseSerialGC -XX:MinHeapFreeRatio=40 -XX:MaxHeapFreeRatio=60 -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:./gc.log -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=10M -Dspring.profiles.active=${spring.profile} -Duser.timezone=Asia/Shanghai /${project.build.finalName}.jar"]
</entryPoint>