Commit 826d792ff2d24416a5cd7981979485adb2700fb3

Authored by YunaiV
1 parent e384b810

trade:增加自动取消的 job

yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderCancelTypeEnum.java
... ... @@ -17,8 +17,7 @@ public enum TradeOrderCancelTypeEnum implements IntArrayValuable {
17 17  
18 18 PAY_TIMEOUT(10, "超时未支付"),
19 19 AFTER_SALE_CLOSE(20, "退款关闭"),
20   - MEMBER_CANCEL(30, "买家取消"),
21   - PAY_ON_DELIVERY(40, "已通过货到付款交易"),; // TODO 芋艿:这个类型,是不是可以去掉
  20 + MEMBER_CANCEL(30, "买家取消");
22 21  
23 22 public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(TradeOrderCancelTypeEnum::getType).toArray();
24 23  
... ...
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderOperateTypeEnum.java
... ... @@ -16,8 +16,10 @@ public enum TradeOrderOperateTypeEnum {
16 16 MEMBER_CREATE(1, "用户下单"),
17 17 MEMBER_RECEIVE(30, "用户已收货"),
18 18 MEMBER_COMMENT(31, "用户评价"),
19   - MEMBER_CANCEL(40, "取消订单"),
20   - MEMBER_DELETE(41, "删除订单"),
  19 + MEMBER_CANCEL(40, "手动取消订单"),
  20 + SYSTEM_CANCEL(41, "系统取消订单"),
  21 + // 42 预留:管理员取消订单
  22 + MEMBER_DELETE(43, "删除订单"),
21 23 ;
22 24  
23 25 /**
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java
... ... @@ -90,7 +90,7 @@ public interface TradeOrderConvert {
90 90  
91 91 default ProductSkuUpdateStockReqDTO convert(List<TradeOrderItemDO> list) {
92 92 List<ProductSkuUpdateStockReqDTO.Item> items = CollectionUtils.convertList(list, item ->
93   - new ProductSkuUpdateStockReqDTO.Item().setId(item.getSkuId()).setIncrCount(-item.getCount()));
  93 + new ProductSkuUpdateStockReqDTO.Item().setId(item.getSkuId()).setIncrCount(item.getCount()));
94 94 return new ProductSkuUpdateStockReqDTO(items);
95 95 }
96 96 default ProductSkuUpdateStockReqDTO convertNegative(List<AppTradeOrderSettlementReqVO.Item> list) {
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/order/TradeOrderMapper.java
... ... @@ -9,6 +9,8 @@ import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
9 9 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
10 10 import org.apache.ibatis.annotations.Mapper;
11 11  
  12 +import java.time.LocalDateTime;
  13 +import java.util.List;
12 14 import java.util.Set;
13 15  
14 16 @Mapper
... ... @@ -58,4 +60,11 @@ public interface TradeOrderMapper extends BaseMapperX&lt;TradeOrderDO&gt; {
58 60 .eq(TradeOrderDO::getId, orderId)
59 61 .eq(TradeOrderDO::getUserId, loginUserId));
60 62 }
  63 +
  64 + default List<TradeOrderDO> selectListByStatusAndCreateTimeLt(Integer status, LocalDateTime expireTime) {
  65 + return selectList(new LambdaUpdateWrapper<TradeOrderDO>()
  66 + .eq(TradeOrderDO::getStatus, status)
  67 + .lt(TradeOrderDO::getCreateTime, expireTime));
  68 + }
  69 +
61 70 }
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/job/order/TradeOrderAutoCancelJob.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.job.order;
  2 +
  3 +import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler;
  4 +import cn.iocoder.yudao.framework.tenant.core.job.TenantJob;
  5 +import cn.iocoder.yudao.module.trade.service.order.TradeOrderUpdateService;
  6 +import org.springframework.stereotype.Component;
  7 +
  8 +import javax.annotation.Resource;
  9 +
  10 +/**
  11 + * 交易订单的自动过期 Job
  12 + *
  13 + * @author 芋道源码
  14 + */
  15 +@Component
  16 +@TenantJob
  17 +public class TradeOrderAutoCancelJob implements JobHandler {
  18 +
  19 + @Resource
  20 + private TradeOrderUpdateService tradeOrderUpdateService;
  21 +
  22 + @Override
  23 + public String execute(String param) {
  24 + int count = tradeOrderUpdateService.autoCancelOrder();
  25 + return String.format("过期订单 %s 个", count);
  26 + }
  27 +
  28 +}
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateService.java
... ... @@ -71,6 +71,13 @@ public interface TradeOrderUpdateService {
71 71 void cancelOrder(Long userId, Long id);
72 72  
73 73 /**
  74 + * 【系统】自动取消订单
  75 + *
  76 + * @return 取消数量
  77 + */
  78 + int autoCancelOrder();
  79 +
  80 + /**
74 81 * 【会员】删除订单
75 82 *
76 83 * @param userId 用户编号
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java
... ... @@ -76,6 +76,7 @@ import java.util.Set;
76 76  
77 77 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
78 78 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
  79 +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.addTime;
79 80 import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*;
80 81  
81 82 /**
... ... @@ -629,6 +630,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
629 630  
630 631 @Override
631 632 @Transactional(rollbackFor = Exception.class)
  633 + // TODO 芋艿:
632 634 public void updateOrderItemAfterSaleStatus(Long id, Integer oldAfterSaleStatus, Integer newAfterSaleStatus,
633 635 Long afterSaleId, Integer refundPrice) {
634 636 // 如果退款成功,则 refundPrice 非空
... ... @@ -663,12 +665,15 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
663 665  
664 666 // TODO 芋艿:记录订单日志
665 667  
  668 + // TODO 芋艿:要不要退优惠劵
  669 +
666 670 // TODO 芋艿:站内信?
667 671 } else { // 如果部分售后,则更新退款金额
668 672 tradeOrderMapper.updateById(new TradeOrderDO().setId(order.getId())
669 673 .setRefundStatus(TradeOrderRefundStatusEnum.PART.getStatus()).setRefundPrice(orderRefundPrice));
670 674 }
671 675  
  676 + // TODO 芋艿:这块扣减规则,需要在考虑下
672 677 // 售后成功后,执行数据回滚逻辑
673 678 if (Objects.equals(newAfterSaleStatus, TradeOrderItemAfterSaleStatusEnum.SUCCESS.getStatus())) {
674 679 // 扣减用户积分(赠送的)
... ... @@ -732,31 +737,76 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
732 737 throw exception(ORDER_CANCEL_FAIL_STATUS_NOT_UNPAID);
733 738 }
734 739  
735   - // 2. 更新 TradeOrderDO 状态为已取消
  740 + // 2. 取消订单
  741 + cancelOrder0(order, TradeOrderCancelTypeEnum.MEMBER_CANCEL);
  742 + }
  743 +
  744 + @Override
  745 + public int autoCancelOrder() {
  746 + // 1. 查询过期的待支付订单
  747 + LocalDateTime expireTime = addTime(tradeOrderProperties.getExpireTime());
  748 + List<TradeOrderDO> orders = tradeOrderMapper.selectListByStatusAndCreateTimeLt(
  749 + TradeOrderStatusEnum.UNPAID.getStatus(), expireTime);
  750 + if (CollUtil.isEmpty(orders)) {
  751 + return 0;
  752 + }
  753 +
  754 + // 2. 遍历执行,逐个取消
  755 + int count = 0;
  756 + for (TradeOrderDO order : orders) {
  757 + try {
  758 + getSelf().autoCancelOrder(order);
  759 + count ++;
  760 + } catch (Throwable e) {
  761 + log.error("[autoCancelOrder][order({}) 过期订单异常]", order.getId(), e);
  762 + }
  763 + }
  764 + return count;
  765 + }
  766 +
  767 + /**
  768 + * 自动取消单个订单
  769 + *
  770 + * @param order 订单
  771 + */
  772 + @Transactional(rollbackFor = Exception.class)
  773 + @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.SYSTEM_CANCEL)
  774 + public void autoCancelOrder(TradeOrderDO order) {
  775 + cancelOrder0(order, TradeOrderCancelTypeEnum.PAY_TIMEOUT);
  776 + }
  777 +
  778 + /**
  779 + * 取消订单的核心实现
  780 + *
  781 + * @param order 订单
  782 + * @param cancelType 取消类型
  783 + */
  784 + private void cancelOrder0(TradeOrderDO order, TradeOrderCancelTypeEnum cancelType) {
  785 + Long id = order.getId();
  786 + // 1. 更新 TradeOrderDO 状态为已取消
736 787 int updateCount = tradeOrderMapper.updateByIdAndStatus(id, order.getStatus(),
737 788 new TradeOrderDO().setStatus(TradeOrderStatusEnum.CANCELED.getStatus())
738   - .setCancelTime(LocalDateTime.now())
739   - .setCancelType(TradeOrderCancelTypeEnum.MEMBER_CANCEL.getType()));
  789 + .setCancelType(cancelType.getType()).setCancelTime(LocalDateTime.now()));
740 790 if (updateCount == 0) {
741 791 throw exception(ORDER_CANCEL_FAIL_STATUS_NOT_UNPAID);
742 792 }
743 793  
744   - // 3. TODO 活动相关库存回滚需要活动 id,活动 id 怎么获取?app 端能否传过来;回复:从订单里拿呀
  794 + // 2. TODO 活动相关库存回滚需要活动 id,活动 id 怎么获取?app 端能否传过来;回复:从订单里拿呀
745 795 tradeOrderHandlers.forEach(handler -> handler.rollback());
746 796  
747   - // 4. 回滚库存
  797 + // 3. 回滚库存
748 798 List<TradeOrderItemDO> orderItems = tradeOrderItemMapper.selectListByOrderId(id);
749 799 productSkuApi.updateSkuStock(TradeOrderConvert.INSTANCE.convert(orderItems));
750 800  
751   - // 5. 回滚优惠券
752   - if (order.getCouponId() > 0) {
  801 + // 4. 回滚优惠券
  802 + if (order.getCouponId() != null && order.getCouponId() > 0) {
753 803 couponApi.returnUsedCoupon(order.getCouponId());
754 804 }
755 805  
756   - // 6. 回滚积分(抵扣的)
  806 + // 5. 回滚积分(抵扣的)
757 807 addUserPoint(order.getUserId(), order.getUsePoint(), MemberPointBizTypeEnum.ORDER_CANCEL, order.getId());
758 808  
759   - // 7. 增加订单日志
  809 + // 6. 增加订单日志
760 810 TradeOrderLogUtils.setOrderInfo(order.getId(), order.getStatus(), TradeOrderStatusEnum.CANCELED.getStatus());
761 811 }
762 812  
... ...