Commit 67809be46d94a124d0bb7a92171f1f672072a791
1 parent
d7236068
【功能完善】商城: APP 完善积分商城活动下单
Showing
11 changed files
with
223 additions
and
3 deletions
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/point/PointActivityApi.java
| ... | ... | @@ -21,5 +21,22 @@ public interface PointActivityApi { |
| 21 | 21 | */ |
| 22 | 22 | PointValidateJoinRespDTO validateJoinPointActivity(Long activityId, Long skuId, Integer count); |
| 23 | 23 | |
| 24 | + /** | |
| 25 | + * 更新积分商城商品库存(减少) | |
| 26 | + * | |
| 27 | + * @param id 活动编号 | |
| 28 | + * @param skuId sku 编号 | |
| 29 | + * @param count 数量(正数) | |
| 30 | + */ | |
| 31 | + void updatePointStockDecr(Long id, Long skuId, Integer count); | |
| 32 | + | |
| 33 | + /** | |
| 34 | + * 更新积分商城商品库存(增加) | |
| 35 | + * | |
| 36 | + * @param id 活动编号 | |
| 37 | + * @param skuId sku 编号 | |
| 38 | + * @param count 数量(正数) | |
| 39 | + */ | |
| 40 | + void updatePointStockIncr(Long id, Long skuId, Integer count); | |
| 24 | 41 | |
| 25 | 42 | } | ... | ... |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/point/PointActivityApiImpl.java
| ... | ... | @@ -23,4 +23,14 @@ public class PointActivityApiImpl implements PointActivityApi { |
| 23 | 23 | return pointActivityService.validateJoinPointActivity(activityId, skuId, count); |
| 24 | 24 | } |
| 25 | 25 | |
| 26 | + @Override | |
| 27 | + public void updatePointStockDecr(Long id, Long skuId, Integer count) { | |
| 28 | + pointActivityService.updatePointStockDecr(id, skuId, count); | |
| 29 | + } | |
| 30 | + | |
| 31 | + @Override | |
| 32 | + public void updatePointStockIncr(Long id, Long skuId, Integer count) { | |
| 33 | + pointActivityService.updatePointStockIncr(id, skuId, count); | |
| 34 | + } | |
| 35 | + | |
| 26 | 36 | } | ... | ... |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/point/PointActivityMapper.java
| 1 | 1 | package cn.iocoder.yudao.module.promotion.dal.mysql.point; |
| 2 | 2 | |
| 3 | +import cn.hutool.core.lang.Assert; | |
| 3 | 4 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 4 | 5 | import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; |
| 5 | 6 | import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; |
| 6 | 7 | import cn.iocoder.yudao.module.promotion.controller.admin.point.vo.activity.PointActivityPageReqVO; |
| 7 | 8 | import cn.iocoder.yudao.module.promotion.dal.dataobject.point.PointActivityDO; |
| 9 | +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; | |
| 8 | 10 | import org.apache.ibatis.annotations.Mapper; |
| 9 | 11 | |
| 10 | 12 | /** |
| ... | ... | @@ -25,4 +27,33 @@ public interface PointActivityMapper extends BaseMapperX<PointActivityDO> { |
| 25 | 27 | .orderByDesc(PointActivityDO::getId)); |
| 26 | 28 | } |
| 27 | 29 | |
| 30 | + /** | |
| 31 | + * 更新活动库存(减少) | |
| 32 | + * | |
| 33 | + * @param id 活动编号 | |
| 34 | + * @param count 扣减的库存数量(正数) | |
| 35 | + * @return 影响的行数 | |
| 36 | + */ | |
| 37 | + default int updateStockDecr(Long id, int count) { | |
| 38 | + Assert.isTrue(count > 0); | |
| 39 | + return update(null, new LambdaUpdateWrapper<PointActivityDO>() | |
| 40 | + .eq(PointActivityDO::getId, id) | |
| 41 | + .ge(PointActivityDO::getStock, count) | |
| 42 | + .setSql("stock = stock - " + count)); | |
| 43 | + } | |
| 44 | + | |
| 45 | + /** | |
| 46 | + * 更新活动库存(增加) | |
| 47 | + * | |
| 48 | + * @param id 活动编号 | |
| 49 | + * @param count 增加的库存数量(正数) | |
| 50 | + * @return 影响的行数 | |
| 51 | + */ | |
| 52 | + default int updateStockIncr(Long id, int count) { | |
| 53 | + Assert.isTrue(count > 0); | |
| 54 | + return update(null, new LambdaUpdateWrapper<PointActivityDO>() | |
| 55 | + .eq(PointActivityDO::getId, id) | |
| 56 | + .setSql("stock = stock + " + count)); | |
| 57 | + } | |
| 58 | + | |
| 28 | 59 | } |
| 29 | 60 | \ No newline at end of file | ... | ... |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/point/PointProductMapper.java
| 1 | 1 | package cn.iocoder.yudao.module.promotion.dal.mysql.point; |
| 2 | 2 | |
| 3 | +import cn.hutool.core.lang.Assert; | |
| 3 | 4 | import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; |
| 4 | 5 | import cn.iocoder.yudao.module.promotion.dal.dataobject.point.PointProductDO; |
| 5 | 6 | import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; |
| ... | ... | @@ -34,4 +35,32 @@ public interface PointProductMapper extends BaseMapperX<PointProductDO> { |
| 34 | 35 | PointProductDO::getSkuId, skuId); |
| 35 | 36 | } |
| 36 | 37 | |
| 38 | + /** | |
| 39 | + * 更新活动库存(减少) | |
| 40 | + * | |
| 41 | + * @param id 活动编号 | |
| 42 | + * @param count 扣减的库存数量(减少库存) | |
| 43 | + * @return 影响的行数 | |
| 44 | + */ | |
| 45 | + default int updateStockDecr(Long id, int count) { | |
| 46 | + Assert.isTrue(count > 0); | |
| 47 | + return update(null, new LambdaUpdateWrapper<PointProductDO>() | |
| 48 | + .eq(PointProductDO::getId, id) | |
| 49 | + .ge(PointProductDO::getStock, count) | |
| 50 | + .setSql("stock = stock - " + count)); | |
| 51 | + } | |
| 52 | + | |
| 53 | + /** | |
| 54 | + * 更新活动库存(增加) | |
| 55 | + * | |
| 56 | + * @param id 活动编号 | |
| 57 | + * @param count 需要增加的库存(增加库存) | |
| 58 | + * @return 影响的行数 | |
| 59 | + */ | |
| 60 | + default int updateStockIncr(Long id, int count) { | |
| 61 | + Assert.isTrue(count > 0); | |
| 62 | + return update(null, new LambdaUpdateWrapper<PointProductDO>() | |
| 63 | + .eq(PointProductDO::getId, id) | |
| 64 | + .setSql("stock = stock + " + count)); | |
| 65 | + } | |
| 37 | 66 | } |
| 38 | 67 | \ No newline at end of file | ... | ... |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/point/PointActivityService.java
| ... | ... | @@ -34,6 +34,24 @@ public interface PointActivityService { |
| 34 | 34 | void updatePointActivity(@Valid PointActivitySaveReqVO updateReqVO); |
| 35 | 35 | |
| 36 | 36 | /** |
| 37 | + * 更新积分商城商品库存(减少) | |
| 38 | + * | |
| 39 | + * @param id 活动编号 | |
| 40 | + * @param skuId sku 编号 | |
| 41 | + * @param count 数量(正数) | |
| 42 | + */ | |
| 43 | + void updatePointStockDecr(Long id, Long skuId, Integer count); | |
| 44 | + | |
| 45 | + /** | |
| 46 | + * 更新积分商城商品库存(增加) | |
| 47 | + * | |
| 48 | + * @param id 活动编号 | |
| 49 | + * @param skuId sku 编号 | |
| 50 | + * @param count 数量(正数) | |
| 51 | + */ | |
| 52 | + void updatePointStockIncr(Long id, Long skuId, Integer count); | |
| 53 | + | |
| 54 | + /** | |
| 37 | 55 | * 关闭积分商城活动 |
| 38 | 56 | * |
| 39 | 57 | * @param id 编号 | ... | ... |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/point/PointActivityServiceImpl.java
| ... | ... | @@ -105,6 +105,43 @@ public class PointActivityServiceImpl implements PointActivityService { |
| 105 | 105 | |
| 106 | 106 | @Override |
| 107 | 107 | @Transactional(rollbackFor = Exception.class) |
| 108 | + public void updatePointStockDecr(Long id, Long skuId, Integer count) { | |
| 109 | + // 1.1 校验活动库存是否充足 | |
| 110 | + PointActivityDO activity = validatePointActivityExists(id); | |
| 111 | + if (count > activity.getStock()) { | |
| 112 | + throw exception(POINT_ACTIVITY_UPDATE_STOCK_FAIL); | |
| 113 | + } | |
| 114 | + // 1.2 校验商品库存是否充足 | |
| 115 | + PointProductDO product = pointProductMapper.selectListByActivityIdAndSkuId(id, skuId); | |
| 116 | + if (product == null || count > product.getStock()) { | |
| 117 | + throw exception(POINT_ACTIVITY_UPDATE_STOCK_FAIL); | |
| 118 | + } | |
| 119 | + | |
| 120 | + // 2.1 更新活动商品库存 | |
| 121 | + int updateCount = pointProductMapper.updateStockDecr(product.getId(), count); | |
| 122 | + if (updateCount == 0) { | |
| 123 | + throw exception(POINT_ACTIVITY_UPDATE_STOCK_FAIL); | |
| 124 | + } | |
| 125 | + | |
| 126 | + // 2.2 更新活动库存 | |
| 127 | + updateCount = pointActivityMapper.updateStockDecr(id, count); | |
| 128 | + if (updateCount == 0) { | |
| 129 | + throw exception(POINT_ACTIVITY_UPDATE_STOCK_FAIL); | |
| 130 | + } | |
| 131 | + } | |
| 132 | + | |
| 133 | + @Override | |
| 134 | + @Transactional(rollbackFor = Exception.class) | |
| 135 | + public void updatePointStockIncr(Long id, Long skuId, Integer count) { | |
| 136 | + PointProductDO product = pointProductMapper.selectListByActivityIdAndSkuId(id, skuId); | |
| 137 | + // 更新活动商品库存 | |
| 138 | + pointProductMapper.updateStockIncr(product.getId(), count); | |
| 139 | + // 更新活动库存 | |
| 140 | + pointActivityMapper.updateStockIncr(id, count); | |
| 141 | + } | |
| 142 | + | |
| 143 | + @Override | |
| 144 | + @Transactional(rollbackFor = Exception.class) | |
| 108 | 145 | public void closePointActivity(Long id) { |
| 109 | 146 | // 校验存在 |
| 110 | 147 | PointActivityDO pointActivity = validatePointActivityExists(id); | ... | ... |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityServiceImpl.java
| ... | ... | @@ -160,7 +160,7 @@ public class SeckillActivityServiceImpl implements SeckillActivityService { |
| 160 | 160 | public void updateSeckillStockDecr(Long id, Long skuId, Integer count) { |
| 161 | 161 | // 1.1 校验活动库存是否充足 |
| 162 | 162 | SeckillActivityDO seckillActivity = validateSeckillActivityExists(id); |
| 163 | - if (count > seckillActivity.getTotalStock()) { | |
| 163 | + if (count > seckillActivity.getStock()) { | |
| 164 | 164 | throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL); |
| 165 | 165 | } |
| 166 | 166 | // 1.2 校验商品库存是否充足 | ... | ... |
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderTypeEnum.java
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderDO.java
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradePointOrderHandler.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.service.order.handler; | |
| 2 | + | |
| 3 | +import cn.hutool.core.collection.CollUtil; | |
| 4 | +import cn.hutool.core.lang.Assert; | |
| 5 | +import cn.iocoder.yudao.module.promotion.api.point.PointActivityApi; | |
| 6 | +import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; | |
| 7 | +import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; | |
| 8 | +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum; | |
| 9 | +import jakarta.annotation.Resource; | |
| 10 | +import org.springframework.stereotype.Component; | |
| 11 | + | |
| 12 | +import java.util.List; | |
| 13 | + | |
| 14 | +/** | |
| 15 | + * 积分商城活动订单的 {@link TradeOrderHandler} 实现类 | |
| 16 | + * | |
| 17 | + * @author HUIHUI | |
| 18 | + */ | |
| 19 | +@Component | |
| 20 | +public class TradePointOrderHandler implements TradeOrderHandler { | |
| 21 | + | |
| 22 | + @Resource | |
| 23 | + private PointActivityApi pointActivityApi; | |
| 24 | + | |
| 25 | + @Override | |
| 26 | + public void beforeOrderCreate(TradeOrderDO order, List<TradeOrderItemDO> orderItems) { | |
| 27 | + if (!TradeOrderTypeEnum.isPoint(order.getType())) { | |
| 28 | + return; | |
| 29 | + } | |
| 30 | + // 明确校验一下 | |
| 31 | + Assert.isTrue(orderItems.size() == 1, "积分商城活动兑换商品兑换时,只允许选择一个商品"); | |
| 32 | + | |
| 33 | + // 扣减积分商城活动的库存 | |
| 34 | + pointActivityApi.updatePointStockDecr(order.getPointActivityId(), | |
| 35 | + orderItems.get(0).getSkuId(), orderItems.get(0).getCount()); | |
| 36 | + } | |
| 37 | + | |
| 38 | + @Override | |
| 39 | + public void afterCancelOrder(TradeOrderDO order, List<TradeOrderItemDO> orderItems) { | |
| 40 | + if (!TradeOrderTypeEnum.isPoint(order.getType())) { | |
| 41 | + return; | |
| 42 | + } | |
| 43 | + // 明确校验一下 | |
| 44 | + Assert.isTrue(orderItems.size() == 1, "积分商城活动兑换商品兑换时,只允许选择一个商品"); | |
| 45 | + | |
| 46 | + // 售后的订单项,已经在 afterCancelOrderItem 回滚库存,所以这里不需要重复回滚 | |
| 47 | + orderItems = filterOrderItemListByNoneAfterSale(orderItems); | |
| 48 | + if (CollUtil.isEmpty(orderItems)) { | |
| 49 | + return; | |
| 50 | + } | |
| 51 | + afterCancelOrderItem(order, orderItems.get(0)); | |
| 52 | + } | |
| 53 | + | |
| 54 | + @Override | |
| 55 | + public void afterCancelOrderItem(TradeOrderDO order, TradeOrderItemDO orderItem) { | |
| 56 | + if (!TradeOrderTypeEnum.isPoint(order.getType())) { | |
| 57 | + return; | |
| 58 | + } | |
| 59 | + // 恢复积分商城活动的库存 | |
| 60 | + pointActivityApi.updatePointStockIncr(order.getPointActivityId(), | |
| 61 | + orderItem.getSkuId(), orderItem.getCount()); | |
| 62 | + } | |
| 63 | + | |
| 64 | +} | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePointActivityPriceCalculator.java
| ... | ... | @@ -63,15 +63,18 @@ public class TradePointActivityPriceCalculator implements TradePriceCalculator { |
| 63 | 63 | // 3.1 记录优惠明细 |
| 64 | 64 | int discountPrice = orderItem.getPayPrice(); // 情况一:单使用积分兑换 |
| 65 | 65 | Assert.isTrue(activity.getPoint() >= 1, "积分商城商品兑换积分必须大于 1"); |
| 66 | - result.setUsePoint(activity.getPoint()); | |
| 66 | + result.setUsePoint(activity.getPoint() * orderItem.getCount()); | |
| 67 | + orderItem.setUsePoint(activity.getPoint() * orderItem.getCount()); | |
| 67 | 68 | if (activity.getPrice() != null && activity.getPrice() > 0) { // 情况二:积分 + 金额 |
| 68 | 69 | discountPrice = orderItem.getPayPrice() - activity.getPrice() * orderItem.getCount(); |
| 69 | 70 | } |
| 71 | + // 3.2 记录优惠明细 | |
| 70 | 72 | TradePriceCalculatorHelper.addPromotion(result, orderItem, |
| 71 | 73 | param.getPointActivityId(), "积分商城活动", PromotionTypeEnum.POINT.getType(), |
| 72 | 74 | StrUtil.format("积分商城活动:省 {} 元", TradePriceCalculatorHelper.formatPrice(discountPrice)), |
| 73 | 75 | discountPrice); |
| 74 | - // 3.2 更新 SKU 优惠金额 | |
| 76 | + | |
| 77 | + // 3.3 更新 SKU 优惠金额 | |
| 75 | 78 | orderItem.setDiscountPrice(orderItem.getDiscountPrice() + discountPrice); |
| 76 | 79 | TradePriceCalculatorHelper.recountPayPrice(orderItem); |
| 77 | 80 | TradePriceCalculatorHelper.recountAllPrice(result); | ... | ... |