diff --git a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderCancelTypeEnum.java b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderCancelTypeEnum.java index 1dabec1948..8ec1e9b168 100644 --- a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderCancelTypeEnum.java +++ b/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 { PAY_TIMEOUT(10, "超时未支付"), AFTER_SALE_CLOSE(20, "退款关闭"), - MEMBER_CANCEL(30, "买家取消"), - PAY_ON_DELIVERY(40, "已通过货到付款交易"),; // TODO 芋艿:这个类型,是不是可以去掉 + MEMBER_CANCEL(30, "买家取消"); public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(TradeOrderCancelTypeEnum::getType).toArray(); diff --git a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderOperateTypeEnum.java b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderOperateTypeEnum.java index 5179285512..c379584517 100644 --- a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderOperateTypeEnum.java +++ b/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 { MEMBER_CREATE(1, "用户下单"), MEMBER_RECEIVE(30, "用户已收货"), MEMBER_COMMENT(31, "用户评价"), - MEMBER_CANCEL(40, "取消订单"), - MEMBER_DELETE(41, "删除订单"), + MEMBER_CANCEL(40, "手动取消订单"), + SYSTEM_CANCEL(41, "系统取消订单"), + // 42 预留:管理员取消订单 + MEMBER_DELETE(43, "删除订单"), ; /** 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 1dcbda7e00..b1aa44cfab 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 @@ -90,7 +90,7 @@ public interface TradeOrderConvert { default ProductSkuUpdateStockReqDTO convert(List list) { List items = CollectionUtils.convertList(list, item -> - new ProductSkuUpdateStockReqDTO.Item().setId(item.getSkuId()).setIncrCount(-item.getCount())); + new ProductSkuUpdateStockReqDTO.Item().setId(item.getSkuId()).setIncrCount(item.getCount())); return new ProductSkuUpdateStockReqDTO(items); } default ProductSkuUpdateStockReqDTO convertNegative(List list) { diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/order/TradeOrderMapper.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/order/TradeOrderMapper.java index 0aae7ec690..b19940e6d8 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/order/TradeOrderMapper.java +++ b/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; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import org.apache.ibatis.annotations.Mapper; +import java.time.LocalDateTime; +import java.util.List; import java.util.Set; @Mapper @@ -58,4 +60,11 @@ public interface TradeOrderMapper extends BaseMapperX { .eq(TradeOrderDO::getId, orderId) .eq(TradeOrderDO::getUserId, loginUserId)); } + + default List selectListByStatusAndCreateTimeLt(Integer status, LocalDateTime expireTime) { + return selectList(new LambdaUpdateWrapper() + .eq(TradeOrderDO::getStatus, status) + .lt(TradeOrderDO::getCreateTime, expireTime)); + } + } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/job/order/TradeOrderAutoCancelJob.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/job/order/TradeOrderAutoCancelJob.java new file mode 100644 index 0000000000..1833b9a698 --- /dev/null +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/job/order/TradeOrderAutoCancelJob.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.trade.job.order; + +import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler; +import cn.iocoder.yudao.framework.tenant.core.job.TenantJob; +import cn.iocoder.yudao.module.trade.service.order.TradeOrderUpdateService; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +/** + * 交易订单的自动过期 Job + * + * @author 芋道源码 + */ +@Component +@TenantJob +public class TradeOrderAutoCancelJob implements JobHandler { + + @Resource + private TradeOrderUpdateService tradeOrderUpdateService; + + @Override + public String execute(String param) { + int count = tradeOrderUpdateService.autoCancelOrder(); + return String.format("过期订单 %s 个", count); + } + +} 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 3de830df9a..87ffc457fd 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 @@ -70,6 +70,13 @@ public interface TradeOrderUpdateService { */ void cancelOrder(Long userId, Long id); + /** + * 【系统】自动取消订单 + * + * @return 取消数量 + */ + int autoCancelOrder(); + /** * 【会员】删除订单 * 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 42e77fc4b8..a1e668582f 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 @@ -76,6 +76,7 @@ import java.util.Set; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.addTime; import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*; /** @@ -629,6 +630,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { @Override @Transactional(rollbackFor = Exception.class) + // TODO 芋艿: public void updateOrderItemAfterSaleStatus(Long id, Integer oldAfterSaleStatus, Integer newAfterSaleStatus, Long afterSaleId, Integer refundPrice) { // 如果退款成功,则 refundPrice 非空 @@ -663,12 +665,15 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { // TODO 芋艿:记录订单日志 + // TODO 芋艿:要不要退优惠劵 + // TODO 芋艿:站内信? } else { // 如果部分售后,则更新退款金额 tradeOrderMapper.updateById(new TradeOrderDO().setId(order.getId()) .setRefundStatus(TradeOrderRefundStatusEnum.PART.getStatus()).setRefundPrice(orderRefundPrice)); } + // TODO 芋艿:这块扣减规则,需要在考虑下 // 售后成功后,执行数据回滚逻辑 if (Objects.equals(newAfterSaleStatus, TradeOrderItemAfterSaleStatusEnum.SUCCESS.getStatus())) { // 扣减用户积分(赠送的) @@ -732,31 +737,76 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { throw exception(ORDER_CANCEL_FAIL_STATUS_NOT_UNPAID); } - // 2. 更新 TradeOrderDO 状态为已取消 + // 2. 取消订单 + cancelOrder0(order, TradeOrderCancelTypeEnum.MEMBER_CANCEL); + } + + @Override + public int autoCancelOrder() { + // 1. 查询过期的待支付订单 + LocalDateTime expireTime = addTime(tradeOrderProperties.getExpireTime()); + List orders = tradeOrderMapper.selectListByStatusAndCreateTimeLt( + TradeOrderStatusEnum.UNPAID.getStatus(), expireTime); + if (CollUtil.isEmpty(orders)) { + return 0; + } + + // 2. 遍历执行,逐个取消 + int count = 0; + for (TradeOrderDO order : orders) { + try { + getSelf().autoCancelOrder(order); + count ++; + } catch (Throwable e) { + log.error("[autoCancelOrder][order({}) 过期订单异常]", order.getId(), e); + } + } + return count; + } + + /** + * 自动取消单个订单 + * + * @param order 订单 + */ + @Transactional(rollbackFor = Exception.class) + @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.SYSTEM_CANCEL) + public void autoCancelOrder(TradeOrderDO order) { + cancelOrder0(order, TradeOrderCancelTypeEnum.PAY_TIMEOUT); + } + + /** + * 取消订单的核心实现 + * + * @param order 订单 + * @param cancelType 取消类型 + */ + private void cancelOrder0(TradeOrderDO order, TradeOrderCancelTypeEnum cancelType) { + Long id = order.getId(); + // 1. 更新 TradeOrderDO 状态为已取消 int updateCount = tradeOrderMapper.updateByIdAndStatus(id, order.getStatus(), new TradeOrderDO().setStatus(TradeOrderStatusEnum.CANCELED.getStatus()) - .setCancelTime(LocalDateTime.now()) - .setCancelType(TradeOrderCancelTypeEnum.MEMBER_CANCEL.getType())); + .setCancelType(cancelType.getType()).setCancelTime(LocalDateTime.now())); if (updateCount == 0) { throw exception(ORDER_CANCEL_FAIL_STATUS_NOT_UNPAID); } - // 3. TODO 活动相关库存回滚需要活动 id,活动 id 怎么获取?app 端能否传过来;回复:从订单里拿呀 + // 2. TODO 活动相关库存回滚需要活动 id,活动 id 怎么获取?app 端能否传过来;回复:从订单里拿呀 tradeOrderHandlers.forEach(handler -> handler.rollback()); - // 4. 回滚库存 + // 3. 回滚库存 List orderItems = tradeOrderItemMapper.selectListByOrderId(id); productSkuApi.updateSkuStock(TradeOrderConvert.INSTANCE.convert(orderItems)); - // 5. 回滚优惠券 - if (order.getCouponId() > 0) { + // 4. 回滚优惠券 + if (order.getCouponId() != null && order.getCouponId() > 0) { couponApi.returnUsedCoupon(order.getCouponId()); } - // 6. 回滚积分(抵扣的) + // 5. 回滚积分(抵扣的) addUserPoint(order.getUserId(), order.getUsePoint(), MemberPointBizTypeEnum.ORDER_CANCEL, order.getId()); - // 7. 增加订单日志 + // 6. 增加订单日志 TradeOrderLogUtils.setOrderInfo(order.getId(), order.getStatus(), TradeOrderStatusEnum.CANCELED.getStatus()); }