Commit 826d792ff2d24416a5cd7981979485adb2700fb3
1 parent
e384b810
trade:增加自动取消的 job
Showing
7 changed files
with
109 additions
and
14 deletions
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<TradeOrderDO> { | @@ -58,4 +60,11 @@ public interface TradeOrderMapper extends BaseMapperX<TradeOrderDO> { | ||
| 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 |