Bläddra i källkod

mall+order: 订单活动特殊逻辑的抽离

puhui999 1 år sedan
förälder
incheckning
254d7828aa
23 ändrade filer med 526 tillägg och 141 borttagningar
  1. 19 0
      yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/CombinationApi.java
  2. 40 0
      yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/dto/CombinationActivityUpdateStockReqDTO.java
  3. 8 49
      yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/dto/CombinationRecordCreateReqDTO.java
  4. 2 0
      yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/seckill/dto/SeckillActivityUpdateStockReqDTO.java
  5. 10 9
      yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java
  6. 5 0
      yudao-module-mall/yudao-module-promotion-biz/pom.xml
  7. 23 0
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/CombinationApiImpl.java
  8. 8 0
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationActivityService.java
  9. 38 4
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationActivityServiceImpl.java
  10. 26 4
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationRecordServiceImpl.java
  11. 11 0
      yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/api/order/TradeOrderApi.java
  12. 6 0
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/api/order/TradeOrderApiImpl.java
  13. 32 14
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java
  14. 1 1
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/order/TradeOrderItemMapper.java
  15. 9 0
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderQueryService.java
  16. 7 0
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderQueryServiceImpl.java
  17. 16 60
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java
  18. 39 0
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/bo/TradeAfterOrderCreateReqBO.java
  19. 57 0
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/bo/TradeBeforeOrderCreateReqBO.java
  20. 44 0
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeBargainHandler.java
  21. 49 0
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeCombinationHandler.java
  22. 32 0
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeOrderHandler.java
  23. 44 0
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeSeckillHandler.java

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

@@ -0,0 +1,19 @@
+package cn.iocoder.yudao.module.promotion.api.combination;
+
+import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationActivityUpdateStockReqDTO;
+
+/**
+ * 拼团活动 Api 接口
+ *
+ * @author HUIHUI
+ */
+public interface CombinationApi {
+
+    /**
+     * 更新活动库存
+     *
+     * @param reqDTO 请求
+     */
+    void validateCombination(CombinationActivityUpdateStockReqDTO reqDTO);
+
+}

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

@@ -0,0 +1,40 @@
+package cn.iocoder.yudao.module.promotion.api.combination.dto;
+
+import lombok.Data;
+
+import javax.validation.Valid;
+import javax.validation.constraints.NotNull;
+
+/**
+ * 拼团活动更新活动库存 Request DTO
+ *
+ * @author HUIHUI
+ */
+@Data
+public class CombinationActivityUpdateStockReqDTO {
+
+    @NotNull(message = "活动编号不能为空")
+    private Long activityId;
+
+    @NotNull(message = "购买数量不能为空")
+    private Integer count;
+
+    @NotNull(message = "活动商品不能为空")
+    private Item item;
+
+    @Data
+    @Valid
+    public static class Item {
+
+        @NotNull(message = "SPU 编号不能为空")
+        private Long spuId;
+
+        @NotNull(message = "SKU 编号活动商品不能为空")
+        private Long skuId;
+
+        @NotNull(message = "购买数量不能为空")
+        private Integer count;
+
+    }
+
+}

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

@@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.promotion.api.combination.dto;
 
 import lombok.Data;
 
-import javax.validation.constraints.NotEmpty;
 import javax.validation.constraints.NotNull;
 
 // TODO @芋艿:这块要在看看
@@ -14,65 +13,25 @@ import javax.validation.constraints.NotNull;
 @Data
 public class CombinationRecordCreateReqDTO {
 
-    /**
-     * 拼团活动编号
-     */
     @NotNull(message = "拼团活动编号不能为空")
     private Long activityId;
-    /**
-     * spu 编号
-     */
+
     @NotNull(message = "spu 编号不能为空")
     private Long spuId;
-    /**
-     * sku 编号
-     */
+
     @NotNull(message = "sku 编号不能为空")
     private Long skuId;
-    /**
-     * 用户编号
-     */
-    @NotNull(message = "用户编号不能为空")
-    private Long userId;
-    /**
-     * 订单编号
-     */
+
     @NotNull(message = "订单编号不能为空")
     private Long orderId;
-    /**
-     * 团长编号
-     */
+
+    @NotNull(message = "用户编号不能为空")
+    private Long userId;
+
     @NotNull(message = "团长编号不能为空")
     private Long headId;
-    /**
-     * 商品名字
-     */
-    @NotEmpty(message = "商品名字不能为空")
-    private String spuName;
-    /**
-     * 商品图片
-     */
-    @NotEmpty(message = "商品图片不能为空")
-    private String picUrl;
-    /**
-     * 拼团商品单价
-     */
+
     @NotNull(message = "拼团商品单价不能为空")
     private Integer combinationPrice;
-    /**
-     * 用户昵称
-     */
-    @NotEmpty(message = "用户昵称不能为空")
-    private String nickname;
-    /**
-     * 用户头像
-     */
-    @NotEmpty(message = "用户头像不能为空")
-    private String avatar;
-    /**
-     * 开团状态:正在开团 拼团成功 拼团失败
-     */
-    @NotNull(message = "开团状态不能为空")
-    private Integer status;
 
 }

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

@@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.promotion.api.seckill.dto;
 
 import lombok.Data;
 
+import javax.validation.Valid;
 import javax.validation.constraints.NotNull;
 
 /**
@@ -22,6 +23,7 @@ public class SeckillActivityUpdateStockReqDTO {
     private Item item;
 
     @Data
+    @Valid
     public static class Item {
 
         @NotNull(message = "SPU 编号不能为空")

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

@@ -65,18 +65,19 @@ public interface ErrorCodeConstants {
     // ========== 拼团活动 1013010000 ==========
     ErrorCode COMBINATION_ACTIVITY_NOT_EXISTS = new ErrorCode(1013010000, "拼团活动不存在");
     ErrorCode COMBINATION_ACTIVITY_SPU_CONFLICTS = new ErrorCode(1013010001, "存在商品参加了其它拼团活动");
-    ErrorCode COMBINATION_ACTIVITY_STATUS_DISABLE = new ErrorCode(1013010002, "拼团活动已关闭不能修改");
+    ErrorCode COMBINATION_ACTIVITY_STATUS_DISABLE_NOT_UPDATE = new ErrorCode(1013010002, "拼团活动已关闭不能修改");
     ErrorCode COMBINATION_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END = new ErrorCode(1013010003, "拼团活动未关闭或未结束,不能删除");
-    ErrorCode COMBINATION_RECORD_NOT_EXISTS = new ErrorCode(1013010004, "拼团不存在");
+    ErrorCode COMBINATION_ACTIVITY_STATUS_DISABLE = new ErrorCode(1013010004, "拼团失败,原因:拼团活动已关闭");
 
     // ========== 拼团记录 1013011000 ==========
-    ErrorCode COMBINATION_RECORD_EXISTS = new ErrorCode(1013011000, "拼团失败,已参与过该拼团");
-    ErrorCode COMBINATION_RECORD_HEAD_NOT_EXISTS = new ErrorCode(1013011001, "拼团失败,父拼团不存在");
-    ErrorCode COMBINATION_RECORD_USER_FULL = new ErrorCode(1013011002, "拼团失败,拼团人数已满");
-    ErrorCode COMBINATION_RECORD_FAILED_HAVE_JOINED = new ErrorCode(1013011003, "拼团失败,已参与其它拼团");
-    ErrorCode COMBINATION_RECORD_FAILED_TIME_END = new ErrorCode(1013011004, "拼团失败,活动已经结束");
-    ErrorCode COMBINATION_RECORD_FAILED_SINGLE_LIMIT_COUNT_EXCEED = new ErrorCode(1013011005, "拼团失败,单次限购超出");
-    ErrorCode COMBINATION_RECORD_FAILED_TOTAL_LIMIT_COUNT_EXCEED = new ErrorCode(1013011006, "拼团失败,单次限购超出");
+    ErrorCode COMBINATION_RECORD_NOT_EXISTS = new ErrorCode(1013011000, "拼团不存在");
+    ErrorCode COMBINATION_RECORD_EXISTS = new ErrorCode(1013011001, "拼团失败,已参与过该拼团");
+    ErrorCode COMBINATION_RECORD_HEAD_NOT_EXISTS = new ErrorCode(1013011002, "拼团失败,父拼团不存在");
+    ErrorCode COMBINATION_RECORD_USER_FULL = new ErrorCode(1013011003, "拼团失败,拼团人数已满");
+    ErrorCode COMBINATION_RECORD_FAILED_HAVE_JOINED = new ErrorCode(1013011004, "拼团失败,已参与其它拼团");
+    ErrorCode COMBINATION_RECORD_FAILED_TIME_END = new ErrorCode(1013011005, "拼团失败,活动已经结束");
+    ErrorCode COMBINATION_RECORD_FAILED_SINGLE_LIMIT_COUNT_EXCEED = new ErrorCode(1013011006, "拼团失败,原因:单次限购超出");
+    ErrorCode COMBINATION_RECORD_FAILED_TOTAL_LIMIT_COUNT_EXCEED = new ErrorCode(1013011007, "拼团失败,原因:超出总购买次数");
 
     // ========== 砍价活动 1013012000 ==========
     ErrorCode BARGAIN_ACTIVITY_NOT_EXISTS = new ErrorCode(1013012000, "砍价活动不存在");

+ 5 - 0
yudao-module-mall/yudao-module-promotion-biz/pom.xml

@@ -31,6 +31,11 @@
         </dependency>
         <dependency>
             <groupId>cn.iocoder.boot</groupId>
+            <artifactId>yudao-module-trade-api</artifactId>
+            <version>${revision}</version>
+        </dependency>
+        <dependency>
+            <groupId>cn.iocoder.boot</groupId>
             <artifactId>yudao-module-member-api</artifactId>
             <version>${revision}</version>
         </dependency>

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

@@ -0,0 +1,23 @@
+package cn.iocoder.yudao.module.promotion.api.combination;
+
+import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationActivityUpdateStockReqDTO;
+import cn.iocoder.yudao.module.promotion.service.combination.CombinationActivityService;
+
+import javax.annotation.Resource;
+
+/**
+ * 拼团活动 Api 接口实现类
+ *
+ * @author HUIHUI
+ */
+public class CombinationApiImpl implements CombinationApi {
+
+    @Resource
+    private CombinationActivityService activityService;
+
+    @Override
+    public void validateCombination(CombinationActivityUpdateStockReqDTO reqDTO) {
+        activityService.validateCombination(reqDTO);
+    }
+
+}

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

@@ -1,6 +1,7 @@
 package cn.iocoder.yudao.module.promotion.service.combination;
 
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationActivityUpdateStockReqDTO;
 import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityCreateReqVO;
 import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityPageReqVO;
 import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityUpdateReqVO;
@@ -72,4 +73,11 @@ public interface CombinationActivityService {
      */
     List<CombinationProductDO> getCombinationProductsByActivityIds(Collection<Long> activityIds);
 
+    /**
+     * 更新拼图活动库存
+     *
+     * @param reqDTO 请求
+     */
+    void validateCombination(CombinationActivityUpdateStockReqDTO reqDTO);
+
 }

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

@@ -9,6 +9,7 @@ import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
 import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
 import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
+import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationActivityUpdateStockReqDTO;
 import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityCreateReqVO;
 import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityPageReqVO;
 import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityUpdateReqVO;
@@ -16,8 +17,11 @@ 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.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.validation.annotation.Validated;
@@ -28,8 +32,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.convertMap;
-import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
+import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
 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.*;
@@ -48,11 +52,15 @@ public class CombinationActivityServiceImpl implements CombinationActivityServic
     private CombinationActivityMapper combinationActivityMapper;
     @Resource
     private CombinationProductMapper combinationProductMapper;
+    @Resource
+    private CombinationRecordService combinationRecordService;
 
     @Resource
     private ProductSpuApi productSpuApi;
     @Resource
     private ProductSkuApi productSkuApi;
+    @Resource
+    private TradeOrderApi tradeOrderApi;
 
     @Override
     @Transactional(rollbackFor = Exception.class)
@@ -97,7 +105,7 @@ public class CombinationActivityServiceImpl implements CombinationActivityServic
      * 校验拼团商品是否都存在
      *
      * @param spuId 商品 SPU 编号
-     * @param products 秒杀商品
+     * @param products 拼团商品
      */
     private void validateProductExists(Long spuId, List<CombinationProductBaseVO> products) {
         // 1. 校验商品 spu 是否存在
@@ -123,7 +131,7 @@ public class CombinationActivityServiceImpl implements CombinationActivityServic
         CombinationActivityDO activityDO = validateCombinationActivityExists(updateReqVO.getId());
         // 校验状态
         if (ObjectUtil.equal(activityDO.getStatus(), CommonStatusEnum.DISABLE.getStatus())) {
-            throw exception(COMBINATION_ACTIVITY_STATUS_DISABLE);
+            throw exception(COMBINATION_ACTIVITY_STATUS_DISABLE_NOT_UPDATE);
         }
         // 校验商品冲突
         validateProductConflict(updateReqVO.getSpuId(), updateReqVO.getId());
@@ -205,4 +213,30 @@ public class CombinationActivityServiceImpl implements CombinationActivityServic
         return combinationProductMapper.selectListByActivityIds(activityIds);
     }
 
+    @Override
+    public void validateCombination(CombinationActivityUpdateStockReqDTO reqDTO) {
+        // 1、校验拼团活动是否存在
+        CombinationActivityDO activity = validateCombinationActivityExists(reqDTO.getActivityId());
+        // 1.1、校验活动是否开启
+        if (ObjectUtil.equal(activity.getStatus(), CommonStatusEnum.DISABLE.getStatus())) {
+            throw exception(COMBINATION_ACTIVITY_STATUS_DISABLE);
+        }
+        // 1.2、校验是否超出单次限购数量
+        if (activity.getSingleLimitCount() < reqDTO.getCount()) {
+            throw exception(COMBINATION_RECORD_FAILED_SINGLE_LIMIT_COUNT_EXCEED);
+        }
+        // 1.3、校验是否超出总限购数量
+        List<CombinationRecordDO> recordList = combinationRecordService.getRecordListByUserIdAndActivityId(getLoginUserId(), reqDTO.getActivityId());
+        if (CollUtil.isNotEmpty(recordList)) {
+            // 过滤出拼团成功的
+            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);
+            }
+        }
+    }
+
 }

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

@@ -2,12 +2,19 @@ package cn.iocoder.yudao.module.promotion.service.combination;
 
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.util.ObjectUtil;
+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;
+import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
+import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
+import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
 import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO;
 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.CombinationRecordDO;
 import cn.iocoder.yudao.module.promotion.dal.mysql.combination.CombinationRecordMapper;
 import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum;
+import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.validation.annotation.Validated;
@@ -32,10 +39,18 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
 
     @Resource
     private CombinationActivityService combinationActivityService;
-
     @Resource
     private CombinationRecordMapper recordMapper;
 
+    @Resource
+    private MemberUserApi memberUserApi;
+    @Resource
+    @Lazy
+    private ProductSpuApi productSpuApi;
+    @Resource
+    @Lazy
+    private ProductSkuApi productSkuApi;
+
     @Override
     @Transactional(rollbackFor = Exception.class)
     public void updateCombinationRecordStatusByUserIdAndOrderId(Integer status, Long userId, Long orderId) {
@@ -102,12 +117,12 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
         // 1.5 父拼团是否存在,是否已经满了
         if (reqDTO.getHeadId() != null) {
             // 查询进行中的父拼团
-            CombinationRecordDO recordDO1 = recordMapper.selectOneByHeadId(reqDTO.getHeadId(), CombinationRecordStatusEnum.IN_PROGRESS.getStatus());
-            if (recordDO1 == null) {
+            CombinationRecordDO record = recordMapper.selectOneByHeadId(reqDTO.getHeadId(), CombinationRecordStatusEnum.IN_PROGRESS.getStatus());
+            if (record == null) {
                 throw exception(COMBINATION_RECORD_HEAD_NOT_EXISTS);
             }
             // 校验拼团是否满足要求
-            if (ObjectUtil.equal(recordDO1.getUserCount(), recordDO1.getUserSize())) {
+            if (ObjectUtil.equal(record.getUserCount(), record.getUserSize())) {
                 throw exception(COMBINATION_RECORD_USER_FULL);
             }
         }
@@ -117,6 +132,13 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
         record.setVirtualGroup(false);
         record.setExpireTime(record.getStartTime().plusHours(activity.getLimitDuration()));
         record.setUserSize(activity.getUserSize());
+        MemberUserRespDTO user = memberUserApi.getUser(reqDTO.getUserId());
+        record.setNickname(user.getNickname());
+        record.setAvatar(user.getAvatar());
+        ProductSpuRespDTO spu = productSpuApi.getSpu(record.getSpuId());
+        record.setSpuName(spu.getName());
+        ProductSkuRespDTO sku = productSkuApi.getSku(record.getSkuId());
+        record.setPicUrl(sku.getPicUrl());
         recordMapper.insert(record);
     }
 

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

@@ -1,5 +1,7 @@
 package cn.iocoder.yudao.module.trade.api.order;
 
+import java.util.Collection;
+
 /**
  * 订单 API 接口
  *
@@ -16,4 +18,13 @@ public interface TradeOrderApi {
      */
     Long validateOrder(Long userId, Long orderItemId);
 
+    /**
+     * 获取订单项商品购买数量总和
+     *
+     * @param orderIds 订单编号
+     * @param skuIds   sku 编号
+     * @return 订单项商品购买数量总和
+     */
+    Integer getOrderItemCountSumByOrderIdAndSkuId(Collection<Long> orderIds, Collection<Long> skuIds);
+
 }

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

@@ -6,6 +6,7 @@ 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;
@@ -32,4 +33,9 @@ public class TradeOrderApiImpl implements TradeOrderApi {
         return item.getOrderId();
     }
 
+    @Override
+    public Integer getOrderItemCountSumByOrderIdAndSkuId(Collection<Long> orderIds, Collection<Long> skuIds) {
+        return tradeOrderQueryService.getOrderItemCountSumByOrderIdAndSkuId(orderIds, skuIds);
+    }
+
 }

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

@@ -14,7 +14,9 @@ import cn.iocoder.yudao.module.product.api.comment.dto.ProductCommentCreateReqDT
 import cn.iocoder.yudao.module.product.api.property.dto.ProductPropertyValueDetailRespDTO;
 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO;
+import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationActivityUpdateStockReqDTO;
 import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO;
+import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillActivityUpdateStockReqDTO;
 import cn.iocoder.yudao.module.trade.api.order.dto.TradeOrderRespDTO;
 import cn.iocoder.yudao.module.trade.controller.admin.base.member.user.MemberUserRespVO;
 import cn.iocoder.yudao.module.trade.controller.admin.base.product.property.ProductPropertyValueDetailRespVO;
@@ -31,6 +33,8 @@ import cn.iocoder.yudao.module.trade.enums.order.TradeOrderItemAfterSaleStatusEn
 import cn.iocoder.yudao.module.trade.framework.delivery.core.client.dto.ExpressTrackRespDTO;
 import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties;
 import cn.iocoder.yudao.module.trade.service.brokerage.bo.BrokerageAddReqBO;
+import cn.iocoder.yudao.module.trade.service.order.bo.TradeAfterOrderCreateReqBO;
+import cn.iocoder.yudao.module.trade.service.order.bo.TradeBeforeOrderCreateReqBO;
 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO;
 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO;
 import org.mapstruct.Mapper;
@@ -253,21 +257,15 @@ public interface TradeOrderConvert {
     AppTradeOrderSettlementRespVO convert0(TradePriceCalculateRespBO calculate, AddressRespDTO address);
 
     @Mappings({
-            @Mapping(target = "activityId", source = "createReqVO.combinationActivityId"),
-            @Mapping(target = "spuId", source = "orderItem.spuId"),
-            @Mapping(target = "skuId", source = "orderItem.skuId"),
-            @Mapping(target = "userId", source = "order.userId"),
-            @Mapping(target = "orderId", source = "order.id"),
-            @Mapping(target = "headId", source = "createReqVO.combinationHeadId"),
-            @Mapping(target = "spuName", source = "orderItem.spuName"),
-            @Mapping(target = "picUrl", source = "orderItem.picUrl"),
-            @Mapping(target = "combinationPrice", source = "orderItem.payPrice"),
-            @Mapping(target = "nickname", source = "user.nickname"),
-            @Mapping(target = "avatar", source = "user.avatar"),
-            @Mapping(target = "status", ignore = true)
+            @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(TradeOrderDO order, TradeOrderItemDO orderItem,
-                                          AppTradeOrderCreateReqVO createReqVO, MemberUserRespDTO user);
+    CombinationRecordCreateReqDTO convert(TradeAfterOrderCreateReqBO afterOrderCreateReqBO);
 
     List<AppOrderExpressTrackRespDTO> convertList02(List<ExpressTrackRespDTO> list);
 
@@ -283,4 +281,24 @@ public interface TradeOrderConvert {
                 .setFirstFixedPrice(sku.getFirstBrokerageRecord())
                 .setSecondFixedPrice(sku.getSecondBrokerageRecord());
     }
+
+    @Mapping(target = "activityId", source = "reqBO.seckillActivityId")
+    SeckillActivityUpdateStockReqDTO convert(TradeBeforeOrderCreateReqBO reqBO);
+
+    @Mapping(target = "activityId", source = "reqBO.combinationActivityId")
+    CombinationActivityUpdateStockReqDTO convert1(TradeBeforeOrderCreateReqBO reqBO);
+
+    TradeBeforeOrderCreateReqBO convert(AppTradeOrderCreateReqVO createReqVO);
+
+    @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 = "payPrice", source = "tradeOrderDO.payPrice"),
+    })
+    TradeAfterOrderCreateReqBO convert(Long userId, AppTradeOrderCreateReqVO createReqVO, TradeOrderDO tradeOrderDO, TradeOrderItemDO orderItem);
+
 }

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

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

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

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

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

@@ -4,6 +4,7 @@ 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;
@@ -167,4 +168,10 @@ 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);
+    }
+
 }

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

@@ -13,8 +13,6 @@ import cn.iocoder.yudao.module.member.api.address.AddressApi;
 import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO;
 import cn.iocoder.yudao.module.member.api.level.MemberLevelApi;
 import cn.iocoder.yudao.module.member.api.point.MemberPointApi;
-import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
-import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
 import cn.iocoder.yudao.module.member.enums.MemberExperienceBizTypeEnum;
 import cn.iocoder.yudao.module.member.enums.point.MemberPointBizTypeEnum;
 import cn.iocoder.yudao.module.pay.api.order.PayOrderApi;
@@ -24,15 +22,10 @@ import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum;
 import cn.iocoder.yudao.module.product.api.comment.ProductCommentApi;
 import cn.iocoder.yudao.module.product.api.comment.dto.ProductCommentCreateReqDTO;
 import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
-import cn.iocoder.yudao.module.promotion.api.bargain.BargainActivityApi;
 import cn.iocoder.yudao.module.promotion.api.bargain.BargainRecordApi;
 import cn.iocoder.yudao.module.promotion.api.combination.CombinationRecordApi;
-import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordRespDTO;
 import cn.iocoder.yudao.module.promotion.api.coupon.CouponApi;
 import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponUseReqDTO;
-import cn.iocoder.yudao.module.promotion.api.seckill.SeckillActivityApi;
-import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillActivityUpdateStockReqDTO;
-import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum;
 import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderDeliveryReqVO;
 import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderRemarkReqVO;
 import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderUpdateAddressReqVO;
@@ -59,6 +52,8 @@ 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.handler.TradeOrderHandler;
 import cn.iocoder.yudao.module.trade.service.price.TradePriceService;
 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO;
 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO;
@@ -95,6 +90,8 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
     private TradeOrderItemMapper tradeOrderItemMapper;
     @Resource
     private TradeOrderNoRedisDAO orderNoRedisDAO;
+    @Resource
+    private List<TradeOrderHandler> orderHandlers;
 
     @Resource
     private CartService cartService;
@@ -118,12 +115,6 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
     @Resource
     private BargainRecordApi bargainRecordApi;
     @Resource
-    private SeckillActivityApi seckillActivityApi;
-    @Resource
-    private BargainActivityApi bargainActivityApi;
-    @Resource
-    private MemberUserApi memberUserApi;
-    @Resource
     private MemberLevelApi memberLevelApi;
     @Resource
     private MemberPointApi memberPointApi;
@@ -188,7 +179,13 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
     @Override
     @Transactional(rollbackFor = Exception.class)
     public TradeOrderDO createOrder(Long userId, String userIp, AppTradeOrderCreateReqVO createReqVO) {
-        // 1. 价格计算
+        // 1、执行订单创建前置处理器
+        TradeBeforeOrderCreateReqBO beforeOrderCreateReqBO = TradeOrderConvert.INSTANCE.convert(createReqVO);
+        beforeOrderCreateReqBO.setOrderType(validateActivity(createReqVO));
+        beforeOrderCreateReqBO.setCount(CollectionUtils.getSumValue(createReqVO.getItems(), AppTradeOrderSettlementReqVO.Item::getCount, Integer::sum));
+        orderHandlers.forEach(handler -> handler.beforeOrderCreate(beforeOrderCreateReqBO));
+
+        // 2. 价格计算
         TradePriceCalculateRespBO calculateRespBO = calculatePrice(userId, createReqVO);
 
         // 2.1 插入 TradeOrderDO 订单
@@ -198,37 +195,11 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
 
         // 3. 订单创建完后的逻辑
         afterCreateTradeOrder(userId, createReqVO, order, orderItems, calculateRespBO);
-        // 3.1 拼团的特殊逻辑
-        // TODO @puhui999:这个逻辑,先抽个小方法;未来要通过设计模式,把这些拼团之类的逻辑,抽象出去
-        // 拼团
-        if (Objects.equals(TradeOrderTypeEnum.COMBINATION.getType(), order.getType())) {
-            createCombinationRecord(userId, createReqVO, orderItems, order);
-        }
-        // 3.2 秒杀的特殊逻辑
-        if (Objects.equals(TradeOrderTypeEnum.SECKILL.getType(), order.getType())) {
-
-        }
-        // 3.3 砍价的特殊逻辑
 
         // TODO @LeeYan9: 是可以思考下, 订单的营销优惠记录, 应该记录在哪里, 微信讨论起来!
         return order;
     }
 
-    private void createCombinationRecord(Long userId, AppTradeOrderCreateReqVO createReqVO, List<TradeOrderItemDO> orderItems, TradeOrderDO order) {
-        MemberUserRespDTO user = memberUserApi.getUser(userId);
-        List<CombinationRecordRespDTO> recordRespDTOS = combinationRecordApi.getRecordListByUserIdAndActivityId(userId, createReqVO.getCombinationActivityId());
-        // TODO 拼团一次应该只能选择一种规格的商品
-        TradeOrderItemDO orderItemDO = orderItems.get(0);
-        if (CollUtil.isNotEmpty(recordRespDTOS)) {
-            List<Long> skuIds = convertList(recordRespDTOS, CombinationRecordRespDTO::getSkuId, item -> ObjectUtil.equals(item.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus()));
-            List<TradeOrderItemDO> tradeOrderItemDOS = tradeOrderItemMapper.selectListByOrderIdAnSkuId(convertList(recordRespDTOS,
-                    CombinationRecordRespDTO::getOrderId, item -> ObjectUtil.equals(item.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus())), skuIds);
-            combinationRecordApi.validateCombinationLimitCount(createReqVO.getCombinationActivityId(),
-                    CollectionUtils.getSumValue(tradeOrderItemDOS, TradeOrderItemDO::getCount, Integer::sum), orderItemDO.getCount());
-        }
-
-        combinationRecordApi.createCombinationRecord(TradeOrderConvert.INSTANCE.convert(order, orderItemDO, createReqVO, user));
-    }
 
     // TODO @puhui999:订单超时,自动取消;
 
@@ -310,13 +281,8 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
     private void afterCreateTradeOrder(Long userId, AppTradeOrderCreateReqVO createReqVO,
                                        TradeOrderDO tradeOrderDO, List<TradeOrderItemDO> orderItems,
                                        TradePriceCalculateRespBO calculateRespBO) {
-        Integer count = getSumValue(orderItems, TradeOrderItemDO::getCount, Integer::sum);
-        // 1)如果是秒杀商品:额外扣减秒杀的库存;
-        if (Objects.equals(TradeOrderTypeEnum.SECKILL.getType(), tradeOrderDO.getType())) {
-            seckillActivityApi.updateSeckillStock(getSeckillActivityUpdateStockReqDTO(createReqVO, orderItems, count));
-        }
-        // 2)如果是砍价活动:额外扣减砍价的库存;
-        bargainActivityApi.updateBargainActivityStock(createReqVO.getBargainActivityId(), count);
+        // 执行订单创建后置处理器
+        orderHandlers.forEach(handler -> handler.afterOrderCreate(TradeOrderConvert.INSTANCE.convert(userId, createReqVO, tradeOrderDO, orderItems.get(0))));
         // 扣减积分 TODO 芋艿:待实现,需要前置;
         // 这个是不是应该放到支付成功之后?如果支付后的话,可能积分可以重复使用哈。资源类,都要预扣
 
@@ -341,19 +307,6 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
         // 增加订单日志 TODO 芋艿:待实现
     }
 
-    private SeckillActivityUpdateStockReqDTO getSeckillActivityUpdateStockReqDTO(AppTradeOrderCreateReqVO createReqVO, List<TradeOrderItemDO> orderItems, Integer count) {
-        SeckillActivityUpdateStockReqDTO updateStockReqDTO = new SeckillActivityUpdateStockReqDTO();
-        updateStockReqDTO.setActivityId(createReqVO.getSeckillActivityId());
-        updateStockReqDTO.setCount(count);
-        // 秒杀活动只能选择一个商品
-        TradeOrderItemDO item = orderItems.get(0);
-        SeckillActivityUpdateStockReqDTO.Item item1 = new SeckillActivityUpdateStockReqDTO.Item();
-        item1.setSpuId(item.getSpuId());
-        item1.setSkuId(item.getSkuId());
-        item1.setCount(item.getCount());
-        updateStockReqDTO.setItem(item1);
-        return updateStockReqDTO;
-    }
 
     private void createPayOrder(TradeOrderDO order, List<TradeOrderItemDO> orderItems, TradePriceCalculateRespBO calculateRespBO) {
         // 创建支付单,用于后续的支付
@@ -768,6 +721,9 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
             throw exception(ORDER_CANCEL_FAIL_STATUS_NOT_UNPAID);
         }
 
+        // TODO 活动相关库存回滚需要活动 id,活动 id 怎么获取?app 端能否传过来
+        orderHandlers.forEach(handler -> handler.rollbackStock());
+
         // 2.回滚库存
         List<TradeOrderItemDO> orderItems = tradeOrderItemMapper.selectListByOrderId(id);
         productSkuApi.updateSkuStock(TradeOrderConvert.INSTANCE.convert(orderItems));

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

@@ -0,0 +1,39 @@
+package cn.iocoder.yudao.module.trade.service.order.bo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+
+/**
+ * 订单创建之后 Request BO
+ *
+ * @author HUIHUI
+ */
+@Data
+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;
+
+}

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

@@ -0,0 +1,57 @@
+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;
+
+/**
+ * 订单创建之前 Request BO
+ *
+ * @author HUIHUI
+ */
+@Data
+public class TradeBeforeOrderCreateReqBO {
+
+    @NotNull(message = "订单类型不能为空")
+    private Integer orderType;
+
+    // ========== 秒杀活动相关字段 ==========
+
+    @Schema(description = "秒杀活动编号", example = "1024")
+    private Long seckillActivityId;
+
+    // ========== 拼团活动相关字段 ==========
+
+    @Schema(description = "拼团活动编号", example = "1024")
+    private Long combinationActivityId;
+
+    @Schema(description = "拼团团长编号", example = "2048")
+    private Long combinationHeadId;
+
+    @Schema(description = "砍价活动编号", example = "123")
+    private Long bargainActivityId;
+
+    @NotNull(message = "购买数量不能为空")
+    private Integer count;
+
+    @NotNull(message = "活动商品不能为空")
+    private Item item;
+
+    @Data
+    @Valid
+    public static class Item {
+
+        @NotNull(message = "SPU 编号不能为空")
+        private Long spuId;
+
+        @NotNull(message = "SKU 编号活动商品不能为空")
+        private Long skuId;
+
+        @NotNull(message = "购买数量不能为空")
+        private Integer count;
+
+    }
+
+}

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

@@ -0,0 +1,44 @@
+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;
+
+import javax.annotation.Resource;
+
+/**
+ * 砍价订单 handler 实现类
+ *
+ * @author HUIHUI
+ */
+@Component
+public class TradeBargainHandler implements TradeOrderHandler {
+
+    @Resource
+    private BargainActivityApi bargainActivityApi;
+
+    @Override
+    public void beforeOrderCreate(TradeBeforeOrderCreateReqBO reqBO) {
+        // 如果是秒杀订单
+        if (ObjectUtil.notEqual(TradeOrderTypeEnum.BARGAIN.getType(), reqBO.getOrderType())) {
+            return;
+        }
+
+        // 额外扣减砍价的库存
+        bargainActivityApi.updateBargainActivityStock(reqBO.getBargainActivityId(), reqBO.getCount());
+    }
+
+    @Override
+    public void afterOrderCreate(TradeAfterOrderCreateReqBO reqBO) {
+
+    }
+
+    @Override
+    public void rollbackStock() {
+
+    }
+
+}

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

@@ -0,0 +1,49 @@
+package cn.iocoder.yudao.module.trade.service.order.handler;
+
+import cn.hutool.core.util.ObjectUtil;
+import cn.iocoder.yudao.module.promotion.api.combination.CombinationApi;
+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.TradeBeforeOrderCreateReqBO;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+
+/**
+ * 拼团订单 handler 接口实现类
+ *
+ * @author HUIHUI
+ */
+@Component
+public class TradeCombinationHandler implements TradeOrderHandler {
+
+    @Resource
+    private CombinationApi combinationApi;
+    @Resource
+    private CombinationRecordApi combinationRecordApi;
+
+    @Override
+    public void beforeOrderCreate(TradeBeforeOrderCreateReqBO reqBO) {
+        // 如果是拼团订单;
+        if (ObjectUtil.notEqual(TradeOrderTypeEnum.COMBINATION.getType(), reqBO.getOrderType())) {
+            return;
+        }
+
+        // 校验是否满足拼团活动相关限制
+        combinationApi.validateCombination(TradeOrderConvert.INSTANCE.convert1(reqBO));
+    }
+
+    @Override
+    public void afterOrderCreate(TradeAfterOrderCreateReqBO reqBO) {
+        // 创建砍价记录
+        combinationRecordApi.createCombinationRecord(TradeOrderConvert.INSTANCE.convert(reqBO));
+    }
+
+    @Override
+    public void rollbackStock() {
+
+    }
+
+}

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

@@ -0,0 +1,32 @@
+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.TradeBeforeOrderCreateReqBO;
+
+/**
+ * 订单活动特殊逻辑处理器 handler 接口
+ *
+ * @author HUIHUI
+ */
+public interface TradeOrderHandler {
+
+    /**
+     * 订单创建前
+     *
+     * @param reqBO 请求
+     */
+    void beforeOrderCreate(TradeBeforeOrderCreateReqBO reqBO);
+
+    /**
+     * 订单创建后
+     *
+     * @param reqBO 请求
+     */
+    void afterOrderCreate(TradeAfterOrderCreateReqBO reqBO);
+
+    /**
+     * 回滚活动相关库存
+     */
+    void rollbackStock();
+
+}

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

@@ -0,0 +1,44 @@
+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.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.TradeBeforeOrderCreateReqBO;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+
+/**
+ * 秒杀订单 handler 实现类
+ *
+ * @author HUIHUI
+ */
+@Component
+public class TradeSeckillHandler implements TradeOrderHandler {
+
+    @Resource
+    private SeckillActivityApi seckillActivityApi;
+
+    @Override
+    public void beforeOrderCreate(TradeBeforeOrderCreateReqBO reqBO) {
+        // 如果是秒杀订单:额外扣减秒杀的库存;
+        if (ObjectUtil.notEqual(TradeOrderTypeEnum.SECKILL.getType(), reqBO.getOrderType())) {
+            return;
+        }
+
+        seckillActivityApi.updateSeckillStock(TradeOrderConvert.INSTANCE.convert(reqBO));
+    }
+
+    @Override
+    public void afterOrderCreate(TradeAfterOrderCreateReqBO reqBO) {
+
+    }
+
+    @Override
+    public void rollbackStock() {
+
+    }
+
+}