Browse Source

!643 订单:完善拼团活动和一些 TODO
Merge pull request !643 from puhui999/feature/mall_product

芋道源码 1 year ago
parent
commit
4f7d6b4959
42 changed files with 605 additions and 283 deletions
  1. 40 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/date/LocalDateTimeUtils.java
  2. 0 9
      yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/bargain/BargainRecordApi.java
  3. 0 10
      yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/CombinationActivityApi.java
  4. 10 0
      yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/CombinationRecordApi.java
  5. 5 0
      yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/dto/CombinationRecordCreateReqDTO.java
  6. 14 0
      yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/seckill/SeckillActivityApi.java
  7. 65 0
      yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/seckill/dto/SeckillActivityProductRespDTO.java
  8. 5 3
      yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java
  9. 0 5
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/bargain/BargainRecordApiImpl.java
  10. 0 11
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/CombinationActivityApiImpl.java
  11. 5 0
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/CombinationRecordApiImpl.java
  12. 9 0
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/seckill/SeckillActivityApiImpl.java
  13. 1 1
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/combination/CombinationActivityConvert.java
  14. 12 6
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/seckill/seckillactivity/SeckillActivityConvert.java
  15. 4 0
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/combination/CombinationRecordDO.java
  16. 4 0
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/combination/CombinationRecordMapper.java
  17. 4 4
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/bargain/BargainActivityServiceImpl.java
  18. 0 11
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationActivityService.java
  19. 2 41
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationActivityServiceImpl.java
  20. 11 0
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationRecordService.java
  21. 64 13
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationRecordServiceImpl.java
  22. 12 3
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityService.java
  23. 15 0
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityServiceImpl.java
  24. 4 16
      yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/api/order/TradeOrderApi.java
  25. 7 14
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/api/order/TradeOrderApiImpl.java
  26. 13 1
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/AppTradeOrderSettlementReqVO.java
  27. 28 18
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java
  28. 0 6
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/order/TradeOrderItemMapper.java
  29. 0 8
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderQueryService.java
  30. 0 7
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderQueryServiceImpl.java
  31. 9 24
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java
  32. 56 9
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/bo/TradeAfterOrderCreateReqBO.java
  33. 43 0
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/bo/TradeAfterPayOrderReqBO.java
  34. 29 23
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/bo/TradeBeforeOrderCreateReqBO.java
  35. 5 13
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeBargainHandler.java
  36. 14 9
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeCombinationHandler.java
  37. 34 0
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeOrderDefaultHandler.java
  38. 10 4
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeOrderHandler.java
  39. 5 13
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeSeckillHandler.java
  40. 18 1
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/bo/TradePriceCalculateRespBO.java
  41. 3 0
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePriceCalculatorHelper.java
  42. 45 0
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeSeckillActivityPriceCalculator.java

+ 40 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/date/LocalDateTimeUtils.java

@@ -97,4 +97,44 @@ public class LocalDateTimeUtils {
                 LocalDateTime.of(nowDate, startTime2), LocalDateTime.of(nowDate, endTime2));
     }
 
+    /**
+     * 构建日期时间 TODO 后面有需要的话再继续扩展
+     *
+     * @author HUIHUI
+     */
+    public static class BuilderDateTime {
+
+        /**
+         * 日期;2023-10-01
+         */
+        private String localDate;
+        /**
+         * 时间;10:01:00
+         */
+        private String localTime;
+
+        public BuilderDateTime() {
+        }
+
+        public BuilderDateTime withDate(String date) {
+            this.localDate = date;
+            return this;
+        }
+
+        public BuilderDateTime withDate(LocalDateTime date) {
+            this.localDate = LocalDateTimeUtil.format(date, "yyyy-MM-dd");
+            return this;
+        }
+
+        public BuilderDateTime withTime(String time) {
+            this.localTime = time;
+            return this;
+        }
+
+        public LocalDateTime build() {
+            return LocalDateTimeUtil.parse(this.localDate + " " + this.localTime, "yyyy-MM-dd HH:mm:ss");
+        }
+
+    }
+
 }

+ 0 - 9
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/bargain/BargainRecordApi.java

@@ -20,13 +20,4 @@ public interface BargainRecordApi {
      */
     void createBargainRecord(@Valid BargainRecordCreateReqDTO reqDTO);
 
-    /**
-     * 查询砍价是否成功
-     *
-     * @param userId  用户编号
-     * @param orderId 订单编号
-     * @return 砍价是否成功
-     */
-    boolean isBargainRecordSuccess(Long userId, Long orderId);
-
 }

+ 0 - 10
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/CombinationActivityApi.java

@@ -7,14 +7,4 @@ package cn.iocoder.yudao.module.promotion.api.combination;
  */
 public interface CombinationActivityApi {
 
-    /**
-     * 校验是否满足拼团条件
-     *
-     * @param activityId 活动编号
-     * @param userId 用户编号
-     * @param skuId sku 编号
-     * @param count 数量
-     */
-    void validateCombination(Long activityId, Long userId, Long skuId, Integer count);
-
 }

+ 10 - 0
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/CombinationRecordApi.java

@@ -14,6 +14,16 @@ import java.time.LocalDateTime;
  */
 public interface CombinationRecordApi {
 
+    /**
+     * 校验是否满足拼团条件
+     *
+     * @param activityId 活动编号
+     * @param userId     用户编号
+     * @param skuId      sku 编号
+     * @param count      数量
+     */
+    void validateCombinationRecord(Long activityId, Long userId, Long skuId, Integer count);
+
     /**
      * 创建开团记录
      *

+ 5 - 0
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/dto/CombinationRecordCreateReqDTO.java

@@ -28,6 +28,11 @@ public class CombinationRecordCreateReqDTO {
      */
     @NotNull(message = "sku 编号不能为空")
     private Long skuId;
+    /**
+     * 购买的商品数量
+     */
+    @NotNull(message = "购买数量不能为空")
+    private Integer count;
     /**
      * 订单编号
      */

+ 14 - 0
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/seckill/SeckillActivityApi.java

@@ -1,5 +1,10 @@
 package cn.iocoder.yudao.module.promotion.api.seckill;
 
+import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillActivityProductRespDTO;
+
+import java.util.Collection;
+import java.util.List;
+
 /**
  * 秒杀活动 API 接口
  *
@@ -16,4 +21,13 @@ public interface SeckillActivityApi {
      */
     void updateSeckillStock(Long id, Long skuId, Integer count);
 
+    /**
+     * 获取秒杀活动商品信息
+     *
+     * @param id     活动编号
+     * @param skuIds sku 编号
+     * @return 秒杀活动商品信息列表
+     */
+    List<SeckillActivityProductRespDTO> getSeckillActivityProductList(Long id, Collection<Long> skuIds);
+
 }

+ 65 - 0
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/seckill/dto/SeckillActivityProductRespDTO.java

@@ -0,0 +1,65 @@
+package cn.iocoder.yudao.module.promotion.api.seckill.dto;
+
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+/**
+ * 秒杀活动商品 Response DTO
+ *
+ * @author HUIHUI
+ */
+@Data
+public class SeckillActivityProductRespDTO {
+
+    /**
+     * 秒杀参与商品编号
+     */
+    private Long id;
+    /**
+     * 秒杀活动 id
+     *
+     * 关联 SeckillActivityDO#getId()
+     */
+    private Long activityId;
+    /**
+     * 秒杀时段 id
+     *
+     * 关联 SeckillConfigDO#getId()
+     */
+    private List<Long> configIds;
+    /**
+     * 商品 SPU 编号
+     */
+    private Long spuId;
+    /**
+     * 商品 SKU 编号
+     */
+    private Long skuId;
+    /**
+     * 秒杀金额,单位:分
+     */
+    private Integer seckillPrice;
+    /**
+     * 秒杀库存
+     */
+    private Integer stock;
+
+    /**
+     * 秒杀商品状态
+     *
+     * 枚举 {@link CommonStatusEnum 对应的类}
+     */
+    private Integer activityStatus;
+    /**
+     * 活动开始时间点
+     */
+    private LocalDateTime activityStartTime;
+    /**
+     * 活动结束时间点
+     */
+    private LocalDateTime activityEndTime;
+
+}

+ 5 - 3
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java

@@ -75,9 +75,11 @@ public interface ErrorCodeConstants {
     ErrorCode COMBINATION_RECORD_HEAD_NOT_EXISTS = new ErrorCode(1_013_011_002, "拼团失败,父拼团不存在");
     ErrorCode COMBINATION_RECORD_USER_FULL = new ErrorCode(1_013_011_003, "拼团失败,拼团人数已满");
     ErrorCode COMBINATION_RECORD_FAILED_HAVE_JOINED = new ErrorCode(1_013_011_004, "拼团失败,已参与其它拼团");
-    ErrorCode COMBINATION_RECORD_FAILED_TIME_END = new ErrorCode(1_013_011_005, "拼团失败,活动已经结束");
-    ErrorCode COMBINATION_RECORD_FAILED_SINGLE_LIMIT_COUNT_EXCEED = new ErrorCode(1_013_011_006, "拼团失败,原因:单次限购超出");
-    ErrorCode COMBINATION_RECORD_FAILED_TOTAL_LIMIT_COUNT_EXCEED = new ErrorCode(1_013_011_007, "拼团失败,原因:超出总购买次数");
+    ErrorCode COMBINATION_RECORD_FAILED_TIME_NOT_START = new ErrorCode(1_013_011_005, "拼团失败,活动未开始");
+    ErrorCode COMBINATION_RECORD_FAILED_TIME_END = new ErrorCode(1_013_011_006, "拼团失败,活动已经结束");
+    ErrorCode COMBINATION_RECORD_FAILED_SINGLE_LIMIT_COUNT_EXCEED = new ErrorCode(1_013_011_007, "拼团失败,原因:单次限购超出");
+    ErrorCode COMBINATION_RECORD_FAILED_TOTAL_LIMIT_COUNT_EXCEED = new ErrorCode(1_013_011_008, "拼团失败,原因:超出总购买次数");
+    ErrorCode COMBINATION_RECORD_FAILED_ORDER_STATUS_UNPAID = new ErrorCode(1_013_011_009, "拼团失败,原因:存在未支付订单,请先支付");
 
     // ========== 砍价活动 1-013-012-000 ==========
     ErrorCode BARGAIN_ACTIVITY_NOT_EXISTS = new ErrorCode(1_013_012_000, "砍价活动不存在");

+ 0 - 5
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/bargain/BargainRecordApiImpl.java

@@ -16,9 +16,4 @@ public class BargainRecordApiImpl implements BargainRecordApi {
 
     }
 
-    @Override
-    public boolean isBargainRecordSuccess(Long userId, Long orderId) {
-        return false;
-    }
-
 }

+ 0 - 11
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/CombinationActivityApiImpl.java

@@ -1,10 +1,7 @@
 package cn.iocoder.yudao.module.promotion.api.combination;
 
-import cn.iocoder.yudao.module.promotion.service.combination.CombinationActivityService;
 import org.springframework.stereotype.Service;
 
-import javax.annotation.Resource;
-
 /**
  * 拼团活动 Api 接口实现类
  *
@@ -13,12 +10,4 @@ import javax.annotation.Resource;
 @Service
 public class CombinationActivityApiImpl implements CombinationActivityApi {
 
-    @Resource
-    private CombinationActivityService activityService;
-
-    @Override
-    public void validateCombination(Long activityId, Long userId, Long skuId, Integer count) {
-        activityService.validateCombination(activityId, userId, skuId, count);
-    }
-
 }

+ 5 - 0
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/CombinationRecordApiImpl.java

@@ -19,6 +19,11 @@ public class CombinationRecordApiImpl implements CombinationRecordApi {
     @Resource
     private CombinationRecordService recordService;
 
+    @Override
+    public void validateCombinationRecord(Long activityId, Long userId, Long skuId, Integer count) {
+        recordService.validateCombinationRecord(activityId, userId, skuId, count);
+    }
+
     @Override
     public void createCombinationRecord(CombinationRecordCreateReqDTO reqDTO) {
         recordService.createCombinationRecord(reqDTO);

+ 9 - 0
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/seckill/SeckillActivityApiImpl.java

@@ -1,9 +1,13 @@
 package cn.iocoder.yudao.module.promotion.api.seckill;
 
+import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillActivityProductRespDTO;
+import cn.iocoder.yudao.module.promotion.convert.seckill.seckillactivity.SeckillActivityConvert;
 import cn.iocoder.yudao.module.promotion.service.seckill.SeckillActivityService;
 import org.springframework.stereotype.Service;
 
 import javax.annotation.Resource;
+import java.util.Collection;
+import java.util.List;
 
 /**
  * 秒杀活动接口 Api 接口实现类
@@ -21,4 +25,9 @@ public class SeckillActivityApiImpl implements SeckillActivityApi {
         activityService.updateSeckillStock(id, skuId, count);
     }
 
+    @Override
+    public List<SeckillActivityProductRespDTO> getSeckillActivityProductList(Long id, Collection<Long> skuIds) {
+        return SeckillActivityConvert.INSTANCE.convertList4(activityService.getSeckillActivityProductList(id, skuIds));
+    }
+
 }

+ 1 - 1
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/combination/CombinationActivityConvert.java

@@ -97,8 +97,8 @@ public interface CombinationActivityConvert {
     default CombinationRecordDO convert(CombinationRecordCreateReqDTO reqDTO,
                                         CombinationActivityDO activity, MemberUserRespDTO user,
                                         ProductSpuRespDTO spu, ProductSkuRespDTO sku) {
-        // TODO @puhui999:订单付款后需要设置开始时间和结束时间;
         return convert(reqDTO)
+                .setCount(reqDTO.getCount())
                 .setVirtualGroup(false)
                 .setExpireTime(activity.getStartTime().plusHours(activity.getLimitDuration()))
                 .setUserSize(activity.getUserSize())

+ 12 - 6
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/seckill/seckillactivity/SeckillActivityConvert.java

@@ -1,12 +1,13 @@
 package cn.iocoder.yudao.module.promotion.convert.seckill.seckillactivity;
 
-import cn.hutool.core.date.LocalDateTimeUtil;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
 import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
+import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
 import cn.iocoder.yudao.framework.dict.core.util.DictFrameworkUtils;
 import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
 import cn.iocoder.yudao.module.product.enums.DictTypeConstants;
+import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillActivityProductRespDTO;
 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityCreateReqVO;
 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityDetailRespVO;
 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityRespVO;
@@ -128,11 +129,16 @@ public interface SeckillActivityConvert {
     default AppSeckillActivityDetailRespVO convert3(SeckillActivityDO seckillActivity, List<SeckillProductDO> products, SeckillConfigDO filteredConfig) {
         return convert2(seckillActivity)
                 .setProducts(convertList1(products))
-                // TODO @puhui999:要不要在里面 default 一个方法,处理这个事件;简洁一点;
-                .setStartTime(LocalDateTimeUtil.parse(LocalDateTimeUtil.format(seckillActivity.getStartTime(), "yyyy-MM-dd") + " " + filteredConfig.getStartTime(),
-                        "yyyy-MM-dd HH:mm:ss")) // 活动开始日期和时段结合
-                .setEndTime(LocalDateTimeUtil.parse(LocalDateTimeUtil.format(seckillActivity.getEndTime(), "yyyy-MM-dd") + " " + filteredConfig.getEndTime(),
-                        "yyyy-MM-dd HH:mm:ss")); // 活动结束日期和时段结合
+                .setStartTime(new LocalDateTimeUtils.BuilderDateTime()
+                        .withDate(seckillActivity.getStartTime())
+                        .withTime(filteredConfig.getStartTime())
+                        .build())// 活动开始日期和时段结合
+                .setEndTime(new LocalDateTimeUtils.BuilderDateTime()
+                        .withDate(seckillActivity.getEndTime())
+                        .withTime(filteredConfig.getEndTime())
+                        .build()); // 活动结束日期和时段结合
     }
 
+    List<SeckillActivityProductRespDTO> convertList4(List<SeckillProductDO> seckillActivityProductList);
+
 }

+ 4 - 0
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/combination/CombinationRecordDO.java

@@ -62,6 +62,10 @@ public class CombinationRecordDO extends BaseDO {
      * SKU 编号
      */
     private Long skuId;
+    /**
+     * 购买的商品数量
+     */
+    private Integer count;
 
     /**
      * 用户编号

+ 4 - 0
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/combination/CombinationRecordMapper.java

@@ -20,6 +20,10 @@ public interface CombinationRecordMapper extends BaseMapperX<CombinationRecordDO
                 CombinationRecordDO::getOrderId, orderId);
     }
 
+    default List<CombinationRecordDO> selectListByUserId(Long userId) {
+        return selectList(CombinationRecordDO::getUserId, userId);
+    }
+
     default List<CombinationRecordDO> selectListByUserIdAndStatus(Long userId, Integer status) {
         return selectList(new LambdaQueryWrapperX<CombinationRecordDO>()
                 .eq(CombinationRecordDO::getUserId, userId)

+ 4 - 4
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/bargain/BargainActivityServiceImpl.java

@@ -116,10 +116,10 @@ public class BargainActivityServiceImpl implements BargainActivityService {
     public void deleteBargainActivity(Long id) {
         // 校验存在
         BargainActivityDO activityDO = validateBargainActivityExists(id);
-        // 校验状态 TODO puhui: 测试完成后需要恢复校验
-        //if (ObjectUtil.equal(activityDO.getStatus(), CommonStatusEnum.ENABLE.getStatus())) {
-        //    throw exception(BARGAIN_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END);
-        //}
+        // 校验状态
+        if (ObjectUtil.equal(activityDO.getStatus(), CommonStatusEnum.ENABLE.getStatus())) {
+            throw exception(BARGAIN_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END);
+        }
 
         // 删除
         bargainActivityMapper.deleteById(id);

+ 0 - 11
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationActivityService.java

@@ -84,17 +84,6 @@ public interface CombinationActivityService {
      */
     List<CombinationProductDO> getCombinationProductsByActivityIds(Collection<Long> activityIds);
 
-    /**
-     * 校验是否满足拼团条件
-     * 如果不满足,会抛出异常
-     *
-     * @param activityId 活动编号
-     * @param userId     用户编号
-     * @param skuId      sku 编号
-     * @param count      数量
-     */
-    void validateCombination(Long activityId, Long userId, Long skuId, Integer count);
-
     /**
      * 获取正在进行的活动分页数据
      *

+ 2 - 41
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationActivityServiceImpl.java

@@ -17,12 +17,8 @@ import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product
 import cn.iocoder.yudao.module.promotion.convert.combination.CombinationActivityConvert;
 import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO;
 import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationProductDO;
-import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationRecordDO;
 import cn.iocoder.yudao.module.promotion.dal.mysql.combination.CombinationActivityMapper;
 import cn.iocoder.yudao.module.promotion.dal.mysql.combination.CombinationProductMapper;
-import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum;
-import cn.iocoder.yudao.module.trade.api.order.TradeOrderApi;
-import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.validation.annotation.Validated;
@@ -33,7 +29,8 @@ import java.util.List;
 import java.util.Map;
 
 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.collection.CollectionUtils.convertMap;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList;
 import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_NOT_EXISTS;
 import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SPU_NOT_EXISTS;
 import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
@@ -53,16 +50,10 @@ public class CombinationActivityServiceImpl implements CombinationActivityServic
     @Resource
     private CombinationProductMapper combinationProductMapper;
 
-    @Resource
-    @Lazy // TODO @puhui999:我感觉 validateCombination 可以挪到 CombinationRecordServiceImpl 中,因为它更偏向能不能创建拼团记录;
-    private CombinationRecordService combinationRecordService;
-
     @Resource
     private ProductSpuApi productSpuApi;
     @Resource
     private ProductSkuApi productSkuApi;
-    @Resource
-    private TradeOrderApi tradeOrderApi;
 
     @Override
     @Transactional(rollbackFor = Exception.class)
@@ -215,36 +206,6 @@ public class CombinationActivityServiceImpl implements CombinationActivityServic
         return combinationProductMapper.selectListByActivityIds(activityIds);
     }
 
-    @Override
-    public void validateCombination(Long activityId, Long userId, Long skuId, Integer count) {
-        // 1.1 校验拼团活动是否存在
-        CombinationActivityDO activity = validateCombinationActivityExists(activityId);
-        // 1.2 校验活动是否开启
-        if (ObjectUtil.equal(activity.getStatus(), CommonStatusEnum.DISABLE.getStatus())) {
-            throw exception(COMBINATION_ACTIVITY_STATUS_DISABLE);
-        }
-        // 1.3 校验是否超出单次限购数量
-        if (count > activity.getSingleLimitCount()) {
-            throw exception(COMBINATION_RECORD_FAILED_SINGLE_LIMIT_COUNT_EXCEED);
-        }
-
-        // 2. 校验是否超出总限购数量
-        List<CombinationRecordDO> recordList = combinationRecordService.getRecordListByUserIdAndActivityId(userId, activityId);
-        if (CollUtil.isEmpty(recordList)) {
-            return;
-        }
-        // 过滤出拼团成功的
-        // TODO @puhui999:count 要不存一个在 record 里?
-        List<Long> skuIds = convertList(recordList, CombinationRecordDO::getSkuId,
-                item -> ObjectUtil.equals(item.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus()));
-        Integer countSum = tradeOrderApi.getOrderItemCountSumByOrderIdAndSkuId(convertList(recordList,
-                CombinationRecordDO::getOrderId,
-                item -> ObjectUtil.equals(item.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus())), skuIds);
-        if (activity.getTotalLimitCount() < countSum) {
-            throw exception(COMBINATION_RECORD_FAILED_TOTAL_LIMIT_COUNT_EXCEED);
-        }
-    }
-
     @Override
     public List<CombinationActivityDO> getCombinationActivityListByCount(Integer count) {
         return combinationActivityMapper.selectListByStatus(CommonStatusEnum.ENABLE.getStatus(), count);

+ 11 - 0
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationRecordService.java

@@ -22,6 +22,17 @@ public interface CombinationRecordService {
      */
     void updateCombinationRecordStatusByUserIdAndOrderId(Integer status, Long userId, Long orderId);
 
+    /**
+     * 校验是否满足拼团条件
+     * 如果不满足,会抛出异常
+     *
+     * @param activityId 活动编号
+     * @param userId     用户编号
+     * @param skuId      sku 编号
+     * @param count      数量
+     */
+    void validateCombinationRecord(Long activityId, Long userId, Long skuId, Integer count);
+
     /**
      * 创建拼团记录
      *

+ 64 - 13
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationRecordServiceImpl.java

@@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.promotion.service.combination;
 
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.util.ObjectUtil;
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
 import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
 import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
 import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
@@ -14,6 +15,8 @@ import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationA
 import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationRecordDO;
 import cn.iocoder.yudao.module.promotion.dal.mysql.combination.CombinationRecordMapper;
 import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum;
+import cn.iocoder.yudao.module.trade.api.order.TradeOrderApi;
+import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum;
 import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
@@ -24,6 +27,7 @@ import java.time.LocalDateTime;
 import java.util.List;
 
 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.module.promotion.enums.ErrorCodeConstants.*;
 
 // TODO 芋艿:等拼团记录做完,完整 review 下
@@ -51,6 +55,8 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
     @Resource
     @Lazy
     private ProductSkuApi productSkuApi;
+    @Resource
+    private TradeOrderApi tradeOrderApi;
 
     @Override
     @Transactional(rollbackFor = Exception.class)
@@ -96,30 +102,77 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
         return recordDO;
     }
 
-    // TODO @puhui999:有一个应该在创建那要做下;就是当前 activityId 已经有未支付的订单,不允许在发起新的;要么支付,要么去掉先;
+    @Override
+    public void validateCombinationRecord(Long activityId, Long userId, Long skuId, Integer count) {
+        // 1.1 校验拼团活动是否存在
+        CombinationActivityDO activity = combinationActivityService.validateCombinationActivityExists(activityId);
+        // 1.2 校验活动是否开启
+        if (ObjectUtil.equal(activity.getStatus(), CommonStatusEnum.DISABLE.getStatus())) {
+            throw exception(COMBINATION_ACTIVITY_STATUS_DISABLE);
+        }
+        // 2 校验是否超出单次限购数量
+        if (count > activity.getSingleLimitCount()) {
+            throw exception(COMBINATION_RECORD_FAILED_SINGLE_LIMIT_COUNT_EXCEED);
+        }
+        // 3、校验是否有拼团记录
+        List<CombinationRecordDO> recordList = getRecordListByUserIdAndActivityId(userId, activityId);
+        if (CollUtil.isEmpty(recordList)) {
+            return;
+        }
+        // 4、校验是否超出总限购数量
+        Integer sumValue = getSumValue(convertList(recordList, CombinationRecordDO::getCount,
+                item -> ObjectUtil.equals(item.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus())), i -> i, Integer::sum);
+        if ((sumValue + count) > activity.getTotalLimitCount()) {
+            throw exception(COMBINATION_RECORD_FAILED_TOTAL_LIMIT_COUNT_EXCEED);
+        }
+        // 5、校验拼团记录是否存在未支付的订单(如果存在未支付的订单则不允许发起新的拼团)
+        CombinationRecordDO record = findFirst(recordList, item -> ObjectUtil.equals(item.getStatus(), null));
+        if (record == null) {
+            return;
+        }
+        // 5.1、查询关联的订单是否已经支付
+        // 当前 activityId 已经有未支付的订单,不允许在发起新的;要么支付,要么去掉先;
+        Integer orderStatus = tradeOrderApi.getOrderStatus(record.getOrderId());
+        if (ObjectUtil.equal(orderStatus, TradeOrderStatusEnum.UNPAID.getStatus())) {
+            throw exception(COMBINATION_RECORD_FAILED_ORDER_STATUS_UNPAID);
+        }
+    }
 
     @Override
     @Transactional(rollbackFor = Exception.class)
     public void createCombinationRecord(CombinationRecordCreateReqDTO reqDTO) {
-        // 1.1 校验拼团活动
+
+        // 1.1、 校验拼团活动
         CombinationActivityDO activity = combinationActivityService.validateCombinationActivityExists(reqDTO.getActivityId());
-        // 1.2 需要校验下,他当前是不是已经参加了该拼团;
-        // TODO @puhui999:拼团应该可以重复参加;应该去校验总共的上限哈,就是 activity.totalLimitCount
-        CombinationRecordDO recordDO = recordMapper.selectByUserIdAndOrderId(reqDTO.getUserId(), reqDTO.getOrderId());
-        if (recordDO != null) {
-            throw exception(COMBINATION_RECORD_EXISTS);
+        // 1.2 校验是否超出单次限购数量
+        if (reqDTO.getCount() > activity.getSingleLimitCount()) {
+            throw exception(COMBINATION_RECORD_FAILED_SINGLE_LIMIT_COUNT_EXCEED);
+        }
+        // 1.3、校验是否有拼团记录
+        List<CombinationRecordDO> records = getRecordListByUserIdAndActivityId(reqDTO.getUserId(), reqDTO.getActivityId());
+        if (CollUtil.isEmpty(records)) {
+            return;
         }
-        // 1.3 校验用户是否参加了其它拼团
+        // 1.4、校验是否超出总限购数量
+        Integer sumValue = getSumValue(convertList(records, CombinationRecordDO::getCount,
+                item -> ObjectUtil.equals(item.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus())), i -> i, Integer::sum);
+        if ((sumValue + reqDTO.getCount()) > activity.getTotalLimitCount()) {
+            throw exception(COMBINATION_RECORD_FAILED_TOTAL_LIMIT_COUNT_EXCEED);
+        }
+        // 2、 校验用户是否参加了其它拼团
         List<CombinationRecordDO> recordDOList = recordMapper.selectListByUserIdAndStatus(reqDTO.getUserId(), CombinationRecordStatusEnum.IN_PROGRESS.getStatus());
         if (CollUtil.isNotEmpty(recordDOList)) {
             throw exception(COMBINATION_RECORD_FAILED_HAVE_JOINED);
         }
-        // TODO @puhui999:有个开始时间未校验
-        // 1.4 校验当前活动是否过期
+        // 3、 校验活动是否开启
+        if (LocalDateTime.now().isAfter(activity.getStartTime())) {
+            throw exception(COMBINATION_RECORD_FAILED_TIME_NOT_START);
+        }
+        // 4、 校验当前活动是否过期
         if (LocalDateTime.now().isAfter(activity.getEndTime())) {
             throw exception(COMBINATION_RECORD_FAILED_TIME_END);
         }
-        // 1.5 父拼团是否存在,是否已经满了
+        // 5 父拼团是否存在,是否已经满了
         if (reqDTO.getHeadId() != null) {
             // 查询进行中的父拼团
             CombinationRecordDO record = recordMapper.selectOneByHeadId(reqDTO.getHeadId(), CombinationRecordStatusEnum.IN_PROGRESS.getStatus());
@@ -132,8 +185,6 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
             }
         }
 
-        // TODO @puhui999:单次限购
-
         // 2. 创建拼团记录
         MemberUserRespDTO user = memberUserApi.getUser(reqDTO.getUserId());
         ProductSpuRespDTO spu = productSpuApi.getSpu(reqDTO.getSpuId());

+ 12 - 3
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityService.java

@@ -37,9 +37,9 @@ public interface SeckillActivityService {
     /**
      * 更新秒杀库存
      *
-     * @param id 活动编号
-     * @param skuId      sku 编号
-     * @param count      数量
+     * @param id    活动编号
+     * @param skuId sku 编号
+     * @param count 数量
      */
     void updateSeckillStock(Long id, Long skuId, Integer count);
 
@@ -114,4 +114,13 @@ public interface SeckillActivityService {
      */
     PageResult<SeckillActivityDO> getSeckillActivityAppPageByConfigId(AppSeckillActivityPageReqVO pageReqVO);
 
+    /**
+     * 获取秒杀活动商品信息
+     *
+     * @param id     活动编号
+     * @param skuIds sku 编号
+     * @return 秒杀活动商品信息列表
+     */
+    List<SeckillProductDO> getSeckillActivityProductList(Long id, Collection<Long> skuIds);
+
 }

+ 15 - 0
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityServiceImpl.java

@@ -1,5 +1,6 @@
 package cn.iocoder.yudao.module.promotion.service.seckill;
 
+import cn.hutool.core.collection.CollectionUtil;
 import cn.hutool.core.util.ObjectUtil;
 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
@@ -278,4 +279,18 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
         return seckillActivityMapper.selectPage(pageReqVO, CommonStatusEnum.ENABLE.getStatus());
     }
 
+    @Override
+    public List<SeckillProductDO> getSeckillActivityProductList(Long id, Collection<Long> skuIds) {
+        // 1、校验秒杀活动是否存在
+        validateSeckillActivityExists(id);
+        // 2、校验活动商品是否存在
+        List<SeckillProductDO> productList = filterList(seckillProductMapper.selectListByActivityId(id),
+                item -> skuIds.contains(item.getSkuId()));
+        if (CollectionUtil.isEmpty(productList)) {
+            throw exception(SKU_NOT_EXISTS);
+        }
+
+        return productList;
+    }
+
 }

+ 4 - 16
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/api/order/TradeOrderApi.java

@@ -1,7 +1,5 @@
 package cn.iocoder.yudao.module.trade.api.order;
 
-import java.util.Collection;
-
 /**
  * 订单 API 接口
  *
@@ -10,21 +8,11 @@ import java.util.Collection;
 public interface TradeOrderApi {
 
     /**
-     * 验证订单
-     *
-     * @param userId      用户 id
-     * @param orderItemId 订单项 id
-     * @return 校验通过返回订单 id
-     */
-    Long validateOrder(Long userId, Long orderItemId);
-
-    /**
-     * 获取订单项商品购买数量总和
+     * 获取订单状态
      *
-     * @param orderIds 订单编号
-     * @param skuIds   sku 编号
-     * @return 订单项商品购买数量总和
+     * @param id 订单编号
+     * @return 订单状态
      */
-    Integer getOrderItemCountSumByOrderIdAndSkuId(Collection<Long> orderIds, Collection<Long> skuIds);
+    Integer getOrderStatus(Long id);
 
 }

+ 7 - 14
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/api/order/TradeOrderApiImpl.java

@@ -1,15 +1,14 @@
 package cn.iocoder.yudao.module.trade.api.order;
 
-import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
+import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
 import cn.iocoder.yudao.module.trade.service.order.TradeOrderQueryService;
 import org.springframework.stereotype.Service;
 import org.springframework.validation.annotation.Validated;
 
 import javax.annotation.Resource;
-import java.util.Collection;
 
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
-import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.ORDER_ITEM_NOT_FOUND;
+import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.ORDER_NOT_FOUND;
 
 /**
  * 订单 API 接口实现类
@@ -24,18 +23,12 @@ public class TradeOrderApiImpl implements TradeOrderApi {
     private TradeOrderQueryService tradeOrderQueryService;
 
     @Override
-    public Long validateOrder(Long userId, Long orderItemId) {
-        // 校验订单项,订单项存在订单就存在
-        TradeOrderItemDO item = tradeOrderQueryService.getOrderItem(userId, orderItemId);
-        if (item == null) {
-            throw exception(ORDER_ITEM_NOT_FOUND);
+    public Integer getOrderStatus(Long id) {
+        TradeOrderDO order = tradeOrderQueryService.getOrder(id);
+        if (order == null) {
+            throw exception(ORDER_NOT_FOUND);
         }
-        return item.getOrderId();
-    }
-
-    @Override
-    public Integer getOrderItemCountSumByOrderIdAndSkuId(Collection<Long> orderIds, Collection<Long> skuIds) {
-        return tradeOrderQueryService.getOrderItemCountSumByOrderIdAndSkuId(orderIds, skuIds);
+        return order.getStatus();
     }
 
 }

+ 13 - 1
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/AppTradeOrderSettlementReqVO.java

@@ -16,6 +16,7 @@ import java.util.List;
 
 @Schema(description = "用户 App - 交易订单结算 Request VO")
 @Data
+@Valid
 public class AppTradeOrderSettlementReqVO {
 
     @Schema(description = "商品项数组", requiredMode = Schema.RequiredMode.REQUIRED)
@@ -62,7 +63,16 @@ public class AppTradeOrderSettlementReqVO {
     @Schema(description = "砍价活动编号", example = "123")
     private Long bargainActivityId;
 
-    // TODO @puhui999:可以写个参数校验,如果 seckillActivityId 或 combinationActivityId 或 combinationHeadId 的情况,items 应该只有一个
+    @AssertTrue(message = "活动商品每次只能购买一种规格")
+    @JsonIgnore
+    public boolean isValidActivityItems() {
+        // 校验是否是活动订单
+        if (seckillActivityId == null && combinationActivityId == null && combinationHeadId == null) {
+            return true;
+        }
+        // 校验订单项是否超出
+        return items.size() == 1;
+    }
 
     @Data
     @Schema(description = "用户 App - 商品项")
@@ -70,7 +80,9 @@ public class AppTradeOrderSettlementReqVO {
     public static class Item {
 
         @Schema(description = "商品 SKU 编号", example = "2048")
+        @NotNull(message = "商品 SKU 编号不能为空")
         private Long skuId;
+
         @Schema(description = "购买数量", example = "1")
         @Min(value = 1, message = "购买数量最小值为 {value}")
         private Integer count;

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

@@ -93,6 +93,7 @@ public interface TradeOrderConvert {
                 new ProductSkuUpdateStockReqDTO.Item().setId(item.getSkuId()).setIncrCount(item.getCount()));
         return new ProductSkuUpdateStockReqDTO(items);
     }
+
     default ProductSkuUpdateStockReqDTO convertNegative(List<AppTradeOrderSettlementReqVO.Item> list) {
         List<ProductSkuUpdateStockReqDTO.Item> items = CollectionUtils.convertList(list, item ->
                 new ProductSkuUpdateStockReqDTO.Item().setId(item.getSkuId()).setIncrCount(-item.getCount()));
@@ -209,6 +210,8 @@ public interface TradeOrderConvert {
     })
     ProductCommentCreateReqDTO convert04(AppTradeOrderItemCommentCreateReqVO createReqVO, TradeOrderItemDO tradeOrderItemDO);
 
+    TradePriceCalculateReqBO convert(AppTradeOrderSettlementReqVO settlementReqVO);
+
     default TradePriceCalculateReqBO convert(Long userId, AppTradeOrderSettlementReqVO settlementReqVO,
                                              List<CartDO> cartList) {
         TradePriceCalculateReqBO reqBO = new TradePriceCalculateReqBO().setUserId(userId)
@@ -249,17 +252,6 @@ public interface TradeOrderConvert {
 
     AppTradeOrderSettlementRespVO convert0(TradePriceCalculateRespBO calculate, AddressRespDTO address);
 
-    @Mappings({
-            @Mapping(target = "activityId", source = "afterOrderCreateReqBO.combinationActivityId"),
-            @Mapping(target = "spuId", source = "afterOrderCreateReqBO.spuId"),
-            @Mapping(target = "skuId", source = "afterOrderCreateReqBO.skuId"),
-            @Mapping(target = "orderId", source = "afterOrderCreateReqBO.orderId"),
-            @Mapping(target = "userId", source = "afterOrderCreateReqBO.userId"),
-            @Mapping(target = "headId", source = "afterOrderCreateReqBO.combinationHeadId"),
-            @Mapping(target = "combinationPrice", source = "afterOrderCreateReqBO.payPrice"),
-    })
-    CombinationRecordCreateReqDTO convert(TradeAfterOrderCreateReqBO afterOrderCreateReqBO);
-
     List<AppOrderExpressTrackRespDTO> convertList02(List<ExpressTrackRespDTO> list);
 
     TradeOrderDO convert(TradeOrderUpdateAddressReqVO reqVO);
@@ -280,18 +272,36 @@ public interface TradeOrderConvert {
         return bo;
     }
 
-    TradeBeforeOrderCreateReqBO convert(AppTradeOrderCreateReqVO createReqVO);
+    @Mappings({
+            @Mapping(target = "userId", source = "userId"),
+            @Mapping(target = "orderType", source = "calculateRespBO.type"),
+            @Mapping(target = "items", source = "createReqVO.items"),
+    })
+    TradeBeforeOrderCreateReqBO convert(Long userId, AppTradeOrderCreateReqVO createReqVO, TradePriceCalculateRespBO calculateRespBO);
+
+
+    List<TradeAfterOrderCreateReqBO.Item> convertList(List<TradeOrderItemDO> orderItems);
+
 
     @Mappings({
-            @Mapping(target = "combinationActivityId", source = "createReqVO.combinationActivityId"),
-            @Mapping(target = "combinationHeadId", source = "createReqVO.combinationHeadId"),
-            @Mapping(target = "spuId", source = "orderItem.spuId"),
-            @Mapping(target = "skuId", source = "orderItem.skuId"),
-            @Mapping(target = "orderId", source = "tradeOrderDO.id"),
             @Mapping(target = "userId", source = "userId"),
+            @Mapping(target = "orderId", source = "tradeOrderDO.id"),
             @Mapping(target = "payPrice", source = "tradeOrderDO.payPrice"),
+            @Mapping(target = "items", source = "orderItems"),
     })
     TradeAfterOrderCreateReqBO convert(Long userId, AppTradeOrderCreateReqVO createReqVO,
-                                       TradeOrderDO tradeOrderDO, TradeOrderItemDO orderItem);
+                                       TradeOrderDO tradeOrderDO, List<TradeOrderItemDO> orderItems);
+
+    @Mappings({
+            @Mapping(target = "activityId", source = "combinationActivityId"),
+            @Mapping(target = "spuId", expression = "java(reqBO.getItems().get(0).getSpuId())"),
+            @Mapping(target = "skuId", expression = "java(reqBO.getItems().get(0).getSkuId())"),// TODO 艿艿看看这里
+            @Mapping(target = "count", expression = "java(reqBO.getItems().get(0).getCount())"),
+            @Mapping(target = "orderId", source = "orderId"),
+            @Mapping(target = "userId", source = "userId"),
+            @Mapping(target = "headId", source = "combinationHeadId"),
+            @Mapping(target = "combinationPrice", source = "payPrice")
+    })
+    CombinationRecordCreateReqDTO convert(TradeAfterOrderCreateReqBO reqBO);
 
 }

+ 0 - 6
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/order/TradeOrderItemMapper.java

@@ -26,12 +26,6 @@ public interface TradeOrderItemMapper extends BaseMapperX<TradeOrderItemDO> {
         return selectList(TradeOrderItemDO::getOrderId, orderIds);
     }
 
-    default List<TradeOrderItemDO> selectListByOrderIdAnSkuId(Collection<Long> orderIds, Collection<Long> skuIds) {
-        return selectList(new LambdaQueryWrapperX<TradeOrderItemDO>()
-                .in(TradeOrderItemDO::getOrderId, orderIds)
-                .in(TradeOrderItemDO::getSkuId, skuIds));
-    }
-
     default TradeOrderItemDO selectByIdAndUserId(Long orderItemId, Long loginUserId) {
         return selectOne(new LambdaQueryWrapperX<TradeOrderItemDO>()
                 .eq(TradeOrderItemDO::getId, orderItemId)

+ 0 - 8
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderQueryService.java

@@ -119,13 +119,5 @@ public interface TradeOrderQueryService {
      */
     List<TradeOrderItemDO> getOrderItemListByOrderId(Collection<Long> orderIds);
 
-    /**
-     * 获取订单项商品购买数量总和
-     *
-     * @param orderIds 订单编号
-     * @param skuIds   sku 编号
-     * @return 订单项商品购买数量总和
-     */
-    Integer getOrderItemCountSumByOrderIdAndSkuId(Collection<Long> orderIds, Collection<Long> skuIds);
 
 }

+ 0 - 7
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderQueryServiceImpl.java

@@ -4,7 +4,6 @@ import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
 import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
 import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
 import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderPageReqVO;
@@ -169,10 +168,4 @@ public class TradeOrderQueryServiceImpl implements TradeOrderQueryService {
         return tradeOrderItemMapper.selectListByOrderId(orderIds);
     }
 
-    @Override
-    public Integer getOrderItemCountSumByOrderIdAndSkuId(Collection<Long> orderIds, Collection<Long> skuIds) {
-        List<TradeOrderItemDO> tradeOrderItems = tradeOrderItemMapper.selectListByOrderIdAnSkuId(orderIds, skuIds);
-        return CollectionUtils.getSumValue(tradeOrderItems, TradeOrderItemDO::getCount, Integer::sum);
-    }
-
 }

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

@@ -59,7 +59,7 @@ import cn.iocoder.yudao.module.trade.service.cart.CartService;
 import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressService;
 import cn.iocoder.yudao.module.trade.service.message.TradeMessageService;
 import cn.iocoder.yudao.module.trade.service.message.bo.TradeOrderMessageWhenDeliveryOrderReqBO;
-import cn.iocoder.yudao.module.trade.service.order.bo.TradeBeforeOrderCreateReqBO;
+import cn.iocoder.yudao.module.trade.service.order.bo.TradeAfterPayOrderReqBO;
 import cn.iocoder.yudao.module.trade.service.order.handler.TradeOrderHandler;
 import cn.iocoder.yudao.module.trade.service.price.TradePriceService;
 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO;
@@ -253,12 +253,9 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
     private void beforeCreateTradeOrder(Long userId, AppTradeOrderCreateReqVO createReqVO,
                                         TradePriceCalculateRespBO calculateRespBO) {
         // 1. 执行订单创建前置处理器
-        TradeBeforeOrderCreateReqBO beforeOrderCreateReqBO = TradeOrderConvert.INSTANCE.convert(createReqVO);
-        beforeOrderCreateReqBO.setOrderType(calculateRespBO.getType());
-        beforeOrderCreateReqBO.setUserId(userId);
-        beforeOrderCreateReqBO.setCount(getSumValue(createReqVO.getItems(), AppTradeOrderSettlementReqVO.Item::getCount, Integer::sum));
         // TODO @puhui999:这里有个纠结点;handler 的定义是只处理指定类型的订单的拓展逻辑;还是通用的 handler,类似可以处理优惠劵等等
-        tradeOrderHandlers.forEach(handler -> handler.beforeOrderCreate(beforeOrderCreateReqBO));
+        tradeOrderHandlers.forEach(handler ->
+                handler.beforeOrderCreate(TradeOrderConvert.INSTANCE.convert(userId, createReqVO, calculateRespBO)));
 
         // 2. 下单时扣减商品库存
         productSkuApi.updateSkuStock(TradeOrderConvert.INSTANCE.convertNegative(createReqVO.getItems()));
@@ -278,9 +275,8 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
                                        TradeOrderDO order, List<TradeOrderItemDO> orderItems,
                                        TradePriceCalculateRespBO calculateRespBO) {
         // 1. 执行订单创建后置处理器
-        // TODO @puhui999:从通用性来说,应该不用 orderItems.get(0)
         tradeOrderHandlers.forEach(handler -> handler.afterOrderCreate(
-                TradeOrderConvert.INSTANCE.convert(userId, createReqVO, order, orderItems.get(0))));
+                TradeOrderConvert.INSTANCE.convert(userId, createReqVO, order, orderItems)));
 
         // 2. 有使用优惠券时更新
         // 不在前置扣减的原因,是因为优惠劵要记录使用的订单号
@@ -337,13 +333,9 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
             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());
-        }
+        // 3、订单支付成功后
+        tradeOrderHandlers.forEach(tradeOrderHandler -> tradeOrderHandler.afterPayOrder(new TradeAfterPayOrderReqBO()
+                .setOrderId(order.getId()).setOrderType(order.getType()).setUserId(order.getUserId()).setPayTime(LocalDateTime.now())));
 
         // 4.1 增加用户积分(赠送)
         addUserPoint(order.getUserId(), order.getGivePoint(), MemberPointBizTypeEnum.ORDER_GIVE, order.getId());
@@ -470,14 +462,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
                 throw exception(ORDER_DELIVERY_FAIL_COMBINATION_RECORD_STATUS_NOT_SUCCESS);
             }
         }
-        // 订单类类型:砍价
-        if (Objects.equals(TradeOrderTypeEnum.BARGAIN.getType(), order.getType())) {
-            // 校验订单砍价是否成功
-            // TODO @puhui999:砍价的话,应该不用校验。因为是砍价成功后,才可以下单
-            if (!bargainRecordApi.isBargainRecordSuccess(order.getUserId(), order.getId())) {
-                throw exception(ORDER_DELIVERY_FAIL_BARGAIN_RECORD_STATUS_NOT_SUCCESS);
-            }
-        }
+
         return order;
     }
 
@@ -644,7 +629,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
         }
 
         // 2. TODO 活动相关库存回滚需要活动 id,活动 id 怎么获取?app 端能否传过来;回复:从订单里拿呀
-        tradeOrderHandlers.forEach(handler -> handler.rollback());
+        tradeOrderHandlers.forEach(handler -> handler.cancelOrder());
 
         // 3. 回滚库存
         List<TradeOrderItemDO> orderItems = tradeOrderItemMapper.selectListByOrderId(id);

+ 56 - 9
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/bo/TradeAfterOrderCreateReqBO.java

@@ -1,9 +1,10 @@
 package cn.iocoder.yudao.module.trade.service.order.bo;
 
-import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
 
+import javax.validation.Valid;
 import javax.validation.constraints.NotNull;
+import java.util.List;
 
 // TODO 芋艿:在想想这些参数的定义
 /**
@@ -16,25 +17,71 @@ public class TradeAfterOrderCreateReqBO {
 
     // ========== 拼团活动相关字段 ==========
 
-    @Schema(description = "拼团活动编号", example = "1024")
+    /**
+     * 拼团活动编号
+     */
     private Long combinationActivityId;
 
-    @Schema(description = "拼团团长编号", example = "2048")
+    /**
+     * 拼团团长编号
+     */
     private Long combinationHeadId;
 
-    @NotNull(message = "SPU 编号不能为空")
-    private Long spuId;
-
-    @NotNull(message = "SKU 编号活动商品不能为空")
-    private Long skuId;
-
+    /**
+     * 订单编号
+     */
     @NotNull(message = "订单编号不能为空")
     private Long orderId;
 
+    /**
+     * 用户编号
+     */
     @NotNull(message = "用户编号不能为空")
     private Long userId;
 
+    /**
+     * 支付金额
+     */
     @NotNull(message = "支付金额不能为空")
     private Integer payPrice;
 
+    // ========== 购买商品相关字段 ==========
+
+    /**
+     * 订单购买的商品信息
+     */
+    private List<Item> items;
+
+    /**
+     * 订单商品信息
+     * 记录购买商品的简要核心信息
+     *
+     * @author HUIHUI
+     */
+    @Data
+    @Valid
+    public static class Item {
+
+        /**
+         * SPU 编号
+         */
+        @NotNull(message = "SPU 编号不能为空")
+        private Long spuId;
+
+        /**
+         * 商品 SKU 编号
+         *
+         * 关联 ProductSkuDO 的 id 编号
+         */
+        @NotNull(message = "SKU 编号活动商品不能为空")
+        private Long skuId;
+
+        /**
+         * 购买的商品数量
+         */
+        @NotNull(message = "购买数量不能为空")
+        private Integer count;
+
+    }
+
 }

+ 43 - 0
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/bo/TradeAfterPayOrderReqBO.java

@@ -0,0 +1,43 @@
+package cn.iocoder.yudao.module.trade.service.order.bo;
+
+import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+/**
+ * 订单支付后 Request BO
+ *
+ * @author HUIHUI
+ */
+@Data
+public class TradeAfterPayOrderReqBO {
+
+    /**
+     * 订单编号
+     */
+    @Schema(description = "订单编号", example = "6")
+    private Long orderId;
+
+    /**
+     * 订单类型
+     *
+     * 枚举 {@link TradeOrderTypeEnum}
+     */
+    @Schema(description = "订单类型", example = "3")
+    private Integer orderType;
+
+    /**
+     * 用户编号
+     */
+    @Schema(description = "用户编号", example = "11")
+    private Long userId;
+
+    /**
+     * 订单支付时间
+     */
+    @Schema(description = "订单支付时间", example = "2023-08-15 10:00:00")
+    private LocalDateTime payTime;
+
+}

+ 29 - 23
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/bo/TradeBeforeOrderCreateReqBO.java

@@ -1,12 +1,13 @@
 package cn.iocoder.yudao.module.trade.service.order.bo;
 
 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
-import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
 
+import javax.validation.Valid;
 import javax.validation.constraints.NotNull;
-
+import java.util.List;
 // TODO 芋艿:在想想这些参数的定义
+
 /**
  * 订单创建之前 Request BO
  *
@@ -34,9 +35,8 @@ public class TradeBeforeOrderCreateReqBO {
     // ========== 秒杀活动相关字段 ==========
 
     /**
-     *
+     * 秒杀活动编号
      */
-    @Schema(description = "秒杀活动编号", example = "1024")
     private Long seckillActivityId;
 
     // ========== 拼团活动相关字段 ==========
@@ -44,13 +44,11 @@ public class TradeBeforeOrderCreateReqBO {
     /**
      * 拼团活动编号
      */
-    @Schema(description = "拼团活动编号", example = "1024")
     private Long combinationActivityId;
 
     /**
      * 拼团团长编号
      */
-    @Schema(description = "拼团团长编号", example = "2048")
     private Long combinationHeadId;
 
     // ========== 砍价活动相关字段 ==========
@@ -58,31 +56,39 @@ public class TradeBeforeOrderCreateReqBO {
     /**
      * 砍价活动编号
      */
-    @Schema(description = "砍价活动编号", example = "123")
     private Long bargainActivityId;
 
-    // ========== 活动购买商品相关字段 ==========
+    // ========== 购买商品相关字段 ==========
 
     /**
-     * 商品 SPU 编号
-     *
-     * 关联 ProductSkuDO 的 spuId 编号
+     * 订单购买的商品信息
      */
-    @NotNull(message = "SPU 编号不能为空")
-    private Long spuId;
+    private List<Item> items;
 
     /**
-     * 商品 SKU 编号
+     * 订单商品信息
+     * 记录购买商品的简要核心信息
      *
-     * 关联 ProductSkuDO 的 id 编号
-     */
-    @NotNull(message = "SKU 编号活动商品不能为空")
-    private Long skuId;
-
-    /**
-     * 购买的商品数量
+     * @author HUIHUI
      */
-    @NotNull(message = "购买数量不能为空")
-    private Integer count;
+    @Data
+    @Valid
+    public static class Item {
+
+        /**
+         * 商品 SKU 编号
+         *
+         * 关联 ProductSkuDO 的 id 编号
+         */
+        @NotNull(message = "SKU 编号活动商品不能为空")
+        private Long skuId;
+
+        /**
+         * 购买的商品数量
+         */
+        @NotNull(message = "购买数量不能为空")
+        private Integer count;
+
+    }
 
 }

+ 5 - 13
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeBargainHandler.java

@@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.trade.service.order.handler;
 import cn.hutool.core.util.ObjectUtil;
 import cn.iocoder.yudao.module.promotion.api.bargain.BargainActivityApi;
 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
-import cn.iocoder.yudao.module.trade.service.order.bo.TradeAfterOrderCreateReqBO;
 import cn.iocoder.yudao.module.trade.service.order.bo.TradeBeforeOrderCreateReqBO;
 import org.springframework.stereotype.Component;
 
@@ -15,7 +14,7 @@ import javax.annotation.Resource;
  * @author HUIHUI
  */
 @Component
-public class TradeBargainHandler implements TradeOrderHandler {
+public class TradeBargainHandler extends TradeOrderDefaultHandler {
 
     @Resource
     private BargainActivityApi bargainActivityApi;
@@ -30,18 +29,11 @@ public class TradeBargainHandler implements TradeOrderHandler {
         if (ObjectUtil.notEqual(TradeOrderTypeEnum.BARGAIN.getType(), reqBO.getOrderType())) {
             return;
         }
-        // 扣减砍价活动的库存
-        bargainActivityApi.updateBargainActivityStock(reqBO.getBargainActivityId(), reqBO.getCount());
-    }
-
-    @Override
-    public void afterOrderCreate(TradeAfterOrderCreateReqBO reqBO) {
-
-    }
-
-    @Override
-    public void rollback() {
 
+        // 获取商品信息
+        TradeBeforeOrderCreateReqBO.Item item = reqBO.getItems().get(0);
+        // 扣减砍价活动的库存
+        bargainActivityApi.updateBargainActivityStock(reqBO.getBargainActivityId(), item.getCount());
     }
 
 }

+ 14 - 9
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeCombinationHandler.java

@@ -1,11 +1,11 @@
 package cn.iocoder.yudao.module.trade.service.order.handler;
 
 import cn.hutool.core.util.ObjectUtil;
-import cn.iocoder.yudao.module.promotion.api.combination.CombinationActivityApi;
 import cn.iocoder.yudao.module.promotion.api.combination.CombinationRecordApi;
 import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert;
 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
 import cn.iocoder.yudao.module.trade.service.order.bo.TradeAfterOrderCreateReqBO;
+import cn.iocoder.yudao.module.trade.service.order.bo.TradeAfterPayOrderReqBO;
 import cn.iocoder.yudao.module.trade.service.order.bo.TradeBeforeOrderCreateReqBO;
 import org.springframework.stereotype.Component;
 
@@ -17,28 +17,27 @@ import javax.annotation.Resource;
  * @author HUIHUI
  */
 @Component
-public class TradeCombinationHandler implements TradeOrderHandler {
+public class TradeCombinationHandler extends TradeOrderDefaultHandler {
 
-    @Resource
-    private CombinationActivityApi combinationActivityApi;
     @Resource
     private CombinationRecordApi combinationRecordApi;
 
     @Override
     public void beforeOrderCreate(TradeBeforeOrderCreateReqBO reqBO) {
-        // 如果是拼团订单;
+        // 如果不是拼团订单则结束
         if (ObjectUtil.notEqual(TradeOrderTypeEnum.COMBINATION.getType(), reqBO.getOrderType())) {
             return;
         }
 
+        // 获取商品信息
+        TradeBeforeOrderCreateReqBO.Item item = reqBO.getItems().get(0);
         // 校验是否满足拼团活动相关限制
-        combinationActivityApi.validateCombination(reqBO.getCombinationActivityId(), reqBO.getUserId(), reqBO.getSkuId(), reqBO.getCount());
+        combinationRecordApi.validateCombinationRecord(reqBO.getCombinationActivityId(), reqBO.getUserId(), item.getSkuId(), item.getCount());
     }
 
     @Override
     public void afterOrderCreate(TradeAfterOrderCreateReqBO reqBO) {
-        // TODO @puhui999:需要判断下;
-        if (true) {
+        if (reqBO.getCombinationActivityId() == null) {
             return;
         }
 
@@ -47,8 +46,14 @@ public class TradeCombinationHandler implements TradeOrderHandler {
     }
 
     @Override
-    public void rollback() {
+    public void afterPayOrder(TradeAfterPayOrderReqBO reqBO) {
+        // 如果不是拼团订单则结束
+        if (ObjectUtil.notEqual(TradeOrderTypeEnum.COMBINATION.getType(), reqBO.getOrderType())) {
+            return;
+        }
 
+        // 更新拼团状态 TODO puhui999:订单支付失败或订单支付过期删除这条拼团记录
+        combinationRecordApi.updateRecordStatusToInProgress(reqBO.getUserId(), reqBO.getOrderId(), reqBO.getPayTime());
     }
 
 }

+ 34 - 0
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeOrderDefaultHandler.java

@@ -0,0 +1,34 @@
+package cn.iocoder.yudao.module.trade.service.order.handler;
+
+import cn.iocoder.yudao.module.trade.service.order.bo.TradeAfterOrderCreateReqBO;
+import cn.iocoder.yudao.module.trade.service.order.bo.TradeAfterPayOrderReqBO;
+import cn.iocoder.yudao.module.trade.service.order.bo.TradeBeforeOrderCreateReqBO;
+
+/**
+ * 订单活动特殊逻辑处理器 handler 默认抽象实现类
+ *
+ * @author HUIHUI
+ */
+public abstract class TradeOrderDefaultHandler implements TradeOrderHandler {
+
+    @Override
+    public void beforeOrderCreate(TradeBeforeOrderCreateReqBO reqBO) {
+
+    }
+
+    @Override
+    public void afterOrderCreate(TradeAfterOrderCreateReqBO reqBO) {
+
+    }
+
+    @Override
+    public void afterPayOrder(TradeAfterPayOrderReqBO reqBO) {
+
+    }
+
+    @Override
+    public void cancelOrder() {
+
+    }
+
+}

+ 10 - 4
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeOrderHandler.java

@@ -1,10 +1,12 @@
 package cn.iocoder.yudao.module.trade.service.order.handler;
 
 import cn.iocoder.yudao.module.trade.service.order.bo.TradeAfterOrderCreateReqBO;
+import cn.iocoder.yudao.module.trade.service.order.bo.TradeAfterPayOrderReqBO;
 import cn.iocoder.yudao.module.trade.service.order.bo.TradeBeforeOrderCreateReqBO;
 
 /**
  * 订单活动特殊逻辑处理器 handler 接口
+ * 提供订单生命周期钩子接口;订单创建前、订单创建后、订单支付后、订单取消
  *
  * @author HUIHUI
  */
@@ -24,12 +26,16 @@ public interface TradeOrderHandler {
      */
     void afterOrderCreate(TradeAfterOrderCreateReqBO reqBO);
 
-    // TODO @puhui999:这个搞成订单取消
     /**
-     * 回滚
+     * 支付订单后
+     *
+     * @param reqBO 请求
      */
-    void rollback();
+    void afterPayOrder(TradeAfterPayOrderReqBO reqBO);
 
-    // TODO @puhui999:再搞个订单项取消哈
+    /**
+     * 订单取消
+     */
+    void cancelOrder();
 
 }

+ 5 - 13
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeSeckillHandler.java

@@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.trade.service.order.handler;
 import cn.hutool.core.util.ObjectUtil;
 import cn.iocoder.yudao.module.promotion.api.seckill.SeckillActivityApi;
 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
-import cn.iocoder.yudao.module.trade.service.order.bo.TradeAfterOrderCreateReqBO;
 import cn.iocoder.yudao.module.trade.service.order.bo.TradeBeforeOrderCreateReqBO;
 import org.springframework.stereotype.Component;
 
@@ -15,7 +14,7 @@ import javax.annotation.Resource;
  * @author HUIHUI
  */
 @Component
-public class TradeSeckillHandler implements TradeOrderHandler {
+public class TradeSeckillHandler extends TradeOrderDefaultHandler {
 
     @Resource
     private SeckillActivityApi seckillActivityApi;
@@ -30,18 +29,11 @@ public class TradeSeckillHandler implements TradeOrderHandler {
         if (ObjectUtil.notEqual(TradeOrderTypeEnum.SECKILL.getType(), reqBO.getOrderType())) {
             return;
         }
-        // 扣减秒杀活动的库存
-        seckillActivityApi.updateSeckillStock(reqBO.getSeckillActivityId(), reqBO.getSkuId(), reqBO.getCount());
-    }
-
-    @Override
-    public void afterOrderCreate(TradeAfterOrderCreateReqBO reqBO) {
-
-    }
-
-    @Override
-    public void rollback() {
 
+        // 获取商品信息
+        TradeBeforeOrderCreateReqBO.Item item = reqBO.getItems().get(0);
+        // 扣减秒杀活动的库存
+        seckillActivityApi.updateSeckillStock(reqBO.getSeckillActivityId(), item.getSkuId(), item.getCount());
     }
 
 }

+ 18 - 1
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/bo/TradePriceCalculateRespBO.java

@@ -98,9 +98,19 @@ public class TradePriceCalculateRespBO {
          * VIP 减免金额,单位:分
          */
         private Integer vipPrice;
+        /**
+         * 秒杀、拼团、砍价活动商品的总金额,单位:分
+         *
+         * 基于 {@link OrderItem#getActivityPrice()} ()} * {@link OrderItem#getCount()} 求和
+         */
+        private Integer activityPrice;
         /**
          * 最终购买金额(总),单位:分
          *
+         * ==========活动情况===========
+         * = {@link #activityPrice}
+         * + {@link #deliveryPrice}
+         * ==========正常情况===========
          * = {@link #totalPrice}
          * - {@link #couponPrice}
          * - {@link #pointPrice}
@@ -176,9 +186,16 @@ public class TradePriceCalculateRespBO {
          * VIP 减免金额,单位:分
          */
         private Integer vipPrice;
+        /**
+         * 秒杀、拼团、砍价活动商品的金额,单位:分
+         */
+        private Integer activityPrice;
         /**
          * 应付金额(总),单位:分
-         *
+         * ==========活动情况===========
+         * = {@link #activityPrice} * {@link #count}
+         * + {@link #deliveryPrice}
+         * ==========正常情况===========
          * = {@link #price} * {@link #count}
          * - {@link #couponPrice}
          * - {@link #pointPrice}

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

@@ -105,6 +105,9 @@ public class TradePriceCalculatorHelper {
             if (!item.getSelected()) {
                 return;
             }
+            // TODO puhui: 需要在这里计算活动的价格
+            // ========== 一、活动情况 ==========
+            // ========== 二、正常情况 ==========
             price.setTotalPrice(price.getTotalPrice() + item.getPrice() * item.getCount());
             price.setDiscountPrice(price.getDiscountPrice() + item.getDiscountPrice());
             price.setDeliveryPrice(price.getDeliveryPrice() + item.getDeliveryPrice());

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

@@ -0,0 +1,45 @@
+package cn.iocoder.yudao.module.trade.service.price.calculator;
+
+import cn.iocoder.yudao.module.promotion.api.seckill.SeckillActivityApi;
+import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillActivityProductRespDTO;
+import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO;
+import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO;
+import org.springframework.core.annotation.Order;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+import java.util.List;
+import java.util.Map;
+
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
+
+/**
+ * 秒杀活动的 {@link TradePriceCalculator} 实现类
+ *
+ * @author HUIHUI
+ */
+@Component
+@Order(TradePriceCalculator.ORDER_DISCOUNT_ACTIVITY)
+public class TradeSeckillActivityPriceCalculator implements TradePriceCalculator {
+
+    @Resource
+    private SeckillActivityApi activityApi;
+
+    @Override
+    public void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) {
+        // 1、判断订单类型和是否具有秒杀活动编号
+        if (param.getSeckillActivityId() == null) {
+            return;
+        }
+        // 2、获取秒杀活动商品信息
+        List<SeckillActivityProductRespDTO> productList = activityApi.getSeckillActivityProductList(param.getSeckillActivityId(), convertSet(param.getItems(),
+                TradePriceCalculateReqBO.Item::getSkuId));
+        Map<Long, SeckillActivityProductRespDTO> productMap = convertMap(productList, SeckillActivityProductRespDTO::getSkuId);
+        result.getItems().forEach(item -> {
+            SeckillActivityProductRespDTO product = productMap.get(item.getSkuId());
+            item.setActivityPrice(product.getSeckillPrice()); // 设置活动金额
+        });
+    }
+
+}