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

This commit is contained in:
puhui999 2023-10-10 10:25:57 +08:00
parent 831983e314
commit 245f14b8f1
8 changed files with 101 additions and 25 deletions

View File

@ -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 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);
/**
* 下单前校验是否参与秒杀活动
@ -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);

View File

@ -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

View File

@ -77,7 +77,8 @@ public class SeckillActivityDO extends BaseDO {
private Integer singleLimitCount;
/**
* 秒杀库存(剩余库存秒杀时扣减)
* 秒杀库存-秒杀下单时怎加恢复库存是减少
* 也就是说这个是记录当前秒杀活动用户购买的商品数量和
*/
private Integer stock;
/**

View File

@ -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 对象列表

View File

@ -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));
}
}

View File

@ -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);

View File

@ -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);
}
/**
* 更新秒杀商品
*

View File

@ -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());
}
}