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,8 +17,7 @@ public enum TradeOrderCancelTypeEnum implements IntArrayValuable {
17 17
18 PAY_TIMEOUT(10, "超时未支付"), 18 PAY_TIMEOUT(10, "超时未支付"),
19 AFTER_SALE_CLOSE(20, "退款关闭"), 19 AFTER_SALE_CLOSE(20, "退款关闭"),
20 - MEMBER_CANCEL(30, "买家取消"),  
21 - PAY_ON_DELIVERY(40, "已通过货到付款交易"),; // TODO 芋艿:这个类型,是不是可以去掉 20 + MEMBER_CANCEL(30, "买家取消");
22 21
23 public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(TradeOrderCancelTypeEnum::getType).toArray(); 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,8 +16,10 @@ public enum TradeOrderOperateTypeEnum {
16 MEMBER_CREATE(1, "用户下单"), 16 MEMBER_CREATE(1, "用户下单"),
17 MEMBER_RECEIVE(30, "用户已收货"), 17 MEMBER_RECEIVE(30, "用户已收货"),
18 MEMBER_COMMENT(31, "用户评价"), 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,7 +90,7 @@ public interface TradeOrderConvert {
90 90
91 default ProductSkuUpdateStockReqDTO convert(List<TradeOrderItemDO> list) { 91 default ProductSkuUpdateStockReqDTO convert(List<TradeOrderItemDO> list) {
92 List<ProductSkuUpdateStockReqDTO.Item> items = CollectionUtils.convertList(list, item -> 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 return new ProductSkuUpdateStockReqDTO(items); 94 return new ProductSkuUpdateStockReqDTO(items);
95 } 95 }
96 default ProductSkuUpdateStockReqDTO convertNegative(List<AppTradeOrderSettlementReqVO.Item> list) { 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,6 +9,8 @@ import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
9 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; 9 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
10 import org.apache.ibatis.annotations.Mapper; 10 import org.apache.ibatis.annotations.Mapper;
11 11
  12 +import java.time.LocalDateTime;
  13 +import java.util.List;
12 import java.util.Set; 14 import java.util.Set;
13 15
14 @Mapper 16 @Mapper
@@ -58,4 +60,11 @@ public interface TradeOrderMapper extends BaseMapperX&lt;TradeOrderDO&gt; { @@ -58,4 +60,11 @@ public interface TradeOrderMapper extends BaseMapperX&lt;TradeOrderDO&gt; {
58 .eq(TradeOrderDO::getId, orderId) 60 .eq(TradeOrderDO::getId, orderId)
59 .eq(TradeOrderDO::getUserId, loginUserId)); 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,6 +71,13 @@ public interface TradeOrderUpdateService {
71 void cancelOrder(Long userId, Long id); 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 * @param userId 用户编号 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,6 +76,7 @@ import java.util.Set;
76 76
77 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 77 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
78 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; 78 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
  79 +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.addTime;
79 import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*; 80 import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*;
80 81
81 /** 82 /**
@@ -629,6 +630,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { @@ -629,6 +630,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
629 630
630 @Override 631 @Override
631 @Transactional(rollbackFor = Exception.class) 632 @Transactional(rollbackFor = Exception.class)
  633 + // TODO 芋艿:
632 public void updateOrderItemAfterSaleStatus(Long id, Integer oldAfterSaleStatus, Integer newAfterSaleStatus, 634 public void updateOrderItemAfterSaleStatus(Long id, Integer oldAfterSaleStatus, Integer newAfterSaleStatus,
633 Long afterSaleId, Integer refundPrice) { 635 Long afterSaleId, Integer refundPrice) {
634 // 如果退款成功,则 refundPrice 非空 636 // 如果退款成功,则 refundPrice 非空
@@ -663,12 +665,15 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { @@ -663,12 +665,15 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
663 665
664 // TODO 芋艿:记录订单日志 666 // TODO 芋艿:记录订单日志
665 667
  668 + // TODO 芋艿:要不要退优惠劵
  669 +
666 // TODO 芋艿:站内信? 670 // TODO 芋艿:站内信?
667 } else { // 如果部分售后,则更新退款金额 671 } else { // 如果部分售后,则更新退款金额
668 tradeOrderMapper.updateById(new TradeOrderDO().setId(order.getId()) 672 tradeOrderMapper.updateById(new TradeOrderDO().setId(order.getId())
669 .setRefundStatus(TradeOrderRefundStatusEnum.PART.getStatus()).setRefundPrice(orderRefundPrice)); 673 .setRefundStatus(TradeOrderRefundStatusEnum.PART.getStatus()).setRefundPrice(orderRefundPrice));
670 } 674 }
671 675
  676 + // TODO 芋艿:这块扣减规则,需要在考虑下
672 // 售后成功后,执行数据回滚逻辑 677 // 售后成功后,执行数据回滚逻辑
673 if (Objects.equals(newAfterSaleStatus, TradeOrderItemAfterSaleStatusEnum.SUCCESS.getStatus())) { 678 if (Objects.equals(newAfterSaleStatus, TradeOrderItemAfterSaleStatusEnum.SUCCESS.getStatus())) {
674 // 扣减用户积分(赠送的) 679 // 扣减用户积分(赠送的)
@@ -732,31 +737,76 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { @@ -732,31 +737,76 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
732 throw exception(ORDER_CANCEL_FAIL_STATUS_NOT_UNPAID); 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 int updateCount = tradeOrderMapper.updateByIdAndStatus(id, order.getStatus(), 787 int updateCount = tradeOrderMapper.updateByIdAndStatus(id, order.getStatus(),
737 new TradeOrderDO().setStatus(TradeOrderStatusEnum.CANCELED.getStatus()) 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 if (updateCount == 0) { 790 if (updateCount == 0) {
741 throw exception(ORDER_CANCEL_FAIL_STATUS_NOT_UNPAID); 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 tradeOrderHandlers.forEach(handler -> handler.rollback()); 795 tradeOrderHandlers.forEach(handler -> handler.rollback());
746 796
747 - // 4. 回滚库存 797 + // 3. 回滚库存
748 List<TradeOrderItemDO> orderItems = tradeOrderItemMapper.selectListByOrderId(id); 798 List<TradeOrderItemDO> orderItems = tradeOrderItemMapper.selectListByOrderId(id);
749 productSkuApi.updateSkuStock(TradeOrderConvert.INSTANCE.convert(orderItems)); 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 couponApi.returnUsedCoupon(order.getCouponId()); 803 couponApi.returnUsedCoupon(order.getCouponId());
754 } 804 }
755 805
756 - // 6. 回滚积分(抵扣的) 806 + // 5. 回滚积分(抵扣的)
757 addUserPoint(order.getUserId(), order.getUsePoint(), MemberPointBizTypeEnum.ORDER_CANCEL, order.getId()); 807 addUserPoint(order.getUserId(), order.getUsePoint(), MemberPointBizTypeEnum.ORDER_CANCEL, order.getId());
758 808
759 - // 7. 增加订单日志 809 + // 6. 增加订单日志
760 TradeOrderLogUtils.setOrderInfo(order.getId(), order.getStatus(), TradeOrderStatusEnum.CANCELED.getStatus()); 810 TradeOrderLogUtils.setOrderInfo(order.getId(), order.getStatus(), TradeOrderStatusEnum.CANCELED.getStatus());
761 } 811 }
762 812