Commit 67809be46d94a124d0bb7a92171f1f672072a791

Authored by puhui999
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&lt;PointProductDO&gt; {
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
... ... @@ -55,4 +55,8 @@ public enum TradeOrderTypeEnum implements IntArrayValuable {
55 55 return ObjectUtil.equal(type, COMBINATION.getType());
56 56 }
57 57  
  58 + public static boolean isPoint(Integer type) {
  59 + return ObjectUtil.equal(type, POINT.getType());
  60 + }
  61 +
58 62 }
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderDO.java
... ... @@ -353,4 +353,11 @@ public class TradeOrderDO extends BaseDO {
353 353 */
354 354 private Long combinationRecordId;
355 355  
  356 + /**
  357 + * 积分商城活动的编号
  358 + *
  359 + * 关联 PointActivityDO 的 id 字段
  360 + */
  361 + private Long pointActivityId;
  362 +
356 363 }
... ...
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);
... ...