Commit 254d7828aa3f4abd927dd7330ddc730af6346b31

Authored by puhui999
1 parent 7fb45509

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

Showing 23 changed files with 526 additions and 141 deletions
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/CombinationApi.java 0 → 100644
  1 +package cn.iocoder.yudao.module.promotion.api.combination;
  2 +
  3 +import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationActivityUpdateStockReqDTO;
  4 +
  5 +/**
  6 + * 拼团活动 Api 接口
  7 + *
  8 + * @author HUIHUI
  9 + */
  10 +public interface CombinationApi {
  11 +
  12 + /**
  13 + * 更新活动库存
  14 + *
  15 + * @param reqDTO 请求
  16 + */
  17 + void validateCombination(CombinationActivityUpdateStockReqDTO reqDTO);
  18 +
  19 +}
... ...
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/dto/CombinationActivityUpdateStockReqDTO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.promotion.api.combination.dto;
  2 +
  3 +import lombok.Data;
  4 +
  5 +import javax.validation.Valid;
  6 +import javax.validation.constraints.NotNull;
  7 +
  8 +/**
  9 + * 拼团活动更新活动库存 Request DTO
  10 + *
  11 + * @author HUIHUI
  12 + */
  13 +@Data
  14 +public class CombinationActivityUpdateStockReqDTO {
  15 +
  16 + @NotNull(message = "活动编号不能为空")
  17 + private Long activityId;
  18 +
  19 + @NotNull(message = "购买数量不能为空")
  20 + private Integer count;
  21 +
  22 + @NotNull(message = "活动商品不能为空")
  23 + private Item item;
  24 +
  25 + @Data
  26 + @Valid
  27 + public static class Item {
  28 +
  29 + @NotNull(message = "SPU 编号不能为空")
  30 + private Long spuId;
  31 +
  32 + @NotNull(message = "SKU 编号活动商品不能为空")
  33 + private Long skuId;
  34 +
  35 + @NotNull(message = "购买数量不能为空")
  36 + private Integer count;
  37 +
  38 + }
  39 +
  40 +}
... ...
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;
2 2  
3 3 import lombok.Data;
4 4  
5   -import javax.validation.constraints.NotEmpty;
6 5 import javax.validation.constraints.NotNull;
7 6  
8 7 // TODO @芋艿:这块要在看看
... ... @@ -14,65 +13,25 @@ import javax.validation.constraints.NotNull;
14 13 @Data
15 14 public class CombinationRecordCreateReqDTO {
16 15  
17   - /**
18   - * 拼团活动编号
19   - */
20 16 @NotNull(message = "拼团活动编号不能为空")
21 17 private Long activityId;
22   - /**
23   - * spu 编号
24   - */
  18 +
25 19 @NotNull(message = "spu 编号不能为空")
26 20 private Long spuId;
27   - /**
28   - * sku 编号
29   - */
  21 +
30 22 @NotNull(message = "sku 编号不能为空")
31 23 private Long skuId;
32   - /**
33   - * 用户编号
34   - */
35   - @NotNull(message = "用户编号不能为空")
36   - private Long userId;
37   - /**
38   - * 订单编号
39   - */
  24 +
40 25 @NotNull(message = "订单编号不能为空")
41 26 private Long orderId;
42   - /**
43   - * 团长编号
44   - */
  27 +
  28 + @NotNull(message = "用户编号不能为空")
  29 + private Long userId;
  30 +
45 31 @NotNull(message = "团长编号不能为空")
46 32 private Long headId;
47   - /**
48   - * 商品名字
49   - */
50   - @NotEmpty(message = "商品名字不能为空")
51   - private String spuName;
52   - /**
53   - * 商品图片
54   - */
55   - @NotEmpty(message = "商品图片不能为空")
56   - private String picUrl;
57   - /**
58   - * 拼团商品单价
59   - */
  33 +
60 34 @NotNull(message = "拼团商品单价不能为空")
61 35 private Integer combinationPrice;
62   - /**
63   - * 用户昵称
64   - */
65   - @NotEmpty(message = "用户昵称不能为空")
66   - private String nickname;
67   - /**
68   - * 用户头像
69   - */
70   - @NotEmpty(message = "用户头像不能为空")
71   - private String avatar;
72   - /**
73   - * 开团状态:正在开团 拼团成功 拼团失败
74   - */
75   - @NotNull(message = "开团状态不能为空")
76   - private Integer status;
77 36  
78 37 }
... ...
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;
2 2  
3 3 import lombok.Data;
4 4  
  5 +import javax.validation.Valid;
5 6 import javax.validation.constraints.NotNull;
6 7  
7 8 /**
... ... @@ -22,6 +23,7 @@ public class SeckillActivityUpdateStockReqDTO {
22 23 private Item item;
23 24  
24 25 @Data
  26 + @Valid
25 27 public static class Item {
26 28  
27 29 @NotNull(message = "SPU 编号不能为空")
... ...
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 {
65 65 // ========== 拼团活动 1013010000 ==========
66 66 ErrorCode COMBINATION_ACTIVITY_NOT_EXISTS = new ErrorCode(1013010000, "拼团活动不存在");
67 67 ErrorCode COMBINATION_ACTIVITY_SPU_CONFLICTS = new ErrorCode(1013010001, "存在商品参加了其它拼团活动");
68   - ErrorCode COMBINATION_ACTIVITY_STATUS_DISABLE = new ErrorCode(1013010002, "拼团活动已关闭不能修改");
  68 + ErrorCode COMBINATION_ACTIVITY_STATUS_DISABLE_NOT_UPDATE = new ErrorCode(1013010002, "拼团活动已关闭不能修改");
69 69 ErrorCode COMBINATION_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END = new ErrorCode(1013010003, "拼团活动未关闭或未结束,不能删除");
70   - ErrorCode COMBINATION_RECORD_NOT_EXISTS = new ErrorCode(1013010004, "拼团不存在");
  70 + ErrorCode COMBINATION_ACTIVITY_STATUS_DISABLE = new ErrorCode(1013010004, "拼团失败,原因:拼团活动已关闭");
71 71  
72 72 // ========== 拼团记录 1013011000 ==========
73   - ErrorCode COMBINATION_RECORD_EXISTS = new ErrorCode(1013011000, "拼团失败,已参与过该拼团");
74   - ErrorCode COMBINATION_RECORD_HEAD_NOT_EXISTS = new ErrorCode(1013011001, "拼团失败,父拼团不存在");
75   - ErrorCode COMBINATION_RECORD_USER_FULL = new ErrorCode(1013011002, "拼团失败,拼团人数已满");
76   - ErrorCode COMBINATION_RECORD_FAILED_HAVE_JOINED = new ErrorCode(1013011003, "拼团失败,已参与其它拼团");
77   - ErrorCode COMBINATION_RECORD_FAILED_TIME_END = new ErrorCode(1013011004, "拼团失败,活动已经结束");
78   - ErrorCode COMBINATION_RECORD_FAILED_SINGLE_LIMIT_COUNT_EXCEED = new ErrorCode(1013011005, "拼团失败,单次限购超出");
79   - ErrorCode COMBINATION_RECORD_FAILED_TOTAL_LIMIT_COUNT_EXCEED = new ErrorCode(1013011006, "拼团失败,单次限购超出");
  73 + ErrorCode COMBINATION_RECORD_NOT_EXISTS = new ErrorCode(1013011000, "拼团不存在");
  74 + ErrorCode COMBINATION_RECORD_EXISTS = new ErrorCode(1013011001, "拼团失败,已参与过该拼团");
  75 + ErrorCode COMBINATION_RECORD_HEAD_NOT_EXISTS = new ErrorCode(1013011002, "拼团失败,父拼团不存在");
  76 + ErrorCode COMBINATION_RECORD_USER_FULL = new ErrorCode(1013011003, "拼团失败,拼团人数已满");
  77 + ErrorCode COMBINATION_RECORD_FAILED_HAVE_JOINED = new ErrorCode(1013011004, "拼团失败,已参与其它拼团");
  78 + ErrorCode COMBINATION_RECORD_FAILED_TIME_END = new ErrorCode(1013011005, "拼团失败,活动已经结束");
  79 + ErrorCode COMBINATION_RECORD_FAILED_SINGLE_LIMIT_COUNT_EXCEED = new ErrorCode(1013011006, "拼团失败,原因:单次限购超出");
  80 + ErrorCode COMBINATION_RECORD_FAILED_TOTAL_LIMIT_COUNT_EXCEED = new ErrorCode(1013011007, "拼团失败,原因:超出总购买次数");
80 81  
81 82 // ========== 砍价活动 1013012000 ==========
82 83 ErrorCode BARGAIN_ACTIVITY_NOT_EXISTS = new ErrorCode(1013012000, "砍价活动不存在");
... ...
yudao-module-mall/yudao-module-promotion-biz/pom.xml
... ... @@ -31,6 +31,11 @@
31 31 </dependency>
32 32 <dependency>
33 33 <groupId>cn.iocoder.boot</groupId>
  34 + <artifactId>yudao-module-trade-api</artifactId>
  35 + <version>${revision}</version>
  36 + </dependency>
  37 + <dependency>
  38 + <groupId>cn.iocoder.boot</groupId>
34 39 <artifactId>yudao-module-member-api</artifactId>
35 40 <version>${revision}</version>
36 41 </dependency>
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/CombinationApiImpl.java 0 → 100644
  1 +package cn.iocoder.yudao.module.promotion.api.combination;
  2 +
  3 +import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationActivityUpdateStockReqDTO;
  4 +import cn.iocoder.yudao.module.promotion.service.combination.CombinationActivityService;
  5 +
  6 +import javax.annotation.Resource;
  7 +
  8 +/**
  9 + * 拼团活动 Api 接口实现类
  10 + *
  11 + * @author HUIHUI
  12 + */
  13 +public class CombinationApiImpl implements CombinationApi {
  14 +
  15 + @Resource
  16 + private CombinationActivityService activityService;
  17 +
  18 + @Override
  19 + public void validateCombination(CombinationActivityUpdateStockReqDTO reqDTO) {
  20 + activityService.validateCombination(reqDTO);
  21 + }
  22 +
  23 +}
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationActivityService.java
1 1 package cn.iocoder.yudao.module.promotion.service.combination;
2 2  
3 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationActivityUpdateStockReqDTO;
4 5 import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityCreateReqVO;
5 6 import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityPageReqVO;
6 7 import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityUpdateReqVO;
... ... @@ -72,4 +73,11 @@ public interface CombinationActivityService {
72 73 */
73 74 List<CombinationProductDO> getCombinationProductsByActivityIds(Collection<Long> activityIds);
74 75  
  76 + /**
  77 + * 更新拼图活动库存
  78 + *
  79 + * @param reqDTO 请求
  80 + */
  81 + void validateCombination(CombinationActivityUpdateStockReqDTO reqDTO);
  82 +
75 83 }
... ...
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;
9 9 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
10 10 import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
11 11 import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
  12 +import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationActivityUpdateStockReqDTO;
12 13 import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityCreateReqVO;
13 14 import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityPageReqVO;
14 15 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
16 17 import cn.iocoder.yudao.module.promotion.convert.combination.CombinationActivityConvert;
17 18 import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO;
18 19 import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationProductDO;
  20 +import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationRecordDO;
19 21 import cn.iocoder.yudao.module.promotion.dal.mysql.combination.CombinationActivityMapper;
20 22 import cn.iocoder.yudao.module.promotion.dal.mysql.combination.CombinationProductMapper;
  23 +import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum;
  24 +import cn.iocoder.yudao.module.trade.api.order.TradeOrderApi;
21 25 import org.springframework.stereotype.Service;
22 26 import org.springframework.transaction.annotation.Transactional;
23 27 import org.springframework.validation.annotation.Validated;
... ... @@ -28,8 +32,8 @@ import java.util.List;
28 32 import java.util.Map;
29 33  
30 34 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
31   -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
32   -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList;
  35 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
  36 +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
33 37 import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_NOT_EXISTS;
34 38 import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SPU_NOT_EXISTS;
35 39 import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
... ... @@ -48,11 +52,15 @@ public class CombinationActivityServiceImpl implements CombinationActivityServic
48 52 private CombinationActivityMapper combinationActivityMapper;
49 53 @Resource
50 54 private CombinationProductMapper combinationProductMapper;
  55 + @Resource
  56 + private CombinationRecordService combinationRecordService;
51 57  
52 58 @Resource
53 59 private ProductSpuApi productSpuApi;
54 60 @Resource
55 61 private ProductSkuApi productSkuApi;
  62 + @Resource
  63 + private TradeOrderApi tradeOrderApi;
56 64  
57 65 @Override
58 66 @Transactional(rollbackFor = Exception.class)
... ... @@ -97,7 +105,7 @@ public class CombinationActivityServiceImpl implements CombinationActivityServic
97 105 * 校验拼团商品是否都存在
98 106 *
99 107 * @param spuId 商品 SPU 编号
100   - * @param products 秒杀商品
  108 + * @param products 拼团商品
101 109 */
102 110 private void validateProductExists(Long spuId, List<CombinationProductBaseVO> products) {
103 111 // 1. 校验商品 spu 是否存在
... ... @@ -123,7 +131,7 @@ public class CombinationActivityServiceImpl implements CombinationActivityServic
123 131 CombinationActivityDO activityDO = validateCombinationActivityExists(updateReqVO.getId());
124 132 // 校验状态
125 133 if (ObjectUtil.equal(activityDO.getStatus(), CommonStatusEnum.DISABLE.getStatus())) {
126   - throw exception(COMBINATION_ACTIVITY_STATUS_DISABLE);
  134 + throw exception(COMBINATION_ACTIVITY_STATUS_DISABLE_NOT_UPDATE);
127 135 }
128 136 // 校验商品冲突
129 137 validateProductConflict(updateReqVO.getSpuId(), updateReqVO.getId());
... ... @@ -205,4 +213,30 @@ public class CombinationActivityServiceImpl implements CombinationActivityServic
205 213 return combinationProductMapper.selectListByActivityIds(activityIds);
206 214 }
207 215  
  216 + @Override
  217 + public void validateCombination(CombinationActivityUpdateStockReqDTO reqDTO) {
  218 + // 1、校验拼团活动是否存在
  219 + CombinationActivityDO activity = validateCombinationActivityExists(reqDTO.getActivityId());
  220 + // 1.1、校验活动是否开启
  221 + if (ObjectUtil.equal(activity.getStatus(), CommonStatusEnum.DISABLE.getStatus())) {
  222 + throw exception(COMBINATION_ACTIVITY_STATUS_DISABLE);
  223 + }
  224 + // 1.2、校验是否超出单次限购数量
  225 + if (activity.getSingleLimitCount() < reqDTO.getCount()) {
  226 + throw exception(COMBINATION_RECORD_FAILED_SINGLE_LIMIT_COUNT_EXCEED);
  227 + }
  228 + // 1.3、校验是否超出总限购数量
  229 + List<CombinationRecordDO> recordList = combinationRecordService.getRecordListByUserIdAndActivityId(getLoginUserId(), reqDTO.getActivityId());
  230 + if (CollUtil.isNotEmpty(recordList)) {
  231 + // 过滤出拼团成功的
  232 + List<Long> skuIds = convertList(recordList, CombinationRecordDO::getSkuId,
  233 + item -> ObjectUtil.equals(item.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus()));
  234 + Integer countSum = tradeOrderApi.getOrderItemCountSumByOrderIdAndSkuId(convertList(recordList, CombinationRecordDO::getOrderId,
  235 + item -> ObjectUtil.equals(item.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus())), skuIds);
  236 + if (activity.getTotalLimitCount() < countSum) {
  237 + throw exception(COMBINATION_RECORD_FAILED_TOTAL_LIMIT_COUNT_EXCEED);
  238 + }
  239 + }
  240 + }
  241 +
208 242 }
... ...
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;
2 2  
3 3 import cn.hutool.core.collection.CollUtil;
4 4 import cn.hutool.core.util.ObjectUtil;
  5 +import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
  6 +import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
  7 +import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
  8 +import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
  9 +import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
  10 +import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
5 11 import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO;
6 12 import cn.iocoder.yudao.module.promotion.convert.combination.CombinationActivityConvert;
7 13 import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO;
8 14 import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationRecordDO;
9 15 import cn.iocoder.yudao.module.promotion.dal.mysql.combination.CombinationRecordMapper;
10 16 import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum;
  17 +import org.springframework.context.annotation.Lazy;
11 18 import org.springframework.stereotype.Service;
12 19 import org.springframework.transaction.annotation.Transactional;
13 20 import org.springframework.validation.annotation.Validated;
... ... @@ -32,10 +39,18 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
32 39  
33 40 @Resource
34 41 private CombinationActivityService combinationActivityService;
35   -
36 42 @Resource
37 43 private CombinationRecordMapper recordMapper;
38 44  
  45 + @Resource
  46 + private MemberUserApi memberUserApi;
  47 + @Resource
  48 + @Lazy
  49 + private ProductSpuApi productSpuApi;
  50 + @Resource
  51 + @Lazy
  52 + private ProductSkuApi productSkuApi;
  53 +
39 54 @Override
40 55 @Transactional(rollbackFor = Exception.class)
41 56 public void updateCombinationRecordStatusByUserIdAndOrderId(Integer status, Long userId, Long orderId) {
... ... @@ -102,12 +117,12 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
102 117 // 1.5 父拼团是否存在,是否已经满了
103 118 if (reqDTO.getHeadId() != null) {
104 119 // 查询进行中的父拼团
105   - CombinationRecordDO recordDO1 = recordMapper.selectOneByHeadId(reqDTO.getHeadId(), CombinationRecordStatusEnum.IN_PROGRESS.getStatus());
106   - if (recordDO1 == null) {
  120 + CombinationRecordDO record = recordMapper.selectOneByHeadId(reqDTO.getHeadId(), CombinationRecordStatusEnum.IN_PROGRESS.getStatus());
  121 + if (record == null) {
107 122 throw exception(COMBINATION_RECORD_HEAD_NOT_EXISTS);
108 123 }
109 124 // 校验拼团是否满足要求
110   - if (ObjectUtil.equal(recordDO1.getUserCount(), recordDO1.getUserSize())) {
  125 + if (ObjectUtil.equal(record.getUserCount(), record.getUserSize())) {
111 126 throw exception(COMBINATION_RECORD_USER_FULL);
112 127 }
113 128 }
... ... @@ -117,6 +132,13 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
117 132 record.setVirtualGroup(false);
118 133 record.setExpireTime(record.getStartTime().plusHours(activity.getLimitDuration()));
119 134 record.setUserSize(activity.getUserSize());
  135 + MemberUserRespDTO user = memberUserApi.getUser(reqDTO.getUserId());
  136 + record.setNickname(user.getNickname());
  137 + record.setAvatar(user.getAvatar());
  138 + ProductSpuRespDTO spu = productSpuApi.getSpu(record.getSpuId());
  139 + record.setSpuName(spu.getName());
  140 + ProductSkuRespDTO sku = productSkuApi.getSku(record.getSkuId());
  141 + record.setPicUrl(sku.getPicUrl());
120 142 recordMapper.insert(record);
121 143 }
122 144  
... ...
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/api/order/TradeOrderApi.java
1 1 package cn.iocoder.yudao.module.trade.api.order;
2 2  
  3 +import java.util.Collection;
  4 +
3 5 /**
4 6 * 订单 API 接口
5 7 *
... ... @@ -16,4 +18,13 @@ public interface TradeOrderApi {
16 18 */
17 19 Long validateOrder(Long userId, Long orderItemId);
18 20  
  21 + /**
  22 + * 获取订单项商品购买数量总和
  23 + *
  24 + * @param orderIds 订单编号
  25 + * @param skuIds sku 编号
  26 + * @return 订单项商品购买数量总和
  27 + */
  28 + Integer getOrderItemCountSumByOrderIdAndSkuId(Collection<Long> orderIds, Collection<Long> skuIds);
  29 +
19 30 }
... ...
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;
6 6 import org.springframework.validation.annotation.Validated;
7 7  
8 8 import javax.annotation.Resource;
  9 +import java.util.Collection;
9 10  
10 11 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
11 12 import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.ORDER_ITEM_NOT_FOUND;
... ... @@ -32,4 +33,9 @@ public class TradeOrderApiImpl implements TradeOrderApi {
32 33 return item.getOrderId();
33 34 }
34 35  
  36 + @Override
  37 + public Integer getOrderItemCountSumByOrderIdAndSkuId(Collection<Long> orderIds, Collection<Long> skuIds) {
  38 + return tradeOrderQueryService.getOrderItemCountSumByOrderIdAndSkuId(orderIds, skuIds);
  39 + }
  40 +
35 41 }
... ...
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
14 14 import cn.iocoder.yudao.module.product.api.property.dto.ProductPropertyValueDetailRespDTO;
15 15 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
16 16 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO;
  17 +import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationActivityUpdateStockReqDTO;
17 18 import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO;
  19 +import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillActivityUpdateStockReqDTO;
18 20 import cn.iocoder.yudao.module.trade.api.order.dto.TradeOrderRespDTO;
19 21 import cn.iocoder.yudao.module.trade.controller.admin.base.member.user.MemberUserRespVO;
20 22 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
31 33 import cn.iocoder.yudao.module.trade.framework.delivery.core.client.dto.ExpressTrackRespDTO;
32 34 import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties;
33 35 import cn.iocoder.yudao.module.trade.service.brokerage.bo.BrokerageAddReqBO;
  36 +import cn.iocoder.yudao.module.trade.service.order.bo.TradeAfterOrderCreateReqBO;
  37 +import cn.iocoder.yudao.module.trade.service.order.bo.TradeBeforeOrderCreateReqBO;
34 38 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO;
35 39 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO;
36 40 import org.mapstruct.Mapper;
... ... @@ -253,21 +257,15 @@ public interface TradeOrderConvert {
253 257 AppTradeOrderSettlementRespVO convert0(TradePriceCalculateRespBO calculate, AddressRespDTO address);
254 258  
255 259 @Mappings({
256   - @Mapping(target = "activityId", source = "createReqVO.combinationActivityId"),
257   - @Mapping(target = "spuId", source = "orderItem.spuId"),
258   - @Mapping(target = "skuId", source = "orderItem.skuId"),
259   - @Mapping(target = "userId", source = "order.userId"),
260   - @Mapping(target = "orderId", source = "order.id"),
261   - @Mapping(target = "headId", source = "createReqVO.combinationHeadId"),
262   - @Mapping(target = "spuName", source = "orderItem.spuName"),
263   - @Mapping(target = "picUrl", source = "orderItem.picUrl"),
264   - @Mapping(target = "combinationPrice", source = "orderItem.payPrice"),
265   - @Mapping(target = "nickname", source = "user.nickname"),
266   - @Mapping(target = "avatar", source = "user.avatar"),
267   - @Mapping(target = "status", ignore = true)
  260 + @Mapping(target = "activityId", source = "afterOrderCreateReqBO.combinationActivityId"),
  261 + @Mapping(target = "spuId", source = "afterOrderCreateReqBO.spuId"),
  262 + @Mapping(target = "skuId", source = "afterOrderCreateReqBO.skuId"),
  263 + @Mapping(target = "orderId", source = "afterOrderCreateReqBO.orderId"),
  264 + @Mapping(target = "userId", source = "afterOrderCreateReqBO.userId"),
  265 + @Mapping(target = "headId", source = "afterOrderCreateReqBO.combinationHeadId"),
  266 + @Mapping(target = "combinationPrice", source = "afterOrderCreateReqBO.payPrice"),
268 267 })
269   - CombinationRecordCreateReqDTO convert(TradeOrderDO order, TradeOrderItemDO orderItem,
270   - AppTradeOrderCreateReqVO createReqVO, MemberUserRespDTO user);
  268 + CombinationRecordCreateReqDTO convert(TradeAfterOrderCreateReqBO afterOrderCreateReqBO);
271 269  
272 270 List<AppOrderExpressTrackRespDTO> convertList02(List<ExpressTrackRespDTO> list);
273 271  
... ... @@ -283,4 +281,24 @@ public interface TradeOrderConvert {
283 281 .setFirstFixedPrice(sku.getFirstBrokerageRecord())
284 282 .setSecondFixedPrice(sku.getSecondBrokerageRecord());
285 283 }
  284 +
  285 + @Mapping(target = "activityId", source = "reqBO.seckillActivityId")
  286 + SeckillActivityUpdateStockReqDTO convert(TradeBeforeOrderCreateReqBO reqBO);
  287 +
  288 + @Mapping(target = "activityId", source = "reqBO.combinationActivityId")
  289 + CombinationActivityUpdateStockReqDTO convert1(TradeBeforeOrderCreateReqBO reqBO);
  290 +
  291 + TradeBeforeOrderCreateReqBO convert(AppTradeOrderCreateReqVO createReqVO);
  292 +
  293 + @Mappings({
  294 + @Mapping(target = "combinationActivityId", source = "createReqVO.combinationActivityId"),
  295 + @Mapping(target = "combinationHeadId", source = "createReqVO.combinationHeadId"),
  296 + @Mapping(target = "spuId", source = "orderItem.spuId"),
  297 + @Mapping(target = "skuId", source = "orderItem.skuId"),
  298 + @Mapping(target = "orderId", source = "tradeOrderDO.id"),
  299 + @Mapping(target = "userId", source = "userId"),
  300 + @Mapping(target = "payPrice", source = "tradeOrderDO.payPrice"),
  301 + })
  302 + TradeAfterOrderCreateReqBO convert(Long userId, AppTradeOrderCreateReqVO createReqVO, TradeOrderDO tradeOrderDO, TradeOrderItemDO orderItem);
  303 +
286 304 }
... ...
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&lt;TradeOrderItemDO&gt; {
29 29 default List<TradeOrderItemDO> selectListByOrderIdAnSkuId(Collection<Long> orderIds, Collection<Long> skuIds) {
30 30 return selectList(new LambdaQueryWrapperX<TradeOrderItemDO>()
31 31 .in(TradeOrderItemDO::getOrderId, orderIds)
32   - .eq(TradeOrderItemDO::getSkuId, skuIds));
  32 + .in(TradeOrderItemDO::getSkuId, skuIds));
33 33 }
34 34  
35 35 default TradeOrderItemDO selectByIdAndUserId(Long orderItemId, Long loginUserId) {
... ...
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 {
119 119 */
120 120 List<TradeOrderItemDO> getOrderItemListByOrderId(Collection<Long> orderIds);
121 121  
  122 + /**
  123 + * 获取订单项商品购买数量总和
  124 + *
  125 + * @param orderIds 订单编号
  126 + * @param skuIds sku 编号
  127 + * @return 订单项商品购买数量总和
  128 + */
  129 + Integer getOrderItemCountSumByOrderIdAndSkuId(Collection<Long> orderIds, Collection<Long> skuIds);
  130 +
122 131 }
... ...
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;
4 4 import cn.hutool.core.util.ObjectUtil;
5 5 import cn.hutool.core.util.StrUtil;
6 6 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  7 +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
7 8 import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
8 9 import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
9 10 import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderPageReqVO;
... ... @@ -167,4 +168,10 @@ public class TradeOrderQueryServiceImpl implements TradeOrderQueryService {
167 168 return tradeOrderItemMapper.selectListByOrderId(orderIds);
168 169 }
169 170  
  171 + @Override
  172 + public Integer getOrderItemCountSumByOrderIdAndSkuId(Collection<Long> orderIds, Collection<Long> skuIds) {
  173 + List<TradeOrderItemDO> tradeOrderItems = tradeOrderItemMapper.selectListByOrderIdAnSkuId(orderIds, skuIds);
  174 + return CollectionUtils.getSumValue(tradeOrderItems, TradeOrderItemDO::getCount, Integer::sum);
  175 + }
  176 +
170 177 }
... ...
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;
13 13 import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO;
14 14 import cn.iocoder.yudao.module.member.api.level.MemberLevelApi;
15 15 import cn.iocoder.yudao.module.member.api.point.MemberPointApi;
16   -import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
17   -import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
18 16 import cn.iocoder.yudao.module.member.enums.MemberExperienceBizTypeEnum;
19 17 import cn.iocoder.yudao.module.member.enums.point.MemberPointBizTypeEnum;
20 18 import cn.iocoder.yudao.module.pay.api.order.PayOrderApi;
... ... @@ -24,15 +22,10 @@ import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum;
24 22 import cn.iocoder.yudao.module.product.api.comment.ProductCommentApi;
25 23 import cn.iocoder.yudao.module.product.api.comment.dto.ProductCommentCreateReqDTO;
26 24 import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
27   -import cn.iocoder.yudao.module.promotion.api.bargain.BargainActivityApi;
28 25 import cn.iocoder.yudao.module.promotion.api.bargain.BargainRecordApi;
29 26 import cn.iocoder.yudao.module.promotion.api.combination.CombinationRecordApi;
30   -import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordRespDTO;
31 27 import cn.iocoder.yudao.module.promotion.api.coupon.CouponApi;
32 28 import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponUseReqDTO;
33   -import cn.iocoder.yudao.module.promotion.api.seckill.SeckillActivityApi;
34   -import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillActivityUpdateStockReqDTO;
35   -import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum;
36 29 import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderDeliveryReqVO;
37 30 import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderRemarkReqVO;
38 31 import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderUpdateAddressReqVO;
... ... @@ -59,6 +52,8 @@ import cn.iocoder.yudao.module.trade.service.cart.CartService;
59 52 import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressService;
60 53 import cn.iocoder.yudao.module.trade.service.message.TradeMessageService;
61 54 import cn.iocoder.yudao.module.trade.service.message.bo.TradeOrderMessageWhenDeliveryOrderReqBO;
  55 +import cn.iocoder.yudao.module.trade.service.order.bo.TradeBeforeOrderCreateReqBO;
  56 +import cn.iocoder.yudao.module.trade.service.order.handler.TradeOrderHandler;
62 57 import cn.iocoder.yudao.module.trade.service.price.TradePriceService;
63 58 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO;
64 59 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO;
... ... @@ -95,6 +90,8 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
95 90 private TradeOrderItemMapper tradeOrderItemMapper;
96 91 @Resource
97 92 private TradeOrderNoRedisDAO orderNoRedisDAO;
  93 + @Resource
  94 + private List<TradeOrderHandler> orderHandlers;
98 95  
99 96 @Resource
100 97 private CartService cartService;
... ... @@ -118,12 +115,6 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
118 115 @Resource
119 116 private BargainRecordApi bargainRecordApi;
120 117 @Resource
121   - private SeckillActivityApi seckillActivityApi;
122   - @Resource
123   - private BargainActivityApi bargainActivityApi;
124   - @Resource
125   - private MemberUserApi memberUserApi;
126   - @Resource
127 118 private MemberLevelApi memberLevelApi;
128 119 @Resource
129 120 private MemberPointApi memberPointApi;
... ... @@ -188,7 +179,13 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
188 179 @Override
189 180 @Transactional(rollbackFor = Exception.class)
190 181 public TradeOrderDO createOrder(Long userId, String userIp, AppTradeOrderCreateReqVO createReqVO) {
191   - // 1. 价格计算
  182 + // 1、执行订单创建前置处理器
  183 + TradeBeforeOrderCreateReqBO beforeOrderCreateReqBO = TradeOrderConvert.INSTANCE.convert(createReqVO);
  184 + beforeOrderCreateReqBO.setOrderType(validateActivity(createReqVO));
  185 + beforeOrderCreateReqBO.setCount(CollectionUtils.getSumValue(createReqVO.getItems(), AppTradeOrderSettlementReqVO.Item::getCount, Integer::sum));
  186 + orderHandlers.forEach(handler -> handler.beforeOrderCreate(beforeOrderCreateReqBO));
  187 +
  188 + // 2. 价格计算
192 189 TradePriceCalculateRespBO calculateRespBO = calculatePrice(userId, createReqVO);
193 190  
194 191 // 2.1 插入 TradeOrderDO 订单
... ... @@ -198,37 +195,11 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
198 195  
199 196 // 3. 订单创建完后的逻辑
200 197 afterCreateTradeOrder(userId, createReqVO, order, orderItems, calculateRespBO);
201   - // 3.1 拼团的特殊逻辑
202   - // TODO @puhui999:这个逻辑,先抽个小方法;未来要通过设计模式,把这些拼团之类的逻辑,抽象出去
203   - // 拼团
204   - if (Objects.equals(TradeOrderTypeEnum.COMBINATION.getType(), order.getType())) {
205   - createCombinationRecord(userId, createReqVO, orderItems, order);
206   - }
207   - // 3.2 秒杀的特殊逻辑
208   - if (Objects.equals(TradeOrderTypeEnum.SECKILL.getType(), order.getType())) {
209   -
210   - }
211   - // 3.3 砍价的特殊逻辑
212 198  
213 199 // TODO @LeeYan9: 是可以思考下, 订单的营销优惠记录, 应该记录在哪里, 微信讨论起来!
214 200 return order;
215 201 }
216 202  
217   - private void createCombinationRecord(Long userId, AppTradeOrderCreateReqVO createReqVO, List<TradeOrderItemDO> orderItems, TradeOrderDO order) {
218   - MemberUserRespDTO user = memberUserApi.getUser(userId);
219   - List<CombinationRecordRespDTO> recordRespDTOS = combinationRecordApi.getRecordListByUserIdAndActivityId(userId, createReqVO.getCombinationActivityId());
220   - // TODO 拼团一次应该只能选择一种规格的商品
221   - TradeOrderItemDO orderItemDO = orderItems.get(0);
222   - if (CollUtil.isNotEmpty(recordRespDTOS)) {
223   - List<Long> skuIds = convertList(recordRespDTOS, CombinationRecordRespDTO::getSkuId, item -> ObjectUtil.equals(item.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus()));
224   - List<TradeOrderItemDO> tradeOrderItemDOS = tradeOrderItemMapper.selectListByOrderIdAnSkuId(convertList(recordRespDTOS,
225   - CombinationRecordRespDTO::getOrderId, item -> ObjectUtil.equals(item.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus())), skuIds);
226   - combinationRecordApi.validateCombinationLimitCount(createReqVO.getCombinationActivityId(),
227   - CollectionUtils.getSumValue(tradeOrderItemDOS, TradeOrderItemDO::getCount, Integer::sum), orderItemDO.getCount());
228   - }
229   -
230   - combinationRecordApi.createCombinationRecord(TradeOrderConvert.INSTANCE.convert(order, orderItemDO, createReqVO, user));
231   - }
232 203  
233 204 // TODO @puhui999:订单超时,自动取消;
234 205  
... ... @@ -310,13 +281,8 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
310 281 private void afterCreateTradeOrder(Long userId, AppTradeOrderCreateReqVO createReqVO,
311 282 TradeOrderDO tradeOrderDO, List<TradeOrderItemDO> orderItems,
312 283 TradePriceCalculateRespBO calculateRespBO) {
313   - Integer count = getSumValue(orderItems, TradeOrderItemDO::getCount, Integer::sum);
314   - // 1)如果是秒杀商品:额外扣减秒杀的库存;
315   - if (Objects.equals(TradeOrderTypeEnum.SECKILL.getType(), tradeOrderDO.getType())) {
316   - seckillActivityApi.updateSeckillStock(getSeckillActivityUpdateStockReqDTO(createReqVO, orderItems, count));
317   - }
318   - // 2)如果是砍价活动:额外扣减砍价的库存;
319   - bargainActivityApi.updateBargainActivityStock(createReqVO.getBargainActivityId(), count);
  284 + // 执行订单创建后置处理器
  285 + orderHandlers.forEach(handler -> handler.afterOrderCreate(TradeOrderConvert.INSTANCE.convert(userId, createReqVO, tradeOrderDO, orderItems.get(0))));
320 286 // 扣减积分 TODO 芋艿:待实现,需要前置;
321 287 // 这个是不是应该放到支付成功之后?如果支付后的话,可能积分可以重复使用哈。资源类,都要预扣
322 288  
... ... @@ -341,19 +307,6 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
341 307 // 增加订单日志 TODO 芋艿:待实现
342 308 }
343 309  
344   - private SeckillActivityUpdateStockReqDTO getSeckillActivityUpdateStockReqDTO(AppTradeOrderCreateReqVO createReqVO, List<TradeOrderItemDO> orderItems, Integer count) {
345   - SeckillActivityUpdateStockReqDTO updateStockReqDTO = new SeckillActivityUpdateStockReqDTO();
346   - updateStockReqDTO.setActivityId(createReqVO.getSeckillActivityId());
347   - updateStockReqDTO.setCount(count);
348   - // 秒杀活动只能选择一个商品
349   - TradeOrderItemDO item = orderItems.get(0);
350   - SeckillActivityUpdateStockReqDTO.Item item1 = new SeckillActivityUpdateStockReqDTO.Item();
351   - item1.setSpuId(item.getSpuId());
352   - item1.setSkuId(item.getSkuId());
353   - item1.setCount(item.getCount());
354   - updateStockReqDTO.setItem(item1);
355   - return updateStockReqDTO;
356   - }
357 310  
358 311 private void createPayOrder(TradeOrderDO order, List<TradeOrderItemDO> orderItems, TradePriceCalculateRespBO calculateRespBO) {
359 312 // 创建支付单,用于后续的支付
... ... @@ -768,6 +721,9 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
768 721 throw exception(ORDER_CANCEL_FAIL_STATUS_NOT_UNPAID);
769 722 }
770 723  
  724 + // TODO 活动相关库存回滚需要活动 id,活动 id 怎么获取?app 端能否传过来
  725 + orderHandlers.forEach(handler -> handler.rollbackStock());
  726 +
771 727 // 2.回滚库存
772 728 List<TradeOrderItemDO> orderItems = tradeOrderItemMapper.selectListByOrderId(id);
773 729 productSkuApi.updateSkuStock(TradeOrderConvert.INSTANCE.convert(orderItems));
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/bo/TradeAfterOrderCreateReqBO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.service.order.bo;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +
  6 +import javax.validation.constraints.NotNull;
  7 +
  8 +/**
  9 + * 订单创建之后 Request BO
  10 + *
  11 + * @author HUIHUI
  12 + */
  13 +@Data
  14 +public class TradeAfterOrderCreateReqBO {
  15 +
  16 + // ========== 拼团活动相关字段 ==========
  17 +
  18 + @Schema(description = "拼团活动编号", example = "1024")
  19 + private Long combinationActivityId;
  20 +
  21 + @Schema(description = "拼团团长编号", example = "2048")
  22 + private Long combinationHeadId;
  23 +
  24 + @NotNull(message = "SPU 编号不能为空")
  25 + private Long spuId;
  26 +
  27 + @NotNull(message = "SKU 编号活动商品不能为空")
  28 + private Long skuId;
  29 +
  30 + @NotNull(message = "订单编号不能为空")
  31 + private Long orderId;
  32 +
  33 + @NotNull(message = "用户编号不能为空")
  34 + private Long userId;
  35 +
  36 + @NotNull(message = "支付金额不能为空")
  37 + private Integer payPrice;
  38 +
  39 +}
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/bo/TradeBeforeOrderCreateReqBO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.service.order.bo;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +
  6 +import javax.validation.Valid;
  7 +import javax.validation.constraints.NotNull;
  8 +
  9 +/**
  10 + * 订单创建之前 Request BO
  11 + *
  12 + * @author HUIHUI
  13 + */
  14 +@Data
  15 +public class TradeBeforeOrderCreateReqBO {
  16 +
  17 + @NotNull(message = "订单类型不能为空")
  18 + private Integer orderType;
  19 +
  20 + // ========== 秒杀活动相关字段 ==========
  21 +
  22 + @Schema(description = "秒杀活动编号", example = "1024")
  23 + private Long seckillActivityId;
  24 +
  25 + // ========== 拼团活动相关字段 ==========
  26 +
  27 + @Schema(description = "拼团活动编号", example = "1024")
  28 + private Long combinationActivityId;
  29 +
  30 + @Schema(description = "拼团团长编号", example = "2048")
  31 + private Long combinationHeadId;
  32 +
  33 + @Schema(description = "砍价活动编号", example = "123")
  34 + private Long bargainActivityId;
  35 +
  36 + @NotNull(message = "购买数量不能为空")
  37 + private Integer count;
  38 +
  39 + @NotNull(message = "活动商品不能为空")
  40 + private Item item;
  41 +
  42 + @Data
  43 + @Valid
  44 + public static class Item {
  45 +
  46 + @NotNull(message = "SPU 编号不能为空")
  47 + private Long spuId;
  48 +
  49 + @NotNull(message = "SKU 编号活动商品不能为空")
  50 + private Long skuId;
  51 +
  52 + @NotNull(message = "购买数量不能为空")
  53 + private Integer count;
  54 +
  55 + }
  56 +
  57 +}
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeBargainHandler.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.service.order.handler;
  2 +
  3 +import cn.hutool.core.util.ObjectUtil;
  4 +import cn.iocoder.yudao.module.promotion.api.bargain.BargainActivityApi;
  5 +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
  6 +import cn.iocoder.yudao.module.trade.service.order.bo.TradeAfterOrderCreateReqBO;
  7 +import cn.iocoder.yudao.module.trade.service.order.bo.TradeBeforeOrderCreateReqBO;
  8 +import org.springframework.stereotype.Component;
  9 +
  10 +import javax.annotation.Resource;
  11 +
  12 +/**
  13 + * 砍价订单 handler 实现类
  14 + *
  15 + * @author HUIHUI
  16 + */
  17 +@Component
  18 +public class TradeBargainHandler implements TradeOrderHandler {
  19 +
  20 + @Resource
  21 + private BargainActivityApi bargainActivityApi;
  22 +
  23 + @Override
  24 + public void beforeOrderCreate(TradeBeforeOrderCreateReqBO reqBO) {
  25 + // 如果是秒杀订单
  26 + if (ObjectUtil.notEqual(TradeOrderTypeEnum.BARGAIN.getType(), reqBO.getOrderType())) {
  27 + return;
  28 + }
  29 +
  30 + // 额外扣减砍价的库存
  31 + bargainActivityApi.updateBargainActivityStock(reqBO.getBargainActivityId(), reqBO.getCount());
  32 + }
  33 +
  34 + @Override
  35 + public void afterOrderCreate(TradeAfterOrderCreateReqBO reqBO) {
  36 +
  37 + }
  38 +
  39 + @Override
  40 + public void rollbackStock() {
  41 +
  42 + }
  43 +
  44 +}
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeCombinationHandler.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.service.order.handler;
  2 +
  3 +import cn.hutool.core.util.ObjectUtil;
  4 +import cn.iocoder.yudao.module.promotion.api.combination.CombinationApi;
  5 +import cn.iocoder.yudao.module.promotion.api.combination.CombinationRecordApi;
  6 +import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert;
  7 +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
  8 +import cn.iocoder.yudao.module.trade.service.order.bo.TradeAfterOrderCreateReqBO;
  9 +import cn.iocoder.yudao.module.trade.service.order.bo.TradeBeforeOrderCreateReqBO;
  10 +import org.springframework.stereotype.Component;
  11 +
  12 +import javax.annotation.Resource;
  13 +
  14 +/**
  15 + * 拼团订单 handler 接口实现类
  16 + *
  17 + * @author HUIHUI
  18 + */
  19 +@Component
  20 +public class TradeCombinationHandler implements TradeOrderHandler {
  21 +
  22 + @Resource
  23 + private CombinationApi combinationApi;
  24 + @Resource
  25 + private CombinationRecordApi combinationRecordApi;
  26 +
  27 + @Override
  28 + public void beforeOrderCreate(TradeBeforeOrderCreateReqBO reqBO) {
  29 + // 如果是拼团订单;
  30 + if (ObjectUtil.notEqual(TradeOrderTypeEnum.COMBINATION.getType(), reqBO.getOrderType())) {
  31 + return;
  32 + }
  33 +
  34 + // 校验是否满足拼团活动相关限制
  35 + combinationApi.validateCombination(TradeOrderConvert.INSTANCE.convert1(reqBO));
  36 + }
  37 +
  38 + @Override
  39 + public void afterOrderCreate(TradeAfterOrderCreateReqBO reqBO) {
  40 + // 创建砍价记录
  41 + combinationRecordApi.createCombinationRecord(TradeOrderConvert.INSTANCE.convert(reqBO));
  42 + }
  43 +
  44 + @Override
  45 + public void rollbackStock() {
  46 +
  47 + }
  48 +
  49 +}
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeOrderHandler.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.service.order.handler;
  2 +
  3 +import cn.iocoder.yudao.module.trade.service.order.bo.TradeAfterOrderCreateReqBO;
  4 +import cn.iocoder.yudao.module.trade.service.order.bo.TradeBeforeOrderCreateReqBO;
  5 +
  6 +/**
  7 + * 订单活动特殊逻辑处理器 handler 接口
  8 + *
  9 + * @author HUIHUI
  10 + */
  11 +public interface TradeOrderHandler {
  12 +
  13 + /**
  14 + * 订单创建前
  15 + *
  16 + * @param reqBO 请求
  17 + */
  18 + void beforeOrderCreate(TradeBeforeOrderCreateReqBO reqBO);
  19 +
  20 + /**
  21 + * 订单创建后
  22 + *
  23 + * @param reqBO 请求
  24 + */
  25 + void afterOrderCreate(TradeAfterOrderCreateReqBO reqBO);
  26 +
  27 + /**
  28 + * 回滚活动相关库存
  29 + */
  30 + void rollbackStock();
  31 +
  32 +}
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeSeckillHandler.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.service.order.handler;
  2 +
  3 +import cn.hutool.core.util.ObjectUtil;
  4 +import cn.iocoder.yudao.module.promotion.api.seckill.SeckillActivityApi;
  5 +import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert;
  6 +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
  7 +import cn.iocoder.yudao.module.trade.service.order.bo.TradeAfterOrderCreateReqBO;
  8 +import cn.iocoder.yudao.module.trade.service.order.bo.TradeBeforeOrderCreateReqBO;
  9 +import org.springframework.stereotype.Component;
  10 +
  11 +import javax.annotation.Resource;
  12 +
  13 +/**
  14 + * 秒杀订单 handler 实现类
  15 + *
  16 + * @author HUIHUI
  17 + */
  18 +@Component
  19 +public class TradeSeckillHandler implements TradeOrderHandler {
  20 +
  21 + @Resource
  22 + private SeckillActivityApi seckillActivityApi;
  23 +
  24 + @Override
  25 + public void beforeOrderCreate(TradeBeforeOrderCreateReqBO reqBO) {
  26 + // 如果是秒杀订单:额外扣减秒杀的库存;
  27 + if (ObjectUtil.notEqual(TradeOrderTypeEnum.SECKILL.getType(), reqBO.getOrderType())) {
  28 + return;
  29 + }
  30 +
  31 + seckillActivityApi.updateSeckillStock(TradeOrderConvert.INSTANCE.convert(reqBO));
  32 + }
  33 +
  34 + @Override
  35 + public void afterOrderCreate(TradeAfterOrderCreateReqBO reqBO) {
  36 +
  37 + }
  38 +
  39 + @Override
  40 + public void rollbackStock() {
  41 +
  42 + }
  43 +
  44 +}
... ...