Procházet zdrojové kódy

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

puhui999 před 1 rokem
rodič
revize
245f14b8f1

+ 16 - 7
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
 public interface SeckillActivityApi {
 
     /**
-     * 更新秒杀库存
+     * 更新秒杀库存(减少)
      *
-     * @param id 活动编号
-     * @param skuId      sku 编号
-     * @param count      数量
+     * @param id    活动编号
+     * @param skuId sku 编号
+     * @param count 数量(正数)
+     */
+    void updateSeckillStockDecr(Long id, Long skuId, Integer count);
+
+    /**
+     * 更新秒杀库存(增加)
+     *
+     * @param id    活动编号
+     * @param skuId sku 编号
+     * @param count 数量(正数)
      */
-    void updateSeckillStock(Long id, Long skuId, Integer count);
+    void updateSeckillStockIncr(Long id, Long skuId, Integer count);
 
     /**
      * 【下单前】校验是否参与秒杀活动
@@ -24,8 +33,8 @@ public interface SeckillActivityApi {
      * 如果校验失败,则抛出业务异常
      *
      * @param activityId 活动编号
-     * @param skuId SKU 编号
-     * @param count 数量
+     * @param skuId      SKU 编号
+     * @param count      数量
      * @return 秒杀信息
      */
     SeckillValidateJoinRespDTO validateJoinSeckill(Long activityId, Long skuId, Integer count);

+ 7 - 2
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 {
     private SeckillActivityService activityService;
 
     @Override
-    public void updateSeckillStock(Long id, Long skuId, Integer count) {
-        activityService.updateSeckillStock(id, skuId, count);
+    public void updateSeckillStockDecr(Long id, Long skuId, Integer count) {
+        activityService.updateSeckillStockDecr(id, skuId, count);
+    }
+
+    @Override
+    public void updateSeckillStockIncr(Long id, Long skuId, Integer count) {
+        activityService.updateSeckillStockIncr(id, skuId, count);
     }
 
     @Override

+ 2 - 1
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 {
     private Integer singleLimitCount;
 
     /**
-     * 秒杀库存(剩余库存秒杀时扣减)
+     * 秒杀库存-秒杀下单时怎加,恢复库存是减少
+     * 也就是说这个是记录当前秒杀活动用户购买的商品数量和
      */
     private Integer stock;
     /**

+ 21 - 3
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/seckill/seckillactivity/SeckillActivityMapper.java

@@ -1,5 +1,6 @@
 package cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckillactivity;
 
+import cn.hutool.core.lang.Assert;
 import cn.hutool.core.util.ObjectUtil;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
@@ -39,13 +40,14 @@ public interface SeckillActivityMapper extends BaseMapperX<SeckillActivityDO> {
     }
 
     /**
-     * 更新活动库存
+     * 更新活动库存(减少)
      *
      * @param id    活动编号
-     * @param count 扣减的库存数量
+     * @param count 扣减的库存数量(正数)
      * @return 影响的行数
      */
-    default int updateStock(Long id, int count) {
+    default int updateStockDecr(Long id, int count) {
+        Assert.isTrue(count > 0);
         return update(null, new LambdaUpdateWrapper<SeckillActivityDO>()
                 .eq(SeckillActivityDO::getId, id)
                 .gt(SeckillActivityDO::getTotalStock, 0)
@@ -53,6 +55,21 @@ public interface SeckillActivityMapper extends BaseMapperX<SeckillActivityDO> {
                 .setSql("total_stock = total_stock - " + count));
     }
 
+    /**
+     * 更新活动库存(增加)
+     *
+     * @param id    活动编号
+     * @param count 增加的库存数量(正数)
+     * @return 影响的行数
+     */
+    default int updateStockIncr(Long id, int count) {
+        Assert.isTrue(count > 0);
+        return update(null, new LambdaUpdateWrapper<SeckillActivityDO>()
+                .eq(SeckillActivityDO::getId, id)
+                .setSql("stock = stock - " + count)
+                .setSql("total_stock = total_stock + " + count));
+    }
+
     default PageResult<SeckillActivityDO> selectPage(AppSeckillActivityPageReqVO pageReqVO, Integer status) {
         return selectPage(pageReqVO, new LambdaQueryWrapperX<SeckillActivityDO>()
                 .eqIfPresent(SeckillActivityDO::getStatus, status)
@@ -62,6 +79,7 @@ public interface SeckillActivityMapper extends BaseMapperX<SeckillActivityDO> {
 
     /**
      * 查询出指定 spuId 的 spu 参加的活动最接近现在的一条记录。多个的话,一个 spuId 对应一个最近的活动编号
+     *
      * @param spuIds spu 编号
      * @param status 状态
      * @return 包含 spuId 和 activityId 的 map 对象列表

+ 19 - 3
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/seckill/seckillactivity/SeckillProductMapper.java

@@ -1,5 +1,6 @@
 package cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckillactivity;
 
+import cn.hutool.core.lang.Assert;
 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillProductDO;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
@@ -30,17 +31,32 @@ public interface SeckillProductMapper extends BaseMapperX<SeckillProductDO> {
     }
 
     /**
-     * 更新活动库存
+     * 更新活动库存(减少)
      *
      * @param id    活动编号
-     * @param count 扣减的库存数量
+     * @param count 扣减的库存数量(减少库存)
      * @return 影响的行数
      */
-    default int updateStock(Long id, int count) {
+    default int updateStockDecr(Long id, int count) {
+        Assert.isTrue(count > 0);
         return update(null, new LambdaUpdateWrapper<SeckillProductDO>()
                 .eq(SeckillProductDO::getId, id)
                 .gt(SeckillProductDO::getStock, count)
                 .setSql("stock = stock - " + count));
     }
 
+    /**
+     * 更新活动库存(增加)
+     *
+     * @param id    活动编号
+     * @param count 需要增加的库存(增加库存)
+     * @return 影响的行数
+     */
+    default int updateStockIncr(Long id, int count) {
+        Assert.isTrue(count > 0);
+        return update(null, new LambdaUpdateWrapper<SeckillProductDO>()
+                .eq(SeckillProductDO::getId, id)
+                .setSql("stock = stock + " + count));
+    }
+
 }

+ 14 - 5
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 {
     void updateSeckillActivity(@Valid SeckillActivityUpdateReqVO updateReqVO);
 
     /**
-     * 更新秒杀库存
+     * 更新秒杀库存(减少)
      *
      * @param id    活动编号
      * @param skuId sku 编号
-     * @param count 数量
+     * @param count 数量(正数)
      */
-    void updateSeckillStock(Long id, Long skuId, Integer count);
+    void updateSeckillStockDecr(Long id, Long skuId, Integer count);
+
+    /**
+     * 更新秒杀库存(增加)
+     *
+     * @param id    活动编号
+     * @param skuId sku 编号
+     * @param count 数量(正数)
+     */
+    void updateSeckillStockIncr(Long id, Long skuId, Integer count);
 
     /**
      * 关闭秒杀活动
@@ -113,8 +122,8 @@ public interface SeckillActivityService {
      * 如果校验失败,则抛出业务异常
      *
      * @param activityId 活动编号
-     * @param skuId SKU 编号
-     * @param count 数量
+     * @param skuId      SKU 编号
+     * @param count      数量
      * @return 秒杀信息
      */
     SeckillValidateJoinRespDTO validateJoinSeckill(Long activityId, Long skuId, Integer count);

+ 13 - 3
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 {
 
     @Override
     @Transactional(rollbackFor = Exception.class)
-    public void updateSeckillStock(Long id, Long skuId, Integer count) {
+    public void updateSeckillStockDecr(Long id, Long skuId, Integer count) {
         // 1.1 校验活动库存是否充足
         SeckillActivityDO seckillActivity = validateSeckillActivityExists(id);
         if (count > seckillActivity.getTotalStock()) {
@@ -170,18 +170,28 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
         }
 
         // 2.1 更新活动商品库存
-        int updateCount = seckillProductMapper.updateStock(product.getId(), count);
+        int updateCount = seckillProductMapper.updateStockDecr(product.getId(), count);
         if (updateCount == 0) {
             throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL);
         }
 
         // 2.2 更新活动库存
-        updateCount = seckillActivityMapper.updateStock(seckillActivity.getId(), count);
+        updateCount = seckillActivityMapper.updateStockDecr(seckillActivity.getId(), count);
         if (updateCount == 0) {
             throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL);
         }
     }
 
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void updateSeckillStockIncr(Long id, Long skuId, Integer count) {
+        SeckillProductDO product = seckillProductMapper.selectByActivityIdAndSkuId(id, skuId);
+        // 更新活动商品库存
+        seckillProductMapper.updateStockIncr(product.getId(), count);
+        // 更新活动库存
+        seckillActivityMapper.updateStockIncr(id, count);
+    }
+
     /**
      * 更新秒杀商品
      *

+ 9 - 1
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeSeckillHandler.java

@@ -1,5 +1,6 @@
 package cn.iocoder.yudao.module.trade.service.order.handler;
 
+import cn.hutool.core.lang.Assert;
 import cn.iocoder.yudao.module.promotion.api.seckill.SeckillActivityApi;
 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
@@ -25,9 +26,11 @@ public class TradeSeckillHandler implements TradeOrderHandler {
         if (TradeOrderTypeEnum.isSeckill(order.getType())) {
             return;
         }
+        // 明确校验一下
+        Assert.isTrue(orderItems.size() == 1, "秒杀时,只允许选择一个商品");
 
         // 扣减秒杀活动的库存
-        seckillActivityApi.updateSeckillStock(order.getSeckillActivityId(),
+        seckillActivityApi.updateSeckillStockDecr(order.getSeckillActivityId(),
                 orderItems.get(0).getSkuId(), orderItems.get(0).getCount());
     }
 
@@ -36,7 +39,12 @@ public class TradeSeckillHandler implements TradeOrderHandler {
         if (TradeOrderTypeEnum.isSeckill(order.getType())) {
             return;
         }
+        // 明确校验一下
+        Assert.isTrue(orderItems.size() == 1, "秒杀时,只允许选择一个商品");
 
+        // 恢复秒杀活动的库存
+        seckillActivityApi.updateSeckillStockIncr(order.getSeckillActivityId(),
+                orderItems.get(0).getSkuId(), orderItems.get(0).getCount());
     }
 
 }