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