优化顺丰超时脚本自动退款逻辑,支持部份退款的订单全额退款剩余的款项。
This commit is contained in:
parent
04042d5a4b
commit
fcfd333853
@ -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", "系统处理异常");
|
||||
|
||||
@ -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);
|
||||
|
||||
/**
|
||||
* 退货单转单-供应商
|
||||
*
|
||||
|
||||
@ -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._("用户信息异常!"));
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 订单流转到供应商
|
||||
*
|
||||
|
||||
@ -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
37
pom.xml
@ -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>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user