Commit 245f14b8f1f4e6b5f1cf38db55a6f81505da11c7

Authored by puhui999
1 parent 831983e3

秒杀活动:完成订单取消时恢复活动库存和商品库存

yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/seckill/SeckillActivityApi.java
... ... @@ -10,13 +10,22 @@ import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillValidateJoinResp
10 10 public interface SeckillActivityApi {
11 11  
12 12 /**
13   - * 更新秒杀库存
  13 + * 更新秒杀库存(减少)
14 14 *
15   - * @param id 活动编号
16   - * @param skuId sku 编号
17   - * @param count 数量
  15 + * @param id 活动编号
  16 + * @param skuId sku 编号
  17 + * @param count 数量(正数)
  18 + */
  19 + void updateSeckillStockDecr(Long id, Long skuId, Integer count);
  20 +
  21 + /**
  22 + * 更新秒杀库存(增加)
  23 + *
  24 + * @param id 活动编号
  25 + * @param skuId sku 编号
  26 + * @param count 数量(正数)
18 27 */
19   - void updateSeckillStock(Long id, Long skuId, Integer count);
  28 + void updateSeckillStockIncr(Long id, Long skuId, Integer count);
20 29  
21 30 /**
22 31 * 【下单前】校验是否参与秒杀活动
... ... @@ -24,8 +33,8 @@ public interface SeckillActivityApi {
24 33 * 如果校验失败,则抛出业务异常
25 34 *
26 35 * @param activityId 活动编号
27   - * @param skuId SKU 编号
28   - * @param count 数量
  36 + * @param skuId SKU 编号
  37 + * @param count 数量
29 38 * @return 秒杀信息
30 39 */
31 40 SeckillValidateJoinRespDTO validateJoinSeckill(Long activityId, Long skuId, Integer count);
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/seckill/SeckillActivityApiImpl.java
... ... @@ -18,8 +18,13 @@ public class SeckillActivityApiImpl implements SeckillActivityApi {
18 18 private SeckillActivityService activityService;
19 19  
20 20 @Override
21   - public void updateSeckillStock(Long id, Long skuId, Integer count) {
22   - activityService.updateSeckillStock(id, skuId, count);
  21 + public void updateSeckillStockDecr(Long id, Long skuId, Integer count) {
  22 + activityService.updateSeckillStockDecr(id, skuId, count);
  23 + }
  24 +
  25 + @Override
  26 + public void updateSeckillStockIncr(Long id, Long skuId, Integer count) {
  27 + activityService.updateSeckillStockIncr(id, skuId, count);
23 28 }
24 29  
25 30 @Override
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/seckill/SeckillActivityDO.java
... ... @@ -77,7 +77,8 @@ public class SeckillActivityDO extends BaseDO {
77 77 private Integer singleLimitCount;
78 78  
79 79 /**
80   - * 秒杀库存(剩余库存秒杀时扣减)
  80 + * 秒杀库存-秒杀下单时怎加,恢复库存是减少
  81 + * 也就是说这个是记录当前秒杀活动用户购买的商品数量和
81 82 */
82 83 private Integer stock;
83 84 /**
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/seckill/seckillactivity/SeckillActivityMapper.java
1 1 package cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckillactivity;
2 2  
  3 +import cn.hutool.core.lang.Assert;
3 4 import cn.hutool.core.util.ObjectUtil;
4 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 6 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
... ... @@ -39,13 +40,14 @@ public interface SeckillActivityMapper extends BaseMapperX<SeckillActivityDO> {
39 40 }
40 41  
41 42 /**
42   - * 更新活动库存
  43 + * 更新活动库存(减少)
43 44 *
44 45 * @param id 活动编号
45   - * @param count 扣减的库存数量
  46 + * @param count 扣减的库存数量(正数)
46 47 * @return 影响的行数
47 48 */
48   - default int updateStock(Long id, int count) {
  49 + default int updateStockDecr(Long id, int count) {
  50 + Assert.isTrue(count > 0);
49 51 return update(null, new LambdaUpdateWrapper<SeckillActivityDO>()
50 52 .eq(SeckillActivityDO::getId, id)
51 53 .gt(SeckillActivityDO::getTotalStock, 0)
... ... @@ -53,6 +55,21 @@ public interface SeckillActivityMapper extends BaseMapperX&lt;SeckillActivityDO&gt; {
53 55 .setSql("total_stock = total_stock - " + count));
54 56 }
55 57  
  58 + /**
  59 + * 更新活动库存(增加)
  60 + *
  61 + * @param id 活动编号
  62 + * @param count 增加的库存数量(正数)
  63 + * @return 影响的行数
  64 + */
  65 + default int updateStockIncr(Long id, int count) {
  66 + Assert.isTrue(count > 0);
  67 + return update(null, new LambdaUpdateWrapper<SeckillActivityDO>()
  68 + .eq(SeckillActivityDO::getId, id)
  69 + .setSql("stock = stock - " + count)
  70 + .setSql("total_stock = total_stock + " + count));
  71 + }
  72 +
56 73 default PageResult<SeckillActivityDO> selectPage(AppSeckillActivityPageReqVO pageReqVO, Integer status) {
57 74 return selectPage(pageReqVO, new LambdaQueryWrapperX<SeckillActivityDO>()
58 75 .eqIfPresent(SeckillActivityDO::getStatus, status)
... ... @@ -62,6 +79,7 @@ public interface SeckillActivityMapper extends BaseMapperX&lt;SeckillActivityDO&gt; {
62 79  
63 80 /**
64 81 * 查询出指定 spuId 的 spu 参加的活动最接近现在的一条记录。多个的话,一个 spuId 对应一个最近的活动编号
  82 + *
65 83 * @param spuIds spu 编号
66 84 * @param status 状态
67 85 * @return 包含 spuId 和 activityId 的 map 对象列表
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/seckill/seckillactivity/SeckillProductMapper.java
1 1 package cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckillactivity;
2 2  
  3 +import cn.hutool.core.lang.Assert;
3 4 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
4 5 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillProductDO;
5 6 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
... ... @@ -30,17 +31,32 @@ public interface SeckillProductMapper extends BaseMapperX&lt;SeckillProductDO&gt; {
30 31 }
31 32  
32 33 /**
33   - * 更新活动库存
  34 + * 更新活动库存(减少)
34 35 *
35 36 * @param id 活动编号
36   - * @param count 扣减的库存数量
  37 + * @param count 扣减的库存数量(减少库存)
37 38 * @return 影响的行数
38 39 */
39   - default int updateStock(Long id, int count) {
  40 + default int updateStockDecr(Long id, int count) {
  41 + Assert.isTrue(count > 0);
40 42 return update(null, new LambdaUpdateWrapper<SeckillProductDO>()
41 43 .eq(SeckillProductDO::getId, id)
42 44 .gt(SeckillProductDO::getStock, count)
43 45 .setSql("stock = stock - " + count));
44 46 }
45 47  
  48 + /**
  49 + * 更新活动库存(增加)
  50 + *
  51 + * @param id 活动编号
  52 + * @param count 需要增加的库存(增加库存)
  53 + * @return 影响的行数
  54 + */
  55 + default int updateStockIncr(Long id, int count) {
  56 + Assert.isTrue(count > 0);
  57 + return update(null, new LambdaUpdateWrapper<SeckillProductDO>()
  58 + .eq(SeckillProductDO::getId, id)
  59 + .setSql("stock = stock + " + count));
  60 + }
  61 +
46 62 }
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityService.java
... ... @@ -36,13 +36,22 @@ public interface SeckillActivityService {
36 36 void updateSeckillActivity(@Valid SeckillActivityUpdateReqVO updateReqVO);
37 37  
38 38 /**
39   - * 更新秒杀库存
  39 + * 更新秒杀库存(减少)
40 40 *
41 41 * @param id 活动编号
42 42 * @param skuId sku 编号
43   - * @param count 数量
  43 + * @param count 数量(正数)
44 44 */
45   - void updateSeckillStock(Long id, Long skuId, Integer count);
  45 + void updateSeckillStockDecr(Long id, Long skuId, Integer count);
  46 +
  47 + /**
  48 + * 更新秒杀库存(增加)
  49 + *
  50 + * @param id 活动编号
  51 + * @param skuId sku 编号
  52 + * @param count 数量(正数)
  53 + */
  54 + void updateSeckillStockIncr(Long id, Long skuId, Integer count);
46 55  
47 56 /**
48 57 * 关闭秒杀活动
... ... @@ -113,8 +122,8 @@ public interface SeckillActivityService {
113 122 * 如果校验失败,则抛出业务异常
114 123 *
115 124 * @param activityId 活动编号
116   - * @param skuId SKU 编号
117   - * @param count 数量
  125 + * @param skuId SKU 编号
  126 + * @param count 数量
118 127 * @return 秒杀信息
119 128 */
120 129 SeckillValidateJoinRespDTO validateJoinSeckill(Long activityId, Long skuId, Integer count);
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityServiceImpl.java
... ... @@ -157,7 +157,7 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
157 157  
158 158 @Override
159 159 @Transactional(rollbackFor = Exception.class)
160   - public void updateSeckillStock(Long id, Long skuId, Integer count) {
  160 + public void updateSeckillStockDecr(Long id, Long skuId, Integer count) {
161 161 // 1.1 校验活动库存是否充足
162 162 SeckillActivityDO seckillActivity = validateSeckillActivityExists(id);
163 163 if (count > seckillActivity.getTotalStock()) {
... ... @@ -170,18 +170,28 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
170 170 }
171 171  
172 172 // 2.1 更新活动商品库存
173   - int updateCount = seckillProductMapper.updateStock(product.getId(), count);
  173 + int updateCount = seckillProductMapper.updateStockDecr(product.getId(), count);
174 174 if (updateCount == 0) {
175 175 throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL);
176 176 }
177 177  
178 178 // 2.2 更新活动库存
179   - updateCount = seckillActivityMapper.updateStock(seckillActivity.getId(), count);
  179 + updateCount = seckillActivityMapper.updateStockDecr(seckillActivity.getId(), count);
180 180 if (updateCount == 0) {
181 181 throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL);
182 182 }
183 183 }
184 184  
  185 + @Override
  186 + @Transactional(rollbackFor = Exception.class)
  187 + public void updateSeckillStockIncr(Long id, Long skuId, Integer count) {
  188 + SeckillProductDO product = seckillProductMapper.selectByActivityIdAndSkuId(id, skuId);
  189 + // 更新活动商品库存
  190 + seckillProductMapper.updateStockIncr(product.getId(), count);
  191 + // 更新活动库存
  192 + seckillActivityMapper.updateStockIncr(id, count);
  193 + }
  194 +
185 195 /**
186 196 * 更新秒杀商品
187 197 *
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeSeckillHandler.java
1 1 package cn.iocoder.yudao.module.trade.service.order.handler;
2 2  
  3 +import cn.hutool.core.lang.Assert;
3 4 import cn.iocoder.yudao.module.promotion.api.seckill.SeckillActivityApi;
4 5 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
5 6 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
... ... @@ -25,9 +26,11 @@ public class TradeSeckillHandler implements TradeOrderHandler {
25 26 if (TradeOrderTypeEnum.isSeckill(order.getType())) {
26 27 return;
27 28 }
  29 + // 明确校验一下
  30 + Assert.isTrue(orderItems.size() == 1, "秒杀时,只允许选择一个商品");
28 31  
29 32 // 扣减秒杀活动的库存
30   - seckillActivityApi.updateSeckillStock(order.getSeckillActivityId(),
  33 + seckillActivityApi.updateSeckillStockDecr(order.getSeckillActivityId(),
31 34 orderItems.get(0).getSkuId(), orderItems.get(0).getCount());
32 35 }
33 36  
... ... @@ -36,7 +39,12 @@ public class TradeSeckillHandler implements TradeOrderHandler {
36 39 if (TradeOrderTypeEnum.isSeckill(order.getType())) {
37 40 return;
38 41 }
  42 + // 明确校验一下
  43 + Assert.isTrue(orderItems.size() == 1, "秒杀时,只允许选择一个商品");
39 44  
  45 + // 恢复秒杀活动的库存
  46 + seckillActivityApi.updateSeckillStockIncr(order.getSeckillActivityId(),
  47 + orderItems.get(0).getSkuId(), orderItems.get(0).getCount());
40 48 }
41 49  
42 50 }
... ...