Переглянути джерело

【功能完善】商城: APP 完善积分商城活动订单价格计算

puhui999 8 місяців тому
батько
коміт
f01c600492
18 змінених файлів з 237 додано та 18 видалено
  1. 25 0
      yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/point/PointActivityApi.java
  2. 24 0
      yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/point/dto/PointValidateJoinRespDTO.java
  3. 4 0
      yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java
  4. 26 0
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/point/PointActivityApiImpl.java
  5. 5 0
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/point/PointProductMapper.java
  6. 13 0
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/point/PointActivityService.java
  7. 25 0
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/point/PointActivityServiceImpl.java
  8. 6 5
      yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java
  9. 1 0
      yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderTypeEnum.java
  10. 6 2
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/AppTradeOrderSettlementReqVO.java
  11. 2 1
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java
  12. 3 3
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderQueryService.java
  13. 2 2
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderQueryServiceImpl.java
  14. 8 2
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/bo/TradePriceCalculateReqBO.java
  15. 81 0
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePointActivityPriceCalculator.java
  16. 1 0
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePriceCalculator.java
  17. 3 0
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePriceCalculatorHelper.java
  18. 2 3
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeSeckillActivityPriceCalculator.java

+ 25 - 0
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/point/PointActivityApi.java

@@ -0,0 +1,25 @@
+package cn.iocoder.yudao.module.promotion.api.point;
+
+import cn.iocoder.yudao.module.promotion.api.point.dto.PointValidateJoinRespDTO;
+
+/**
+ * 积分商城活动 API 接口
+ *
+ * @author HUIHUI
+ */
+public interface PointActivityApi {
+
+    /**
+     * 【下单前】校验是否参与积分商城活动
+     *
+     * 如果校验失败,则抛出业务异常
+     *
+     * @param activityId 活动编号
+     * @param skuId      SKU 编号
+     * @param count      数量
+     * @return 积分商城商品信息
+     */
+    PointValidateJoinRespDTO validateJoinPointActivity(Long activityId, Long skuId, Integer count);
+
+
+}

+ 24 - 0
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/point/dto/PointValidateJoinRespDTO.java

@@ -0,0 +1,24 @@
+package cn.iocoder.yudao.module.promotion.api.point.dto;
+
+import lombok.Data;
+
+/**
+ * 校验参与积分商城 Response DTO
+ */
+@Data
+public class PointValidateJoinRespDTO {
+
+    /**
+     * 可兑换次数
+     */
+    private Integer count;
+    /**
+     * 所需兑换积分
+     */
+    private Integer point;
+    /**
+     * 所需兑换金额,单位:分
+     */
+    private Integer price;
+
+}

+ 4 - 0
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java

@@ -50,6 +50,10 @@ public interface ErrorCodeConstants {
     ErrorCode POINT_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED = new ErrorCode(1_013_007_002, "积分商城活动已关闭,不能修改");
     ErrorCode POINT_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END = new ErrorCode(1_013_007_003, "积分商城活动未关闭或未结束,不能删除");
     ErrorCode POINT_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED = new ErrorCode(1_013_007_004, "积分商城活动已关闭,不能重复关闭");
+    ErrorCode POINT_ACTIVITY_JOIN_ACTIVITY_STATUS_CLOSED = new ErrorCode(1_013_007_005, "积分商品兑换失败,原因:积分商城活动已关闭");
+    ErrorCode POINT_ACTIVITY_JOIN_ACTIVITY_SINGLE_LIMIT_COUNT_EXCEED = new ErrorCode(1_013_007_006, "积分商品兑换失败,原因:单次限购超出");
+    ErrorCode POINT_ACTIVITY_JOIN_ACTIVITY_PRODUCT_NOT_EXISTS = new ErrorCode(1_013_007_007, "积分商品兑换失败,原因:商品不存在");
+    ErrorCode POINT_ACTIVITY_UPDATE_STOCK_FAIL = new ErrorCode(1_013_007_008, "积分商品兑换失败,原因:积分商品库存不足");
 
     // ========== 秒杀活动 1-013-008-000 ==========
     ErrorCode SECKILL_ACTIVITY_NOT_EXISTS = new ErrorCode(1_013_008_000, "秒杀活动不存在");

+ 26 - 0
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/point/PointActivityApiImpl.java

@@ -0,0 +1,26 @@
+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);
+    }
+
+}

+ 5 - 0
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/point/PointProductMapper.java

@@ -29,4 +29,9 @@ 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);
+    }
+
 }

+ 13 - 0
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/point/PointActivityService.java

@@ -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;
@@ -78,4 +79,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);
+
 }

+ 25 - 0
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/point/PointActivityServiceImpl.java

@@ -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;
@@ -244,4 +245,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);
+    }
+
 }

+ 6 - 5
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java

@@ -58,11 +58,12 @@ public interface ErrorCodeConstants {
 
     // ========== Price 相关 1-011-003-000 ============
     ErrorCode PRICE_CALCULATE_PAY_PRICE_ILLEGAL = new ErrorCode(1_011_003_000, "支付价格计算异常,原因:价格小于等于 0");
-    ErrorCode PRICE_CALCULATE_DELIVERY_PRICE_TEMPLATE_NOT_FOUND = new ErrorCode(1_011_003_002, "计算快递运费异常,找不到对应的运费模板");
-    ErrorCode PRICE_CALCULATE_COUPON_NOT_MATCH_NORMAL_ORDER = new ErrorCode(1_011_003_004, "参与秒杀、拼团、砍价的营销商品,无法使用优惠劵");
-    ErrorCode PRICE_CALCULATE_SECKILL_TOTAL_LIMIT_COUNT = new ErrorCode(1_011_003_005, "参与秒杀的商品,超过了秒杀总限购数量");
-    ErrorCode PRICE_CALCULATE_DELIVERY_PRICE_TYPE_ILLEGAL = new ErrorCode(1_011_003_006, "计算快递运费异常,配送方式不匹配");
-    ErrorCode PRICE_CALCULATE_COUPON_CAN_NOT_USE = new ErrorCode(1_011_003_007, "该优惠劵无法使用,原因:{}」");
+    ErrorCode PRICE_CALCULATE_DELIVERY_PRICE_TEMPLATE_NOT_FOUND = new ErrorCode(1_011_003_001, "计算快递运费异常,找不到对应的运费模板");
+    ErrorCode PRICE_CALCULATE_COUPON_NOT_MATCH_NORMAL_ORDER = new ErrorCode(1_011_003_002, "参与秒杀、拼团、砍价的营销商品,无法使用优惠劵");
+    ErrorCode PRICE_CALCULATE_SECKILL_TOTAL_LIMIT_COUNT = new ErrorCode(1_011_003_003, "参与秒杀的商品,超过了秒杀总限购数量");
+    ErrorCode PRICE_CALCULATE_POINT_TOTAL_LIMIT_COUNT = new ErrorCode(1_011_003_004, "参与积分活动的商品,超过了积分活动商品总限购数量");
+    ErrorCode PRICE_CALCULATE_DELIVERY_PRICE_TYPE_ILLEGAL = new ErrorCode(1_011_003_005, "计算快递运费异常,配送方式不匹配");
+    ErrorCode PRICE_CALCULATE_COUPON_CAN_NOT_USE = new ErrorCode(1_011_003_006, "该优惠劵无法使用,原因:{}」");
 
     // ========== 物流 Express 模块 1-011-004-000 ==========
     ErrorCode EXPRESS_NOT_EXISTS = new ErrorCode(1_011_004_000, "快递公司不存在");

+ 1 - 0
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderTypeEnum.java

@@ -20,6 +20,7 @@ public enum TradeOrderTypeEnum implements IntArrayValuable {
     SECKILL(1, "秒杀订单"),
     BARGAIN(2, "砍价订单"),
     COMBINATION(3, "拼团订单"),
+    POINT(4, "积分商城"),
     ;
 
     public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(TradeOrderTypeEnum::getType).toArray();

+ 6 - 2
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/AppTradeOrderSettlementReqVO.java

@@ -6,13 +6,13 @@ import cn.iocoder.yudao.framework.common.validation.Mobile;
 import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum;
 import com.fasterxml.jackson.annotation.JsonIgnore;
 import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-
 import jakarta.validation.Valid;
 import jakarta.validation.constraints.AssertTrue;
 import jakarta.validation.constraints.Min;
 import jakarta.validation.constraints.NotEmpty;
 import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
 import java.util.List;
 
 @Schema(description = "用户 App - 交易订单结算 Request VO")
@@ -62,6 +62,10 @@ public class AppTradeOrderSettlementReqVO {
     @Schema(description = "砍价记录编号", example = "123")
     private Long bargainRecordId;
 
+    // ========== 积分商城活动相关字段 ==========
+    @Schema(description = "积分商城活动编号", example = "123")
+    private Long pointActivityId;
+
     @AssertTrue(message = "活动商品每次只能购买一种规格")
     @JsonIgnore
     public boolean isValidActivityItems() {

+ 2 - 1
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java

@@ -219,7 +219,8 @@ public interface TradeOrderConvert {
                 .setSeckillActivityId(settlementReqVO.getSeckillActivityId())
                 .setBargainRecordId(settlementReqVO.getBargainRecordId())
                 .setCombinationActivityId(settlementReqVO.getCombinationActivityId())
-                .setCombinationHeadId(settlementReqVO.getCombinationHeadId());
+                .setCombinationHeadId(settlementReqVO.getCombinationHeadId())
+                .setPointActivityId(settlementReqVO.getPointActivityId());
         // 商品项的构建
         Map<Long, CartDO> cartMap = convertMap(cartList, CartDO::getId);
         for (AppTradeOrderSettlementReqVO.Item item : settlementReqVO.getItems()) {

+ 3 - 3
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderQueryService.java

@@ -42,9 +42,9 @@ public interface TradeOrderQueryService {
     /**
      * 获得指定用户,指定活动,指定状态的交易订单
      *
-     * @param userId     用户编号
+     * @param userId                用户编号
      * @param combinationActivityId 活动编号
-     * @param status     订单状态
+     * @param status                订单状态
      * @return 交易订单
      */
     TradeOrderDO getOrderByUserIdAndStatusAndCombination(Long userId, Long combinationActivityId, Integer status);
@@ -116,7 +116,7 @@ public interface TradeOrderQueryService {
      * @param activityId 活动编号
      * @return 秒杀商品数量
      */
-    int getSeckillProductCount(Long userId, Long activityId);
+    int getActivityProductCount(Long userId, Long activityId);
 
     // =================== Order Item ===================
 

+ 2 - 2
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderQueryServiceImpl.java

@@ -23,10 +23,10 @@ import cn.iocoder.yudao.module.trade.framework.delivery.core.client.ExpressClien
 import cn.iocoder.yudao.module.trade.framework.delivery.core.client.dto.ExpressTrackQueryReqDTO;
 import cn.iocoder.yudao.module.trade.framework.delivery.core.client.dto.ExpressTrackRespDTO;
 import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressService;
+import jakarta.annotation.Resource;
 import org.springframework.cache.annotation.Cacheable;
 import org.springframework.stereotype.Service;
 
-import jakarta.annotation.Resource;
 import java.util.*;
 
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
@@ -174,7 +174,7 @@ public class TradeOrderQueryServiceImpl implements TradeOrderQueryService {
     }
 
     @Override
-    public int getSeckillProductCount(Long userId, Long activityId) {
+    public int getActivityProductCount(Long userId, Long activityId) {
         // 获得订单列表
         List<TradeOrderDO> orders = tradeOrderMapper.selectListByUserIdAndSeckillActivityId(userId, activityId);
         orders.removeIf(order -> TradeOrderStatusEnum.isCanceled(order.getStatus())); // 过滤掉【已取消】的订单

+ 8 - 2
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/bo/TradePriceCalculateReqBO.java

@@ -1,11 +1,11 @@
 package cn.iocoder.yudao.module.trade.service.price.bo;
 
 import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum;
-import lombok.Data;
-
 import jakarta.validation.Valid;
 import jakarta.validation.constraints.Min;
 import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
 import java.util.List;
 
 /**
@@ -84,6 +84,12 @@ public class TradePriceCalculateReqBO {
      */
     private Long bargainRecordId;
 
+    // ========== 积分商城活动相关字段 ==========
+    /**
+     * 积分商城活动编号
+     */
+    private Long pointActivityId;
+
     /**
      * 商品 SKU
      */

+ 81 - 0
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePointActivityPriceCalculator.java

@@ -0,0 +1,81 @@
+package cn.iocoder.yudao.module.trade.service.price.calculator;
+
+import cn.hutool.core.lang.Assert;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.iocoder.yudao.module.promotion.api.point.PointActivityApi;
+import cn.iocoder.yudao.module.promotion.api.point.dto.PointValidateJoinRespDTO;
+import cn.iocoder.yudao.module.promotion.enums.common.PromotionTypeEnum;
+import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
+import cn.iocoder.yudao.module.trade.service.order.TradeOrderQueryService;
+import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO;
+import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO;
+import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.core.annotation.Order;
+import org.springframework.stereotype.Component;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.PRICE_CALCULATE_POINT_TOTAL_LIMIT_COUNT;
+
+/**
+ * 积分商城的 {@link TradePriceCalculator} 实现类
+ *
+ * @author owen
+ */
+@Component
+@Order(TradePriceCalculator.ORDER_POINT_ACTIVITY)
+@Slf4j
+public class TradePointActivityPriceCalculator implements TradePriceCalculator {
+
+    @Resource
+    private PointActivityApi pointActivityApi;
+
+    @Resource
+    private TradeOrderQueryService tradeOrderQueryService;
+
+    @Override
+    public void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) {
+        // 1. 判断订单类型是否为积分商城活动
+        if (ObjectUtil.notEqual(result.getType(), TradeOrderTypeEnum.POINT.getType())) {
+            return;
+        }
+
+        Assert.isTrue(param.getItems().size() == 1, "积分商城兑换商品时,只允许选择一个商品");
+        // 2. 校验是否可以参与积分商城活动
+        TradePriceCalculateRespBO.OrderItem orderItem = result.getItems().get(0);
+        PointValidateJoinRespDTO activity = validateJoinSeckill(
+                param.getUserId(), param.getPointActivityId(),
+                orderItem.getSkuId(), orderItem.getCount());
+
+        // 3.1 记录优惠明细
+        int discountPrice = 0;
+        Assert.isTrue(activity.getPoint() >= 1, "积分商城商品兑换积分必须大于 1");
+        // 情况一:单使用积分兑换
+        if (activity.getPrice() == null || activity.getPrice() == 0) {
+            discountPrice = orderItem.getPayPrice();
+        } else { // 情况二:积分 + 金额
+            discountPrice = orderItem.getPayPrice() - activity.getPrice() * orderItem.getCount();
+        }
+        TradePriceCalculatorHelper.addPromotion(result, orderItem,
+                param.getPointActivityId(), "积分商城活动", PromotionTypeEnum.POINT.getType(),
+                StrUtil.format("积分商城活动:省 {} 元", TradePriceCalculatorHelper.formatPrice(discountPrice)),
+                discountPrice);
+        // 3.2 更新 SKU 优惠金额
+        orderItem.setDiscountPrice(orderItem.getDiscountPrice() + discountPrice);
+        TradePriceCalculatorHelper.recountPayPrice(orderItem);
+        TradePriceCalculatorHelper.recountAllPrice(result);
+    }
+
+    private PointValidateJoinRespDTO validateJoinSeckill(Long userId, Long activityId, Long skuId, Integer count) {
+        // 1. 校验是否可以参与积分商城活动
+        PointValidateJoinRespDTO pointValidateJoinRespDTO = pointActivityApi.validateJoinPointActivity(activityId, skuId, count);
+        // 2. 校验总限购数量,目前只有 trade 有具体下单的数据,需要交给 trade 价格计算使用
+        int activityProductCount = tradeOrderQueryService.getActivityProductCount(userId, activityId);
+        if (activityProductCount + count > pointValidateJoinRespDTO.getCount()) {
+            throw exception(PRICE_CALCULATE_POINT_TOTAL_LIMIT_COUNT);
+        }
+        return pointValidateJoinRespDTO;
+    }
+
+}

+ 1 - 0
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePriceCalculator.java

@@ -16,6 +16,7 @@ public interface TradePriceCalculator {
     int ORDER_SECKILL_ACTIVITY = 8;
     int ORDER_BARGAIN_ACTIVITY = 8;
     int ORDER_COMBINATION_ACTIVITY = 8;
+    int ORDER_POINT_ACTIVITY = 8;
 
     int ORDER_DISCOUNT_ACTIVITY = 10;
     int ORDER_REWARD_ACTIVITY = 20;

+ 3 - 0
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePriceCalculatorHelper.java

@@ -90,6 +90,9 @@ public class TradePriceCalculatorHelper {
         if (param.getBargainRecordId() != null) {
             return TradeOrderTypeEnum.BARGAIN.getType();
         }
+        if (param.getPointActivityId() != null) {
+            return TradeOrderTypeEnum.POINT.getType();
+        }
         return TradeOrderTypeEnum.NORMAL.getType();
     }
 

+ 2 - 3
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeSeckillActivityPriceCalculator.java

@@ -8,11 +8,10 @@ import cn.iocoder.yudao.module.promotion.enums.common.PromotionTypeEnum;
 import cn.iocoder.yudao.module.trade.service.order.TradeOrderQueryService;
 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO;
 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO;
+import jakarta.annotation.Resource;
 import org.springframework.core.annotation.Order;
 import org.springframework.stereotype.Component;
 
-import jakarta.annotation.Resource;
-
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.PRICE_CALCULATE_SECKILL_TOTAL_LIMIT_COUNT;
 
@@ -61,7 +60,7 @@ public class TradeSeckillActivityPriceCalculator implements TradePriceCalculator
         // 1. 校验是否可以参与秒杀
         SeckillValidateJoinRespDTO seckillActivity = seckillActivityApi.validateJoinSeckill(activityId, skuId, count);
         // 2. 校验总限购数量,目前只有 trade 有具体下单的数据,需要交给 trade 价格计算使用
-        int seckillProductCount = tradeOrderQueryService.getSeckillProductCount(userId, activityId);
+        int seckillProductCount = tradeOrderQueryService.getActivityProductCount(userId, activityId);
         if (seckillProductCount + count > seckillActivity.getTotalLimitCount()) {
             throw exception(PRICE_CALCULATE_SECKILL_TOTAL_LIMIT_COUNT);
         }