diff --git a/src/main/java/com/gxwebsoft/shop/controller/ShopOrderController.java b/src/main/java/com/gxwebsoft/shop/controller/ShopOrderController.java index da8b20b..0a1ebfc 100644 --- a/src/main/java/com/gxwebsoft/shop/controller/ShopOrderController.java +++ b/src/main/java/com/gxwebsoft/shop/controller/ShopOrderController.java @@ -279,7 +279,10 @@ public class ShopOrderController extends BaseController { return fail("订单不存在"); } // 退款相关操作单独走退款接口,便于做财务权限隔离 - if (Objects.equals(shopOrder.getOrderStatus(), 6)) { + if (Objects.equals(shopOrder.getOrderStatus(), 4) + || Objects.equals(shopOrder.getOrderStatus(), 5) + || Objects.equals(shopOrder.getOrderStatus(), 6) + || Objects.equals(shopOrder.getOrderStatus(), 7)) { return fail("退款相关操作请使用退款接口: PUT /api/shop/shop-order/refund"); } ShopOrder shopOrderNow = shopOrderService.getById(shopOrder.getOrderId()); @@ -394,6 +397,20 @@ public class ShopOrderController extends BaseController { // 申请退款:只记录申请时间/原因/金额(如有) if (Objects.equals(req.getOrderStatus(), 4)) { + // 未支付订单不允许进入退款流程(否则会出现“取消订单/超时取消后变成退款申请中”的严重脏状态) + if (!Boolean.TRUE.equals(current.getPayStatus())) { + return fail("订单未支付,无法申请退款"); + } + if (Objects.equals(current.getOrderStatus(), 2)) { + return fail("订单已取消,无法申请退款"); + } + if (Objects.equals(current.getOrderStatus(), 4) + || Objects.equals(current.getOrderStatus(), 5) + || Objects.equals(current.getOrderStatus(), 6) + || Objects.equals(current.getOrderStatus(), 7)) { + return fail("订单已在退款流程中,请勿重复申请"); + } + ShopOrder patch = new ShopOrder(); patch.setOrderId(req.getOrderId()); patch.setOrderStatus(4); @@ -506,7 +523,10 @@ public class ShopOrderController extends BaseController { if (batchParam != null && batchParam.getData() != null) { Integer status = batchParam.getData().getOrderStatus(); // 退款相关操作单独走退款接口,避免绕过财务权限 - if (Objects.equals(status, 4) || Objects.equals(status, 6)) { + if (Objects.equals(status, 4) + || Objects.equals(status, 5) + || Objects.equals(status, 6) + || Objects.equals(status, 7)) { return fail("退款相关操作请使用退款接口: PUT /api/shop/shop-order/refund"); } } @@ -571,6 +591,8 @@ public class ShopOrderController extends BaseController { return fail("订单状态不允许取消"); } + // 标记为用户主动取消(定时任务/系统取消会走默认文案) + order.setCancelReason("用户取消"); boolean success = orderCancelService.cancelOrder(order); if (success) { return success("订单取消成功"); diff --git a/src/main/java/com/gxwebsoft/shop/service/impl/OrderCancelServiceImpl.java b/src/main/java/com/gxwebsoft/shop/service/impl/OrderCancelServiceImpl.java index 825afbb..46901d2 100644 --- a/src/main/java/com/gxwebsoft/shop/service/impl/OrderCancelServiceImpl.java +++ b/src/main/java/com/gxwebsoft/shop/service/impl/OrderCancelServiceImpl.java @@ -1,6 +1,8 @@ package com.gxwebsoft.shop.service.impl; +import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.gxwebsoft.common.core.annotation.IgnoreTenant; import com.gxwebsoft.shop.entity.*; import com.gxwebsoft.shop.service.*; @@ -44,6 +46,11 @@ public class OrderCancelServiceImpl implements OrderCancelService { try { log.info("开始取消订单,订单号:{},订单ID:{}", order.getOrderNo(), order.getOrderId()); + if (order.getOrderId() == null) { + log.warn("订单ID为空,无法取消"); + return false; + } + // 1. 检查订单状态 if (order.getPayStatus() != null && order.getPayStatus()) { log.warn("订单已支付,无法取消,订单号:{}", order.getOrderNo()); @@ -55,17 +62,31 @@ public class OrderCancelServiceImpl implements OrderCancelService { return false; } - // 2. 更新订单状态为已取消 - order.setOrderStatus(2); // 2表示已取消 - order.setCancelTime(LocalDateTime.now()); - order.setCancelReason("系统自动取消(超时未支付)"); + // 2. 更新订单状态为已取消(只更新必要字段 + 加条件,避免并发/越权导致“取消后又被改成退款中”等脏状态) + LocalDateTime now = LocalDateTime.now(); + String reason = StrUtil.isNotBlank(order.getCancelReason()) + ? order.getCancelReason() + : "系统自动取消(超时未支付)"; - boolean updateSuccess = shopOrderService.updateById(order); + boolean updateSuccess = shopOrderService.update( + new LambdaUpdateWrapper() + .eq(ShopOrder::getOrderId, order.getOrderId()) + .eq(ShopOrder::getPayStatus, false) + .eq(ShopOrder::getOrderStatus, 0) + .set(ShopOrder::getOrderStatus, 2) // 2表示已取消 + .set(ShopOrder::getCancelTime, now) + .set(ShopOrder::getCancelReason, reason) + ); if (!updateSuccess) { - log.error("更新订单状态失败,订单号:{}", order.getOrderNo()); + log.error("更新订单状态失败(可能已被支付/退款/取消),订单号:{},订单ID:{}", order.getOrderNo(), order.getOrderId()); return false; } + // 让后续库存/优惠券逻辑使用最新状态(不再依赖 updateById 回写) + order.setOrderStatus(2); + order.setCancelTime(now); + order.setCancelReason(reason); + // 3. 回退库存 boolean stockRestored = restoreOrderStock(order); if (!stockRestored) {