优化顺丰超时脚本自动退款逻辑,支持部份退款的订单全额退款剩余的款项。

This commit is contained in:
Jack 2025-09-11 17:00:31 +08:00
parent 04042d5a4b
commit fcfd333853
6 changed files with 371 additions and 189 deletions

View File

@ -2264,120 +2264,121 @@ public class LakalaApiServiceImpl implements LakalaApiService {
*/
@Override
public JSONObject sacsSeparateNotify(HttpServletRequest request) {
log.info("开始处理拉卡拉分账结果通知异步回调");
log.info("[拉卡拉分账通知] 开始处理拉卡拉分账结果通知异步回调");
// 1. 验签处理 - 验证通知来源的合法性
log.debug("开始进行通知签名验证");
Pair<Boolean, String> signCheckResult = LakalaUtil.chkLklApiNotifySign(request, lklNotifyCerPath, false);
if (!signCheckResult.getFirst()) {
String errorMsg = "分账通知验签失败: " + signCheckResult.getSecond();
log.warn(errorMsg);
return JSONUtil.createObj()
.set("code", "FAIL")
.set("retMsg", signCheckResult.getSecond());
}
// 2. 解析请求参数 - 将验签后的参数转换为JSON对象
log.debug("解析通知参数");
JSONObject paramsJson = JSONUtil.parseObj(signCheckResult.getSecond());
if (paramsJson == null) {
String errorMsg = "分账通知参数解析失败: 请求参数为空";
log.error(errorMsg);
return JSONUtil.createObj()
.put("code", "FAIL")
.put("message", "请求参数为空");
}
// 3. 提取关键参数并校验 - 确保必要参数完整
log.debug("校验必要参数完整性");
String logNo = paramsJson.getStr("log_no"); // 合单订单是子单流水号非合单时是主单流水号
String separateNo = paramsJson.getStr("separate_no");
String outSeparateNo = paramsJson.getStr("out_separate_no");
String status = paramsJson.getStr("status");
String finalStatus = paramsJson.getStr("final_status");
List<String> missingParams = new ArrayList<>();
if (StrUtil.isBlank(outSeparateNo)) missingParams.add("outSeparateNo");
if (StrUtil.isBlank(separateNo)) missingParams.add("separateNo");
if (StrUtil.isBlank(status)) missingParams.add("status");
if (!missingParams.isEmpty()) {
String errorMsg = "分账通知缺少必要参数: " + String.join(", ", missingParams);
log.error(errorMsg + ", 参数详情: {}", paramsJson);
return JSONUtil.createObj()
.put("code", "FAIL")
.put("message", errorMsg);
}
LklOrderSeparate lklOrderSeparateExist = lklOrderSeparateService.getByLogNoAndOutTradeNo(logNo, outSeparateNo);
if (lklOrderSeparateExist == null) {
String errorMsg = "未找到对应的分账记录";
log.error(errorMsg + ", 外部分账单号={}, 分账单号={}, 参数详情: {}", outSeparateNo, separateNo, paramsJson);
return JSONUtil.createObj()
.put("code", "FAIL")
.put("message", errorMsg);
}
if ("SUCCESS".equals(lklOrderSeparateExist.getFinal_status())) {
String errorMsg = "分账已处理成功,请不要重复通知";
log.warn(errorMsg + ", 订单号={}, 外部分账单号={}, 参数详情: {}", logNo, outSeparateNo, paramsJson);
return JSONUtil.createObj()
.put("code", "SUCCESS")
.put("message", "分账已处理成功,请不要重复通知");
}
if (!"FAIL".equals(lklOrderSeparateExist.getFinal_status())) {
String errorMsg = "已受理或处理中,成功后再通知";
log.warn(errorMsg + ", 订单号={}, 外部分账单号={}, 参数详情: {}", logNo, outSeparateNo, paramsJson);
return JSONUtil.createObj()
.put("code", "FAIL")
.put("message", "已受理或处理中,成功后再通知");
}
// 4. 记录关键参数信息便于问题排查
log.info("接收到分账通知,分账单号={}, 外部分账单号={}, 状态={}, 最终状态={}",
separateNo, outSeparateNo, status, finalStatus);
// 5. 构建分账记录对象 - 准备更新数据库的分账记录
LklOrderSeparate lklOrderSeparate = new LklOrderSeparate();
lklOrderSeparate.setLog_no(logNo);
lklOrderSeparate.setSeparate_no(separateNo);
lklOrderSeparate.setOut_separate_no(outSeparateNo);
lklOrderSeparate.setStatus(status);
lklOrderSeparate.setFinal_status(finalStatus);
lklOrderSeparate.setCal_type(paramsJson.getStr("cal_type"));
lklOrderSeparate.setSeparate_type(paramsJson.getStr("separate_type"));
lklOrderSeparate.setSeparate_date(paramsJson.getStr("separate_date"));
lklOrderSeparate.setTotal_separate_value(paramsJson.getInt("total_amt"));
lklOrderSeparate.setRemark("分账已完成");
lklOrderSeparate.setFinish_date(paramsJson.getStr("finish_date"));
// 处理detail_datas避免空指针
JSONArray detailDatas = paramsJson.getJSONArray("detail_datas");
lklOrderSeparate.setDetail_datas(detailDatas != null ? detailDatas.toString() : "[]");
// 6. 持久化处理 - 更新分账记录到数据库
log.debug("开始更新分账记录到数据库");
try {
// 1. 验签处理 - 验证通知来源的合法性
Pair<Boolean, String> signCheckResult = LakalaUtil.chkLklApiNotifySign(request, lklNotifyCerPath, false);
if (!signCheckResult.getFirst()) {
String errorMsg = "分账通知验签失败: " + signCheckResult.getSecond();
log.warn("[拉卡拉分账通知] {}", errorMsg);
return JSONUtil.createObj()
.set("code", "FAIL")
.set("message", signCheckResult.getSecond());
}
// 2. 解析请求参数 - 将验签后的参数转换为JSON对象
JSONObject paramsJson = JSONUtil.parseObj(signCheckResult.getSecond());
if (paramsJson == null) {
String errorMsg = "分账通知参数解析失败: 请求参数为空";
log.error("[拉卡拉分账通知] {}", errorMsg);
return JSONUtil.createObj()
.put("code", "FAIL")
.put("message", "请求参数为空");
}
// 3. 提取关键参数并校验 - 确保必要参数完整
String logNo = paramsJson.getStr("log_no"); // 合单订单是子单流水号非合单时是主单流水号
String separateNo = paramsJson.getStr("separate_no");
String outSeparateNo = paramsJson.getStr("out_separate_no");
String status = paramsJson.getStr("status");
String finalStatus = paramsJson.getStr("final_status");
List<String> missingParams = new ArrayList<>();
if (StrUtil.isBlank(outSeparateNo)) missingParams.add("outSeparateNo");
if (StrUtil.isBlank(separateNo)) missingParams.add("separateNo");
if (StrUtil.isBlank(status)) missingParams.add("status");
if (!missingParams.isEmpty()) {
String errorMsg = "分账通知缺少必要参数: " + String.join(", ", missingParams);
log.error("[拉卡拉分账通知] {},参数详情: {}", errorMsg, paramsJson);
return JSONUtil.createObj()
.put("code", "FAIL")
.put("message", errorMsg);
}
// 4. 查询现有分账记录
LklOrderSeparate lklOrderSeparateExist = lklOrderSeparateService.getByLogNoAndOutTradeNo(logNo, outSeparateNo);
if (lklOrderSeparateExist == null) {
String errorMsg = "未找到对应的分账记录";
log.error("[拉卡拉分账通知] {},外部分账单号={},分账单号={},参数详情: {}",
errorMsg, outSeparateNo, separateNo, paramsJson);
return JSONUtil.createObj()
.put("code", "FAIL")
.put("message", errorMsg);
}
// 5. 检查分账记录状态避免重复处理
String existingFinalStatus = lklOrderSeparateExist.getFinal_status();
if ("SUCCESS".equals(existingFinalStatus)) {
String warnMsg = "分账已处理成功,请不要重复通知";
log.warn("[拉卡拉分账通知] {},订单号={},外部分账单号={},参数详情: {}",
warnMsg, logNo, outSeparateNo, paramsJson);
return JSONUtil.createObj()
.put("code", "SUCCESS")
.put("message", "分账已处理成功,请不要重复通知");
}
if (!"FAIL".equals(existingFinalStatus) && StrUtil.isNotBlank(existingFinalStatus)) {
String warnMsg = "已受理或处理中,成功后再通知";
log.warn("[拉卡拉分账通知] {},订单号={},外部分账单号={},参数详情: {}",
warnMsg, logNo, outSeparateNo, paramsJson);
return JSONUtil.createObj()
.put("code", "FAIL")
.put("message", "已受理或处理中,成功后再通知");
}
// 6. 记录关键参数信息便于问题排查
log.info("[拉卡拉分账通知] 接收到分账通知,分账单号={},外部分账单号={},状态={},最终状态={}",
separateNo, outSeparateNo, status, finalStatus);
// 7. 构建分账记录对象 - 准备更新数据库的分账记录
LklOrderSeparate lklOrderSeparate = new LklOrderSeparate();
lklOrderSeparate.setLog_no(logNo);
lklOrderSeparate.setSeparate_no(separateNo);
lklOrderSeparate.setOut_separate_no(outSeparateNo);
lklOrderSeparate.setStatus(status);
lklOrderSeparate.setFinal_status(finalStatus);
lklOrderSeparate.setCal_type(paramsJson.getStr("cal_type"));
lklOrderSeparate.setSeparate_type(paramsJson.getStr("separate_type"));
lklOrderSeparate.setSeparate_date(paramsJson.getStr("separate_date"));
lklOrderSeparate.setTotal_separate_value(paramsJson.getInt("total_separate_value", 0));
lklOrderSeparate.setRemark("分账已完成");
lklOrderSeparate.setFinish_date(paramsJson.getStr("finish_date"));
// 处理detail_datas避免空指针
JSONArray detailDatas = paramsJson.getJSONArray("detail_datas");
lklOrderSeparate.setDetail_datas(detailDatas != null ? detailDatas.toString() : "[]");
// 8. 持久化处理 - 更新分账记录到数据库
boolean updateSuccess = lklOrderSeparateService.addOrUpdateByReceiverNo(lklOrderSeparate);
if (!updateSuccess) {
String errorMsg = String.format("分账记录更新失败, separateNo=%s", separateNo);
log.error(errorMsg);
log.error("[拉卡拉分账通知] {}", errorMsg);
return JSONUtil.createObj()
.put("code", "FAIL")
.put("message", "数据更新失败");
}
// 7. 记录处理成功日志
log.info("分账通知处理成功, separateNo={}, status={}", separateNo, status);
// 9. 记录处理成功日志
log.info("[拉卡拉分账通知] 分账通知处理成功, separateNo={}, status={}", separateNo, status);
return JSONUtil.createObj()
.put("code", "SUCCESS")
.put("message", "操作成功");
} catch (Exception e) {
// 8. 异常处理
String errorMsg = String.format("分账通知数据处理异常, separateNo=%s: %s", separateNo, e.getMessage());
log.error(errorMsg, e);
// 10. 异常处理
String errorMsg = String.format("分账通知数据处理异常: %s", e.getMessage());
log.error("[拉卡拉分账通知] {}", errorMsg, e);
return JSONUtil.createObj()
.put("code", "FAIL")
.put("message", "系统处理异常");

View File

@ -175,6 +175,17 @@ public interface ShopOrderReturnService extends IBaseService<ShopOrderReturn> {
*/
CommonResult addWholeItems(String orderId, Boolean isSystemOpt, String remark);
/**
* 对已存在部分退款的订单进行剩余商品的全部退款
* 该方法用于处理订单中部分商品已经申请退款后对剩余商品进行整单退款的场景
*
* @param orderId 订单ID
* @param isSystemOpt 是否系统自动操作
* @param remark 退单备注
* @return CommonResult 退款申请结果
*/
CommonResult addRemainingItems(String orderId, Boolean isSystemOpt, String remark);
/**
* 退货单转单-供应商
*

View File

@ -2347,10 +2347,10 @@ public class ShopOrderBaseServiceImpl extends BaseServiceImpl<ShopOrderBaseMappe
queryWrapper.eq("order_state_id", order_state_id).in("order_is_shipped", Arrays.asList(StateCode.ORDER_SHIPPED_STATE_NO, StateCode.ORDER_SHIPPED_STATE_PART)).eq("order_is_received", 0);
break;
case StateCode.ORDER_STATE_SHIPPED: // 待收获确认
shopOrderInfo.setOrder_is_received(1);
shopOrderInfo.setOrder_is_received(CommonConstant.Enable);
shopOrderInfo.setOrder_settlement_time(time);
shopOrderInfo.setOrder_qs_time(time);
queryWrapper.eq("order_state_id", order_state_id).eq("order_is_received", 0);
queryWrapper.eq("order_state_id", order_state_id).eq("order_is_received", CommonConstant.Disable);
break;
default:
shopOrderInfo.setOrder_settlement_time(time);
@ -4818,7 +4818,7 @@ public class ShopOrderBaseServiceImpl extends BaseServiceImpl<ShopOrderBaseMappe
throw new ApiException(ResultCode.FAILED);
}
// 权限判断
// 用户权限判断
UserDto user = getCurrentUser();
if (user == null) {
throw new ApiUserException(I18nUtil._("用户信息异常!"));

View File

@ -924,40 +924,58 @@ public class ShopOrderReturnServiceImpl extends BaseServiceImpl<ShopOrderReturnM
/**
* 支付订单顺丰同城配送超时自动取消订单并退款加库存
* <p>
* 该方法用于处理顺丰同城配送超时的情况自动为订单创建退货申请并处理退款流程
* 主要包括以下几个步骤
* 1. 创建整单退货申请
* 2. 查询创建的退货单
* 3. 设置退货相关信息
* 4. 处理退货审核流程
* </p>
*
* @param shopOrderId <p>
* RETURN_PROCESS_SUBMIT = 3100; //客户提交退单1ReturnReturn
* RETURN_PROCESS_CHECK = 3105; //退单审核1ReturnReturn
* RETURN_PROCESS_RECEIVED = 3110; //收货确认0ReturnReturn
* RETURN_PROCESS_REFUND = 3115; //退款确认0ReturnReturn
* RETURN_PROCESS_RECEIPT_CONFIRMATION = 3120; //[客户收款确认0 ReturnReturn
* RETURN_PROCESS_FINISH = 3125; //完成1退货退款
* RETURN_PROCESS_REFUSED = 3130; //-商家拒绝退货
* RETURN_PROCESS_CANCEL = 3135; //-买家取消退款
* @return
* @param shopOrderId 商城订单ID
* @return Boolean 处理结果true表示成功false表示失败
*/
@GlobalTransactional
@GlobalTransactional(timeoutMills = 30000, name = "sf-express-expired-force-refund")
@Override
public Boolean sfExpressExpiredForceRefund(String shopOrderId) {
logger.info("[顺丰超时自动退款] 开始处理订单: shopOrderId={}", shopOrderId);
String remark = "配送异常自动退款!";
// 先整单退货申请
CommonResult commonResult = addWholeItems(shopOrderId, true, remark);
commonResult.checkFenResult();
try {
String remark = "同城配送异常自动退款!";
QueryWrapper<ShopOrderReturn> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("order_id", shopOrderId);
ShopOrderReturn shopOrderReturn = findOne(queryWrapper);
if (shopOrderReturn == null) {
throw new ApiException(I18nUtil._("订单信息异常!"));
// 先整单退货申请
CommonResult commonResult = addWholeItems(shopOrderId, true, remark);
commonResult.checkFenResult();
logger.debug("[顺丰超时自动退款] 整单退货申请创建成功: shopOrderId={}", shopOrderId);
QueryWrapper<ShopOrderReturn> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("order_id", shopOrderId);
ShopOrderReturn shopOrderReturn = findOne(queryWrapper);
if (shopOrderReturn == null) {
logger.error("[顺丰超时自动退款] 订单信息异常,未找到退货单: shopOrderId={}", shopOrderId);
throw new ApiException(I18nUtil._("订单信息异常!"));
}
shopOrderReturn.setReturn_flag(0); // 0-不用退货;1-需要退货
shopOrderReturn.setReturn_buyer_message(remark);
shopOrderReturn.setReturn_store_message(remark);
logger.debug("[顺丰超时自动退款] 退货单信息设置完成: returnId={}", shopOrderReturn.getReturn_id());
// 退货审核商家同意退款仅仅退款因为商品还没有配送出去
Boolean result = processReviewList(shopOrderReturn, 0);
if (result) {
logger.info("[顺丰超时自动退款] 处理完成: shopOrderId={}", shopOrderId);
} else {
logger.error("[顺丰超时自动退款] 退货审核处理失败: shopOrderId={}", shopOrderId);
}
return result;
} catch (Exception e) {
logger.error("[顺丰超时自动退款] 处理过程中发生异常: shopOrderId={}", shopOrderId, e);
throw e;
}
shopOrderReturn.setReturn_flag(0); // 0-不用退货;1-需要退货
shopOrderReturn.setReturn_buyer_message(remark);
shopOrderReturn.setReturn_store_message(remark);
// 退货审核商家同意退款仅仅退款因为商品还没有配送出去
return processReviewList(shopOrderReturn, 0);
}
/**
@ -2176,6 +2194,114 @@ public class ShopOrderReturnServiceImpl extends BaseServiceImpl<ShopOrderReturnM
return addItem(orderReturnInputVo, true);
}
/**
* 对已存在部分退款的订单进行剩余商品的全部退款
* 该方法用于处理订单中部分商品已经申请退款后对剩余商品进行整单退款的场景
*
* @param orderId 订单ID
* @param isSystemOpt 是否系统自动操作
* @param remark 退单备注
* @return CommonResult 退款申请结果
*/
@Override
@Transactional
public CommonResult addRemainingItems(String orderId, Boolean isSystemOpt, String remark) {
ShopOrderInfo orderInfo = shopOrderInfoService.get(orderId);
if (orderInfo == null) {
throw new ApiException(I18nUtil._("此订单信息为空!"));
}
if (orderInfo.getOrder_is_paid().equals(StateCode.ORDER_PAID_STATE_NO)) {
throw new ApiException(I18nUtil._("该订单未付款,无法申请!"));
}
if (isSystemOpt == null) {
isSystemOpt = false;
}
if (StrUtil.isBlank(remark)) {
remark = "剩余商品退款!";
}
// 获取订单中所有商品
QueryWrapper<ShopOrderItem> itemQueryWrapper = new QueryWrapper<>();
itemQueryWrapper.eq("order_id", orderId);
List<ShopOrderItem> allOrderItems = shopOrderItemService.find(itemQueryWrapper);
if (CollectionUtil.isEmpty(allOrderItems)) {
throw new ApiException(I18nUtil._("订单商品表为空!"));
}
// 获取已申请退款的商品ID列表
Set<Long> refundedItemIds = getRefundedItemIds(orderId);
// 筛选出尚未申请退款的商品
List<ShopOrderItem> remainingItems = allOrderItems.stream()
.filter(item -> !refundedItemIds.contains(item.getOrder_item_id()))
.collect(Collectors.toList());
if (CollectionUtil.isEmpty(remainingItems)) {
throw new ApiException(I18nUtil._("订单中所有商品均已申请退款!"));
}
// 生成退款单
OrderReturnInputVo orderReturnInputVo = new OrderReturnInputVo();
orderReturnInputVo.setOrder_id(orderId);
orderReturnInputVo.setReturn_tel("");
orderReturnInputVo.setReturn_buyer_message(I18nUtil._(remark));
orderReturnInputVo.setUser_id(orderInfo.getBuyer_user_id());
orderReturnInputVo.setSystem_opear(isSystemOpt);
// 为剩余商品创建退款申请
for (ShopOrderItem orderItem : remainingItems) {
OrderReturnItemInputVo returnItemInputVo = new OrderReturnItemInputVo();
returnItemInputVo.setOrder_item_id(orderItem.getOrder_item_id());
returnItemInputVo.setReturn_item_num(orderItem.getOrder_item_quantity());
returnItemInputVo.setReturn_refund_amount(orderItem.getOrder_item_payment_amount());
orderReturnInputVo.getReturn_items().add(returnItemInputVo);
}
return addItem(orderReturnInputVo, true);
}
/**
* 获取订单中已申请退款的商品ID列表
*
* @param orderId 订单ID
* @return Set<Long> 已申请退款的商品ID集合
*/
private Set<Long> getRefundedItemIds(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);
List<ShopOrderReturn> shopOrderReturns = find(returnQueryWrapper);
if (CollectionUtil.isNotEmpty(shopOrderReturns)) {
// 获取这些退款单对应的商品ID
List<String> returnIds = shopOrderReturns.stream()
.map(ShopOrderReturn::getReturn_id)
.collect(Collectors.toList());
QueryWrapper<ShopOrderReturnItem> returnItemQueryWrapper = new QueryWrapper<>();
returnItemQueryWrapper.in("return_id", returnIds);
List<ShopOrderReturnItem> returnItems = orderReturnItemService.find(returnItemQueryWrapper);
if (CollectionUtil.isNotEmpty(returnItems)) {
refundedItemIds = returnItems.stream()
.map(ShopOrderReturnItem::getOrder_item_id)
.collect(Collectors.toSet());
}
}
return refundedItemIds;
}
/**
* 订单流转到供应商
*

View File

@ -809,66 +809,99 @@ public class SFExpressApiServiceImpl implements SFExpressApiService {
/**
* 接收顺丰原因订单取消回调
* <p>
* 该方法用于处理顺丰同城配送订单取消的回调通知当顺丰因为某种原因取消订单时
* 会调用此接口通知商城系统商城系统需要更新订单状态为已取消并执行相关业务逻辑
* </p>
*
* @param jsonData
* @param sign
* @return
* @param jsonData 包含订单取消信息的JSON数据
* @param sign 请求签名用于验证请求的合法性
* @return ThirdApiRes 处理结果响应对象
* <ul>
* <li>成功: {"error_code": 0, "reason": "success"}</li>
* <li>失败: {"error_code": 错误码, "reason": "错误信息"}</li>
* </ul>
*/
@Override
public ThirdApiRes receiveCancelOrderNotify(String jsonData, String sign) {
// 参数校验
if (StrUtil.isBlank(jsonData) || StrUtil.isBlank(sign)) {
logger.warn("[顺丰订单取消回调] 缺少必要参数: jsonData或sign为空");
return new ThirdApiRes().fail(1003, "缺少必要参数!");
}
// 签名校验
if (!checkOpenSign(sign, jsonData)) {
logger.warn("[顺丰订单取消回调] 请求签名sign校验失败");
return new ThirdApiRes().fail(2002, "请求签名sign校验失败");
}
logger.info("接收顺丰原因订单取消回调返回的 JSON 数据:{}", jsonData);
logger.info("[顺丰订单取消回调] 接收回调数据: {}", jsonData);
// 更改顺丰同城订单状态
ShopStoreSfOrder shopStoreSfOrder = toShopStoreSfOrder(jsonData);
String shopOrderId = shopStoreSfOrder.getShop_order_id();
String sfOrderId = shopStoreSfOrder.getSf_order_id();
// 判断订单的状态是否已经取消了已取消不再执行
ShopStoreSfOrder shopStoreSfOrderExist = shopStoreSfOrderService.getBySfOrderId(sfOrderId);
if (shopStoreSfOrderExist != null && shopStoreSfOrderExist.getOrder_status() != null
&& (shopStoreSfOrderExist.getOrder_status().equals(StateCode.SF_ORDER_STATUS_CANCELED) ||
(shopStoreSfOrderExist.getOrder_status().equals(StateCode.SF_ORDER_STATUS_CANCELING)))) {
return new ThirdApiRes().success("success");
}
Boolean success = shopStoreSfOrderService.updateShopStoreSfOrderStatus(shopStoreSfOrder);
if (!success) {
return new ThirdApiRes().fail(-1, "状态处理失败!");
}
// 重要更改商城订单状态为已取消注意事务问题
success = shopOrderReturnService.sfExpressExpiredForceRefund(shopOrderId);
if (!success) {
return new ThirdApiRes().fail(-1, "取消订单业务处理失败!");
}
// 获取顺丰同城的物流轨迹
Map<String, Object> params = new HashMap<>();
params.put("order_id", sfOrderId);
ThirdApiRes feedRes = listOrderFeed(params);
if (feedRes != null && feedRes.getError_code().equals(0)) {
JSONObject result = JSONUtil.parseObj(feedRes.getResult());
if (result != null && result.get("feed") != null) {
shopStoreSfOrder.setFeed(JSONUtil.toJsonStr(result.get("feed")));
try {
// 解析并更新顺丰同城订单状态
ShopStoreSfOrder shopStoreSfOrder = toShopStoreSfOrder(jsonData);
if (shopStoreSfOrder == null) {
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);
// 判断订单的状态是否已经取消了已取消不再执行
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={}",
sfOrderId, shopStoreSfOrderExist.getOrder_status());
return new ThirdApiRes().success("success");
}
// 更新顺丰订单状态
Boolean success = shopStoreSfOrderService.updateShopStoreSfOrderStatus(shopStoreSfOrder);
if (!success) {
logger.error("[顺丰订单取消回调] 更新顺丰订单状态失败: sfOrderId={}", sfOrderId);
return new ThirdApiRes().fail(-1, "状态处理失败!");
}
logger.debug("[顺丰订单取消回调] 顺丰订单状态更新成功: sfOrderId={}", sfOrderId);
// 重要更改商城订单状态为已取消注意事务问题
success = shopOrderReturnService.sfExpressExpiredForceRefund(shopOrderId);
if (!success) {
logger.error("[顺丰订单取消回调] 取消商城订单业务处理失败: shopOrderId={}", shopOrderId);
return new ThirdApiRes().fail(-1, "取消订单业务处理失败!");
}
logger.debug("[顺丰订单取消回调] 商城订单取消处理成功: shopOrderId={}", shopOrderId);
// 获取顺丰同城的物流轨迹
Map<String, Object> params = new HashMap<>();
params.put("order_id", sfOrderId);
ThirdApiRes feedRes = listOrderFeed(params);
if (feedRes != null && ObjectUtil.equal(feedRes.getError_code(), 0)) {
JSONObject result = JSONUtil.parseObj(feedRes.getResult());
if (result != null && result.get("feed") != null) {
shopStoreSfOrder.setFeed(JSONUtil.toJsonStr(result.get("feed")));
logger.debug("[顺丰订单取消回调] 获取物流轨迹成功: sfOrderId={}", sfOrderId);
}
}
// 个推推送消息
JSONObject payload = new JSONObject();
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);
return new ThirdApiRes().success("success");
} catch (Exception e) {
logger.error("[顺丰订单取消回调] 处理过程中发生异常", e);
return new ThirdApiRes().fail(-1, "系统处理异常: " + e.getMessage());
}
// 个推推送消息
JSONObject payload = new JSONObject();
payload.put("category", CommonConstant.PUSH_MSG_CATE_MCH_ORDER_DETAIL);
payload.put("orderId", shopOrderId);
pushMessageService.noticeMerchantEmployeeOrderAction(null, shopOrderId, "您有一笔取消订单", "您有一笔取消订单[" + shopOrderId + "],请及时处理。", null);
return new ThirdApiRes().success("success");
}
/**
@ -959,7 +992,7 @@ public class SFExpressApiServiceImpl implements SFExpressApiService {
// 顺丰同城状态17-配送员妥投完单;
// orderStatus = StateCode.ORDER_STATE_FINISH;
pushRemark = "已完成配送";
orderStatus = StateCode.ORDER_STATE_RECEIVED;
orderStatus = StateCode.ORDER_STATE_RECEIVED; //已签收
// 通知微信用户确认收货(同城配送不能调用微信的确认收货)
// wxOrderShippingService.notifyConfirmReceive(shopStoreSfOrder.getShop_order_id());

37
pom.xml
View File

@ -517,7 +517,7 @@
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<configuration>
<layers>
<enabled>true</enabled>
</layers>
@ -529,13 +529,13 @@
</exclude>
</excludes>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
</plugin>
<plugin>
<groupId>com.spotify</groupId>
<artifactId>docker-maven-plugin</artifactId>
@ -557,7 +557,6 @@
<dockerHost>${docker.host}</dockerHost>
<!--定义基础镜像-->
<!-- <baseImage>java:8</baseImage>-->
<!-- <baseImage>openjdk:8-jre-alpine</baseImage>-->
<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"]
@ -568,16 +567,27 @@
<!-- 添加清理命令来过滤无用文件 -->
<runs>
<!-- 清理 APK 缓存(镜像) -->
<run>rm -rf /var/cache/apk/*</run>
<!-- 删除 Maven 构建过程中产生的临时文件 -->
<run>rm -rf /root/.m2</run>
<!-- 删除可能存在的日志文件 -->
<run>find / -name "*.log" -type f -delete 2>/dev/null || true</run>
<!-- 删除测试相关文件 -->
<run>find / -name "*test*" -type f -delete 2>/dev/null || true</run>
<!-- 删除文档文件 -->
<run>find / -name "*.md" -type f -delete 2>/dev/null || true</run>
<!-- 原有清理命令 -->
<run>rm -rf /var/cache/apk/*</run>
<run>rm -rf /root/.m2</run>
<run>find / -name "*.log" -type f -delete 2>/dev/null || true</run>
<run>find / -name "*test*" -type f -delete 2>/dev/null || true</run>
<run>find / -name "*.md" -type f -delete 2>/dev/null || true</run>
<!-- 新增:清理系统临时文件 -->
<run>rm -rf /tmp/* /var/tmp/*</run>
<!-- 新增删除冗余文档和手册页适用于Alpine/Debian等 -->
<run>rm -rf /usr/share/doc/* /usr/share/man/* /usr/share/info/*</run>
<!-- 新增清理包管理工具残留若使用yum/dnf -->
<run>rm -rf /var/cache/yum/* /var/cache/dnf/* 2>/dev/null || true</run>
<!-- 新增删除构建过程中下载的源码包如从wget/curl获取的临时文件 -->
<run>rm -rf /tmp/*.tar.gz /tmp/*.zip /app/*.tar.gz 2>/dev/null || true</run>
<!-- 新增移除不必要的系统工具根据应用依赖选择如vim、curl等非必需工具 -->
<run>apk del --purge vim curl wget tar gzip 2>/dev/null || true</run>
<!-- 新增清理Java相关临时文件如JVM日志、编译缓存 -->
<run>rm -rf /root/.java /tmp/hsperfdata_* 2>/dev/null || true</run>
<!-- 新增:删除空目录(减少镜像层冗余) -->
<run>find / -type d -empty -delete 2>/dev/null || true</run>
</runs>
<resources>
@ -591,6 +601,7 @@
</plugin>
</plugins>
</pluginManagement>
</build>