秒杀活动:完成订单取消时恢复活动库存和商品库存
This commit is contained in:
parent
831983e314
commit
245f14b8f1
|
@ -10,13 +10,22 @@ import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillValidateJoinResp
|
||||||
public interface SeckillActivityApi {
|
public interface SeckillActivityApi {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新秒杀库存
|
* 更新秒杀库存(减少)
|
||||||
*
|
*
|
||||||
* @param id 活动编号
|
* @param id 活动编号
|
||||||
* @param skuId sku 编号
|
* @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);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 【下单前】校验是否参与秒杀活动
|
* 【下单前】校验是否参与秒杀活动
|
||||||
|
@ -24,8 +33,8 @@ public interface SeckillActivityApi {
|
||||||
* 如果校验失败,则抛出业务异常
|
* 如果校验失败,则抛出业务异常
|
||||||
*
|
*
|
||||||
* @param activityId 活动编号
|
* @param activityId 活动编号
|
||||||
* @param skuId SKU 编号
|
* @param skuId SKU 编号
|
||||||
* @param count 数量
|
* @param count 数量
|
||||||
* @return 秒杀信息
|
* @return 秒杀信息
|
||||||
*/
|
*/
|
||||||
SeckillValidateJoinRespDTO validateJoinSeckill(Long activityId, Long skuId, Integer count);
|
SeckillValidateJoinRespDTO validateJoinSeckill(Long activityId, Long skuId, Integer count);
|
||||||
|
|
|
@ -18,8 +18,13 @@ public class SeckillActivityApiImpl implements SeckillActivityApi {
|
||||||
private SeckillActivityService activityService;
|
private SeckillActivityService activityService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateSeckillStock(Long id, Long skuId, Integer count) {
|
public void updateSeckillStockDecr(Long id, Long skuId, Integer count) {
|
||||||
activityService.updateSeckillStock(id, skuId, count);
|
activityService.updateSeckillStockDecr(id, skuId, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateSeckillStockIncr(Long id, Long skuId, Integer count) {
|
||||||
|
activityService.updateSeckillStockIncr(id, skuId, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -77,7 +77,8 @@ public class SeckillActivityDO extends BaseDO {
|
||||||
private Integer singleLimitCount;
|
private Integer singleLimitCount;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 秒杀库存(剩余库存秒杀时扣减)
|
* 秒杀库存-秒杀下单时怎加,恢复库存是减少
|
||||||
|
* 也就是说这个是记录当前秒杀活动用户购买的商品数量和
|
||||||
*/
|
*/
|
||||||
private Integer stock;
|
private Integer stock;
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckillactivity;
|
package cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckillactivity;
|
||||||
|
|
||||||
|
import cn.hutool.core.lang.Assert;
|
||||||
import cn.hutool.core.util.ObjectUtil;
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||||
|
@ -39,13 +40,14 @@ public interface SeckillActivityMapper extends BaseMapperX<SeckillActivityDO> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新活动库存
|
* 更新活动库存(减少)
|
||||||
*
|
*
|
||||||
* @param id 活动编号
|
* @param id 活动编号
|
||||||
* @param count 扣减的库存数量
|
* @param count 扣减的库存数量(正数)
|
||||||
* @return 影响的行数
|
* @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>()
|
return update(null, new LambdaUpdateWrapper<SeckillActivityDO>()
|
||||||
.eq(SeckillActivityDO::getId, id)
|
.eq(SeckillActivityDO::getId, id)
|
||||||
.gt(SeckillActivityDO::getTotalStock, 0)
|
.gt(SeckillActivityDO::getTotalStock, 0)
|
||||||
|
@ -53,6 +55,21 @@ public interface SeckillActivityMapper extends BaseMapperX<SeckillActivityDO> {
|
||||||
.setSql("total_stock = total_stock - " + count));
|
.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) {
|
default PageResult<SeckillActivityDO> selectPage(AppSeckillActivityPageReqVO pageReqVO, Integer status) {
|
||||||
return selectPage(pageReqVO, new LambdaQueryWrapperX<SeckillActivityDO>()
|
return selectPage(pageReqVO, new LambdaQueryWrapperX<SeckillActivityDO>()
|
||||||
.eqIfPresent(SeckillActivityDO::getStatus, status)
|
.eqIfPresent(SeckillActivityDO::getStatus, status)
|
||||||
|
@ -62,6 +79,7 @@ public interface SeckillActivityMapper extends BaseMapperX<SeckillActivityDO> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询出指定 spuId 的 spu 参加的活动最接近现在的一条记录。多个的话,一个 spuId 对应一个最近的活动编号
|
* 查询出指定 spuId 的 spu 参加的活动最接近现在的一条记录。多个的话,一个 spuId 对应一个最近的活动编号
|
||||||
|
*
|
||||||
* @param spuIds spu 编号
|
* @param spuIds spu 编号
|
||||||
* @param status 状态
|
* @param status 状态
|
||||||
* @return 包含 spuId 和 activityId 的 map 对象列表
|
* @return 包含 spuId 和 activityId 的 map 对象列表
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckillactivity;
|
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.framework.mybatis.core.mapper.BaseMapperX;
|
||||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillProductDO;
|
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillProductDO;
|
||||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||||
|
@ -30,17 +31,32 @@ public interface SeckillProductMapper extends BaseMapperX<SeckillProductDO> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新活动库存
|
* 更新活动库存(减少)
|
||||||
*
|
*
|
||||||
* @param id 活动编号
|
* @param id 活动编号
|
||||||
* @param count 扣减的库存数量
|
* @param count 扣减的库存数量(减少库存)
|
||||||
* @return 影响的行数
|
* @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>()
|
return update(null, new LambdaUpdateWrapper<SeckillProductDO>()
|
||||||
.eq(SeckillProductDO::getId, id)
|
.eq(SeckillProductDO::getId, id)
|
||||||
.gt(SeckillProductDO::getStock, count)
|
.gt(SeckillProductDO::getStock, count)
|
||||||
.setSql("stock = stock - " + 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));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,13 +36,22 @@ public interface SeckillActivityService {
|
||||||
void updateSeckillActivity(@Valid SeckillActivityUpdateReqVO updateReqVO);
|
void updateSeckillActivity(@Valid SeckillActivityUpdateReqVO updateReqVO);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新秒杀库存
|
* 更新秒杀库存(减少)
|
||||||
*
|
*
|
||||||
* @param id 活动编号
|
* @param id 活动编号
|
||||||
* @param skuId sku 编号
|
* @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 activityId 活动编号
|
||||||
* @param skuId SKU 编号
|
* @param skuId SKU 编号
|
||||||
* @param count 数量
|
* @param count 数量
|
||||||
* @return 秒杀信息
|
* @return 秒杀信息
|
||||||
*/
|
*/
|
||||||
SeckillValidateJoinRespDTO validateJoinSeckill(Long activityId, Long skuId, Integer count);
|
SeckillValidateJoinRespDTO validateJoinSeckill(Long activityId, Long skuId, Integer count);
|
||||||
|
|
|
@ -157,7 +157,7 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public void updateSeckillStock(Long id, Long skuId, Integer count) {
|
public void updateSeckillStockDecr(Long id, Long skuId, Integer count) {
|
||||||
// 1.1 校验活动库存是否充足
|
// 1.1 校验活动库存是否充足
|
||||||
SeckillActivityDO seckillActivity = validateSeckillActivityExists(id);
|
SeckillActivityDO seckillActivity = validateSeckillActivityExists(id);
|
||||||
if (count > seckillActivity.getTotalStock()) {
|
if (count > seckillActivity.getTotalStock()) {
|
||||||
|
@ -170,18 +170,28 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2.1 更新活动商品库存
|
// 2.1 更新活动商品库存
|
||||||
int updateCount = seckillProductMapper.updateStock(product.getId(), count);
|
int updateCount = seckillProductMapper.updateStockDecr(product.getId(), count);
|
||||||
if (updateCount == 0) {
|
if (updateCount == 0) {
|
||||||
throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL);
|
throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2.2 更新活动库存
|
// 2.2 更新活动库存
|
||||||
updateCount = seckillActivityMapper.updateStock(seckillActivity.getId(), count);
|
updateCount = seckillActivityMapper.updateStockDecr(seckillActivity.getId(), count);
|
||||||
if (updateCount == 0) {
|
if (updateCount == 0) {
|
||||||
throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL);
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新秒杀商品
|
* 更新秒杀商品
|
||||||
*
|
*
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package cn.iocoder.yudao.module.trade.service.order.handler;
|
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.promotion.api.seckill.SeckillActivityApi;
|
||||||
import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
|
import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
|
||||||
import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
|
import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
|
||||||
|
@ -25,9 +26,11 @@ public class TradeSeckillHandler implements TradeOrderHandler {
|
||||||
if (TradeOrderTypeEnum.isSeckill(order.getType())) {
|
if (TradeOrderTypeEnum.isSeckill(order.getType())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// 明确校验一下
|
||||||
|
Assert.isTrue(orderItems.size() == 1, "秒杀时,只允许选择一个商品");
|
||||||
|
|
||||||
// 扣减秒杀活动的库存
|
// 扣减秒杀活动的库存
|
||||||
seckillActivityApi.updateSeckillStock(order.getSeckillActivityId(),
|
seckillActivityApi.updateSeckillStockDecr(order.getSeckillActivityId(),
|
||||||
orderItems.get(0).getSkuId(), orderItems.get(0).getCount());
|
orderItems.get(0).getSkuId(), orderItems.get(0).getCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,7 +39,12 @@ public class TradeSeckillHandler implements TradeOrderHandler {
|
||||||
if (TradeOrderTypeEnum.isSeckill(order.getType())) {
|
if (TradeOrderTypeEnum.isSeckill(order.getType())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// 明确校验一下
|
||||||
|
Assert.isTrue(orderItems.size() == 1, "秒杀时,只允许选择一个商品");
|
||||||
|
|
||||||
|
// 恢复秒杀活动的库存
|
||||||
|
seckillActivityApi.updateSeckillStockIncr(order.getSeckillActivityId(),
|
||||||
|
orderItems.get(0).getSkuId(), orderItems.get(0).getCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue