Commit bdd81e4cbc2e8a0dfc72756d6f6a865614e7bfe5

Authored by YunaiV
2 parents 82c6354e 950ec10c

Merge branch 'feature/mall_product' of https://gitee.com/puhui999/ruoyi-vue-pro …

…into feature/mall_product

 Conflicts:
	yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java
Showing 54 changed files with 816 additions and 374 deletions
yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/sku/dto/ProductSkuRespDTO.java
... ... @@ -59,15 +59,13 @@ public class ProductSkuRespDTO {
59 59 * 商品体积,单位:m^3 平米
60 60 */
61 61 private Double volume;
62   -
63   - // TODO @puhui:这 2 字段,需要改下;firstBrokerageRecord、secondBrokerageRecord;和分佣保持一致;
64 62 /**
65 63 * 一级分销的佣金,单位:分
66 64 */
67   - private Integer subCommissionFirstPrice;
  65 + private Integer firstBrokerageRecord;
68 66 /**
69 67 * 二级分销的佣金,单位:分
70 68 */
71   - private Integer subCommissionSecondPrice;
  69 + private Integer secondBrokerageRecord;
72 70  
73 71 }
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/sku/vo/ProductSkuBaseVO.java
... ... @@ -51,10 +51,10 @@ public class ProductSkuBaseVO {
51 51 private Double volume;
52 52  
53 53 @Schema(description = "一级分销的佣金,单位:分", example = "199")
54   - private Integer subCommissionFirstPrice;
  54 + private Integer firstBrokerageRecord;
55 55  
56 56 @Schema(description = "二级分销的佣金,单位:分", example = "19")
57   - private Integer subCommissionSecondPrice;
  57 + private Integer secondBrokerageRecord;
58 58  
59 59 @Schema(description = "属性数组")
60 60 private List<Property> properties;
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/sku/ProductSkuDO.java
... ... @@ -81,11 +81,11 @@ public class ProductSkuDO extends BaseDO {
81 81 /**
82 82 * 一级分销的佣金,单位:分
83 83 */
84   - private Integer subCommissionFirstPrice;
  84 + private Integer firstBrokerageRecord;
85 85 /**
86 86 * 二级分销的佣金,单位:分
87 87 */
88   - private Integer subCommissionSecondPrice;
  88 + private Integer secondBrokerageRecord;
89 89  
90 90 // ========== 营销相关字段 =========
91 91  
... ...
yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImplTest.java
... ... @@ -92,8 +92,8 @@ public class ProductSpuServiceImplTest extends BaseDbUnitTest {
92 92 o.setMarketPrice(generaInt());
93 93 o.setStock(generaInt());
94 94 o.setWarnStock(10);
95   - o.setSubCommissionFirstPrice(generaInt());
96   - o.setSubCommissionSecondPrice(generaInt());
  95 + o.setFirstBrokerageRecord(generaInt());
  96 + o.setSecondBrokerageRecord(generaInt());
97 97 // 限制分数为两位数
98 98 o.setWeight(RandomUtil.randomDouble(10,2, RoundingMode.HALF_UP));
99 99 o.setVolume(RandomUtil.randomDouble(10,2, RoundingMode.HALF_UP));
... ... @@ -143,8 +143,8 @@ public class ProductSpuServiceImplTest extends BaseDbUnitTest {
143 143 o.setMarketPrice(generaInt());
144 144 o.setStock(generaInt());
145 145 o.setWarnStock(10);
146   - o.setSubCommissionFirstPrice(generaInt());
147   - o.setSubCommissionSecondPrice(generaInt());
  146 + o.setFirstBrokerageRecord(generaInt());
  147 + o.setSecondBrokerageRecord(generaInt());
148 148 // 限制分数为两位数
149 149 o.setWeight(RandomUtil.randomDouble(10,2, RoundingMode.HALF_UP));
150 150 o.setVolume(RandomUtil.randomDouble(10,2, RoundingMode.HALF_UP));
... ...
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/bargain/BargainActivityApi.java
... ... @@ -10,9 +10,9 @@ public interface BargainActivityApi {
10 10 /**
11 11 * 更新砍价活动库存
12 12 *
13   - * @param activityId 砍价活动编号
  13 + * @param id 砍价活动编号
14 14 * @param count 购买数量
15 15 */
16   - void updateBargainActivityStock(Long activityId, Integer count);
  16 + void updateBargainActivityStock(Long id, Integer count);
17 17  
18 18 }
... ...
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,7 +2,8 @@ package cn.iocoder.yudao.module.promotion.api.seckill.dto;
2 2  
3 3 import lombok.Data;
4 4  
5   -import java.util.List;
  5 +import javax.validation.Valid;
  6 +import javax.validation.constraints.NotNull;
6 7  
7 8 /**
8 9 * 更新秒杀库存 request DTO
... ... @@ -12,37 +13,26 @@ import java.util.List;
12 13 @Data
13 14 public class SeckillActivityUpdateStockReqDTO {
14 15  
15   - // TODO @puhui999:参数校验
16   -
17   - // TODO @puhui999:秒杀的话,一次只能购买一种商品哈;不能多个哈;
18   -
19   - /**
20   - * 活动编号
21   - */
  16 + @NotNull(message = "活动编号不能为空")
22 17 private Long activityId;
23   - /**
24   - * 总购买数量
25   - */
  18 +
  19 + @NotNull(message = "购买数量不能为空")
26 20 private Integer count;
27   - /**
28   - * 活动商品
29   - */
30   - private List<Item> items;
  21 +
  22 + @NotNull(message = "活动商品不能为空")
  23 + private Item item;
31 24  
32 25 @Data
  26 + @Valid
33 27 public static class Item {
34 28  
35   - /**
36   - * SPU 编号
37   - */
  29 + @NotNull(message = "SPU 编号不能为空")
38 30 private Long spuId;
39   - /**
40   - * SKU 编号
41   - */
  31 +
  32 + @NotNull(message = "SKU 编号活动商品不能为空")
42 33 private Long skuId;
43   - /**
44   - * 购买数量
45   - */
  34 +
  35 + @NotNull(message = "购买数量不能为空")
46 36 private Integer count;
47 37  
48 38 }
... ...
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java
... ... @@ -55,7 +55,7 @@ public interface ErrorCodeConstants {
55 55 ErrorCode SECKILL_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED = new ErrorCode(1013008003, "秒杀活动已关闭,不能修改");
56 56 ErrorCode SECKILL_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END = new ErrorCode(1013008004, "秒杀活动未关闭或未结束,不能删除");
57 57 ErrorCode SECKILL_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED = new ErrorCode(1013008005, "秒杀活动已关闭,不能重复关闭");
58   - ErrorCode SECKILL_ACTIVITY_UPDATE_STOCK_FAIL = new ErrorCode(1013008006, "更新秒杀活动库存失败,原因秒杀库存不足");
  58 + ErrorCode SECKILL_ACTIVITY_UPDATE_STOCK_FAIL = new ErrorCode(1013008006, "秒杀失败,原因秒杀库存不足");
59 59  
60 60 // ========== 秒杀时段 1013009000 ==========
61 61 ErrorCode SECKILL_CONFIG_NOT_EXISTS = new ErrorCode(1013009000, "秒杀时段不存在");
... ... @@ -65,24 +65,26 @@ 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, "砍价活动不存在");
83 84 ErrorCode BARGAIN_ACTIVITY_SPU_CONFLICTS = new ErrorCode(1013012001, "存在商品参加了其它砍价活动");
84 85 ErrorCode BARGAIN_ACTIVITY_STATUS_DISABLE = new ErrorCode(1013012002, "砍价活动已关闭不能修改");
85 86 ErrorCode BARGAIN_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END = new ErrorCode(1013012003, "砍价活动未关闭或未结束,不能删除");
  87 + ErrorCode BARGAIN_ACTIVITY_UPDATE_STOCK_FAIL = new ErrorCode(1013012004, "砍价失败,原因:该砍价活动库存不足");
86 88  
87 89 // ========== 砍价记录 1013013000 ==========
88 90 ErrorCode BARGAIN_RECORD_NOT_EXISTS = new ErrorCode(1013013000, "砍价记录不存在");
... ...
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/bargain/BargainActivityApiImpl.java
1 1 package cn.iocoder.yudao.module.promotion.api.bargain;
2 2  
3   -import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityUpdateReqVO;
4   -import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainActivityDO;
5 3 import cn.iocoder.yudao.module.promotion.service.bargain.BargainActivityService;
6 4 import org.springframework.stereotype.Service;
7 5  
8 6 import javax.annotation.Resource;
9 7  
10   -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
11   -import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.BARGAIN_ACTIVITY_NOT_EXISTS;
12   -
13 8 /**
14 9 * 砍价活动 Api 接口实现类
15 10 *
... ... @@ -22,20 +17,8 @@ public class BargainActivityApiImpl implements BargainActivityApi {
22 17 private BargainActivityService bargainActivityService;
23 18  
24 19 @Override
25   - public void updateBargainActivityStock(Long activityId, Integer count) {
26   - // TODO @puhui999:可以整个实现到 bargainActivityService 中
27   - // 查询砍价活动
28   - BargainActivityDO activity = bargainActivityService.getBargainActivity(activityId);
29   - if (activity == null) {
30   - throw exception(BARGAIN_ACTIVITY_NOT_EXISTS);
31   - }
32   -
33   - // 更新砍价库存
34   - // TODO @puhui999:考虑下并发更新问题
35   - BargainActivityUpdateReqVO reqVO = new BargainActivityUpdateReqVO();
36   - reqVO.setId(activityId);
37   - reqVO.setStock(activity.getStock() - count);
38   - bargainActivityService.updateBargainActivity(reqVO);
  20 + public void updateBargainActivityStock(Long id, Integer count) {
  21 + bargainActivityService.updateBargainActivityStock(id, count);
39 22 }
40 23  
41 24 }
... ...
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/api/seckill/SeckillActivityApiImpl.java
1 1 package cn.iocoder.yudao.module.promotion.api.seckill;
2 2  
3   -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
4 3 import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillActivityUpdateStockReqDTO;
5   -import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillActivityDO;
6   -import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillProductDO;
7 4 import cn.iocoder.yudao.module.promotion.service.seckill.SeckillActivityService;
8 5 import org.springframework.stereotype.Service;
9 6  
10 7 import javax.annotation.Resource;
11   -import java.util.ArrayList;
12   -import java.util.HashMap;
13   -import java.util.List;
14   -import java.util.Map;
15   -
16   -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
17   -import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.SECKILL_ACTIVITY_UPDATE_STOCK_FAIL;
18 8  
19 9 /**
20 10 * 秒杀活动接口 Api 接口实现类
... ... @@ -27,58 +17,9 @@ public class SeckillActivityApiImpl implements SeckillActivityApi {
27 17 @Resource
28 18 private SeckillActivityService activityService;
29 19  
30   - // TODO @puhui:建议这块弄到 activityService 实现哈;
31   - // TODO @puhui:这个方法,要考虑事务性
32 20 @Override
33 21 public void updateSeckillStock(SeckillActivityUpdateStockReqDTO updateStockReqDTO) {
34   - // TODO @puhui999:长方法,最好有 1.1 1.2 2.1 这种步骤哈;
35   - SeckillActivityDO seckillActivity = activityService.getSeckillActivity(updateStockReqDTO.getActivityId());
36   - if (seckillActivity.getStock() < updateStockReqDTO.getCount()) {
37   - throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL);
38   - }
39   - // 获取活动商品
40   - // TODO @puhui999:在一个方法里,dos 和 dolist 最好保持一致,要么用 s,要么用 list 哈;
41   - List<SeckillProductDO> productDOs = activityService.getSeckillProductListByActivityId(updateStockReqDTO.getActivityId());
42   - // TODO @puhui999:这个是不是搞成 CollectionUtils.convertMultiMap()
43   - List<SeckillActivityUpdateStockReqDTO.Item> items = updateStockReqDTO.getItems();
44   - Map<Long, List<Long>> map = new HashMap<>();
45   - items.forEach(item -> {
46   - if (map.containsKey(item.getSpuId())) {
47   - List<Long> skuIds = map.get(item.getSpuId());
48   - skuIds.add(item.getSkuId());
49   - map.put(item.getSpuId(), skuIds);
50   - } else {
51   - List<Long> list = new ArrayList<>();
52   - list.add(item.getSkuId());
53   - map.put(item.getSpuId(), list);
54   - }
55   - });
56   - // 过滤出购买的商品
57   - // TODO @puhui999:productDOList 可以简化成 productList;一般来说,do 之类不用带着哈,在变量里;
58   - List<SeckillProductDO> productDOList = CollectionUtils.filterList(productDOs, item -> map.get(item.getSpuId()).contains(item.getSkuId()));
59   - Map<Long, SeckillActivityUpdateStockReqDTO.Item> productDOMap = CollectionUtils.convertMap(items, SeckillActivityUpdateStockReqDTO.Item::getSkuId, p -> p);
60   - // 检查活动商品库存是否充足
61   - // TODO @puhui999:避免 b 这种无业务含义的变量;
62   - boolean b = CollectionUtils.anyMatch(productDOList, item -> {
63   - SeckillActivityUpdateStockReqDTO.Item item1 = productDOMap.get(item.getSkuId());
64   - return (item.getStock() < item1.getCount()) || (item.getStock() - item1.getCount()) < 0;
65   - });
66   - if (b) {
67   - throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL);
68   - }
69   - // TODO @puhui999:类似 doList,应该和下面的 update 逻辑粘的更紧密一点;so 在空行的时候,应该挪到 74 之后里去;甚至更合理,应该是 79 之后;说白了,逻辑要分块,每个模块涉及的代码要紧密在一起;
70   - List<SeckillProductDO> doList = CollectionUtils.convertList(productDOList, item -> {
71   - item.setStock(item.getStock() - productDOMap.get(item.getSkuId()).getCount());
72   - return item;
73   - });
74   -
75   - // 更新活动库存
76   - // TODO @puhui999:考虑下并发更新
77   - seckillActivity.setStock(seckillActivity.getStock() + updateStockReqDTO.getCount());
78   - seckillActivity.setTotalStock(seckillActivity.getTotalStock() - updateStockReqDTO.getCount());
79   - activityService.updateSeckillActivity(seckillActivity);
80   - // 更新活动商品库存
81   - activityService.updateSeckillActivityProductList(doList);
  22 + activityService.updateSeckillStock(updateStockReqDTO);
82 23 }
83 24  
84 25 }
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/bargain/BargainActivityMapper.java
... ... @@ -5,6 +5,7 @@ import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
5 5 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
6 6 import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityPageReqVO;
7 7 import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainActivityDO;
  8 +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
8 9 import org.apache.ibatis.annotations.Mapper;
9 10  
10 11 import java.util.List;
... ... @@ -28,4 +29,18 @@ public interface BargainActivityMapper extends BaseMapperX&lt;BargainActivityDO&gt; {
28 29 return selectList(BargainActivityDO::getStatus, status);
29 30 }
30 31  
  32 + /**
  33 + * 更新活动库存
  34 + *
  35 + * @param id 活动编号
  36 + * @param count 扣减的库存数量
  37 + * @return 影响的行数
  38 + */
  39 + default int updateActivityStock(Long id, int count) {
  40 + return update(null, new LambdaUpdateWrapper<BargainActivityDO>()
  41 + .eq(BargainActivityDO::getId, id)
  42 + .gt(BargainActivityDO::getStock, 0)
  43 + .setSql("stock = stock - " + count));
  44 + }
  45 +
31 46 }
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/seckill/seckillactivity/SeckillActivityMapper.java
... ... @@ -6,6 +6,7 @@ import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
6 6 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
7 7 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityPageReqVO;
8 8 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillActivityDO;
  9 +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
9 10 import org.apache.ibatis.annotations.Mapper;
10 11  
11 12 import java.util.List;
... ... @@ -32,4 +33,19 @@ public interface SeckillActivityMapper extends BaseMapperX&lt;SeckillActivityDO&gt; {
32 33 .eqIfPresent(SeckillActivityDO::getStatus, status));
33 34 }
34 35  
  36 + /**
  37 + * 更新活动库存
  38 + *
  39 + * @param id 活动编号
  40 + * @param count 扣减的库存数量
  41 + * @return 影响的行数
  42 + */
  43 + default int updateActivityStock(Long id, int count) {
  44 + return update(null, new LambdaUpdateWrapper<SeckillActivityDO>()
  45 + .eq(SeckillActivityDO::getId, id)
  46 + .gt(SeckillActivityDO::getTotalStock, 0)
  47 + .setSql("stock = stock + " + count)
  48 + .setSql("totalStock = totalStock - " + count));
  49 + }
  50 +
35 51 }
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/seckill/seckillactivity/SeckillProductMapper.java
... ... @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckillactivity;
2 2  
3 3 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
4 4 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillProductDO;
  5 +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
5 6 import org.apache.ibatis.annotations.Mapper;
6 7  
7 8 import java.util.Collection;
... ... @@ -23,4 +24,18 @@ public interface SeckillProductMapper extends BaseMapperX&lt;SeckillProductDO&gt; {
23 24 return selectList(SeckillProductDO::getActivityId, ids);
24 25 }
25 26  
  27 + /**
  28 + * 更新活动库存
  29 + *
  30 + * @param id 活动编号
  31 + * @param count 扣减的库存数量
  32 + * @return 影响的行数
  33 + */
  34 + default int updateActivityStock(Long id, int count) {
  35 + return update(null, new LambdaUpdateWrapper<SeckillProductDO>()
  36 + .eq(SeckillProductDO::getId, id)
  37 + .gt(SeckillProductDO::getStock, 0)
  38 + .setSql("stock = stock - " + count));
  39 + }
  40 +
26 41 }
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/bargain/BargainActivityService.java
... ... @@ -31,6 +31,14 @@ public interface BargainActivityService {
31 31 void updateBargainActivity(@Valid BargainActivityUpdateReqVO updateReqVO);
32 32  
33 33 /**
  34 + * 更新砍价活动库存
  35 + *
  36 + * @param id 砍价活动编号
  37 + * @param count 购买数量
  38 + */
  39 + void updateBargainActivityStock(Long id, Integer count);
  40 +
  41 + /**
34 42 * 删除砍价活动
35 43 *
36 44 * @param id 编号
... ... @@ -53,5 +61,4 @@ public interface BargainActivityService {
53 61 */
54 62 PageResult<BargainActivityDO> getBargainActivityPage(BargainActivityPageReqVO pageReqVO);
55 63  
56   -
57 64 }
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/bargain/BargainActivityServiceImpl.java
... ... @@ -39,6 +39,7 @@ public class BargainActivityServiceImpl implements BargainActivityService {
39 39 private ProductSkuApi productSkuApi;
40 40  
41 41 @Override
  42 + @Transactional(rollbackFor = Exception.class)
42 43 public Long createBargainActivity(BargainActivityCreateReqVO createReqVO) {
43 44 // 校验商品 SPU 是否存在是否参加的别的活动
44 45 validateBargainConflict(createReqVO.getSpuId(), null);
... ... @@ -53,6 +54,7 @@ public class BargainActivityServiceImpl implements BargainActivityService {
53 54 }
54 55  
55 56 @Override
  57 + @Transactional(rollbackFor = Exception.class)
56 58 public void updateBargainActivity(BargainActivityUpdateReqVO updateReqVO) {
57 59 // 校验存在
58 60 BargainActivityDO activityDO = validateBargainActivityExists(updateReqVO.getId());
... ... @@ -70,6 +72,22 @@ public class BargainActivityServiceImpl implements BargainActivityService {
70 72 bargainActivityMapper.updateById(updateObj);
71 73 }
72 74  
  75 + @Override
  76 + @Transactional(rollbackFor = Exception.class)
  77 + public void updateBargainActivityStock(Long id, Integer count) {
  78 + // 查询砍价活动
  79 + BargainActivityDO activity = getBargainActivity(id);
  80 + if (activity == null) {
  81 + throw exception(BARGAIN_ACTIVITY_NOT_EXISTS);
  82 + }
  83 +
  84 + // 更新砍价库存
  85 + int row = bargainActivityMapper.updateActivityStock(id, count);
  86 + if (row == 0) {
  87 + throw exception(BARGAIN_ACTIVITY_UPDATE_STOCK_FAIL);
  88 + }
  89 + }
  90 +
73 91 private void validateBargainConflict(Long spuId, Long activityId) {
74 92 // 查询所有开启的砍价活动
75 93 List<BargainActivityDO> activityList = bargainActivityMapper.selectListByStatus(CommonStatusEnum.ENABLE.getStatus());
... ...
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-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityService.java
1 1 package cn.iocoder.yudao.module.promotion.service.seckill;
2 2  
3 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillActivityUpdateStockReqDTO;
4 5 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityCreateReqVO;
5 6 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityPageReqVO;
6 7 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityUpdateReqVO;
... ... @@ -41,6 +42,12 @@ public interface SeckillActivityService {
41 42 void updateSeckillActivity(SeckillActivityDO activityDO);
42 43  
43 44 /**
  45 + * 更新秒杀库存
  46 + *
  47 + * @param updateStockReqDTO 更新信息
  48 + */
  49 + void updateSeckillStock(SeckillActivityUpdateStockReqDTO updateStockReqDTO);
  50 + /**
44 51 * 更新秒杀活动商品
45 52 *
46 53 * @param productList 活动商品列表
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityServiceImpl.java
... ... @@ -7,6 +7,7 @@ import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
7 7 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
8 8 import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
9 9 import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
  10 +import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillActivityUpdateStockReqDTO;
10 11 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityCreateReqVO;
11 12 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityPageReqVO;
12 13 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityUpdateReqVO;
... ... @@ -150,6 +151,39 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
150 151 }
151 152  
152 153 @Override
  154 + @Transactional(rollbackFor = Exception.class)
  155 + public void updateSeckillStock(SeckillActivityUpdateStockReqDTO updateStockReqDTO) {
  156 + // 1、校验秒杀活动是否存在
  157 + SeckillActivityDO seckillActivity = getSeckillActivity(updateStockReqDTO.getActivityId());
  158 + // 1.1、校验库存是否充足
  159 + if (seckillActivity.getTotalStock() < updateStockReqDTO.getCount()) {
  160 + throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL);
  161 + }
  162 +
  163 + // 2、获取活动商品
  164 + List<SeckillProductDO> products = getSeckillProductListByActivityId(updateStockReqDTO.getActivityId());
  165 + // 2.1、过滤出购买的商品
  166 + SeckillProductDO product = findFirst(products, item -> ObjectUtil.equal(updateStockReqDTO.getItem().getSkuId(), item.getSkuId()));
  167 + // 2.2、检查活动商品库存是否充足
  168 + boolean isSufficient = product == null || (product.getStock() == 0 || (product.getStock() < updateStockReqDTO.getItem().getCount()) || (product.getStock() - updateStockReqDTO.getItem().getCount()) < 0);
  169 + if (isSufficient) {
  170 + throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL);
  171 + }
  172 +
  173 + // 3、更新活动商品库存
  174 + int itemRow = seckillProductMapper.updateActivityStock(product.getId(), updateStockReqDTO.getItem().getCount());
  175 + if (itemRow == 0) {
  176 + throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL);
  177 + }
  178 +
  179 + // 4、更新活动库存
  180 + int row = seckillActivityMapper.updateActivityStock(seckillActivity.getId(), updateStockReqDTO.getCount());
  181 + if (row == 0) {
  182 + throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL);
  183 + }
  184 + }
  185 +
  186 + @Override
153 187 public void updateSeckillActivityProductList(List<SeckillProductDO> productList) {
154 188 seckillProductMapper.updateBatch(productList);
155 189 }
... ...
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-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java
... ... @@ -34,6 +34,9 @@ public interface ErrorCodeConstants {
34 34 ErrorCode ORDER_DELIVERY_FAIL_BARGAIN_RECORD_STATUS_NOT_SUCCESS = new ErrorCode(1011000023, "交易订单发货失败,砍价未成功");
35 35 ErrorCode ORDER_DELIVERY_FAIL_DELIVERY_TYPE_NOT_EXPRESS = new ErrorCode(1011000024, "交易订单发货失败,发货类型不是快递");
36 36 ErrorCode ORDER_CANCEL_FAIL_STATUS_NOT_UNPAID = new ErrorCode(1011000025, "交易订单取消失败,订单不是【待支付】状态");
  37 + ErrorCode ORDER_UPDATE_PRICE_FAIL_PAID = new ErrorCode(1011000026, "支付订单调价失败,原因:支付订单已付款,不能调价");
  38 + ErrorCode ORDER_UPDATE_PRICE_FAIL_EQUAL = new ErrorCode(1011000027, "支付订单调价失败,原因:价格没有变化");
  39 + ErrorCode ORDER_UPDATE_PRICE_FAIL_NOT_ITEM = new ErrorCode(1011000028, "支付订单调价失败,原因:订单项不存在");
37 40  
38 41 // ========== After Sale 模块 1011000100 ==========
39 42 ErrorCode AFTER_SALE_NOT_FOUND = new ErrorCode(1011000100, "售后单不存在");
... ...
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/controller/admin/aftersale/TradeAfterSaleController.java
... ... @@ -76,10 +76,9 @@ public class TradeAfterSaleController {
76 76 public CommonResult<TradeAfterSaleDetailRespVO> getOrderDetail(@RequestParam("id") Long id) {
77 77 // 查询订单
78 78 TradeAfterSaleDO afterSale = afterSaleService.getAfterSale(id);
79   - // TODO @puhui999:这里建议改成,如果为 null,直接返回 success null;主要查询操作,尽量不要有非空的提示哈;交给前端处理;
80   -// if (afterSale == null) {
81   -// return success(null, AFTER_SALE_NOT_FOUND.getMsg());
82   -// }
  79 + if (afterSale == null) {
  80 + return success(null);
  81 + }
83 82  
84 83 // 查询订单
85 84 TradeOrderDO order = tradeOrderQueryService.getOrder(afterSale.getOrderId());
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/TradeOrderController.java
... ... @@ -67,10 +67,9 @@ public class TradeOrderController {
67 67 public CommonResult<TradeOrderDetailRespVO> getOrderDetail(@RequestParam("id") Long id) {
68 68 // 查询订单
69 69 TradeOrderDO order = tradeOrderQueryService.getOrder(id);
70   - // TODO @puhui999:这里建议改成,如果为 null,直接返回 success null;主要查询操作,尽量不要有非空的提示哈;交给前端处理;
71   -// if (order == null) {
72   -// return success(null, ORDER_NOT_FOUND.getMsg());
73   -// }
  70 + if (order == null) {
  71 + return success(null);
  72 + }
74 73  
75 74 // 查询订单项
76 75 List<TradeOrderItemDO> orderItems = tradeOrderQueryService.getOrderItemListByOrderId(id);
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/vo/TradeOrderPageReqVO.java
... ... @@ -31,19 +31,15 @@ public class TradeOrderPageReqVO extends PageParam {
31 31 @Mobile
32 32 private String userMobile;
33 33  
  34 + @Schema(description = "配送方式", example = "1")
  35 + private Integer deliveryType;
  36 +
34 37 @Schema(description = "发货物流公司编号", example = "1")
35 38 private Long logisticsId;
36 39  
37 40 @Schema(description = "自提门店编号", example = "[1,2]")
38 41 private List<Long> pickUpStoreIds;
39 42  
40   - @Schema(description = "收件人名称", example = "小红")
41   - private String receiverName;
42   -
43   - @Schema(description = "收件人手机", example = "1560")
44   - @Mobile
45   - private String receiverMobile;
46   -
47 43 @Schema(description = "订单类型", example = "1")
48 44 private Integer type;
49 45  
... ... @@ -61,5 +57,5 @@ public class TradeOrderPageReqVO extends PageParam {
61 57 @Schema(description = "订单来源", example = "10")
62 58 @InEnum(value = TerminalEnum.class, message = "订单来源 {value}")
63 59 private Integer terminal;
64   -// TODO 添加配送方式筛选
  60 +
65 61 }
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java
... ... @@ -81,10 +81,9 @@ public class AppTradeOrderController {
81 81 public CommonResult<AppTradeOrderDetailRespVO> getOrder(@RequestParam("id") Long id) {
82 82 // 查询订单
83 83 TradeOrderDO order = tradeOrderQueryService.getOrder(getLoginUserId(), id);
84   - // TODO @puhui999:这里建议改成,如果为 null,直接返回 success null;主要查询操作,尽量不要有非空的提示哈;交给前端处理;
85   -// if (order == null) {
86   -// return success(null, ORDER_NOT_FOUND.getMsg());
87   -// }
  84 + if (order == null) {
  85 + return success(null);
  86 + }
88 87  
89 88 // 查询订单项
90 89 List<TradeOrderItemDO> orderItems = tradeOrderQueryService.getOrderItemListByOrderId(order.getId());
... ...
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;
... ... @@ -32,6 +34,9 @@ import cn.iocoder.yudao.module.trade.enums.order.TradeOrderItemAfterSaleStatusEn
32 34 import cn.iocoder.yudao.module.trade.framework.delivery.core.client.dto.ExpressTrackRespDTO;
33 35 import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties;
34 36 import cn.iocoder.yudao.module.trade.service.brokerage.bo.BrokerageAddReqBO;
  37 +import cn.iocoder.yudao.module.trade.service.brokerage.bo.BrokerageAddReqBO;
  38 +import cn.iocoder.yudao.module.trade.service.order.bo.TradeAfterOrderCreateReqBO;
  39 +import cn.iocoder.yudao.module.trade.service.order.bo.TradeBeforeOrderCreateReqBO;
35 40 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO;
36 41 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO;
37 42 import org.mapstruct.Mapper;
... ... @@ -254,21 +259,15 @@ public interface TradeOrderConvert {
254 259 AppTradeOrderSettlementRespVO convert0(TradePriceCalculateRespBO calculate, AddressRespDTO address);
255 260  
256 261 @Mappings({
257   - @Mapping(target = "activityId", source = "createReqVO.combinationActivityId"),
258   - @Mapping(target = "spuId", source = "orderItem.spuId"),
259   - @Mapping(target = "skuId", source = "orderItem.skuId"),
260   - @Mapping(target = "userId", source = "order.userId"),
261   - @Mapping(target = "orderId", source = "order.id"),
262   - @Mapping(target = "headId", source = "createReqVO.combinationHeadId"),
263   - @Mapping(target = "spuName", source = "orderItem.spuName"),
264   - @Mapping(target = "picUrl", source = "orderItem.picUrl"),
265   - @Mapping(target = "combinationPrice", source = "orderItem.payPrice"),
266   - @Mapping(target = "nickname", source = "user.nickname"),
267   - @Mapping(target = "avatar", source = "user.avatar"),
268   - @Mapping(target = "status", ignore = true)
  262 + @Mapping(target = "activityId", source = "afterOrderCreateReqBO.combinationActivityId"),
  263 + @Mapping(target = "spuId", source = "afterOrderCreateReqBO.spuId"),
  264 + @Mapping(target = "skuId", source = "afterOrderCreateReqBO.skuId"),
  265 + @Mapping(target = "orderId", source = "afterOrderCreateReqBO.orderId"),
  266 + @Mapping(target = "userId", source = "afterOrderCreateReqBO.userId"),
  267 + @Mapping(target = "headId", source = "afterOrderCreateReqBO.combinationHeadId"),
  268 + @Mapping(target = "combinationPrice", source = "afterOrderCreateReqBO.payPrice"),
269 269 })
270   - CombinationRecordCreateReqDTO convert(TradeOrderDO order, TradeOrderItemDO orderItem,
271   - AppTradeOrderCreateReqVO createReqVO, MemberUserRespDTO user);
  270 + CombinationRecordCreateReqDTO convert(TradeAfterOrderCreateReqBO afterOrderCreateReqBO);
272 271  
273 272 List<AppOrderExpressTrackRespDTO> convertList02(List<ExpressTrackRespDTO> list);
274 273  
... ... @@ -282,6 +281,26 @@ public interface TradeOrderConvert {
282 281 return new BrokerageAddReqBO().setBizId(String.valueOf(item.getId())).setSourceUserId(item.getUserId())
283 282 .setBasePrice(item.getPayPrice() * item.getCount())
284 283 .setTitle(BrokerageRecordBizTypeEnum.ORDER.getTitle()) // TODO @疯狂:标题类似:木晴冰雪成功购买云时代的JVM原理与实战;茫农成功购买深入拆解消息队列47讲
285   - .setFirstFixedPrice(sku.getSubCommissionFirstPrice()).setSecondFixedPrice(sku.getSubCommissionSecondPrice());
  284 + .setFirstFixedPrice(sku.getFirstBrokerageRecord()).getSecondBrokerageRecord(sku.getSecondBrokerageRecord());
286 285 }
  286 +
  287 + @Mapping(target = "activityId", source = "reqBO.seckillActivityId")
  288 + SeckillActivityUpdateStockReqDTO convert(TradeBeforeOrderCreateReqBO reqBO);
  289 +
  290 + @Mapping(target = "activityId", source = "reqBO.combinationActivityId")
  291 + CombinationActivityUpdateStockReqDTO convert1(TradeBeforeOrderCreateReqBO reqBO);
  292 +
  293 + TradeBeforeOrderCreateReqBO convert(AppTradeOrderCreateReqVO createReqVO);
  294 +
  295 + @Mappings({
  296 + @Mapping(target = "combinationActivityId", source = "createReqVO.combinationActivityId"),
  297 + @Mapping(target = "combinationHeadId", source = "createReqVO.combinationHeadId"),
  298 + @Mapping(target = "spuId", source = "orderItem.spuId"),
  299 + @Mapping(target = "skuId", source = "orderItem.skuId"),
  300 + @Mapping(target = "orderId", source = "tradeOrderDO.id"),
  301 + @Mapping(target = "userId", source = "userId"),
  302 + @Mapping(target = "payPrice", source = "tradeOrderDO.payPrice"),
  303 + })
  304 + TradeAfterOrderCreateReqBO convert(Long userId, AppTradeOrderCreateReqVO createReqVO, TradeOrderDO tradeOrderDO, TradeOrderItemDO orderItem);
  305 +
287 306 }
... ...
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/dal/mysql/order/TradeOrderMapper.java
... ... @@ -27,13 +27,12 @@ public interface TradeOrderMapper extends BaseMapperX&lt;TradeOrderDO&gt; {
27 27 return selectPage(reqVO, new LambdaQueryWrapperX<TradeOrderDO>()
28 28 .likeIfPresent(TradeOrderDO::getNo, reqVO.getNo())
29 29 .eqIfPresent(TradeOrderDO::getUserId, reqVO.getUserId())
  30 + .eqIfPresent(TradeOrderDO::getDeliveryType, reqVO.getDeliveryType())
30 31 .inIfPresent(TradeOrderDO::getUserId, userIds)
31   - .likeIfPresent(TradeOrderDO::getReceiverName, reqVO.getReceiverName())
32   - .likeIfPresent(TradeOrderDO::getReceiverMobile, reqVO.getReceiverMobile())
33 32 .eqIfPresent(TradeOrderDO::getType, reqVO.getType())
34 33 .eqIfPresent(TradeOrderDO::getStatus, reqVO.getStatus())
35 34 .eqIfPresent(TradeOrderDO::getPayChannelCode, reqVO.getPayChannelCode())
36   - .eqIfPresent(TradeOrderDO::getTerminal,reqVO.getTerminal())
  35 + .eqIfPresent(TradeOrderDO::getTerminal, reqVO.getTerminal())
37 36 .eqIfPresent(TradeOrderDO::getLogisticsId, reqVO.getLogisticsId())
38 37 .inIfPresent(TradeOrderDO::getPickUpStoreId, reqVO.getPickUpStoreIds())
39 38 .betweenIfPresent(TradeOrderDO::getCreateTime, reqVO.getCreateTime()));
... ...
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;
... ... @@ -53,12 +46,14 @@ import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordBizTypeEnum;
53 46 import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum;
54 47 import cn.iocoder.yudao.module.trade.enums.order.*;
55 48 import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties;
56   -import cn.iocoder.yudao.module.trade.service.brokerage.record.BrokerageRecordService;
57 49 import cn.iocoder.yudao.module.trade.service.brokerage.bo.BrokerageAddReqBO;
  50 +import cn.iocoder.yudao.module.trade.service.brokerage.record.BrokerageRecordService;
58 51 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;
... ... @@ -70,14 +65,13 @@ import org.springframework.transaction.annotation.Transactional;
70 65  
71 66 import javax.annotation.Resource;
72 67 import java.time.LocalDateTime;
  68 +import java.util.ArrayList;
73 69 import java.util.List;
74 70 import java.util.Objects;
75 71 import java.util.Set;
76 72  
77 73 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
78 74 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
79   -import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.ORDER_UPDATE_PRICE_FAIL_EQUAL;
80   -import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.ORDER_UPDATE_PRICE_FAIL_PAID;
81 75 import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*;
82 76  
83 77 /**
... ... @@ -96,6 +90,8 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
96 90 private TradeOrderItemMapper tradeOrderItemMapper;
97 91 @Resource
98 92 private TradeOrderNoRedisDAO orderNoRedisDAO;
  93 + @Resource
  94 + private List<TradeOrderHandler> orderHandlers;
99 95  
100 96 @Resource
101 97 private CartService cartService;
... ... @@ -119,12 +115,6 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
119 115 @Resource
120 116 private BargainRecordApi bargainRecordApi;
121 117 @Resource
122   - private SeckillActivityApi seckillActivityApi;
123   - @Resource
124   - private BargainActivityApi bargainActivityApi;
125   - @Resource
126   - private MemberUserApi memberUserApi;
127   - @Resource
128 118 private MemberLevelApi memberLevelApi;
129 119 @Resource
130 120 private MemberPointApi memberPointApi;
... ... @@ -189,7 +179,13 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
189 179 @Override
190 180 @Transactional(rollbackFor = Exception.class)
191 181 public TradeOrderDO createOrder(Long userId, String userIp, AppTradeOrderCreateReqVO createReqVO) {
192   - // 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. 价格计算
193 189 TradePriceCalculateRespBO calculateRespBO = calculatePrice(userId, createReqVO);
194 190  
195 191 // 2.1 插入 TradeOrderDO 订单
... ... @@ -199,37 +195,11 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
199 195  
200 196 // 3. 订单创建完后的逻辑
201 197 afterCreateTradeOrder(userId, createReqVO, order, orderItems, calculateRespBO);
202   - // 3.1 拼团的特殊逻辑
203   - // TODO @puhui999:这个逻辑,先抽个小方法;未来要通过设计模式,把这些拼团之类的逻辑,抽象出去
204   - // 拼团
205   - if (Objects.equals(TradeOrderTypeEnum.COMBINATION.getType(), order.getType())) {
206   - createCombinationRecord(userId, createReqVO, orderItems, order);
207   - }
208   - // 3.2 秒杀的特殊逻辑
209   - if (Objects.equals(TradeOrderTypeEnum.SECKILL.getType(), order.getType())) {
210   -
211   - }
212   - // 3.3 砍价的特殊逻辑
213 198  
214 199 // TODO @LeeYan9: 是可以思考下, 订单的营销优惠记录, 应该记录在哪里, 微信讨论起来!
215 200 return order;
216 201 }
217 202  
218   - private void createCombinationRecord(Long userId, AppTradeOrderCreateReqVO createReqVO, List<TradeOrderItemDO> orderItems, TradeOrderDO order) {
219   - MemberUserRespDTO user = memberUserApi.getUser(userId);
220   - List<CombinationRecordRespDTO> recordRespDTOS = combinationRecordApi.getRecordListByUserIdAndActivityId(userId, createReqVO.getCombinationActivityId());
221   - // TODO 拼团一次应该只能选择一种规格的商品
222   - TradeOrderItemDO orderItemDO = orderItems.get(0);
223   - if (CollUtil.isNotEmpty(recordRespDTOS)) {
224   - List<Long> skuIds = convertList(recordRespDTOS, CombinationRecordRespDTO::getSkuId, item -> ObjectUtil.equals(item.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus()));
225   - List<TradeOrderItemDO> tradeOrderItemDOS = tradeOrderItemMapper.selectListByOrderIdAnSkuId(convertList(recordRespDTOS,
226   - CombinationRecordRespDTO::getOrderId, item -> ObjectUtil.equals(item.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus())), skuIds);
227   - combinationRecordApi.validateCombinationLimitCount(createReqVO.getCombinationActivityId(),
228   - CollectionUtils.getSumValue(tradeOrderItemDOS, TradeOrderItemDO::getCount, Integer::sum), orderItemDO.getCount());
229   - }
230   -
231   - combinationRecordApi.createCombinationRecord(TradeOrderConvert.INSTANCE.convert(order, orderItemDO, createReqVO, user));
232   - }
233 203  
234 204 // TODO @puhui999:订单超时,自动取消;
235 205  
... ... @@ -311,23 +281,8 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
311 281 private void afterCreateTradeOrder(Long userId, AppTradeOrderCreateReqVO createReqVO,
312 282 TradeOrderDO tradeOrderDO, List<TradeOrderItemDO> orderItems,
313 283 TradePriceCalculateRespBO calculateRespBO) {
314   - Integer count = getSumValue(orderItems, TradeOrderItemDO::getCount, Integer::sum);
315   - // 1)如果是秒杀商品:额外扣减秒杀的库存;
316   - if (Objects.equals(TradeOrderTypeEnum.SECKILL.getType(), tradeOrderDO.getType())) {
317   - SeckillActivityUpdateStockReqDTO updateStockReqDTO = new SeckillActivityUpdateStockReqDTO();
318   - updateStockReqDTO.setActivityId(createReqVO.getSeckillActivityId());
319   - updateStockReqDTO.setCount(count);
320   - updateStockReqDTO.setItems(CollectionUtils.convertList(orderItems, item -> {
321   - SeckillActivityUpdateStockReqDTO.Item item1 = new SeckillActivityUpdateStockReqDTO.Item();
322   - item1.setSpuId(item.getSpuId());
323   - item1.setSkuId(item.getSkuId());
324   - item1.setCount(item.getCount());
325   - return item1;
326   - }));
327   - seckillActivityApi.updateSeckillStock(updateStockReqDTO);
328   - }
329   - // 2)如果是砍价活动:额外扣减砍价的库存;
330   - bargainActivityApi.updateBargainActivityStock(createReqVO.getBargainActivityId(), count);
  284 + // 执行订单创建后置处理器
  285 + orderHandlers.forEach(handler -> handler.afterOrderCreate(TradeOrderConvert.INSTANCE.convert(userId, createReqVO, tradeOrderDO, orderItems.get(0))));
331 286 // 扣减积分 TODO 芋艿:待实现,需要前置;
332 287 // 这个是不是应该放到支付成功之后?如果支付后的话,可能积分可以重复使用哈。资源类,都要预扣
333 288  
... ... @@ -352,6 +307,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
352 307 // 增加订单日志 TODO 芋艿:待实现
353 308 }
354 309  
  310 +
355 311 private void createPayOrder(TradeOrderDO order, List<TradeOrderItemDO> orderItems, TradePriceCalculateRespBO calculateRespBO) {
356 312 // 创建支付单,用于后续的支付
357 313 PayOrderCreateReqDTO payOrderCreateReqDTO = TradeOrderConvert.INSTANCE.convert(
... ... @@ -562,35 +518,67 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
562 518 }
563 519  
564 520 @Override
565   - // TODO @puhui999:考虑事务性
  521 + @Transactional(rollbackFor = Exception.class)
566 522 public void updateOrderPrice(TradeOrderUpdatePriceReqVO reqVO) {
567   - // 校验交易订单
  523 + // 1、校验交易订单
568 524 TradeOrderDO order = validateOrderExists(reqVO.getId());
569 525 if (order.getPayStatus()) {
570 526 throw exception(ORDER_UPDATE_PRICE_FAIL_PAID);
571 527 }
  528 + // 2、校验订单项
  529 + List<TradeOrderItemDO> items = tradeOrderItemMapper.selectListByOrderId(order.getId());
  530 + if (CollUtil.isEmpty(items)) {
  531 + throw exception(ORDER_UPDATE_PRICE_FAIL_NOT_ITEM);
  532 + }
  533 + // 3、校验调价金额是否变化
572 534 if (ObjectUtil.equal(order.getAdjustPrice(), reqVO.getAdjustPrice())) {
573 535 throw exception(ORDER_UPDATE_PRICE_FAIL_EQUAL);
574 536 }
575 537  
576   - // TODO @puhui999:应该是按照 payPrice 分配;并且要考虑取余问题;payPrice 也要考虑,item 里的
577   - List<TradeOrderItemDO> itemDOs = tradeOrderItemMapper.selectListByOrderId(order.getId());
578   - // TradeOrderItemDO 需要做 adjustPrice 的分摊
579   - int price = reqVO.getAdjustPrice() / itemDOs.size();
580   - itemDOs.forEach(item -> {
581   - item.setAdjustPrice(price);
582   - });
583   - // 更新 TradeOrderItem
584   - // TODO @puhui999:不要整个对象去更新哈;应该 new 一下;
585   - tradeOrderItemMapper.updateBatch(itemDOs);
586   - // 更新订单
587   - // TODO @puhui999:要考虑多次修改价格,不能单单的 payPrice + 价格;
588   - TradeOrderDO update = TradeOrderConvert.INSTANCE.convert(reqVO);
589   - update.setPayPrice(update.getPayPrice() + update.getAdjustPrice());
  538 + // 4、更新订单
  539 + TradeOrderDO update = new TradeOrderDO();
  540 + update.setId(order.getId());
  541 + update.setAdjustPrice(reqVO.getAdjustPrice());
  542 + int orderPayPrice = order.getAdjustPrice() != null ? (order.getPayPrice() - order.getAdjustPrice())
  543 + + reqVO.getAdjustPrice() : order.getPayPrice() + reqVO.getAdjustPrice();
  544 + update.setPayPrice(orderPayPrice);
590 545 // TODO @芋艿:改价时,赠送的积分,要不要做改动???
591 546 tradeOrderMapper.updateById(update);
592   - // 更新支付订单
593   - payOrderApi.updatePayOrderPriceById(order.getPayOrderId(), update.getPayPrice());
  547 +
  548 + // TODO @puhui999:应该是按照 payPrice 分配;并且要考虑取余问题;payPrice 也要考虑,item 里的
  549 + // TODO:先按 adjustPrice 实现,没明白 payPrice 怎么搞哈哈哈
  550 + // 5、更新 TradeOrderItem
  551 + if (items.size() > 1) {
  552 + // TradeOrderItemDO 需要做 adjustPrice 的分摊
  553 + int price = reqVO.getAdjustPrice() / items.size();
  554 + int remainderPrice = reqVO.getAdjustPrice() % items.size();
  555 + List<TradeOrderItemDO> orders = new ArrayList<>();
  556 + for (int i = 0; i < items.size(); i++) {
  557 + // 把平摊后剩余的金额加到第一个订单项
  558 + if (remainderPrice != 0 && i == 0) {
  559 + orders.add(convertOrderItemPrice(items.get(i), price + remainderPrice));
  560 + }
  561 + orders.add(convertOrderItemPrice(items.get(i), price));
  562 + }
  563 + tradeOrderItemMapper.updateBatch(orders);
  564 + } else {
  565 + TradeOrderItemDO orderItem = items.get(0);
  566 + TradeOrderItemDO updateItem = convertOrderItemPrice(orderItem, reqVO.getAdjustPrice());
  567 + tradeOrderItemMapper.updateById(updateItem);
  568 + }
  569 +
  570 + // 6、更新支付订单
  571 + payOrderApi.updatePayOrderPrice(order.getPayOrderId(), update.getPayPrice());
  572 + }
  573 +
  574 + private TradeOrderItemDO convertOrderItemPrice(TradeOrderItemDO orderItem, Integer price) {
  575 + TradeOrderItemDO newOrderItem = new TradeOrderItemDO();
  576 + newOrderItem.setId(orderItem.getId());
  577 + newOrderItem.setAdjustPrice(price);
  578 + int payPrice = orderItem.getAdjustPrice() != null ? (orderItem.getPayPrice() - orderItem.getAdjustPrice())
  579 + + price : orderItem.getPayPrice() + price;
  580 + newOrderItem.setPayPrice(payPrice);
  581 + return newOrderItem;
594 582 }
595 583  
596 584 @Override
... ... @@ -733,6 +721,9 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
733 721 throw exception(ORDER_CANCEL_FAIL_STATUS_NOT_UNPAID);
734 722 }
735 723  
  724 + // TODO 活动相关库存回滚需要活动 id,活动 id 怎么获取?app 端能否传过来
  725 + orderHandlers.forEach(handler -> handler.rollbackStock());
  726 +
736 727 // 2.回滚库存
737 728 List<TradeOrderItemDO> orderItems = tradeOrderItemMapper.selectListByOrderId(id);
738 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 +}
... ...
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/order/PayOrderApi.java
... ... @@ -29,13 +29,12 @@ public interface PayOrderApi {
29 29 */
30 30 PayOrderRespDTO getOrder(Long id);
31 31  
32   - // TODO @puhui999:可以去掉 byId;然后 payOrderId 参数改成 id;
33 32 /**
34 33 * 更新支付订单价格
35 34 *
36   - * @param payOrderId 支付单编号
  35 + * @param id 支付单编号
37 36 * @param payPrice 支付单价格
38 37 */
39   - void updatePayOrderPriceById(Long payOrderId, Integer payPrice);
  38 + void updatePayOrderPrice(Long id, Integer payPrice);
40 39  
41 40 }
... ...
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/ErrorCodeConstants.java
... ... @@ -21,19 +21,17 @@ public interface ErrorCodeConstants {
21 21 ErrorCode CHANNEL_EXIST_SAME_CHANNEL_ERROR = new ErrorCode(1007001004, "已存在相同的渠道");
22 22  
23 23 // ========== ORDER 模块 1007002000 ==========
24   - ErrorCode ORDER_NOT_FOUND = new ErrorCode(1007002000, "支付订单不存在");
25   - ErrorCode ORDER_STATUS_IS_NOT_WAITING = new ErrorCode(1007002001, "支付订单不处于待支付");
26   - ErrorCode ORDER_STATUS_IS_SUCCESS = new ErrorCode(1007002002, "订单已支付,请刷新页面");
27   - ErrorCode ORDER_IS_EXPIRED = new ErrorCode(1007002003, "支付订单已经过期");
28   - ErrorCode ORDER_SUBMIT_CHANNEL_ERROR = new ErrorCode(1007002004, "发起支付报错,错误码:{},错误提示:{}");
29   - ErrorCode ORDER_REFUND_FAIL_STATUS_ERROR = new ErrorCode(1007002005, "支付订单退款失败,原因:状态不是已支付或已退款");
30   - ErrorCode ORDER_UPDATE_PRICE_FAIL_PAID = new ErrorCode(1007002006, "支付订单调价失败,原因:支付订单已付款,不能调价");
31   - ErrorCode ORDER_UPDATE_PRICE_FAIL_EQUAL = new ErrorCode(1007002007, "支付订单调价失败,原因:价格没有变化");
  24 + ErrorCode PAY_ORDER_NOT_FOUND = new ErrorCode(1007002000, "支付订单不存在");
  25 + ErrorCode PAY_ORDER_STATUS_IS_NOT_WAITING = new ErrorCode(1007002001, "支付订单不处于待支付");
  26 + ErrorCode PAY_ORDER_STATUS_IS_SUCCESS = new ErrorCode(1007002002, "订单已支付,请刷新页面");
  27 + ErrorCode PAY_ORDER_IS_EXPIRED = new ErrorCode(1007002003, "支付订单已经过期");
  28 + ErrorCode PAY_ORDER_SUBMIT_CHANNEL_ERROR = new ErrorCode(1007002004, "发起支付报错,错误码:{},错误提示:{}");
  29 + ErrorCode PAY_ORDER_REFUND_FAIL_STATUS_ERROR = new ErrorCode(1007002005, "支付订单退款失败,原因:状态不是已支付或已退款");
32 30  
33 31 // ========== ORDER 模块(拓展单) 1007003000 ==========
34   - ErrorCode ORDER_EXTENSION_NOT_FOUND = new ErrorCode(1007003000, "支付交易拓展单不存在");
35   - ErrorCode ORDER_EXTENSION_STATUS_IS_NOT_WAITING = new ErrorCode(1007003001, "支付交易拓展单不处于待支付");
36   - ErrorCode ORDER_EXTENSION_IS_PAID = new ErrorCode(1007003002, "订单已支付,请等待支付结果");
  32 + ErrorCode PAY_ORDER_EXTENSION_NOT_FOUND = new ErrorCode(1007003000, "支付交易拓展单不存在");
  33 + ErrorCode PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING = new ErrorCode(1007003001, "支付交易拓展单不处于待支付");
  34 + ErrorCode PAY_ORDER_EXTENSION_IS_PAID = new ErrorCode(1007003002, "订单已支付,请等待支付结果");
37 35  
38 36 // ========== 支付模块(退款) 1007006000 ==========
39 37 ErrorCode REFUND_PRICE_EXCEED = new ErrorCode(1007006000, "退款金额超过订单可退款金额");
... ...
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/api/order/PayOrderApiImpl.java
... ... @@ -32,8 +32,8 @@ public class PayOrderApiImpl implements PayOrderApi {
32 32 }
33 33  
34 34 @Override
35   - public void updatePayOrderPriceById(Long payOrderId, Integer payPrice) {
36   - payOrderService.updatePayOrderPriceById(payOrderId, payPrice);
  35 + public void updatePayOrderPrice(Long id, Integer payPrice) {
  36 + payOrderService.updatePayOrderPrice(id, payPrice);
37 37 }
38 38  
39 39 }
... ...
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/framework/pay/wallet/WalletPayClient.java
... ... @@ -26,7 +26,7 @@ import lombok.extern.slf4j.Slf4j;
26 26 import java.util.Map;
27 27  
28 28 import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR;
29   -import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.ORDER_EXTENSION_NOT_FOUND;
  29 +import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.PAY_ORDER_EXTENSION_NOT_FOUND;
30 30 import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.REFUND_NOT_FOUND;
31 31  
32 32 /**
... ... @@ -98,8 +98,8 @@ public class WalletPayClient extends AbstractPayClient&lt;NonePayClientConfig&gt; {
98 98 PayOrderExtensionDO orderExtension = orderService.getOrderExtensionByNo(outTradeNo);
99 99 // 支付交易拓展单不存在, 返回关闭状态
100 100 if (orderExtension == null) {
101   - return PayOrderRespDTO.closedOf(String.valueOf(ORDER_EXTENSION_NOT_FOUND.getCode()),
102   - ORDER_EXTENSION_NOT_FOUND.getMsg(), outTradeNo, "");
  101 + return PayOrderRespDTO.closedOf(String.valueOf(PAY_ORDER_EXTENSION_NOT_FOUND.getCode()),
  102 + PAY_ORDER_EXTENSION_NOT_FOUND.getMsg(), outTradeNo, "");
103 103 }
104 104 // 关闭状态
105 105 if (PayOrderStatusEnum.isClosed(orderExtension.getStatus())) {
... ...
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/demo/PayDemoOrderServiceImpl.java
... ... @@ -25,7 +25,7 @@ import java.util.HashMap;
25 25 import java.util.Map;
26 26 import java.util.Objects;
27 27  
28   -import static cn.hutool.core.util.ObjectUtil.*;
  28 +import static cn.hutool.core.util.ObjectUtil.notEqual;
29 29 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
30 30 import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.addTime;
31 31 import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
... ... @@ -156,7 +156,7 @@ public class PayDemoOrderServiceImpl implements PayDemoOrderService {
156 156 PayOrderRespDTO payOrder = payOrderApi.getOrder(payOrderId);
157 157 if (payOrder == null) {
158 158 log.error("[validateDemoOrderCanPaid][order({}) payOrder({}) 不存在,请进行处理!]", id, payOrderId);
159   - throw exception(ORDER_NOT_FOUND);
  159 + throw exception(PAY_ORDER_NOT_FOUND);
160 160 }
161 161 // 2.2 校验支付单已支付
162 162 if (!PayOrderStatusEnum.isSuccess(payOrder.getStatus())) {
... ...
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderService.java
... ... @@ -101,10 +101,10 @@ public interface PayOrderService {
101 101 /**
102 102 * 更新支付订单价格
103 103 *
104   - * @param payOrderId 支付单编号
  104 + * @param id 支付单编号
105 105 * @param payPrice 支付单价格
106 106 */
107   - void updatePayOrderPriceById(Long payOrderId, Integer payPrice);
  107 + void updatePayOrderPrice(Long id, Integer payPrice);
108 108  
109 109 /**
110 110 * 获得支付订单
... ...
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderServiceImpl.java
... ... @@ -160,7 +160,7 @@ public class PayOrderServiceImpl implements PayOrderService {
160 160 getSelf().notifyOrder(channel, unifiedOrderResp);
161 161 // 如有渠道错误码,则抛出业务异常,提示用户
162 162 if (StrUtil.isNotEmpty(unifiedOrderResp.getChannelErrorCode())) {
163   - throw exception(ORDER_SUBMIT_CHANNEL_ERROR, unifiedOrderResp.getChannelErrorCode(),
  163 + throw exception(PAY_ORDER_SUBMIT_CHANNEL_ERROR, unifiedOrderResp.getChannelErrorCode(),
164 164 unifiedOrderResp.getChannelErrorMsg());
165 165 }
166 166 // 此处需要读取最新的状态
... ... @@ -172,16 +172,16 @@ public class PayOrderServiceImpl implements PayOrderService {
172 172 private PayOrderDO validateOrderCanSubmit(Long id) {
173 173 PayOrderDO order = orderMapper.selectById(id);
174 174 if (order == null) { // 是否存在
175   - throw exception(ORDER_NOT_FOUND);
  175 + throw exception(PAY_ORDER_NOT_FOUND);
176 176 }
177 177 if (PayOrderStatusEnum.isSuccess(order.getStatus())) { // 校验状态,发现已支付
178   - throw exception(ORDER_STATUS_IS_SUCCESS);
  178 + throw exception(PAY_ORDER_STATUS_IS_SUCCESS);
179 179 }
180 180 if (!PayOrderStatusEnum.WAITING.getStatus().equals(order.getStatus())) { // 校验状态,必须是待支付
181   - throw exception(ORDER_STATUS_IS_NOT_WAITING);
  181 + throw exception(PAY_ORDER_STATUS_IS_NOT_WAITING);
182 182 }
183 183 if (LocalDateTimeUtils.beforeNow(order.getExpireTime())) { // 校验是否过期
184   - throw exception(ORDER_IS_EXPIRED);
  184 + throw exception(PAY_ORDER_IS_EXPIRED);
185 185 }
186 186  
187 187 // 【重要】校验是否支付拓展单已支付,只是没有回调、或者数据不正常
... ... @@ -202,7 +202,7 @@ public class PayOrderServiceImpl implements PayOrderService {
202 202 if (PayOrderStatusEnum.isSuccess(orderExtension.getStatus())) {
203 203 log.warn("[validateOrderCanSubmit][order({}) 的 extension({}) 已支付,可能是数据不一致]",
204 204 id, orderExtension.getId());
205   - throw exception(ORDER_EXTENSION_IS_PAID);
  205 + throw exception(PAY_ORDER_EXTENSION_IS_PAID);
206 206 }
207 207 // 情况二:调用三方接口,查询支付单状态,是不是已支付
208 208 PayClient payClient = payClientFactory.getPayClient(orderExtension.getChannelId());
... ... @@ -214,7 +214,7 @@ public class PayOrderServiceImpl implements PayOrderService {
214 214 if (respDTO != null && PayOrderStatusRespEnum.isSuccess(respDTO.getStatus())) {
215 215 log.warn("[validateOrderCanSubmit][order({}) 的 PayOrderRespDTO({}) 已支付,可能是回调延迟]",
216 216 id, toJsonString(respDTO));
217   - throw exception(ORDER_EXTENSION_IS_PAID);
  217 + throw exception(PAY_ORDER_EXTENSION_IS_PAID);
218 218 }
219 219 });
220 220 }
... ... @@ -254,9 +254,10 @@ public class PayOrderServiceImpl implements PayOrderService {
254 254 * 通知并更新订单的支付结果
255 255 *
256 256 * @param channel 支付渠道
257   - * @param notify 通知
  257 + * @param notify 通知
258 258 */
259   - @Transactional(rollbackFor = Exception.class) // 注意,如果是方法内调用该方法,需要通过 getSelf().notifyPayOrder(channel, notify) 调用,否则事务不生效
  259 + @Transactional(rollbackFor = Exception.class)
  260 + // 注意,如果是方法内调用该方法,需要通过 getSelf().notifyPayOrder(channel, notify) 调用,否则事务不生效
260 261 public void notifyOrder(PayChannelDO channel, PayOrderRespDTO notify) {
261 262 // 情况一:支付成功的回调
262 263 if (PayOrderStatusRespEnum.isSuccess(notify.getStatus())) {
... ... @@ -295,21 +296,21 @@ public class PayOrderServiceImpl implements PayOrderService {
295 296 // 1. 查询 PayOrderExtensionDO
296 297 PayOrderExtensionDO orderExtension = orderExtensionMapper.selectByNo(notify.getOutTradeNo());
297 298 if (orderExtension == null) {
298   - throw exception(ORDER_EXTENSION_NOT_FOUND);
  299 + throw exception(PAY_ORDER_EXTENSION_NOT_FOUND);
299 300 }
300 301 if (PayOrderStatusEnum.isSuccess(orderExtension.getStatus())) { // 如果已经是成功,直接返回,不用重复更新
301 302 log.info("[updateOrderExtensionSuccess][orderExtension({}) 已经是已支付,无需更新]", orderExtension.getId());
302 303 return orderExtension;
303 304 }
304 305 if (ObjectUtil.notEqual(orderExtension.getStatus(), PayOrderStatusEnum.WAITING.getStatus())) { // 校验状态,必须是待支付
305   - throw exception(ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
  306 + throw exception(PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
306 307 }
307 308  
308 309 // 2. 更新 PayOrderExtensionDO
309 310 int updateCounts = orderExtensionMapper.updateByIdAndStatus(orderExtension.getId(), orderExtension.getStatus(),
310 311 PayOrderExtensionDO.builder().status(PayOrderStatusEnum.SUCCESS.getStatus()).channelNotifyData(toJsonString(notify)).build());
311 312 if (updateCounts == 0) { // 校验状态,必须是待支付
312   - throw exception(ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
  313 + throw exception(PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
313 314 }
314 315 log.info("[updateOrderExtensionSuccess][orderExtension({}) 更新为已支付]", orderExtension.getId());
315 316 return orderExtension;
... ... @@ -318,17 +319,17 @@ public class PayOrderServiceImpl implements PayOrderService {
318 319 /**
319 320 * 更新 PayOrderDO 支付成功
320 321 *
321   - * @param channel 支付渠道
  322 + * @param channel 支付渠道
322 323 * @param orderExtension 支付拓展单
323   - * @param notify 通知回调
  324 + * @param notify 通知回调
324 325 * @return 是否之前已经成功回调
325 326 */
326 327 private Boolean updateOrderSuccess(PayChannelDO channel, PayOrderExtensionDO orderExtension,
327   - PayOrderRespDTO notify) {
  328 + PayOrderRespDTO notify) {
328 329 // 1. 判断 PayOrderDO 是否处于待支付
329 330 PayOrderDO order = orderMapper.selectById(orderExtension.getOrderId());
330 331 if (order == null) {
331   - throw exception(ORDER_NOT_FOUND);
  332 + throw exception(PAY_ORDER_NOT_FOUND);
332 333 }
333 334 if (PayOrderStatusEnum.isSuccess(order.getStatus()) // 如果已经是成功,直接返回,不用重复更新
334 335 && Objects.equals(order.getExtensionId(), orderExtension.getId())) {
... ... @@ -336,7 +337,7 @@ public class PayOrderServiceImpl implements PayOrderService {
336 337 return true;
337 338 }
338 339 if (!PayOrderStatusEnum.WAITING.getStatus().equals(order.getStatus())) { // 校验状态,必须是待支付
339   - throw exception(ORDER_STATUS_IS_NOT_WAITING);
  340 + throw exception(PAY_ORDER_STATUS_IS_NOT_WAITING);
340 341 }
341 342  
342 343 // 2. 更新 PayOrderDO
... ... @@ -346,10 +347,10 @@ public class PayOrderServiceImpl implements PayOrderService {
346 347 .successTime(notify.getSuccessTime()).extensionId(orderExtension.getId()).no(orderExtension.getNo())
347 348 .channelOrderNo(notify.getChannelOrderNo()).channelUserId(notify.getChannelUserId())
348 349 .channelFeeRate(channel.getFeeRate())
349   - .channelFeePrice(MoneyUtils.calculateRatePrice(order.getPrice(), channel.getFeeRate()))
  350 + .channelFeePrice(MoneyUtils.calculateRatePrice(order.getPrice(), channel.getFeeRate()))
350 351 .build());
351 352 if (updateCounts == 0) { // 校验状态,必须是待支付
352   - throw exception(ORDER_STATUS_IS_NOT_WAITING);
  353 + throw exception(PAY_ORDER_STATUS_IS_NOT_WAITING);
353 354 }
354 355 log.info("[updateOrderExtensionSuccess][order({}) 更新为已支付]", order.getId());
355 356 return false;
... ... @@ -363,7 +364,7 @@ public class PayOrderServiceImpl implements PayOrderService {
363 364 // 1. 查询 PayOrderExtensionDO
364 365 PayOrderExtensionDO orderExtension = orderExtensionMapper.selectByNo(notify.getOutTradeNo());
365 366 if (orderExtension == null) {
366   - throw exception(ORDER_EXTENSION_NOT_FOUND);
  367 + throw exception(PAY_ORDER_EXTENSION_NOT_FOUND);
367 368 }
368 369 if (PayOrderStatusEnum.isClosed(orderExtension.getStatus())) { // 如果已经是关闭,直接返回,不用重复更新
369 370 log.info("[updateOrderExtensionClosed][orderExtension({}) 已经是支付关闭,无需更新]", orderExtension.getId());
... ... @@ -375,7 +376,7 @@ public class PayOrderServiceImpl implements PayOrderService {
375 376 return;
376 377 }
377 378 if (ObjectUtil.notEqual(orderExtension.getStatus(), PayOrderStatusEnum.WAITING.getStatus())) { // 校验状态,必须是待支付
378   - throw exception(ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
  379 + throw exception(PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
379 380 }
380 381  
381 382 // 2. 更新 PayOrderExtensionDO
... ... @@ -383,7 +384,7 @@ public class PayOrderServiceImpl implements PayOrderService {
383 384 PayOrderExtensionDO.builder().status(PayOrderStatusEnum.CLOSED.getStatus()).channelNotifyData(toJsonString(notify))
384 385 .channelErrorCode(notify.getChannelErrorCode()).channelErrorMsg(notify.getChannelErrorMsg()).build());
385 386 if (updateCounts == 0) { // 校验状态,必须是待支付
386   - throw exception(ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
  387 + throw exception(PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
387 388 }
388 389 log.info("[updateOrderExtensionClosed][orderExtension({}) 更新为支付关闭]", orderExtension.getId());
389 390 }
... ... @@ -392,10 +393,10 @@ public class PayOrderServiceImpl implements PayOrderService {
392 393 public void updateOrderRefundPrice(Long id, Integer incrRefundPrice) {
393 394 PayOrderDO order = orderMapper.selectById(id);
394 395 if (order == null) {
395   - throw exception(ORDER_NOT_FOUND);
  396 + throw exception(PAY_ORDER_NOT_FOUND);
396 397 }
397 398 if (!PayOrderStatusEnum.isSuccessOrRefund(order.getStatus())) {
398   - throw exception(ORDER_REFUND_FAIL_STATUS_ERROR);
  399 + throw exception(PAY_ORDER_REFUND_FAIL_STATUS_ERROR);
399 400 }
400 401 if (order.getRefundPrice() + incrRefundPrice > order.getPrice()) {
401 402 throw exception(REFUND_PRICE_EXCEED);
... ... @@ -407,16 +408,21 @@ public class PayOrderServiceImpl implements PayOrderService {
407 408 .setStatus(PayOrderStatusEnum.REFUND.getStatus());
408 409 int updateCount = orderMapper.updateByIdAndStatus(id, order.getStatus(), updateObj);
409 410 if (updateCount == 0) {
410   - throw exception(ORDER_REFUND_FAIL_STATUS_ERROR);
  411 + throw exception(PAY_ORDER_REFUND_FAIL_STATUS_ERROR);
411 412 }
412 413 }
413 414  
414 415 @Override
415   - public void updatePayOrderPriceById(Long payOrderId, Integer payPrice) {
416   - // TODO @puhui999:不能直接这样修改哈;应该只有未支付状态的订单才可以改;另外,如果价格如果没变,可以直接 return 哈;
417   - PayOrderDO order = orderMapper.selectById(payOrderId);
  416 + public void updatePayOrderPrice(Long id, Integer payPrice) {
  417 + PayOrderDO order = orderMapper.selectById(id);
418 418 if (order == null) {
419   - throw exception(ORDER_NOT_FOUND);
  419 + throw exception(PAY_ORDER_NOT_FOUND);
  420 + }
  421 + if (ObjectUtil.notEqual(PayOrderStatusEnum.WAITING.getStatus(), order.getStatus())) {
  422 + throw exception(PAY_ORDER_STATUS_IS_NOT_WAITING);
  423 + }
  424 + if (ObjectUtil.equal(order.getPrice(), payPrice)) {
  425 + return;
420 426 }
421 427  
422 428 order.setPrice(payPrice);
... ...
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/refund/PayRefundServiceImpl.java
... ... @@ -160,11 +160,11 @@ public class PayRefundServiceImpl implements PayRefundService {
160 160 private PayOrderDO validatePayOrderCanRefund(PayRefundCreateReqDTO reqDTO) {
161 161 PayOrderDO order = orderService.getOrder(reqDTO.getAppId(), reqDTO.getMerchantOrderId());
162 162 if (order == null) {
163   - throw exception(ORDER_NOT_FOUND);
  163 + throw exception(PAY_ORDER_NOT_FOUND);
164 164 }
165 165 // 校验状态,必须是已支付、或者已退款
166 166 if (!PayOrderStatusEnum.isSuccessOrRefund(order.getStatus())) {
167   - throw exception(ORDER_REFUND_FAIL_STATUS_ERROR);
  167 + throw exception(PAY_ORDER_REFUND_FAIL_STATUS_ERROR);
168 168 }
169 169  
170 170 // 校验金额,退款金额不能大于原定的金额
... ...
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletServiceImpl.java
... ... @@ -61,7 +61,7 @@ public class PayWalletServiceImpl implements PayWalletService {
61 61 // 1. 判断支付交易拓展单是否存
62 62 PayOrderExtensionDO orderExtension = orderService.getOrderExtensionByNo(outTradeNo);
63 63 if (orderExtension == null) {
64   - throw exception(ORDER_EXTENSION_NOT_FOUND);
  64 + throw exception(PAY_ORDER_EXTENSION_NOT_FOUND);
65 65 }
66 66 // 2. 扣减余额
67 67 return reduceWalletBalance(userId, userType, orderExtension.getOrderId(), PAYMENT, price);
... ...
yudao-module-pay/yudao-module-pay-biz/src/test/java/cn/iocoder/yudao/module/pay/service/order/PayOrderServiceTest.java
... ... @@ -261,7 +261,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
261 261 String userIp = randomString();
262 262  
263 263 // 调用, 并断言异常
264   - assertServiceException(() -> orderService.submitOrder(reqVO, userIp), ORDER_NOT_FOUND);
  264 + assertServiceException(() -> orderService.submitOrder(reqVO, userIp), PAY_ORDER_NOT_FOUND);
265 265 }
266 266  
267 267 @Test
... ... @@ -274,7 +274,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
274 274 String userIp = randomString();
275 275  
276 276 // 调用, 并断言异常
277   - assertServiceException(() -> orderService.submitOrder(reqVO, userIp), ORDER_STATUS_IS_NOT_WAITING);
  277 + assertServiceException(() -> orderService.submitOrder(reqVO, userIp), PAY_ORDER_STATUS_IS_NOT_WAITING);
278 278 }
279 279  
280 280 @Test
... ... @@ -287,7 +287,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
287 287 String userIp = randomString();
288 288  
289 289 // 调用, 并断言异常
290   - assertServiceException(() -> orderService.submitOrder(reqVO, userIp), ORDER_STATUS_IS_SUCCESS);
  290 + assertServiceException(() -> orderService.submitOrder(reqVO, userIp), PAY_ORDER_STATUS_IS_SUCCESS);
291 291 }
292 292  
293 293 @Test
... ... @@ -301,7 +301,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
301 301 String userIp = randomString();
302 302  
303 303 // 调用, 并断言异常
304   - assertServiceException(() -> orderService.submitOrder(reqVO, userIp), ORDER_IS_EXPIRED);
  304 + assertServiceException(() -> orderService.submitOrder(reqVO, userIp), PAY_ORDER_IS_EXPIRED);
305 305 }
306 306  
307 307 @Test
... ... @@ -366,7 +366,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
366 366  
367 367 // 调用,并断言异常
368 368 assertServiceException(() -> orderService.submitOrder(reqVO, userIp),
369   - ORDER_SUBMIT_CHANNEL_ERROR, "001", "模拟异常");
  369 + PAY_ORDER_SUBMIT_CHANNEL_ERROR, "001", "模拟异常");
370 370 // 断言,数据记录(PayOrderExtensionDO)
371 371 PayOrderExtensionDO orderExtension = orderExtensionMapper.selectOne(null);
372 372 assertNotNull(orderExtension);
... ... @@ -450,7 +450,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
450 450  
451 451 // 调用,并断言异常
452 452 assertServiceException(() -> orderService.validateOrderActuallyPaid(id),
453   - ORDER_EXTENSION_IS_PAID);
  453 + PAY_ORDER_EXTENSION_IS_PAID);
454 454 }
455 455  
456 456 @Test
... ... @@ -469,7 +469,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
469 469  
470 470 // 调用,并断言异常
471 471 assertServiceException(() -> orderService.validateOrderActuallyPaid(id),
472   - ORDER_EXTENSION_IS_PAID);
  472 + PAY_ORDER_EXTENSION_IS_PAID);
473 473 }
474 474  
475 475 @Test
... ... @@ -519,7 +519,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
519 519  
520 520 // 调用,并断言异常
521 521 assertServiceException(() -> orderService.notifyOrder(channel, notify),
522   - ORDER_EXTENSION_NOT_FOUND);
  522 + PAY_ORDER_EXTENSION_NOT_FOUND);
523 523 }
524 524  
525 525 @Test
... ... @@ -537,7 +537,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
537 537  
538 538 // 调用,并断言异常
539 539 assertServiceException(() -> orderService.notifyOrder(channel, notify),
540   - ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
  540 + PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
541 541 }
542 542  
543 543 @Test
... ... @@ -555,7 +555,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
555 555  
556 556 // 调用,并断言异常
557 557 assertServiceException(() -> orderService.notifyOrder(channel, notify),
558   - ORDER_NOT_FOUND);
  558 + PAY_ORDER_NOT_FOUND);
559 559 // 断言 PayOrderExtensionDO :数据更新被回滚
560 560 assertPojoEquals(orderExtension, orderExtensionMapper.selectOne(null));
561 561 }
... ... @@ -588,7 +588,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
588 588  
589 589 // 调用,并断言异常
590 590 assertServiceException(() -> orderService.notifyOrder(channel, notify),
591   - ORDER_STATUS_IS_NOT_WAITING);
  591 + PAY_ORDER_STATUS_IS_NOT_WAITING);
592 592 // 断言 PayOrderExtensionDO :数据未更新,因为它是 SUCCESS
593 593 assertPojoEquals(orderExtension, orderExtensionMapper.selectOne(null));
594 594 }
... ... @@ -673,7 +673,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
673 673  
674 674 // 调用,并断言异常
675 675 assertServiceException(() -> orderService.notifyOrder(channel, notify),
676   - ORDER_EXTENSION_NOT_FOUND);
  676 + PAY_ORDER_EXTENSION_NOT_FOUND);
677 677 }
678 678  
679 679 @Test
... ... @@ -729,7 +729,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
729 729  
730 730 // 调用,并断言异常
731 731 assertServiceException(() -> orderService.notifyOrder(channel, notify),
732   - ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
  732 + PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
733 733 }
734 734  
735 735 @Test
... ... @@ -762,7 +762,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
762 762  
763 763 // 调用,并断言异常
764 764 assertServiceException(() -> orderService.updateOrderRefundPrice(id, incrRefundPrice),
765   - ORDER_NOT_FOUND);
  765 + PAY_ORDER_NOT_FOUND);
766 766 }
767 767  
768 768 @Test
... ... @@ -786,7 +786,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
786 786  
787 787 // 调用,并断言异常
788 788 assertServiceException(() -> orderService.updateOrderRefundPrice(id, incrRefundPrice),
789   - ORDER_REFUND_FAIL_STATUS_ERROR);
  789 + PAY_ORDER_REFUND_FAIL_STATUS_ERROR);
790 790 }
791 791  
792 792 @Test
... ...
yudao-module-pay/yudao-module-pay-biz/src/test/java/cn/iocoder/yudao/module/pay/service/refund/PayRefundServiceTest.java
... ... @@ -219,7 +219,7 @@ public class PayRefundServiceTest extends BaseDbAndRedisUnitTest {
219 219  
220 220 // 调用,并断言异常
221 221 assertServiceException(() -> refundService.createPayRefund(reqDTO),
222   - ORDER_NOT_FOUND);
  222 + PAY_ORDER_NOT_FOUND);
223 223 }
224 224  
225 225 @Test
... ... @@ -245,7 +245,7 @@ public class PayRefundServiceTest extends BaseDbAndRedisUnitTest {
245 245  
246 246 // 调用,并断言异常
247 247 assertServiceException(() -> refundService.createPayRefund(reqDTO),
248   - ORDER_REFUND_FAIL_STATUS_ERROR);
  248 + PAY_ORDER_REFUND_FAIL_STATUS_ERROR);
249 249 }
250 250  
251 251 @Test
... ...