Merge branch 'develop' of https://gitee.com/zhijiantianya/ruoyi-vue-pro into master-jdk17

This commit is contained in:
YunaiV
2024-10-04 19:41:03 +08:00
26 changed files with 496 additions and 19 deletions

View File

@@ -0,0 +1,36 @@
package cn.iocoder.yudao.module.promotion.api.point;
import cn.iocoder.yudao.module.promotion.api.point.dto.PointValidateJoinRespDTO;
import cn.iocoder.yudao.module.promotion.service.point.PointActivityService;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
/**
* 积分商城活动 Api 接口实现类
*
* @author HUIHUI
*/
@Service
@Validated
public class PointActivityApiImpl implements PointActivityApi {
@Resource
private PointActivityService pointActivityService;
@Override
public PointValidateJoinRespDTO validateJoinPointActivity(Long activityId, Long skuId, Integer count) {
return pointActivityService.validateJoinPointActivity(activityId, skuId, count);
}
@Override
public void updatePointStockDecr(Long id, Long skuId, Integer count) {
pointActivityService.updatePointStockDecr(id, skuId, count);
}
@Override
public void updatePointStockIncr(Long id, Long skuId, Integer count) {
pointActivityService.updatePointStockIncr(id, skuId, count);
}
}

View File

@@ -76,8 +76,11 @@ public class AppPointActivityController {
// 2. 拼接数据
List<PointProductDO> products = pointActivityService.getPointProductListByActivityIds(Collections.singletonList(id));
AppPointActivityDetailRespVO respVO = BeanUtils.toBean(activity, AppPointActivityDetailRespVO.class);
respVO.setProducts(BeanUtils.toBean(products, AppPointActivityDetailRespVO.Product.class));
PointProductDO minProduct = getMinObject(products, PointProductDO::getPoint);
assert minProduct != null;
AppPointActivityDetailRespVO respVO = BeanUtils.toBean(activity, AppPointActivityDetailRespVO.class)
.setProducts(BeanUtils.toBean(products, AppPointActivityDetailRespVO.Product.class))
.setPoint(minProduct.getPoint()).setPrice(minProduct.getPrice());
return success(respVO);
}

View File

@@ -30,6 +30,14 @@ public class AppPointActivityDetailRespVO {
@Schema(description = "商品信息数组", requiredMode = Schema.RequiredMode.REQUIRED)
private List<Product> products;
//======================= 显示所需兑换积分最少的 SKU 信息 =======================
@Schema(description = "兑换积分", requiredMode = Schema.RequiredMode.REQUIRED)
private Integer point;
@Schema(description = "兑换金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "15860")
private Integer price;
@Schema(description = "商品信息")
@Data
public static class Product {

View File

@@ -1,10 +1,12 @@
package cn.iocoder.yudao.module.promotion.dal.mysql.point;
import cn.hutool.core.lang.Assert;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.promotion.controller.admin.point.vo.activity.PointActivityPageReqVO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.point.PointActivityDO;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import org.apache.ibatis.annotations.Mapper;
/**
@@ -25,4 +27,33 @@ public interface PointActivityMapper extends BaseMapperX<PointActivityDO> {
.orderByDesc(PointActivityDO::getId));
}
/**
* 更新活动库存(减少)
*
* @param id 活动编号
* @param count 扣减的库存数量(正数)
* @return 影响的行数
*/
default int updateStockDecr(Long id, int count) {
Assert.isTrue(count > 0);
return update(null, new LambdaUpdateWrapper<PointActivityDO>()
.eq(PointActivityDO::getId, id)
.ge(PointActivityDO::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<PointActivityDO>()
.eq(PointActivityDO::getId, id)
.setSql("stock = stock + " + count));
}
}

View File

@@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.promotion.dal.mysql.point;
import cn.hutool.core.lang.Assert;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.module.promotion.dal.dataobject.point.PointProductDO;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
@@ -29,4 +30,37 @@ public interface PointProductMapper extends BaseMapperX<PointProductDO> {
.eq(PointProductDO::getActivityId, pointProductDO.getActivityId()));
}
default PointProductDO selectListByActivityIdAndSkuId(Long activityId, Long skuId) {
return selectOne(PointProductDO::getActivityId, activityId,
PointProductDO::getSkuId, skuId);
}
/**
* 更新活动库存(减少)
*
* @param id 活动编号
* @param count 扣减的库存数量(减少库存)
* @return 影响的行数
*/
default int updateStockDecr(Long id, int count) {
Assert.isTrue(count > 0);
return update(null, new LambdaUpdateWrapper<PointProductDO>()
.eq(PointProductDO::getId, id)
.ge(PointProductDO::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<PointProductDO>()
.eq(PointProductDO::getId, id)
.setSql("stock = stock + " + count));
}
}

View File

@@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.promotion.service.point;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.promotion.api.point.dto.PointValidateJoinRespDTO;
import cn.iocoder.yudao.module.promotion.controller.admin.point.vo.activity.PointActivityPageReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.point.vo.activity.PointActivitySaveReqVO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.point.PointActivityDO;
@@ -32,6 +33,24 @@ public interface PointActivityService {
*/
void updatePointActivity(@Valid PointActivitySaveReqVO updateReqVO);
/**
* 更新积分商城商品库存(减少)
*
* @param id 活动编号
* @param skuId sku 编号
* @param count 数量(正数)
*/
void updatePointStockDecr(Long id, Long skuId, Integer count);
/**
* 更新积分商城商品库存(增加)
*
* @param id 活动编号
* @param skuId sku 编号
* @param count 数量(正数)
*/
void updatePointStockIncr(Long id, Long skuId, Integer count);
/**
* 关闭积分商城活动
*
@@ -78,4 +97,16 @@ public interface PointActivityService {
*/
List<PointProductDO> getPointProductListByActivityIds(Collection<Long> activityIds);
/**
* 【下单前】校验是否参与积分商城活动
*
* 如果校验失败,则抛出业务异常
*
* @param activityId 活动编号
* @param skuId SKU 编号
* @param count 数量
* @return 积分商城商品信息
*/
PointValidateJoinRespDTO validateJoinPointActivity(Long activityId, Long skuId, Integer count);
}

View File

@@ -8,6 +8,7 @@ import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
import cn.iocoder.yudao.module.promotion.api.point.dto.PointValidateJoinRespDTO;
import cn.iocoder.yudao.module.promotion.controller.admin.point.vo.activity.PointActivityPageReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.point.vo.activity.PointActivitySaveReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.point.vo.product.PointProductSaveReqVO;
@@ -102,6 +103,43 @@ public class PointActivityServiceImpl implements PointActivityService {
updateSeckillProduct(updateObj, updateReqVO.getProducts());
}
@Override
@Transactional(rollbackFor = Exception.class)
public void updatePointStockDecr(Long id, Long skuId, Integer count) {
// 1.1 校验活动库存是否充足
PointActivityDO activity = validatePointActivityExists(id);
if (count > activity.getStock()) {
throw exception(POINT_ACTIVITY_UPDATE_STOCK_FAIL);
}
// 1.2 校验商品库存是否充足
PointProductDO product = pointProductMapper.selectListByActivityIdAndSkuId(id, skuId);
if (product == null || count > product.getStock()) {
throw exception(POINT_ACTIVITY_UPDATE_STOCK_FAIL);
}
// 2.1 更新活动商品库存
int updateCount = pointProductMapper.updateStockDecr(product.getId(), count);
if (updateCount == 0) {
throw exception(POINT_ACTIVITY_UPDATE_STOCK_FAIL);
}
// 2.2 更新活动库存
updateCount = pointActivityMapper.updateStockDecr(id, count);
if (updateCount == 0) {
throw exception(POINT_ACTIVITY_UPDATE_STOCK_FAIL);
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public void updatePointStockIncr(Long id, Long skuId, Integer count) {
PointProductDO product = pointProductMapper.selectListByActivityIdAndSkuId(id, skuId);
// 更新活动商品库存
pointProductMapper.updateStockIncr(product.getId(), count);
// 更新活动库存
pointActivityMapper.updateStockIncr(id, count);
}
@Override
@Transactional(rollbackFor = Exception.class)
public void closePointActivity(Long id) {
@@ -244,4 +282,28 @@ public class PointActivityServiceImpl implements PointActivityService {
return pointProductMapper.selectListByActivityId(activityIds);
}
@Override
public PointValidateJoinRespDTO validateJoinPointActivity(Long activityId, Long skuId, Integer count) {
// 1. 校验积分商城活动是否存在
PointActivityDO activity = validatePointActivityExists(activityId);
if (CommonStatusEnum.isDisable(activity.getStatus())) {
throw exception(POINT_ACTIVITY_JOIN_ACTIVITY_STATUS_CLOSED);
}
// 2.1 校验积分商城商品是否存在
PointProductDO product = pointProductMapper.selectListByActivityIdAndSkuId(activityId, skuId);
if (product == null) {
throw exception(POINT_ACTIVITY_JOIN_ACTIVITY_PRODUCT_NOT_EXISTS);
}
// 2.2 超过单次购买限制
if (count > product.getCount()) {
throw exception(POINT_ACTIVITY_JOIN_ACTIVITY_SINGLE_LIMIT_COUNT_EXCEED);
}
// 2.2 校验库存是否充足
if (count > product.getStock()) {
throw exception(POINT_ACTIVITY_UPDATE_STOCK_FAIL);
}
return BeanUtils.toBean(product, PointValidateJoinRespDTO.class);
}
}

View File

@@ -160,7 +160,7 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
public void updateSeckillStockDecr(Long id, Long skuId, Integer count) {
// 1.1 校验活动库存是否充足
SeckillActivityDO seckillActivity = validateSeckillActivityExists(id);
if (count > seckillActivity.getTotalStock()) {
if (count > seckillActivity.getStock()) {
throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL);
}
// 1.2 校验商品库存是否充足