فهرست منبع

Merge remote-tracking branch 'origin/feature/mall_product' into feature/mall_product

owen 1 سال پیش
والد
کامیت
cd2d0b7089
24فایلهای تغییر یافته به همراه323 افزوده شده و 188 حذف شده
  1. 7 5
      yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/spu/dto/ProductSpuRespDTO.java
  2. 5 3
      yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderOperateTypeEnum.java
  3. 2 2
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java
  4. 2 2
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java
  5. 4 2
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderItemDO.java
  6. 8 2
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/order/TradeOrderMapper.java
  7. 7 1
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/order/config/TradeOrderProperties.java
  8. 4 1
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/order/core/annotations/TradeOrderLog.java
  9. 15 0
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/order/core/aop/TradeOrderLogAspect.java
  10. 4 0
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/order/core/utils/TradeOrderLogUtils.java
  11. 1 1
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/job/order/TradeOrderAutoCancelJob.java
  12. 28 0
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/job/order/TradeOrderAutoReceiveJob.java
  13. 11 4
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateService.java
  14. 194 151
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java
  15. 4 1
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePointGiveCalculator.java
  16. 9 4
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePointUsePriceCalculator.java
  17. 3 1
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePriceCalculator.java
  18. 2 0
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePriceCalculatorHelper.java
  19. 2 2
      yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceTest.java
  20. 1 0
      yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/point/MemberPointApi.java
  21. 2 0
      yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/point/dto/MemberPointConfigRespDTO.java
  22. 1 0
      yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/user/dto/MemberUserRespDTO.java
  23. 5 5
      yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/enums/point/MemberPointBizTypeEnum.java
  24. 2 1
      yudao-server/src/main/resources/application.yaml

+ 7 - 5
yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/spu/dto/ProductSpuRespDTO.java

@@ -110,11 +110,6 @@ public class ProductSpuRespDTO {
 
     // ========== 物流相关字段 =========
 
-    /**
-     * 赠送积分
-     */
-    private Integer giveIntegral;
-
     /**
      * 物流配置模板编号
      *
@@ -122,6 +117,13 @@ public class ProductSpuRespDTO {
      */
     private Long deliveryTemplateId;
 
+    // ========== 营销相关字段 =========
+
+    /**
+     * 赠送积分
+     */
+    private Integer giveIntegral;
+
     // ========== 统计相关字段 =========
 
     /**

+ 5 - 3
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderOperateTypeEnum.java

@@ -14,10 +14,12 @@ import lombok.RequiredArgsConstructor;
 public enum TradeOrderOperateTypeEnum {
 
     MEMBER_CREATE(1, "用户下单"),
+    MEMBER_PAY(20, "用户付款成功"),
     MEMBER_RECEIVE(30, "用户已收货"),
-    MEMBER_COMMENT(31, "用户评价"),
-    MEMBER_CANCEL(40, "手动取消订单"),
-    SYSTEM_CANCEL(41, "系统取消订单"),
+    SYSTEM_RECEIVE(31, "到期未收货,系统自动确认收货"),
+    MEMBER_COMMENT(33, "用户评价"),
+    MEMBER_CANCEL(40, "取消订单"),
+    SYSTEM_CANCEL(41, "到期未支付,系统自动取消订单"),
     // 42 预留:管理员取消订单
     MEMBER_DELETE(43, "删除订单"),
     ;

+ 2 - 2
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java

@@ -140,7 +140,7 @@ public class AppTradeOrderController {
     @Operation(summary = "确认交易订单收货")
     @Parameter(name = "id", description = "交易订单编号")
     public CommonResult<Boolean> receiveOrder(@RequestParam("id") Long id) {
-        tradeOrderUpdateService.receiveOrder(getLoginUserId(), id);
+        tradeOrderUpdateService.receiveOrderByMember(getLoginUserId(), id);
         return success(true);
     }
 
@@ -148,7 +148,7 @@ public class AppTradeOrderController {
     @Operation(summary = "取消交易订单")
     @Parameter(name = "id", description = "交易订单编号")
     public CommonResult<Boolean> cancelOrder(@RequestParam("id") Long id) {
-        tradeOrderUpdateService.cancelOrder(getLoginUserId(), id);
+        tradeOrderUpdateService.cancelOrderByMember(getLoginUserId(), id);
         return success(true);
     }
 

+ 2 - 2
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java

@@ -110,7 +110,7 @@ public interface TradeOrderConvert {
         createReqDTO.setSubject(subject);
         createReqDTO.setBody(subject); // TODO 芋艿:临时写死
         // 订单相关字段
-        createReqDTO.setPrice(order.getPayPrice()).setExpireTime(addTime(orderProperties.getExpireTime()));
+        createReqDTO.setPrice(order.getPayPrice()).setExpireTime(addTime(orderProperties.getPayExpireTime()));
         return createReqDTO;
     }
 
@@ -180,7 +180,7 @@ public interface TradeOrderConvert {
                                                 TradeOrderProperties tradeOrderProperties,
                                                 DeliveryExpressDO express) {
         AppTradeOrderDetailRespVO orderVO = convert3(order, orderItems);
-        orderVO.setPayExpireTime(addTime(tradeOrderProperties.getExpireTime()));
+        orderVO.setPayExpireTime(addTime(tradeOrderProperties.getPayExpireTime()));
         if (StrUtil.isNotEmpty(order.getPayChannelCode())) {
             orderVO.setPayChannelName(DictFrameworkUtils.getDictDataLabel(DictTypeConstants.CHANNEL_CODE, order.getPayChannelCode()));
         }

+ 4 - 2
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderItemDO.java

@@ -146,18 +146,20 @@ public class TradeOrderItemDO extends BaseDO {
     private Integer pointPrice;
     /**
      * 使用的积分
+     *
+     * 目的:用于后续取消或者售后订单时,需要归还赠送
      */
     private Integer usePoint;
     /**
      * 赠送的积分
+     *
+     * 目的:用于后续取消或者售后订单时,需要扣减赠送
      */
     private Integer givePoint;
     /**
      * VIP 减免金额,单位:分
      */
     private Integer vipPrice;
-    // TODO @芋艿:如果商品 vip 折扣时,到底是新增一个 vipPrice 记录优惠记录,还是 vipDiscountPrice,记录 vip 的优惠;还是直接使用 vipPrice;
-    // 目前 crmeb 的选择,单独一个 vipPrice 记录优惠价格;感觉不一定合理,可以在看看有赞的;
 
     // ========== 售后基本信息 ==========
 

+ 8 - 2
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/order/TradeOrderMapper.java

@@ -61,10 +61,16 @@ public interface TradeOrderMapper extends BaseMapperX<TradeOrderDO> {
                 .eq(TradeOrderDO::getUserId, loginUserId));
     }
 
-    default List<TradeOrderDO> selectListByStatusAndCreateTimeLt(Integer status, LocalDateTime expireTime) {
+    default List<TradeOrderDO> selectListByStatusAndCreateTimeLt(Integer status, LocalDateTime createTime) {
         return selectList(new LambdaUpdateWrapper<TradeOrderDO>()
                 .eq(TradeOrderDO::getStatus, status)
-                .lt(TradeOrderDO::getCreateTime, expireTime));
+                .lt(TradeOrderDO::getCreateTime, createTime));
+    }
+
+    default List<TradeOrderDO> selectListByStatusAndDeliveryTimeLt(Integer status, LocalDateTime deliveryTime) {
+        return selectList(new LambdaUpdateWrapper<TradeOrderDO>()
+                .eq(TradeOrderDO::getStatus, status)
+                .lt(TradeOrderDO::getDeliveryTime, deliveryTime));
     }
 
 }

+ 7 - 1
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/order/config/TradeOrderProperties.java

@@ -28,6 +28,12 @@ public class TradeOrderProperties {
      * 支付超时时间
      */
     @NotNull(message = "支付超时时间不能为空")
-    private Duration expireTime;
+    private Duration payExpireTime;
+
+    /**
+     * 收货超时时间
+     */
+    @NotNull(message = "收货超时时间不能为空")
+    private Duration receiveExpireTime;
 
 }

+ 4 - 1
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/order/core/annotations/TradeOrderLog.java

@@ -2,7 +2,10 @@ package cn.iocoder.yudao.module.trade.framework.order.core.annotations;
 
 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderOperateTypeEnum;
 
-import java.lang.annotation.*;
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
 
 import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
 import static java.lang.annotation.ElementType.METHOD;

+ 15 - 0
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/order/core/aop/TradeOrderLogAspect.java

@@ -31,6 +31,16 @@ import static java.util.Collections.emptyMap;
 @Slf4j
 public class TradeOrderLogAspect {
 
+    /**
+     * 用户编号
+     *
+     * 目前的使用场景:支付回调时,需要强制设置下用户编号
+     */
+    private static final ThreadLocal<Long> USER_ID = new ThreadLocal<>();
+    /**
+     * 用户类型
+     */
+    private static final ThreadLocal<Integer> USER_TYPE = new ThreadLocal<>();
     /**
      * 订单编号
      */
@@ -112,4 +122,9 @@ public class TradeOrderLogAspect {
         EXTS.set(exts);
     }
 
+    public static void setUserInfo(Long userId, Integer userType) {
+        USER_ID.set(userId);
+        USER_TYPE.set(userType);
+    }
+
 }

+ 4 - 0
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/order/core/utils/TradeOrderLogUtils.java

@@ -20,4 +20,8 @@ public class TradeOrderLogUtils {
         TradeOrderLogAspect.setOrderInfo(id, beforeStatus, afterStatus, exts);
     }
 
+    public static void setUserInfo(Long userId, Integer userType) {
+        TradeOrderLogAspect.setUserInfo(userId, userType);
+    }
+
 }

+ 1 - 1
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/job/order/TradeOrderAutoCancelJob.java

@@ -21,7 +21,7 @@ public class TradeOrderAutoCancelJob implements JobHandler {
 
     @Override
     public String execute(String param) {
-        int count = tradeOrderUpdateService.autoCancelOrder();
+        int count = tradeOrderUpdateService.cancelOrderBySystem();
         return String.format("过期订单 %s 个", count);
     }
 

+ 28 - 0
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/job/order/TradeOrderAutoReceiveJob.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 TradeOrderAutoReceiveJob implements JobHandler {
+
+    @Resource
+    private TradeOrderUpdateService tradeOrderUpdateService;
+
+    @Override
+    public String execute(String param) {
+        int count = tradeOrderUpdateService.receiveOrderBySystem();
+        return String.format("自动收货 %s 个", count);
+    }
+
+}

+ 11 - 4
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateService.java

@@ -60,22 +60,29 @@ public interface TradeOrderUpdateService {
      * @param userId 用户编号
      * @param id     订单编号
      */
-    void receiveOrder(Long userId, Long id);
+    void receiveOrderByMember(Long userId, Long id);
 
     /**
-     * 【会员】取消订单
+     * 【系统】自动收货交易订单
+     *
+     * @return 收货数量
+     */
+    int receiveOrderBySystem();
+
+    /**
+     * 【会员】取消交易订单
      *
      * @param userId 用户编号
      * @param id     订单编号
      */
-    void cancelOrder(Long userId, Long id);
+    void cancelOrderByMember(Long userId, Long id);
 
     /**
      * 【系统】自动取消订单
      *
      * @return 取消数量
      */
-    int autoCancelOrder();
+    int cancelOrderBySystem();
 
     /**
      * 【会员】删除订单

+ 194 - 151
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java

@@ -8,6 +8,7 @@ import cn.hutool.core.util.StrUtil;
 import cn.hutool.extra.spring.SpringUtil;
 import cn.iocoder.yudao.framework.common.core.KeyValue;
 import cn.iocoder.yudao.framework.common.enums.TerminalEnum;
+import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
 import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
 import cn.iocoder.yudao.module.member.api.address.AddressApi;
 import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO;
@@ -321,38 +322,39 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
 
     @Override
     @Transactional(rollbackFor = Exception.class)
+    @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.MEMBER_PAY)
     public void updateOrderPaid(Long id, Long payOrderId) {
-        // 校验并获得交易订单(可支付)
+        // 1. 校验并获得交易订单(可支付)
         KeyValue<TradeOrderDO, PayOrderRespDTO> orderResult = validateOrderPayable(id, payOrderId);
         TradeOrderDO order = orderResult.getKey();
         PayOrderRespDTO payOrder = orderResult.getValue();
 
-        // 更新 TradeOrderDO 状态为已支付,等待发货
+        // 2. 更新 TradeOrderDO 状态为已支付,等待发货
         int updateCount = tradeOrderMapper.updateByIdAndStatus(id, order.getStatus(),
                 new TradeOrderDO().setStatus(TradeOrderStatusEnum.UNDELIVERED.getStatus()).setPayStatus(true)
                         .setPayTime(LocalDateTime.now()).setPayChannelCode(payOrder.getChannelCode()));
         if (updateCount == 0) {
             throw exception(ORDER_UPDATE_PAID_STATUS_NOT_UNPAID);
         }
-        // 校验活动
+
+        // 3. 校验活动
         // 1、拼团活动
         // TODO @puhui999:这块也抽象到 handler 里
         if (Objects.equals(TradeOrderTypeEnum.COMBINATION.getType(), order.getType())) {
             // 更新拼团状态 TODO puhui999:订单支付失败或订单支付过期删除这条拼团记录
             combinationRecordApi.updateRecordStatusToInProgress(order.getUserId(), order.getId(), LocalDateTime.now());
         }
-        // TODO 芋艿:发送订单变化的消息
-
-        // TODO 芋艿:发送站内信
 
-        // TODO 芋艿:OrderLog
-
-        // 增加用户积分(赠送)
-        addUserPoint(order.getUserId(), order.getGivePoint(), MemberPointBizTypeEnum.ORDER_REWARD, order.getId());
-        // 增加用户经验
+        // 4.1 增加用户积分(赠送)
+        addUserPoint(order.getUserId(), order.getGivePoint(), MemberPointBizTypeEnum.ORDER_GIVE, order.getId());
+        // 4.2 增加用户经验
         getSelf().addUserExperienceAsync(order.getUserId(), order.getPayPrice(), order.getId());
-        // 增加用户佣金
+        // 4.3 增加用户佣金
         getSelf().addBrokerageAsync(order.getUserId(), order.getId());
+
+        // 5. 记录订单日志
+        TradeOrderLogUtils.setOrderInfo(order.getId(), order.getStatus(), TradeOrderStatusEnum.UNDELIVERED.getStatus());
+        TradeOrderLogUtils.setUserInfo(order.getUserId(), UserTypeEnum.MEMBER.getValue());
     }
 
     /**
@@ -435,8 +437,6 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
             throw exception(ORDER_DELIVERY_FAIL_STATUS_NOT_UNDELIVERED);
         }
 
-        // TODO 芋艿:发送订单变化的消息
-
         // 发送站内信
         tradeMessageService.sendMessageWhenDeliveryOrder(new TradeOrderMessageWhenDeliveryOrderReqBO().setOrderId(order.getId())
                 .setUserId(order.getUserId()).setMessage(null));
@@ -488,10 +488,54 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
     @Override
     @Transactional(rollbackFor = Exception.class)
     @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.MEMBER_RECEIVE)
-    public void receiveOrder(Long userId, Long id) {
+    public void receiveOrderByMember(Long userId, Long id) {
         // 校验并获得交易订单(可收货)
         TradeOrderDO order = validateOrderReceivable(userId, id);
 
+        // 收货订单
+        receiveOrder0(order);
+    }
+
+    @Override
+    public int receiveOrderBySystem() {
+        // 1. 查询过期的待支付订单
+        LocalDateTime expireTime = addTime(tradeOrderProperties.getReceiveExpireTime());
+        List<TradeOrderDO> orders = tradeOrderMapper.selectListByStatusAndDeliveryTimeLt(
+                TradeOrderStatusEnum.DELIVERED.getStatus(), expireTime);
+        if (CollUtil.isEmpty(orders)) {
+            return 0;
+        }
+
+        // 2. 遍历执行,逐个取消
+        int count = 0;
+        for (TradeOrderDO order : orders) {
+            try {
+                getSelf().receiveOrderBySystem(order);
+                count ++;
+            } catch (Throwable e) {
+                log.error("[autoReceiveOrder][order({}) 自动收货订单异常]", order.getId(), e);
+            }
+        }
+        return count;
+    }
+
+    /**
+     * 自动收货单个订单
+     *
+     * @param order 订单
+     */
+    @Transactional(rollbackFor = Exception.class)
+    @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.SYSTEM_RECEIVE)
+    public void receiveOrderBySystem(TradeOrderDO order) {
+        receiveOrder0(order);
+    }
+
+    /**
+     * 收货订单的核心实现
+     *
+     * @param order 订单
+     */
+    private void receiveOrder0(TradeOrderDO order) {
         // 更新 TradeOrderDO 状态为已完成
         int updateCount = tradeOrderMapper.updateByIdAndStatus(order.getId(), order.getStatus(),
                 new TradeOrderDO().setStatus(TradeOrderStatusEnum.COMPLETED.getStatus()).setReceiveTime(LocalDateTime.now()));
@@ -499,14 +543,137 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
             throw exception(ORDER_RECEIVE_FAIL_STATUS_NOT_DELIVERED);
         }
 
-        // TODO 芋艿:lili 发送订单变化的消息
+        // 插入订单日志
+        TradeOrderLogUtils.setOrderInfo(order.getId(), order.getStatus(), TradeOrderStatusEnum.COMPLETED.getStatus());
+    }
+
+    /**
+     * 校验交易订单满足可售货的条件
+     *
+     * 1. 交易订单待收货
+     *
+     * @param userId 用户编号
+     * @param id     交易订单编号
+     * @return 交易订单
+     */
+    private TradeOrderDO validateOrderReceivable(Long userId, Long id) {
+        // 校验订单是否存在
+        TradeOrderDO order = tradeOrderMapper.selectByIdAndUserId(id, userId);
+        if (order == null) {
+            throw exception(ORDER_NOT_FOUND);
+        }
+        // 校验订单是否是待收货状态
+        if (!TradeOrderStatusEnum.isDelivered(order.getStatus())) {
+            throw exception(ORDER_RECEIVE_FAIL_STATUS_NOT_DELIVERED);
+        }
+        return order;
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.MEMBER_CANCEL)
+    public void cancelOrderByMember(Long userId, Long id) {
+        // 1.1 校验存在
+        TradeOrderDO order = tradeOrderMapper.selectOrderByIdAndUserId(id, userId);
+        if (order == null) {
+            throw exception(ORDER_NOT_FOUND);
+        }
+        // 1.2 校验状态
+        if (ObjectUtil.notEqual(order.getStatus(), TradeOrderStatusEnum.UNPAID.getStatus())) {
+            throw exception(ORDER_CANCEL_FAIL_STATUS_NOT_UNPAID);
+        }
+
+        // 2. 取消订单
+        cancelOrder0(order, TradeOrderCancelTypeEnum.MEMBER_CANCEL);
+    }
+
+    @Override
+    public int cancelOrderBySystem() {
+        // 1. 查询过期的待支付订单
+        LocalDateTime expireTime = addTime(tradeOrderProperties.getPayExpireTime());
+        List<TradeOrderDO> orders = tradeOrderMapper.selectListByStatusAndCreateTimeLt(
+                TradeOrderStatusEnum.UNPAID.getStatus(), expireTime);
+        if (CollUtil.isEmpty(orders)) {
+            return 0;
+        }
 
-        // TODO 芋艿:lili 发送商品被购买完成的数据
+        // 2. 遍历执行,逐个取消
+        int count = 0;
+        for (TradeOrderDO order : orders) {
+            try {
+                getSelf().cancelOrderBySystem(order);
+                count ++;
+            } catch (Throwable e) {
+                log.error("[autoCancelOrder][order({}) 过期订单异常]", order.getId(), e);
+            }
+        }
+        return count;
+    }
 
-        // TODO 芋艿:销售佣金的记录;
+    /**
+     * 自动取消单个订单
+     *
+     * @param order 订单
+     */
+    @Transactional(rollbackFor = Exception.class)
+    @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.SYSTEM_CANCEL)
+    public void cancelOrderBySystem(TradeOrderDO order) {
+        cancelOrder0(order, TradeOrderCancelTypeEnum.PAY_TIMEOUT);
+    }
 
-        // 插入订单日志
-        TradeOrderLogUtils.setOrderInfo(order.getId(), order.getStatus(), TradeOrderStatusEnum.COMPLETED.getStatus());
+    /**
+     * 取消订单的核心实现
+     *
+     * @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())
+                        .setCancelType(cancelType.getType()).setCancelTime(LocalDateTime.now()));
+        if (updateCount == 0) {
+            throw exception(ORDER_CANCEL_FAIL_STATUS_NOT_UNPAID);
+        }
+
+        // 2. TODO 活动相关库存回滚需要活动 id,活动 id 怎么获取?app 端能否传过来;回复:从订单里拿呀
+        tradeOrderHandlers.forEach(handler -> handler.rollback());
+
+        // 3. 回滚库存
+        List<TradeOrderItemDO> orderItems = tradeOrderItemMapper.selectListByOrderId(id);
+        productSkuApi.updateSkuStock(TradeOrderConvert.INSTANCE.convert(orderItems));
+
+        // 4. 回滚优惠券
+        if (order.getCouponId() != null && order.getCouponId() > 0) {
+            couponApi.returnUsedCoupon(order.getCouponId());
+        }
+
+        // 5. 回滚积分(抵扣的)
+        addUserPoint(order.getUserId(), order.getUsePoint(), MemberPointBizTypeEnum.ORDER_CANCEL, order.getId());
+
+        // 6. 增加订单日志
+        TradeOrderLogUtils.setOrderInfo(order.getId(), order.getStatus(), TradeOrderStatusEnum.CANCELED.getStatus());
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.MEMBER_DELETE)
+    public void deleteOrder(Long userId, Long id) {
+        // 1.1 校验存在
+        TradeOrderDO order = tradeOrderMapper.selectOrderByIdAndUserId(id, userId);
+        if (order == null) {
+            throw exception(ORDER_NOT_FOUND);
+        }
+        // 1.2 校验状态
+        if (ObjectUtil.notEqual(order.getStatus(), TradeOrderStatusEnum.CANCELED.getStatus())) {
+            throw exception(ORDER_DELETE_FAIL_STATUS_NOT_CANCEL);
+        }
+        // 2. 删除订单
+        tradeOrderMapper.deleteById(id);
+
+        // 3. 记录日志
+        TradeOrderLogUtils.setOrderInfo(order.getId(), order.getStatus(), order.getStatus());
     }
 
     @Override
@@ -604,33 +771,13 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
         tradeOrderMapper.updateById(update);
     }
 
-    /**
-     * 校验交易订单满足可售货的条件
-     *
-     * 1. 交易订单待收货
-     *
-     * @param userId 用户编号
-     * @param id     交易订单编号
-     * @return 交易订单
-     */
-    private TradeOrderDO validateOrderReceivable(Long userId, Long id) {
-        // 校验订单是否存在
-        TradeOrderDO order = tradeOrderMapper.selectByIdAndUserId(id, userId);
-        if (order == null) {
-            throw exception(ORDER_NOT_FOUND);
-        }
-        // 校验订单是否是待收货状态
-        if (!TradeOrderStatusEnum.isDelivered(order.getStatus())) {
-            throw exception(ORDER_RECEIVE_FAIL_STATUS_NOT_DELIVERED);
-        }
-        return order;
-    }
-
     // =================== Order Item ===================
 
+    // TODO 疯狂:帮我重构下:
+    // 1. updateOrderItemAfterSaleStatus 拆分成三个方法:发起;同意;拒绝。原因是,职责更清晰,操作日志也更容易记录;
+
     @Override
     @Transactional(rollbackFor = Exception.class)
-    // TODO 芋艿:
     public void updateOrderItemAfterSaleStatus(Long id, Integer oldAfterSaleStatus, Integer newAfterSaleStatus,
                                                Long afterSaleId, Integer refundPrice) {
         // 如果退款成功,则 refundPrice 非空
@@ -658,6 +805,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
         TradeOrderItemDO orderItem = tradeOrderItemMapper.selectById(id);
         TradeOrderDO order = tradeOrderMapper.selectById(orderItem.getOrderId());
         Integer orderRefundPrice = order.getRefundPrice() + refundPrice;
+        // TODO @疯狂:809 到 817 改成:cancelOrderByAfterSale:相当于全部售后成功后,就是要取消胆子;
         if (isAllOrderItemAfterSaleSuccess(order.getId())) { // 如果都售后成功,则需要取消订单
             tradeOrderMapper.updateById(new TradeOrderDO().setId(order.getId())
                     .setRefundStatus(TradeOrderRefundStatusEnum.ALL.getStatus()).setRefundPrice(orderRefundPrice).setRefundPoint(order.getRefundPoint() + orderItem.getUsePoint())
@@ -667,7 +815,6 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
 
             // TODO 芋艿:要不要退优惠劵
 
-            // TODO 芋艿:站内信?
         } else { // 如果部分售后,则更新退款金额
             tradeOrderMapper.updateById(new TradeOrderDO().setId(order.getId())
                     .setRefundStatus(TradeOrderRefundStatusEnum.PART.getStatus()).setRefundPrice(orderRefundPrice));
@@ -676,6 +823,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
         // TODO 芋艿:这块扣减规则,需要在考虑下
         // 售后成功后,执行数据回滚逻辑
         if (Objects.equals(newAfterSaleStatus, TradeOrderItemAfterSaleStatusEnum.SUCCESS.getStatus())) {
+            // TODO @疯狂:这里库存也要扣减下;
             // 扣减用户积分(赠送的)
             reduceUserPoint(order.getUserId(), orderItem.getGivePoint(), MemberPointBizTypeEnum.AFTER_SALE_DEDUCT_GIVE, afterSaleId);
             // 增加用户积分(返还抵扣)
@@ -723,113 +871,6 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
         return comment;
     }
 
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.MEMBER_CANCEL)
-    public void cancelOrder(Long userId, Long id) {
-        // 1.1 校验存在
-        TradeOrderDO order = tradeOrderMapper.selectOrderByIdAndUserId(id, userId);
-        if (order == null) {
-            throw exception(ORDER_NOT_FOUND);
-        }
-        // 1.2 校验状态
-        if (ObjectUtil.notEqual(order.getStatus(), TradeOrderStatusEnum.UNPAID.getStatus())) {
-            throw exception(ORDER_CANCEL_FAIL_STATUS_NOT_UNPAID);
-        }
-
-        // 2. 取消订单
-        cancelOrder0(order, TradeOrderCancelTypeEnum.MEMBER_CANCEL);
-    }
-
-    @Override
-    public int autoCancelOrder() {
-        // 1. 查询过期的待支付订单
-        LocalDateTime expireTime = addTime(tradeOrderProperties.getExpireTime());
-        List<TradeOrderDO> 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())
-                        .setCancelType(cancelType.getType()).setCancelTime(LocalDateTime.now()));
-        if (updateCount == 0) {
-            throw exception(ORDER_CANCEL_FAIL_STATUS_NOT_UNPAID);
-        }
-
-        // 2. TODO 活动相关库存回滚需要活动 id,活动 id 怎么获取?app 端能否传过来;回复:从订单里拿呀
-        tradeOrderHandlers.forEach(handler -> handler.rollback());
-
-        // 3. 回滚库存
-        List<TradeOrderItemDO> orderItems = tradeOrderItemMapper.selectListByOrderId(id);
-        productSkuApi.updateSkuStock(TradeOrderConvert.INSTANCE.convert(orderItems));
-
-        // 4. 回滚优惠券
-        if (order.getCouponId() != null && order.getCouponId() > 0) {
-            couponApi.returnUsedCoupon(order.getCouponId());
-        }
-
-        // 5. 回滚积分(抵扣的)
-        addUserPoint(order.getUserId(), order.getUsePoint(), MemberPointBizTypeEnum.ORDER_CANCEL, order.getId());
-
-        // 6. 增加订单日志
-        TradeOrderLogUtils.setOrderInfo(order.getId(), order.getStatus(), TradeOrderStatusEnum.CANCELED.getStatus());
-    }
-
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.MEMBER_DELETE)
-    public void deleteOrder(Long userId, Long id) {
-        // 1.1 校验存在
-        TradeOrderDO order = tradeOrderMapper.selectOrderByIdAndUserId(id, userId);
-        if (order == null) {
-            throw exception(ORDER_NOT_FOUND);
-        }
-        // 1.2 校验状态
-        if (ObjectUtil.notEqual(order.getStatus(), TradeOrderStatusEnum.CANCELED.getStatus())) {
-            throw exception(ORDER_DELETE_FAIL_STATUS_NOT_CANCEL);
-        }
-        // 2. 删除订单
-        tradeOrderMapper.deleteById(id);
-
-        // 3. 记录日志
-        TradeOrderLogUtils.setOrderInfo(order.getId(), order.getStatus(), order.getStatus());
-    }
-
     /**
      * 判断指定订单的所有订单项,是不是都售后成功
      *
@@ -842,6 +883,8 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
                 TradeOrderItemAfterSaleStatusEnum.SUCCESS.getStatus()));
     }
 
+    // =================== 营销相关的操作 ===================
+
     @Async
     protected void addUserExperienceAsync(Long userId, Integer payPrice, Long orderId) {
         int bizType = MemberExperienceBizTypeEnum.ORDER.getType();

+ 4 - 1
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePointGiveCalculator.java

@@ -16,6 +16,7 @@ import java.util.Optional;
 
 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList;
 
+// TODO @疯狂:这个可以搞个单测;
 /**
  * 赠送积分的 {@link TradePriceCalculator} 实现类
  *
@@ -25,6 +26,7 @@ import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.
 @Order(TradePriceCalculator.ORDER_POINT_GIVE)
 @Slf4j
 public class TradePointGiveCalculator implements TradePriceCalculator {
+
     @Resource
     private MemberPointApi memberPointApi;
 
@@ -54,9 +56,10 @@ public class TradePointGiveCalculator implements TradePriceCalculator {
             TradePriceCalculateRespBO.OrderItem orderItem = orderItems.get(i);
             // 商品可能赠送了积分,所以这里要加上
             orderItem.setGivePoint(orderItem.getGivePoint() + dividePoints.get(i));
-            TradePriceCalculatorHelper.recountPayPrice(orderItem);
+            TradePriceCalculatorHelper.recountPayPrice(orderItem); // TODO @疯狂:这个应该不用调用哇?不影响支付金额
         }
         // 3.3 更新订单赠送积分
         TradePriceCalculatorHelper.recountAllGivePoint(result);
     }
+
 }

+ 9 - 4
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePointUsePriceCalculator.java

@@ -20,6 +20,7 @@ import java.util.List;
 
 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList;
 
+// TODO @疯狂:搞个单测,嘿嘿;
 /**
  * 使用积分的 {@link TradePriceCalculator} 实现类
  *
@@ -29,6 +30,7 @@ import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.
 @Order(TradePriceCalculator.ORDER_POINT_USE)
 @Slf4j
 public class TradePointUsePriceCalculator implements TradePriceCalculator {
+
     @Resource
     private MemberPointApi memberPointApi;
     @Resource
@@ -48,13 +50,14 @@ public class TradePointUsePriceCalculator implements TradePriceCalculator {
         }
         // 1.3 校验用户积分余额
         MemberUserRespDTO user = memberUserApi.getUser(param.getUserId());
-        if (user.getPoint() == null || user.getPoint() < 0) {
+        if (user.getPoint() == null || user.getPoint() <= 0) {
             return;
         }
 
         // 2.1 计算积分优惠金额
+        // TODO @疯狂:如果计算出来,优惠金额为 0,那是不是不用执行后续逻辑哈
         int pointPrice = calculatePointPrice(config, user.getPoint(), result);
-        // 2.1 计算分摊的积分、抵扣金额
+        // 2.2 计算分摊的积分、抵扣金额
         List<TradePriceCalculateRespBO.OrderItem> orderItems = filterList(result.getItems(), TradePriceCalculateRespBO.OrderItem::getSelected);
         List<Integer> dividePointPrices = TradePriceCalculatorHelper.dividePrice(orderItems, pointPrice);
         List<Integer> divideUsePoints = TradePriceCalculatorHelper.dividePrice(orderItems, result.getUsePoint());
@@ -74,7 +77,9 @@ public class TradePointUsePriceCalculator implements TradePriceCalculator {
         TradePriceCalculatorHelper.recountAllPrice(result);
     }
 
+    // TODO @疯狂:这个最好是 is 开头;因为 check 或者 validator,更多失败,会抛出异常;
     private boolean checkDeductPointEnable(MemberPointConfigRespDTO config) {
+        // TODO @疯狂:这个要不直接写成 return config != null && config .... 多行这样一个形式;
         if (config == null) {
             return false;
         }
@@ -93,7 +98,7 @@ public class TradePointUsePriceCalculator implements TradePriceCalculator {
         }
         // 积分优惠金额(分)
         int pointPrice = usePoint * config.getTradeDeductUnitPrice();
-        // 0元购!!!:用户积分比较多时,积分可以抵扣的金额要大于支付金额, 这时需要根据支付金额反推使用多少积分
+        // 0 元购!!!:用户积分比较多时,积分可以抵扣的金额要大于支付金额,这时需要根据支付金额反推使用多少积分
         if (result.getPrice().getPayPrice() < pointPrice) {
             pointPrice = result.getPrice().getPayPrice();
             // 反推需要扣除的积分
@@ -103,7 +108,7 @@ public class TradePointUsePriceCalculator implements TradePriceCalculator {
         }
         // 记录使用的积分
         result.setUsePoint(usePoint);
-
         return pointPrice;
     }
+
 }

+ 3 - 1
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePriceCalculator.java

@@ -21,11 +21,13 @@ public interface TradePriceCalculator {
     /**
      * 快递运费的计算
      *
-     * 放在各种营销活动、优惠劵后面 TODO
+     * 放在各种营销活动、优惠劵后面
      */
     int ORDER_DELIVERY = 50;
     /**
      * 赠送积分,放最后
+     *
+     * 放在 {@link #ORDER_DELIVERY} 后面的原因,是运费也会产生费用,需要赠送对应积分
      */
     int ORDER_POINT_GIVE = 999;
 

+ 2 - 0
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePriceCalculatorHelper.java

@@ -199,6 +199,8 @@ public class TradePriceCalculatorHelper {
     /**
      * 按照支付金额,返回每个订单项的分摊金额数组
      *
+     * 实际上 price 不仅仅可以传递的是金额,也可以是积分。因为它的实现逻辑,就是根据 payPrice 做分摊而已
+     *
      * @param orderItems 订单项数组
      * @param price      金额
      * @return 分摊金额数组,和传入的 orderItems 一一对应

+ 2 - 2
yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceTest.java

@@ -87,7 +87,7 @@ public class TradeOrderUpdateServiceTest extends BaseDbUnitTest {
     @BeforeEach
     public void setUp() {
         when(tradeOrderProperties.getAppId()).thenReturn(888L);
-        when(tradeOrderProperties.getExpireTime()).thenReturn(Duration.ofDays(1));
+        when(tradeOrderProperties.getPayExpireTime()).thenReturn(Duration.ofDays(1));
     }
 
     @Test
@@ -306,7 +306,7 @@ public class TradeOrderUpdateServiceTest extends BaseDbUnitTest {
         // mock 方法(支付单)
 
         // 调用
-        tradeOrderUpdateService.receiveOrder(userId, id);
+        tradeOrderUpdateService.receiveOrderByMember(userId, id);
         // 断言
         TradeOrderDO dbOrder = tradeOrderMapper.selectById(1L);
         assertEquals(dbOrder.getStatus(), TradeOrderStatusEnum.COMPLETED.getStatus());

+ 1 - 0
yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/point/MemberPointApi.java

@@ -12,6 +12,7 @@ import javax.validation.constraints.Min;
  */
 public interface MemberPointApi {
 
+    // TODO @疯狂:这个我们要不要搞成通用的会员配置?MemberConfig?
     /**
      * 获得积分配置
      *

+ 2 - 0
yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/point/dto/MemberPointConfigRespDTO.java

@@ -9,6 +9,7 @@ import lombok.Data;
  */
 @Data
 public class MemberPointConfigRespDTO {
+
     /**
      * 积分抵扣开关
      */
@@ -27,4 +28,5 @@ public class MemberPointConfigRespDTO {
      * 1 元赠送多少分
      */
     private Integer tradeGivePoint;
+
 }

+ 1 - 0
yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/user/dto/MemberUserRespDTO.java

@@ -51,4 +51,5 @@ public class MemberUserRespDTO {
      * 积分
      */
     private Integer point;
+
 }

+ 5 - 5
yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/enums/point/MemberPointBizTypeEnum.java

@@ -17,11 +17,11 @@ import java.util.Objects;
 public enum MemberPointBizTypeEnum implements IntArrayValuable {
 
     SIGN(1, "签到", "签到获得 {} 积分", true),
-    ORDER_REWARD(10, "订单奖励", "下单获得 {} 积分", true),
-    ORDER_CANCEL(11, "订单取消", "订单取消,退还 {} 积分", true), // 退回积分
-    ORDER_USE(12, "订单使用", "下单使用 {} 积分", false), // 扣减积分
-    AFTER_SALE_REFUND_USED(13, "订单退款", "订单退款,退还 {} 积分", true), // 退回积分
-    AFTER_SALE_DEDUCT_GIVE(14, "订单退款", "订单退款,扣除赠送的 {} 积分", false), // 扣减积分
+    ORDER_GIVE(10, "订单奖励", "下单获得 {} 积分", true), // 支付订单时,赠送积分
+    ORDER_CANCEL(11, "订单取消", "订单取消,退还 {} 积分", true), // 取消订单时,退回积分
+    ORDER_USE(12, "订单使用", "下单使用 {} 积分", false), // 下单时,扣减积分
+    AFTER_SALE_REFUND_USED(13, "订单退款", "订单退款,退还 {} 积分", true), // 售后订单成功时,退回积分(对应 ORDER_USE 操作)
+    AFTER_SALE_DEDUCT_GIVE(14, "订单退款", "订单退款,扣除赠送的 {} 积分", false), // 售后订单成功时,扣减积分(对应 ORDER_GIVE 操作)
     ;
 
     /**

+ 2 - 1
yudao-server/src/main/resources/application.yaml

@@ -203,7 +203,8 @@ yudao:
   trade:
     order:
       app-id: 1 # 商户编号
-      expire-time: 2h # 支付的过期时间
+      pay-expire-time: 2h # 支付的过期时间
+      receive-expire-time: 14d # 收货的过期时间
     express:
       client: kd_niao
       kd-niao: