diff --git a/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/coupon/CouponApi.java b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/coupon/CouponApi.java index ce7a712da..71e3ca18b 100644 --- a/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/coupon/CouponApi.java +++ b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/coupon/CouponApi.java @@ -28,4 +28,10 @@ public interface CouponApi { */ CouponRespDTO validateCoupon(@Valid CouponValidReqDTO validReqDTO); + /** + * 退还已使用的优惠券 + * + * @param id 优惠券编号 + */ + void returnUsedCoupon(Long id); } diff --git a/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java index 3103b8f30..8f5b8c803 100644 --- a/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java +++ b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java @@ -37,6 +37,7 @@ public interface ErrorCodeConstants { ErrorCode COUPON_DELETE_FAIL_USED = new ErrorCode(1013005001, "回收优惠劵失败,优惠劵已被使用"); ErrorCode COUPON_STATUS_NOT_UNUSED = new ErrorCode(1013005002, "优惠劵不处于待使用状态"); ErrorCode COUPON_VALID_TIME_NOT_NOW = new ErrorCode(1013005003, "优惠券不在使用时间范围内"); + ErrorCode COUPON_STATUS_NOT_USED = new ErrorCode(1013005004, "优惠劵不是已使用状态"); // ========== 满减送活动 1013006000 ========== ErrorCode REWARD_ACTIVITY_NOT_EXISTS = new ErrorCode(1013006000, "满减送活动不存在"); diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/coupon/CouponApiImpl.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/coupon/CouponApiImpl.java index a06ab57cd..d9ecc7d9c 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/coupon/CouponApiImpl.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/coupon/CouponApiImpl.java @@ -34,4 +34,9 @@ public class CouponApiImpl implements CouponApi { return CouponConvert.INSTANCE.convert(coupon); } + @Override + public void returnUsedCoupon(Long id) { + couponService.returnUsedCoupon(id); + } + } diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponService.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponService.java index 17f922ae8..bfe42f363 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponService.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponService.java @@ -116,4 +116,11 @@ public interface CouponService { default void takeCouponByRegister(Long templateId, Long userId) { takeCoupon(templateId, CollUtil.newHashSet(userId), CouponTakeTypeEnum.REGISTER); } + + /** + * 退还已使用的优惠券 + * + * @param id 优惠券编号 + */ + void returnUsedCoupon(Long id); } diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponServiceImpl.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponServiceImpl.java index 115818548..5e608e696 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponServiceImpl.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponServiceImpl.java @@ -202,4 +202,27 @@ public class CouponServiceImpl implements CouponService { userIds.removeIf(userId -> MapUtil.getInt(userTakeCountMap, userId, 0) >= couponTemplate.getTakeLimitCount()); } + @Override + public void returnUsedCoupon(Long id) { + // 校验存在 + CouponDO coupon = couponMapper.selectById(id); + if (coupon == null) { + throw exception(COUPON_NOT_EXISTS); + } + + // 校验状态 + if (!CouponStatusEnum.USED.getStatus().equals(coupon.getStatus())) { + throw exception(COUPON_STATUS_NOT_USED); + } + + // 退还 + Integer status = LocalDateTimeUtils.beforeNow(coupon.getValidEndTime()) + // 退还时可能已经过期了 + ? CouponStatusEnum.EXPIRE.getStatus() + : CouponStatusEnum.UNUSED.getStatus(); + couponMapper.updateById(new CouponDO().setId(id).setStatus(status)); + + // TODO 增加优惠券变动记录? + } + } diff --git a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java index 3aa0e5dd3..40f604e94 100644 --- a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java +++ b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java @@ -33,6 +33,7 @@ public interface ErrorCodeConstants { ErrorCode ORDER_DELIVERY_FAIL_COMBINATION_RECORD_STATUS_NOT_SUCCESS = new ErrorCode(1011000022, "交易订单发货失败,拼团未成功"); ErrorCode ORDER_DELIVERY_FAIL_BARGAIN_RECORD_STATUS_NOT_SUCCESS = new ErrorCode(1011000023, "交易订单发货失败,砍价未成功"); ErrorCode ORDER_DELIVERY_FAIL_DELIVERY_TYPE_NOT_EXPRESS = new ErrorCode(1011000024, "交易订单发货失败,发货类型不是快递"); + ErrorCode ORDER_CANCEL_FAIL_STATUS_NOT_UNPAID = new ErrorCode(1011000025, "交易订单取消失败,订单不是【待支付】状态"); // ========== After Sale 模块 1011000100 ========== ErrorCode AFTER_SALE_NOT_FOUND = new ErrorCode(1011000100, "售后单不存在"); diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java index 92181fca7..5abb6a98c 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java @@ -149,7 +149,7 @@ public class AppTradeOrderController { @Operation(summary = "取消交易订单") @Parameter(name = "id", description = "交易订单编号") public CommonResult cancelOrder(@RequestParam("id") Long id) { - // TODO @芋艿:未实现,mock 用 + tradeOrderUpdateService.cancelOrder(getLoginUserId(), id); return success(true); } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java index a928bb9a5..df7b296f0 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java @@ -88,6 +88,11 @@ public interface TradeOrderConvert { return new ProductSkuUpdateStockReqDTO(TradeOrderConvert.INSTANCE.convertList(list)); } + default ProductSkuUpdateStockReqDTO convertNegative(List list) { + List items = TradeOrderConvert.INSTANCE.convertList(list); + items.forEach(item -> item.setIncrCount(-item.getIncrCount())); + return new ProductSkuUpdateStockReqDTO(items); + } List convertList(List list); @Mappings({ diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateService.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateService.java index bf52358e6..ee9128b6c 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateService.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateService.java @@ -117,4 +117,11 @@ public interface TradeOrderUpdateService { */ Long createOrderItemComment(Long userId, AppTradeOrderItemCommentCreateReqVO createReqVO); + /** + * 【会员】取消订单 + * + * @param userId 用户ID + * @param id 订单编号 + */ + void cancelOrder(Long userId, Long id); } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java index 1242dfdee..4c88226ea 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java @@ -299,7 +299,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { // 1)如果是秒杀商品:额外扣减秒杀的库存; // 2)如果是拼团活动:额外扣减拼团的库存; // 3)如果是砍价活动:额外扣减砍价的库存; - productSkuApi.updateSkuStock(TradeOrderConvert.INSTANCE.convert(orderItems)); + productSkuApi.updateSkuStock(TradeOrderConvert.INSTANCE.convertNegative(orderItems)); // 删除购物车商品 Set cartIds = convertSet(createReqVO.getItems(), AppTradeOrderSettlementReqVO.Item::getCartId); @@ -308,6 +308,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { } // 扣减积分 TODO 芋艿:待实现,需要前置; + // 这个是不是应该放到支付成功之后?如果支付后的话,可能积分可以重复使用哈。资源类,都要预扣 // 有使用优惠券时更新 TODO 芋艿:需要前置; if (createReqVO.getCouponId() != null) { @@ -670,6 +671,41 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { return comment; } + @Override + public void cancelOrder(Long userId, Long id) { + // 校验存在 + TradeOrderDO order = tradeOrderMapper.selectOrderByIdAndUserId(id, userId); + if (order == null) { + throw exception(ORDER_NOT_FOUND); + } + // 校验状态 + if (ObjectUtil.notEqual(order.getStatus(), TradeOrderStatusEnum.UNPAID.getStatus())) { + throw exception(ORDER_CANCEL_FAIL_STATUS_NOT_UNPAID); + } + + // 1.更新 TradeOrderDO 状态为已取消 + int updateCount = tradeOrderMapper.updateByIdAndStatus(id, order.getStatus(), + new TradeOrderDO().setStatus(TradeOrderStatusEnum.CANCELED.getStatus()) + .setCancelTime(LocalDateTime.now()) + .setCancelType(TradeOrderCancelTypeEnum.MEMBER_CANCEL.getType())); + if (updateCount == 0) { + throw exception(ORDER_CANCEL_FAIL_STATUS_NOT_UNPAID); + } + + // 2.回滚库存 + List orderItems = tradeOrderItemMapper.selectListByOrderId(id); + productSkuApi.updateSkuStock(TradeOrderConvert.INSTANCE.convert(orderItems)); + + // 3.回滚优惠券 + couponApi.returnUsedCoupon(order.getCouponId()); + + // 4.回滚积分:积分是支付成功后才增加的吧? + + // TODO 芋艿:OrderLog + + // TODO 芋艿:lili 发送订单变化的消息 + } + /** * 判断指定订单的所有订单项,是不是都售后成功 *