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 | 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<TradeOrderDO> { |
| 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
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 | ... | ... |