Commit 82210a95832fd7be194af8bd365a085c7ef9a2c4

Authored by puhui999
1 parent 597eacaa

订单:完善拼团活动

Showing 21 changed files with 208 additions and 182 deletions
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/bargain/BargainRecordApi.java
... ... @@ -20,13 +20,4 @@ public interface BargainRecordApi {
20 20 */
21 21 void createBargainRecord(@Valid BargainRecordCreateReqDTO reqDTO);
22 22  
23   - /**
24   - * 查询砍价是否成功
25   - *
26   - * @param userId 用户编号
27   - * @param orderId 订单编号
28   - * @return 砍价是否成功
29   - */
30   - boolean isBargainRecordSuccess(Long userId, Long orderId);
31   -
32 23 }
... ...
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/dto/CombinationRecordCreateReqDTO.java
... ... @@ -29,6 +29,11 @@ public class CombinationRecordCreateReqDTO {
29 29 @NotNull(message = "sku 编号不能为空")
30 30 private Long skuId;
31 31 /**
  32 + * 购买的商品数量
  33 + */
  34 + @NotNull(message = "购买数量不能为空")
  35 + private Integer count;
  36 + /**
32 37 * 订单编号
33 38 */
34 39 @NotNull(message = "订单编号不能为空")
... ...
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java
... ... @@ -75,19 +75,11 @@ public interface ErrorCodeConstants {
75 75 ErrorCode COMBINATION_RECORD_HEAD_NOT_EXISTS = new ErrorCode(1_013_011_002, "拼团失败,父拼团不存在");
76 76 ErrorCode COMBINATION_RECORD_USER_FULL = new ErrorCode(1_013_011_003, "拼团失败,拼团人数已满");
77 77 ErrorCode COMBINATION_RECORD_FAILED_HAVE_JOINED = new ErrorCode(1_013_011_004, "拼团失败,已参与其它拼团");
78   - ErrorCode COMBINATION_RECORD_FAILED_TIME_END = new ErrorCode(1_013_011_005, "拼团失败,活动已经结束");
79   - ErrorCode COMBINATION_RECORD_FAILED_SINGLE_LIMIT_COUNT_EXCEED = new ErrorCode(1_013_011_006, "拼团失败,原因:单次限购超出");
80   - ErrorCode COMBINATION_RECORD_FAILED_TOTAL_LIMIT_COUNT_EXCEED = new ErrorCode(1_013_011_007, "拼团失败,原因:超出总购买次数");
81   - // ========== 拼团记录 1013011000 ==========
82   - ErrorCode COMBINATION_RECORD_NOT_EXISTS = new ErrorCode(1013011000, "拼团不存在");
83   - ErrorCode COMBINATION_RECORD_EXISTS = new ErrorCode(1013011001, "拼团失败,已参与过该拼团");
84   - ErrorCode COMBINATION_RECORD_HEAD_NOT_EXISTS = new ErrorCode(1013011002, "拼团失败,父拼团不存在");
85   - ErrorCode COMBINATION_RECORD_USER_FULL = new ErrorCode(1013011003, "拼团失败,拼团人数已满");
86   - ErrorCode COMBINATION_RECORD_FAILED_HAVE_JOINED = new ErrorCode(1013011004, "拼团失败,已参与其它拼团");
87   - ErrorCode COMBINATION_RECORD_FAILED_TIME_NOT_START = new ErrorCode(1013011005, "拼团失败,活动未开始");
88   - ErrorCode COMBINATION_RECORD_FAILED_TIME_END = new ErrorCode(1013011006, "拼团失败,活动已经结束");
89   - ErrorCode COMBINATION_RECORD_FAILED_SINGLE_LIMIT_COUNT_EXCEED = new ErrorCode(1013011007, "拼团失败,原因:单次限购超出");
90   - ErrorCode COMBINATION_RECORD_FAILED_TOTAL_LIMIT_COUNT_EXCEED = new ErrorCode(1013011008, "拼团失败,原因:超出总购买次数");
  78 + ErrorCode COMBINATION_RECORD_FAILED_TIME_NOT_START = new ErrorCode(1_013_011_005, "拼团失败,活动未开始");
  79 + ErrorCode COMBINATION_RECORD_FAILED_TIME_END = new ErrorCode(1_013_011_006, "拼团失败,活动已经结束");
  80 + ErrorCode COMBINATION_RECORD_FAILED_SINGLE_LIMIT_COUNT_EXCEED = new ErrorCode(1_013_011_007, "拼团失败,原因:单次限购超出");
  81 + ErrorCode COMBINATION_RECORD_FAILED_TOTAL_LIMIT_COUNT_EXCEED = new ErrorCode(1_013_011_008, "拼团失败,原因:超出总购买次数");
  82 + ErrorCode COMBINATION_RECORD_FAILED_ORDER_STATUS_UNPAID = new ErrorCode(1_013_011_009, "拼团失败,原因:存在未支付订单,请先支付");
91 83  
92 84 // ========== 砍价活动 1-013-012-000 ==========
93 85 ErrorCode BARGAIN_ACTIVITY_NOT_EXISTS = new ErrorCode(1_013_012_000, "砍价活动不存在");
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/bargain/BargainRecordApiImpl.java
... ... @@ -16,9 +16,4 @@ public class BargainRecordApiImpl implements BargainRecordApi {
16 16  
17 17 }
18 18  
19   - @Override
20   - public boolean isBargainRecordSuccess(Long userId, Long orderId) {
21   - return false;
22   - }
23   -
24 19 }
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/combination/CombinationActivityConvert.java
... ... @@ -97,8 +97,8 @@ public interface CombinationActivityConvert {
97 97 default CombinationRecordDO convert(CombinationRecordCreateReqDTO reqDTO,
98 98 CombinationActivityDO activity, MemberUserRespDTO user,
99 99 ProductSpuRespDTO spu, ProductSkuRespDTO sku) {
100   - // TODO @puhui999:订单付款后需要设置开始时间和结束时间;
101 100 return convert(reqDTO)
  101 + .setCount(reqDTO.getCount())
102 102 .setVirtualGroup(false)
103 103 .setExpireTime(activity.getStartTime().plusHours(activity.getLimitDuration()))
104 104 .setUserSize(activity.getUserSize())
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/combination/CombinationRecordDO.java
... ... @@ -62,6 +62,10 @@ public class CombinationRecordDO extends BaseDO {
62 62 * SKU 编号
63 63 */
64 64 private Long skuId;
  65 + /**
  66 + * 购买的商品数量
  67 + */
  68 + private Integer count;
65 69  
66 70 /**
67 71 * 用户编号
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/bargain/BargainActivityServiceImpl.java
... ... @@ -116,10 +116,10 @@ public class BargainActivityServiceImpl implements BargainActivityService {
116 116 public void deleteBargainActivity(Long id) {
117 117 // 校验存在
118 118 BargainActivityDO activityDO = validateBargainActivityExists(id);
119   - // 校验状态 TODO puhui: 测试完成后需要恢复校验
120   - //if (ObjectUtil.equal(activityDO.getStatus(), CommonStatusEnum.ENABLE.getStatus())) {
121   - // throw exception(BARGAIN_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END);
122   - //}
  119 + // 校验状态
  120 + if (ObjectUtil.equal(activityDO.getStatus(), CommonStatusEnum.ENABLE.getStatus())) {
  121 + throw exception(BARGAIN_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END);
  122 + }
123 123  
124 124 // 删除
125 125 bargainActivityMapper.deleteById(id);
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationRecordServiceImpl.java
... ... @@ -16,6 +16,7 @@ import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationR
16 16 import cn.iocoder.yudao.module.promotion.dal.mysql.combination.CombinationRecordMapper;
17 17 import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum;
18 18 import cn.iocoder.yudao.module.trade.api.order.TradeOrderApi;
  19 +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum;
19 20 import org.springframework.context.annotation.Lazy;
20 21 import org.springframework.stereotype.Service;
21 22 import org.springframework.transaction.annotation.Transactional;
... ... @@ -26,7 +27,7 @@ import java.time.LocalDateTime;
26 27 import java.util.List;
27 28  
28 29 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
29   -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
  30 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
30 31 import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
31 32  
32 33 // TODO 芋艿:等拼团记录做完,完整 review 下
... ... @@ -101,7 +102,6 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
101 102 return recordDO;
102 103 }
103 104  
104   - // TODO @puhui999:有一个应该在创建那要做下;就是当前 activityId 已经有未支付的订单,不允许在发起新的;要么支付,要么去掉先;
105 105 @Override
106 106 public void validateCombinationRecord(Long activityId, Long userId, Long skuId, Integer count) {
107 107 // 1.1 校验拼团活动是否存在
... ... @@ -110,55 +110,69 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
110 110 if (ObjectUtil.equal(activity.getStatus(), CommonStatusEnum.DISABLE.getStatus())) {
111 111 throw exception(COMBINATION_ACTIVITY_STATUS_DISABLE);
112 112 }
113   - // 1.3 校验是否超出单次限购数量
  113 + // 2 校验是否超出单次限购数量
114 114 if (count > activity.getSingleLimitCount()) {
115 115 throw exception(COMBINATION_RECORD_FAILED_SINGLE_LIMIT_COUNT_EXCEED);
116 116 }
117   -
118   - // 2. 校验是否超出总限购数量
  117 + // 3、校验是否有拼团记录
119 118 List<CombinationRecordDO> recordList = getRecordListByUserIdAndActivityId(userId, activityId);
120 119 if (CollUtil.isEmpty(recordList)) {
121 120 return;
122 121 }
123   - // 过滤出拼团成功的
124   - // TODO @puhui999:count 要不存一个在 record 里?
125   - List<Long> skuIds = convertList(recordList, CombinationRecordDO::getSkuId,
126   - item -> ObjectUtil.equals(item.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus()));
127   - Integer countSum = tradeOrderApi.getOrderItemCountSumByOrderIdAndSkuId(convertList(recordList,
128   - CombinationRecordDO::getOrderId,
129   - item -> ObjectUtil.equals(item.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus())), skuIds);
130   - if (activity.getTotalLimitCount() < countSum) {
  122 + // 4、校验是否超出总限购数量
  123 + Integer sumValue = getSumValue(convertList(recordList, CombinationRecordDO::getCount,
  124 + item -> ObjectUtil.equals(item.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus())), i -> i, Integer::sum);
  125 + if ((sumValue + count) > activity.getTotalLimitCount()) {
131 126 throw exception(COMBINATION_RECORD_FAILED_TOTAL_LIMIT_COUNT_EXCEED);
132 127 }
  128 + // 5、校验拼团记录是否存在未支付的订单(如果存在未支付的订单则不允许发起新的拼团)
  129 + CombinationRecordDO record = findFirst(recordList, item -> ObjectUtil.equals(item.getStatus(), null));
  130 + if (record == null) {
  131 + return;
  132 + }
  133 + // 5.1、查询关联的订单是否已经支付
  134 + // 当前 activityId 已经有未支付的订单,不允许在发起新的;要么支付,要么去掉先;
  135 + Integer orderStatus = tradeOrderApi.getOrderStatus(record.getOrderId());
  136 + if (ObjectUtil.equal(orderStatus, TradeOrderStatusEnum.UNPAID.getStatus())) {
  137 + throw exception(COMBINATION_RECORD_FAILED_ORDER_STATUS_UNPAID);
  138 + }
133 139 }
134 140  
135 141 @Override
136 142 @Transactional(rollbackFor = Exception.class)
137 143 public void createCombinationRecord(CombinationRecordCreateReqDTO reqDTO) {
138   - // 1.1 校验拼团活动
139   - CombinationActivityDO activity = combinationActivityService.validateCombinationActivityExists(reqDTO.getActivityId());
140   - // 1.2 需要校验下,他当前是不是已经参加了该拼团;
141   - // TODO @puhui999:拼团应该可以重复参加;应该去校验总共的上限哈,就是 activity.totalLimitCount
142   - List<CombinationRecordDO> records = recordMapper.selectListByUserId(reqDTO.getUserId());
143   - List<Long> orderIds = convertList(records, CombinationRecordDO::getOrderId);
144   - // 1.2.1 如果存在订单才去校验
145   - if (CollUtil.isNotEmpty(orderIds)) {
146 144  
  145 + // 1.1、 校验拼团活动
  146 + CombinationActivityDO activity = combinationActivityService.validateCombinationActivityExists(reqDTO.getActivityId());
  147 + // 1.2 校验是否超出单次限购数量
  148 + if (reqDTO.getCount() > activity.getSingleLimitCount()) {
  149 + throw exception(COMBINATION_RECORD_FAILED_SINGLE_LIMIT_COUNT_EXCEED);
  150 + }
  151 + // 1.3、校验是否有拼团记录
  152 + List<CombinationRecordDO> records = getRecordListByUserIdAndActivityId(reqDTO.getUserId(), reqDTO.getActivityId());
  153 + if (CollUtil.isEmpty(records)) {
  154 + return;
147 155 }
148   - // 1.3 校验用户是否参加了其它拼团
  156 + // 1.4、校验是否超出总限购数量
  157 + Integer sumValue = getSumValue(convertList(records, CombinationRecordDO::getCount,
  158 + item -> ObjectUtil.equals(item.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus())), i -> i, Integer::sum);
  159 + if ((sumValue + reqDTO.getCount()) > activity.getTotalLimitCount()) {
  160 + throw exception(COMBINATION_RECORD_FAILED_TOTAL_LIMIT_COUNT_EXCEED);
  161 + }
  162 + // 2、 校验用户是否参加了其它拼团
149 163 List<CombinationRecordDO> recordDOList = recordMapper.selectListByUserIdAndStatus(reqDTO.getUserId(), CombinationRecordStatusEnum.IN_PROGRESS.getStatus());
150 164 if (CollUtil.isNotEmpty(recordDOList)) {
151 165 throw exception(COMBINATION_RECORD_FAILED_HAVE_JOINED);
152 166 }
153   - // 1、4 校验活动是否开启
  167 + // 3、 校验活动是否开启
154 168 if (LocalDateTime.now().isAfter(activity.getStartTime())) {
155 169 throw exception(COMBINATION_RECORD_FAILED_TIME_NOT_START);
156 170 }
157   - // 1.5 校验当前活动是否过期
  171 + // 4、 校验当前活动是否过期
158 172 if (LocalDateTime.now().isAfter(activity.getEndTime())) {
159 173 throw exception(COMBINATION_RECORD_FAILED_TIME_END);
160 174 }
161   - // 1.6 父拼团是否存在,是否已经满了
  175 + // 5、 父拼团是否存在,是否已经满了
162 176 if (reqDTO.getHeadId() != null) {
163 177 // 查询进行中的父拼团
164 178 CombinationRecordDO record = recordMapper.selectOneByHeadId(reqDTO.getHeadId(), CombinationRecordStatusEnum.IN_PROGRESS.getStatus());
... ... @@ -171,8 +185,6 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
171 185 }
172 186 }
173 187  
174   - // TODO @puhui999:单次限购
175   -
176 188 // 2. 创建拼团记录
177 189 MemberUserRespDTO user = memberUserApi.getUser(reqDTO.getUserId());
178 190 ProductSpuRespDTO spu = productSpuApi.getSpu(reqDTO.getSpuId());
... ...
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   -
5 3 /**
6 4 * 订单 API 接口
7 5 *
... ... @@ -10,21 +8,11 @@ import java.util.Collection;
10 8 public interface TradeOrderApi {
11 9  
12 10 /**
13   - * 验证订单
14   - *
15   - * @param userId 用户 id
16   - * @param orderItemId 订单项 id
17   - * @return 校验通过返回订单 id
18   - */
19   - Long validateOrder(Long userId, Long orderItemId);
20   -
21   - /**
22   - * 获取订单项商品购买数量总和
  11 + * 获取订单状态
23 12 *
24   - * @param orderIds 订单编号
25   - * @param skuIds sku 编号
26   - * @return 订单项商品购买数量总和
  13 + * @param id 订单编号
  14 + * @return 订单状态
27 15 */
28   - Integer getOrderItemCountSumByOrderIdAndSkuId(Collection<Long> orderIds, Collection<Long> skuIds);
  16 + Integer getOrderStatus(Long id);
29 17  
30 18 }
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/api/order/TradeOrderApiImpl.java
1 1 package cn.iocoder.yudao.module.trade.api.order;
2 2  
3   -import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
  3 +import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
4 4 import cn.iocoder.yudao.module.trade.service.order.TradeOrderQueryService;
5 5 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;
10 9  
11 10 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
12   -import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.ORDER_ITEM_NOT_FOUND;
  11 +import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.ORDER_NOT_FOUND;
13 12  
14 13 /**
15 14 * 订单 API 接口实现类
... ... @@ -24,18 +23,12 @@ public class TradeOrderApiImpl implements TradeOrderApi {
24 23 private TradeOrderQueryService tradeOrderQueryService;
25 24  
26 25 @Override
27   - public Long validateOrder(Long userId, Long orderItemId) {
28   - // 校验订单项,订单项存在订单就存在
29   - TradeOrderItemDO item = tradeOrderQueryService.getOrderItem(userId, orderItemId);
30   - if (item == null) {
31   - throw exception(ORDER_ITEM_NOT_FOUND);
  26 + public Integer getOrderStatus(Long id) {
  27 + TradeOrderDO order = tradeOrderQueryService.getOrder(id);
  28 + if (order == null) {
  29 + throw exception(ORDER_NOT_FOUND);
32 30 }
33   - return item.getOrderId();
34   - }
35   -
36   - @Override
37   - public Integer getOrderItemCountSumByOrderIdAndSkuId(Collection<Long> orderIds, Collection<Long> skuIds) {
38   - return tradeOrderQueryService.getOrderItemCountSumByOrderIdAndSkuId(orderIds, skuIds);
  31 + return order.getStatus();
39 32 }
40 33  
41 34 }
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/AppTradeOrderSettlementReqVO.java
... ... @@ -16,6 +16,7 @@ import java.util.List;
16 16  
17 17 @Schema(description = "用户 App - 交易订单结算 Request VO")
18 18 @Data
  19 +@Valid
19 20 public class AppTradeOrderSettlementReqVO {
20 21  
21 22 @Schema(description = "商品项数组", requiredMode = Schema.RequiredMode.REQUIRED)
... ... @@ -62,7 +63,16 @@ public class AppTradeOrderSettlementReqVO {
62 63 @Schema(description = "砍价活动编号", example = "123")
63 64 private Long bargainActivityId;
64 65  
65   - // TODO @puhui999:可以写个参数校验,如果 seckillActivityId 或 combinationActivityId 或 combinationHeadId 的情况,items 应该只有一个
  66 + @AssertTrue(message = "活动商品每次只能购买一种规格")
  67 + @JsonIgnore
  68 + public boolean isValidActivityItems() {
  69 + // 校验是否是活动订单
  70 + if (seckillActivityId == null && combinationActivityId == null && combinationHeadId == null) {
  71 + return true;
  72 + }
  73 + // 校验订单项是否超出
  74 + return items.size() == 1;
  75 + }
66 76  
67 77 @Data
68 78 @Schema(description = "用户 App - 商品项")
... ... @@ -70,7 +80,9 @@ public class AppTradeOrderSettlementReqVO {
70 80 public static class Item {
71 81  
72 82 @Schema(description = "商品 SKU 编号", example = "2048")
  83 + @NotNull(message = "商品 SKU 编号不能为空")
73 84 private Long skuId;
  85 +
74 86 @Schema(description = "购买数量", example = "1")
75 87 @Min(value = 1, message = "购买数量最小值为 {value}")
76 88 private Integer count;
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java
... ... @@ -93,6 +93,7 @@ public interface TradeOrderConvert {
93 93 new ProductSkuUpdateStockReqDTO.Item().setId(item.getSkuId()).setIncrCount(item.getCount()));
94 94 return new ProductSkuUpdateStockReqDTO(items);
95 95 }
  96 +
96 97 default ProductSkuUpdateStockReqDTO convertNegative(List<AppTradeOrderSettlementReqVO.Item> list) {
97 98 List<ProductSkuUpdateStockReqDTO.Item> items = CollectionUtils.convertList(list, item ->
98 99 new ProductSkuUpdateStockReqDTO.Item().setId(item.getSkuId()).setIncrCount(-item.getCount()));
... ... @@ -251,17 +252,6 @@ public interface TradeOrderConvert {
251 252  
252 253 AppTradeOrderSettlementRespVO convert0(TradePriceCalculateRespBO calculate, AddressRespDTO address);
253 254  
254   - @Mappings({
255   - @Mapping(target = "activityId", source = "afterOrderCreateReqBO.combinationActivityId"),
256   - @Mapping(target = "spuId", source = "afterOrderCreateReqBO.spuId"),
257   - @Mapping(target = "skuId", source = "afterOrderCreateReqBO.skuId"),
258   - @Mapping(target = "orderId", source = "afterOrderCreateReqBO.orderId"),
259   - @Mapping(target = "userId", source = "afterOrderCreateReqBO.userId"),
260   - @Mapping(target = "headId", source = "afterOrderCreateReqBO.combinationHeadId"),
261   - @Mapping(target = "combinationPrice", source = "afterOrderCreateReqBO.payPrice"),
262   - })
263   - CombinationRecordCreateReqDTO convert(TradeAfterOrderCreateReqBO afterOrderCreateReqBO);
264   -
265 255 List<AppOrderExpressTrackRespDTO> convertList02(List<ExpressTrackRespDTO> list);
266 256  
267 257 TradeOrderDO convert(TradeOrderUpdateAddressReqVO reqVO);
... ... @@ -282,18 +272,36 @@ public interface TradeOrderConvert {
282 272 return bo;
283 273 }
284 274  
285   - TradeBeforeOrderCreateReqBO convert(AppTradeOrderCreateReqVO createReqVO);
  275 + @Mappings({
  276 + @Mapping(target = "userId", source = "userId"),
  277 + @Mapping(target = "orderType", source = "calculateRespBO.type"),
  278 + @Mapping(target = "items", source = "createReqVO.items"),
  279 + })
  280 + TradeBeforeOrderCreateReqBO convert(Long userId, AppTradeOrderCreateReqVO createReqVO, TradePriceCalculateRespBO calculateRespBO);
  281 +
  282 +
  283 + List<TradeAfterOrderCreateReqBO.Item> convertList(List<TradeOrderItemDO> orderItems);
  284 +
286 285  
287 286 @Mappings({
288   - @Mapping(target = "combinationActivityId", source = "createReqVO.combinationActivityId"),
289   - @Mapping(target = "combinationHeadId", source = "createReqVO.combinationHeadId"),
290   - @Mapping(target = "spuId", source = "orderItem.spuId"),
291   - @Mapping(target = "skuId", source = "orderItem.skuId"),
292   - @Mapping(target = "orderId", source = "tradeOrderDO.id"),
293 287 @Mapping(target = "userId", source = "userId"),
  288 + @Mapping(target = "orderId", source = "tradeOrderDO.id"),
294 289 @Mapping(target = "payPrice", source = "tradeOrderDO.payPrice"),
  290 + @Mapping(target = "items", source = "orderItems"),
295 291 })
296 292 TradeAfterOrderCreateReqBO convert(Long userId, AppTradeOrderCreateReqVO createReqVO,
297   - TradeOrderDO tradeOrderDO, TradeOrderItemDO orderItem);
  293 + TradeOrderDO tradeOrderDO, List<TradeOrderItemDO> orderItems);
  294 +
  295 + @Mappings({
  296 + @Mapping(target = "activityId", source = "combinationActivityId"),
  297 + @Mapping(target = "spuId", expression = "java(reqBO.getItems().get(0).getSpuId())"),
  298 + @Mapping(target = "skuId", expression = "java(reqBO.getItems().get(0).getSkuId())"),// TODO 艿艿看看这里
  299 + @Mapping(target = "count", expression = "java(reqBO.getItems().get(0).getCount())"),
  300 + @Mapping(target = "orderId", source = "orderId"),
  301 + @Mapping(target = "userId", source = "userId"),
  302 + @Mapping(target = "headId", source = "combinationHeadId"),
  303 + @Mapping(target = "combinationPrice", source = "payPrice")
  304 + })
  305 + CombinationRecordCreateReqDTO convert(TradeAfterOrderCreateReqBO reqBO);
298 306  
299 307 }
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/order/TradeOrderItemMapper.java
... ... @@ -26,12 +26,6 @@ public interface TradeOrderItemMapper extends BaseMapperX&lt;TradeOrderItemDO&gt; {
26 26 return selectList(TradeOrderItemDO::getOrderId, orderIds);
27 27 }
28 28  
29   - default List<TradeOrderItemDO> selectListByOrderIdAnSkuId(Collection<Long> orderIds, Collection<Long> skuIds) {
30   - return selectList(new LambdaQueryWrapperX<TradeOrderItemDO>()
31   - .in(TradeOrderItemDO::getOrderId, orderIds)
32   - .in(TradeOrderItemDO::getSkuId, skuIds));
33   - }
34   -
35 29 default TradeOrderItemDO selectByIdAndUserId(Long orderItemId, Long loginUserId) {
36 30 return selectOne(new LambdaQueryWrapperX<TradeOrderItemDO>()
37 31 .eq(TradeOrderItemDO::getId, orderItemId)
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderQueryService.java
... ... @@ -119,13 +119,5 @@ public interface TradeOrderQueryService {
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 123 }
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderQueryServiceImpl.java
... ... @@ -4,7 +4,6 @@ import cn.hutool.core.collection.CollUtil;
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;
8 7 import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
9 8 import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
10 9 import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderPageReqVO;
... ... @@ -168,10 +167,4 @@ public class TradeOrderQueryServiceImpl implements TradeOrderQueryService {
168 167 return tradeOrderItemMapper.selectListByOrderId(orderIds);
169 168 }
170 169  
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   -
177 170 }
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java
... ... @@ -60,7 +60,6 @@ import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressService;
60 60 import cn.iocoder.yudao.module.trade.service.message.TradeMessageService;
61 61 import cn.iocoder.yudao.module.trade.service.message.bo.TradeOrderMessageWhenDeliveryOrderReqBO;
62 62 import cn.iocoder.yudao.module.trade.service.order.bo.TradeAfterPayOrderReqBO;
63   -import cn.iocoder.yudao.module.trade.service.order.bo.TradeBeforeOrderCreateReqBO;
64 63 import cn.iocoder.yudao.module.trade.service.order.handler.TradeOrderHandler;
65 64 import cn.iocoder.yudao.module.trade.service.price.TradePriceService;
66 65 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO;
... ... @@ -254,12 +253,9 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
254 253 private void beforeCreateTradeOrder(Long userId, AppTradeOrderCreateReqVO createReqVO,
255 254 TradePriceCalculateRespBO calculateRespBO) {
256 255 // 1. 执行订单创建前置处理器
257   - TradeBeforeOrderCreateReqBO beforeOrderCreateReqBO = TradeOrderConvert.INSTANCE.convert(createReqVO);
258   - beforeOrderCreateReqBO.setOrderType(calculateRespBO.getType());
259   - beforeOrderCreateReqBO.setUserId(userId);
260   - beforeOrderCreateReqBO.setCount(getSumValue(createReqVO.getItems(), AppTradeOrderSettlementReqVO.Item::getCount, Integer::sum));
261 256 // TODO @puhui999:这里有个纠结点;handler 的定义是只处理指定类型的订单的拓展逻辑;还是通用的 handler,类似可以处理优惠劵等等
262   - tradeOrderHandlers.forEach(handler -> handler.beforeOrderCreate(beforeOrderCreateReqBO));
  257 + tradeOrderHandlers.forEach(handler ->
  258 + handler.beforeOrderCreate(TradeOrderConvert.INSTANCE.convert(userId, createReqVO, calculateRespBO)));
263 259  
264 260 // 2. 下单时扣减商品库存
265 261 productSkuApi.updateSkuStock(TradeOrderConvert.INSTANCE.convertNegative(createReqVO.getItems()));
... ... @@ -279,9 +275,8 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
279 275 TradeOrderDO order, List<TradeOrderItemDO> orderItems,
280 276 TradePriceCalculateRespBO calculateRespBO) {
281 277 // 1. 执行订单创建后置处理器
282   - // TODO @puhui999:从通用性来说,应该不用 orderItems.get(0)
283 278 tradeOrderHandlers.forEach(handler -> handler.afterOrderCreate(
284   - TradeOrderConvert.INSTANCE.convert(userId, createReqVO, order, orderItems.get(0))));
  279 + TradeOrderConvert.INSTANCE.convert(userId, createReqVO, order, orderItems)));
285 280  
286 281 // 2. 有使用优惠券时更新
287 282 // 不在前置扣减的原因,是因为优惠劵要记录使用的订单号
... ... @@ -467,14 +462,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
467 462 throw exception(ORDER_DELIVERY_FAIL_COMBINATION_RECORD_STATUS_NOT_SUCCESS);
468 463 }
469 464 }
470   - // 订单类类型:砍价
471   - if (Objects.equals(TradeOrderTypeEnum.BARGAIN.getType(), order.getType())) {
472   - // 校验订单砍价是否成功
473   - // TODO @puhui999:砍价的话,应该不用校验。因为是砍价成功后,才可以下单
474   - if (!bargainRecordApi.isBargainRecordSuccess(order.getUserId(), order.getId())) {
475   - throw exception(ORDER_DELIVERY_FAIL_BARGAIN_RECORD_STATUS_NOT_SUCCESS);
476   - }
477   - }
  465 +
478 466 return order;
479 467 }
480 468  
... ... @@ -641,8 +629,6 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
641 629 }
642 630  
643 631 // 2. TODO 活动相关库存回滚需要活动 id,活动 id 怎么获取?app 端能否传过来;回复:从订单里拿呀
644   - tradeOrderHandlers.forEach(handler -> handler.rollback());
645   - // 3. TODO 活动相关库存回滚需要活动 id,活动 id 怎么获取?app 端能否传过来;回复:从订单里拿呀
646 632 tradeOrderHandlers.forEach(handler -> handler.cancelOrder());
647 633  
648 634 // 3. 回滚库存
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/bo/TradeAfterOrderCreateReqBO.java
1 1 package cn.iocoder.yudao.module.trade.service.order.bo;
2 2  
3   -import io.swagger.v3.oas.annotations.media.Schema;
4 3 import lombok.Data;
5 4  
  5 +import javax.validation.Valid;
6 6 import javax.validation.constraints.NotNull;
  7 +import java.util.List;
7 8  
8 9 // TODO 芋艿:在想想这些参数的定义
9 10 /**
... ... @@ -16,25 +17,71 @@ public class TradeAfterOrderCreateReqBO {
16 17  
17 18 // ========== 拼团活动相关字段 ==========
18 19  
19   - @Schema(description = "拼团活动编号", example = "1024")
  20 + /**
  21 + * 拼团活动编号
  22 + */
20 23 private Long combinationActivityId;
21 24  
22   - @Schema(description = "拼团团长编号", example = "2048")
  25 + /**
  26 + * 拼团团长编号
  27 + */
23 28 private Long combinationHeadId;
24 29  
25   - @NotNull(message = "SPU 编号不能为空")
26   - private Long spuId;
27   -
28   - @NotNull(message = "SKU 编号活动商品不能为空")
29   - private Long skuId;
30   -
  30 + /**
  31 + * 订单编号
  32 + */
31 33 @NotNull(message = "订单编号不能为空")
32 34 private Long orderId;
33 35  
  36 + /**
  37 + * 用户编号
  38 + */
34 39 @NotNull(message = "用户编号不能为空")
35 40 private Long userId;
36 41  
  42 + /**
  43 + * 支付金额
  44 + */
37 45 @NotNull(message = "支付金额不能为空")
38 46 private Integer payPrice;
39 47  
  48 + // ========== 购买商品相关字段 ==========
  49 +
  50 + /**
  51 + * 订单购买的商品信息
  52 + */
  53 + private List<Item> items;
  54 +
  55 + /**
  56 + * 订单商品信息
  57 + * 记录购买商品的简要核心信息
  58 + *
  59 + * @author HUIHUI
  60 + */
  61 + @Data
  62 + @Valid
  63 + public static class Item {
  64 +
  65 + /**
  66 + * SPU 编号
  67 + */
  68 + @NotNull(message = "SPU 编号不能为空")
  69 + private Long spuId;
  70 +
  71 + /**
  72 + * 商品 SKU 编号
  73 + *
  74 + * 关联 ProductSkuDO 的 id 编号
  75 + */
  76 + @NotNull(message = "SKU 编号活动商品不能为空")
  77 + private Long skuId;
  78 +
  79 + /**
  80 + * 购买的商品数量
  81 + */
  82 + @NotNull(message = "购买数量不能为空")
  83 + private Integer count;
  84 +
  85 + }
  86 +
40 87 }
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/bo/TradeBeforeOrderCreateReqBO.java
1 1 package cn.iocoder.yudao.module.trade.service.order.bo;
2 2  
3 3 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
4   -import io.swagger.v3.oas.annotations.media.Schema;
5 4 import lombok.Data;
6 5  
  6 +import javax.validation.Valid;
7 7 import javax.validation.constraints.NotNull;
8   -
  8 +import java.util.List;
9 9 // TODO 芋艿:在想想这些参数的定义
  10 +
10 11 /**
11 12 * 订单创建之前 Request BO
12 13 *
... ... @@ -34,9 +35,8 @@ public class TradeBeforeOrderCreateReqBO {
34 35 // ========== 秒杀活动相关字段 ==========
35 36  
36 37 /**
37   - *
  38 + * 秒杀活动编号
38 39 */
39   - @Schema(description = "秒杀活动编号", example = "1024")
40 40 private Long seckillActivityId;
41 41  
42 42 // ========== 拼团活动相关字段 ==========
... ... @@ -44,13 +44,11 @@ public class TradeBeforeOrderCreateReqBO {
44 44 /**
45 45 * 拼团活动编号
46 46 */
47   - @Schema(description = "拼团活动编号", example = "1024")
48 47 private Long combinationActivityId;
49 48  
50 49 /**
51 50 * 拼团团长编号
52 51 */
53   - @Schema(description = "拼团团长编号", example = "2048")
54 52 private Long combinationHeadId;
55 53  
56 54 // ========== 砍价活动相关字段 ==========
... ... @@ -58,31 +56,39 @@ public class TradeBeforeOrderCreateReqBO {
58 56 /**
59 57 * 砍价活动编号
60 58 */
61   - @Schema(description = "砍价活动编号", example = "123")
62 59 private Long bargainActivityId;
63 60  
64   - // ========== 活动购买商品相关字段 ==========
  61 + // ========== 购买商品相关字段 ==========
65 62  
66 63 /**
67   - * 商品 SPU 编号
68   - *
69   - * 关联 ProductSkuDO 的 spuId 编号
  64 + * 订单购买的商品信息
70 65 */
71   - @NotNull(message = "SPU 编号不能为空")
72   - private Long spuId;
  66 + private List<Item> items;
73 67  
74 68 /**
75   - * 商品 SKU 编号
  69 + * 订单商品信息
  70 + * 记录购买商品的简要核心信息
76 71 *
77   - * 关联 ProductSkuDO 的 id 编号
78   - */
79   - @NotNull(message = "SKU 编号活动商品不能为空")
80   - private Long skuId;
81   -
82   - /**
83   - * 购买的商品数量
  72 + * @author HUIHUI
84 73 */
85   - @NotNull(message = "购买数量不能为空")
86   - private Integer count;
  74 + @Data
  75 + @Valid
  76 + public static class Item {
  77 +
  78 + /**
  79 + * 商品 SKU 编号
  80 + *
  81 + * 关联 ProductSkuDO 的 id 编号
  82 + */
  83 + @NotNull(message = "SKU 编号活动商品不能为空")
  84 + private Long skuId;
  85 +
  86 + /**
  87 + * 购买的商品数量
  88 + */
  89 + @NotNull(message = "购买数量不能为空")
  90 + private Integer count;
  91 +
  92 + }
87 93  
88 94 }
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeBargainHandler.java
... ... @@ -29,8 +29,11 @@ public class TradeBargainHandler extends TradeOrderDefaultHandler {
29 29 if (ObjectUtil.notEqual(TradeOrderTypeEnum.BARGAIN.getType(), reqBO.getOrderType())) {
30 30 return;
31 31 }
  32 +
  33 + // 获取商品信息
  34 + TradeBeforeOrderCreateReqBO.Item item = reqBO.getItems().get(0);
32 35 // 扣减砍价活动的库存
33   - bargainActivityApi.updateBargainActivityStock(reqBO.getBargainActivityId(), reqBO.getCount());
  36 + bargainActivityApi.updateBargainActivityStock(reqBO.getBargainActivityId(), item.getCount());
34 37 }
35 38  
36 39 }
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeCombinationHandler.java
... ... @@ -29,8 +29,10 @@ public class TradeCombinationHandler extends TradeOrderDefaultHandler {
29 29 return;
30 30 }
31 31  
  32 + // 获取商品信息
  33 + TradeBeforeOrderCreateReqBO.Item item = reqBO.getItems().get(0);
32 34 // 校验是否满足拼团活动相关限制
33   - combinationRecordApi.validateCombinationRecord(reqBO.getCombinationActivityId(), reqBO.getUserId(), reqBO.getSkuId(), reqBO.getCount());
  35 + combinationRecordApi.validateCombinationRecord(reqBO.getCombinationActivityId(), reqBO.getUserId(), item.getSkuId(), item.getCount());
34 36 }
35 37  
36 38 @Override
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeSeckillHandler.java
... ... @@ -29,8 +29,11 @@ public class TradeSeckillHandler extends TradeOrderDefaultHandler {
29 29 if (ObjectUtil.notEqual(TradeOrderTypeEnum.SECKILL.getType(), reqBO.getOrderType())) {
30 30 return;
31 31 }
  32 +
  33 + // 获取商品信息
  34 + TradeBeforeOrderCreateReqBO.Item item = reqBO.getItems().get(0);
32 35 // 扣减秒杀活动的库存
33   - seckillActivityApi.updateSeckillStock(reqBO.getSeckillActivityId(), reqBO.getSkuId(), reqBO.getCount());
  36 + seckillActivityApi.updateSeckillStock(reqBO.getSeckillActivityId(), item.getSkuId(), item.getCount());
34 37 }
35 38  
36 39 }
... ...