Commit f01c600492b29c0e24a99c1e77150a679846729f
1 parent
f72dd272
【功能完善】商城: APP 完善积分商城活动订单价格计算
Showing
18 changed files
with
237 additions
and
18 deletions
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/point/PointActivityApi.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.promotion.api.point; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.module.promotion.api.point.dto.PointValidateJoinRespDTO; | |
| 4 | + | |
| 5 | +/** | |
| 6 | + * 积分商城活动 API 接口 | |
| 7 | + * | |
| 8 | + * @author HUIHUI | |
| 9 | + */ | |
| 10 | +public interface PointActivityApi { | |
| 11 | + | |
| 12 | + /** | |
| 13 | + * 【下单前】校验是否参与积分商城活动 | |
| 14 | + * | |
| 15 | + * 如果校验失败,则抛出业务异常 | |
| 16 | + * | |
| 17 | + * @param activityId 活动编号 | |
| 18 | + * @param skuId SKU 编号 | |
| 19 | + * @param count 数量 | |
| 20 | + * @return 积分商城商品信息 | |
| 21 | + */ | |
| 22 | + PointValidateJoinRespDTO validateJoinPointActivity(Long activityId, Long skuId, Integer count); | |
| 23 | + | |
| 24 | + | |
| 25 | +} | ... | ... |
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/point/dto/PointValidateJoinRespDTO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.promotion.api.point.dto; | |
| 2 | + | |
| 3 | +import lombok.Data; | |
| 4 | + | |
| 5 | +/** | |
| 6 | + * 校验参与积分商城 Response DTO | |
| 7 | + */ | |
| 8 | +@Data | |
| 9 | +public class PointValidateJoinRespDTO { | |
| 10 | + | |
| 11 | + /** | |
| 12 | + * 可兑换次数 | |
| 13 | + */ | |
| 14 | + private Integer count; | |
| 15 | + /** | |
| 16 | + * 所需兑换积分 | |
| 17 | + */ | |
| 18 | + private Integer point; | |
| 19 | + /** | |
| 20 | + * 所需兑换金额,单位:分 | |
| 21 | + */ | |
| 22 | + private Integer price; | |
| 23 | + | |
| 24 | +} | ... | ... |
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 { |
| 50 | 50 | ErrorCode POINT_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED = new ErrorCode(1_013_007_002, "积分商城活动已关闭,不能修改"); |
| 51 | 51 | ErrorCode POINT_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END = new ErrorCode(1_013_007_003, "积分商城活动未关闭或未结束,不能删除"); |
| 52 | 52 | ErrorCode POINT_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED = new ErrorCode(1_013_007_004, "积分商城活动已关闭,不能重复关闭"); |
| 53 | + ErrorCode POINT_ACTIVITY_JOIN_ACTIVITY_STATUS_CLOSED = new ErrorCode(1_013_007_005, "积分商品兑换失败,原因:积分商城活动已关闭"); | |
| 54 | + ErrorCode POINT_ACTIVITY_JOIN_ACTIVITY_SINGLE_LIMIT_COUNT_EXCEED = new ErrorCode(1_013_007_006, "积分商品兑换失败,原因:单次限购超出"); | |
| 55 | + ErrorCode POINT_ACTIVITY_JOIN_ACTIVITY_PRODUCT_NOT_EXISTS = new ErrorCode(1_013_007_007, "积分商品兑换失败,原因:商品不存在"); | |
| 56 | + ErrorCode POINT_ACTIVITY_UPDATE_STOCK_FAIL = new ErrorCode(1_013_007_008, "积分商品兑换失败,原因:积分商品库存不足"); | |
| 53 | 57 | |
| 54 | 58 | // ========== 秒杀活动 1-013-008-000 ========== |
| 55 | 59 | ErrorCode SECKILL_ACTIVITY_NOT_EXISTS = new ErrorCode(1_013_008_000, "秒杀活动不存在"); | ... | ... |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/point/PointActivityApiImpl.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.promotion.api.point; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.module.promotion.api.point.dto.PointValidateJoinRespDTO; | |
| 4 | +import cn.iocoder.yudao.module.promotion.service.point.PointActivityService; | |
| 5 | +import jakarta.annotation.Resource; | |
| 6 | +import org.springframework.stereotype.Service; | |
| 7 | +import org.springframework.validation.annotation.Validated; | |
| 8 | + | |
| 9 | +/** | |
| 10 | + * 积分商城活动 Api 接口实现类 | |
| 11 | + * | |
| 12 | + * @author HUIHUI | |
| 13 | + */ | |
| 14 | +@Service | |
| 15 | +@Validated | |
| 16 | +public class PointActivityApiImpl implements PointActivityApi { | |
| 17 | + | |
| 18 | + @Resource | |
| 19 | + private PointActivityService pointActivityService; | |
| 20 | + | |
| 21 | + @Override | |
| 22 | + public PointValidateJoinRespDTO validateJoinPointActivity(Long activityId, Long skuId, Integer count) { | |
| 23 | + return pointActivityService.validateJoinPointActivity(activityId, skuId, count); | |
| 24 | + } | |
| 25 | + | |
| 26 | +} | ... | ... |
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> { |
| 29 | 29 | .eq(PointProductDO::getActivityId, pointProductDO.getActivityId())); |
| 30 | 30 | } |
| 31 | 31 | |
| 32 | + default PointProductDO selectListByActivityIdAndSkuId(Long activityId, Long skuId) { | |
| 33 | + return selectOne(PointProductDO::getActivityId, activityId, | |
| 34 | + PointProductDO::getSkuId, skuId); | |
| 35 | + } | |
| 36 | + | |
| 32 | 37 | } |
| 33 | 38 | \ 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
| 1 | 1 | package cn.iocoder.yudao.module.promotion.service.point; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 4 | +import cn.iocoder.yudao.module.promotion.api.point.dto.PointValidateJoinRespDTO; | |
| 4 | 5 | import cn.iocoder.yudao.module.promotion.controller.admin.point.vo.activity.PointActivityPageReqVO; |
| 5 | 6 | import cn.iocoder.yudao.module.promotion.controller.admin.point.vo.activity.PointActivitySaveReqVO; |
| 6 | 7 | import cn.iocoder.yudao.module.promotion.dal.dataobject.point.PointActivityDO; |
| ... | ... | @@ -78,4 +79,16 @@ public interface PointActivityService { |
| 78 | 79 | */ |
| 79 | 80 | List<PointProductDO> getPointProductListByActivityIds(Collection<Long> activityIds); |
| 80 | 81 | |
| 82 | + /** | |
| 83 | + * 【下单前】校验是否参与积分商城活动 | |
| 84 | + * | |
| 85 | + * 如果校验失败,则抛出业务异常 | |
| 86 | + * | |
| 87 | + * @param activityId 活动编号 | |
| 88 | + * @param skuId SKU 编号 | |
| 89 | + * @param count 数量 | |
| 90 | + * @return 积分商城商品信息 | |
| 91 | + */ | |
| 92 | + PointValidateJoinRespDTO validateJoinPointActivity(Long activityId, Long skuId, Integer count); | |
| 93 | + | |
| 81 | 94 | } |
| 82 | 95 | \ No newline at end of file | ... | ... |
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; |
| 8 | 8 | import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; |
| 9 | 9 | import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi; |
| 10 | 10 | import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; |
| 11 | +import cn.iocoder.yudao.module.promotion.api.point.dto.PointValidateJoinRespDTO; | |
| 11 | 12 | import cn.iocoder.yudao.module.promotion.controller.admin.point.vo.activity.PointActivityPageReqVO; |
| 12 | 13 | import cn.iocoder.yudao.module.promotion.controller.admin.point.vo.activity.PointActivitySaveReqVO; |
| 13 | 14 | import cn.iocoder.yudao.module.promotion.controller.admin.point.vo.product.PointProductSaveReqVO; |
| ... | ... | @@ -244,4 +245,28 @@ public class PointActivityServiceImpl implements PointActivityService { |
| 244 | 245 | return pointProductMapper.selectListByActivityId(activityIds); |
| 245 | 246 | } |
| 246 | 247 | |
| 248 | + @Override | |
| 249 | + public PointValidateJoinRespDTO validateJoinPointActivity(Long activityId, Long skuId, Integer count) { | |
| 250 | + // 1. 校验积分商城活动是否存在 | |
| 251 | + PointActivityDO activity = validatePointActivityExists(activityId); | |
| 252 | + if (CommonStatusEnum.isDisable(activity.getStatus())) { | |
| 253 | + throw exception(POINT_ACTIVITY_JOIN_ACTIVITY_STATUS_CLOSED); | |
| 254 | + } | |
| 255 | + | |
| 256 | + // 2.1 校验积分商城商品是否存在 | |
| 257 | + PointProductDO product = pointProductMapper.selectListByActivityIdAndSkuId(activityId, skuId); | |
| 258 | + if (product == null) { | |
| 259 | + throw exception(POINT_ACTIVITY_JOIN_ACTIVITY_PRODUCT_NOT_EXISTS); | |
| 260 | + } | |
| 261 | + // 2.2 超过单次购买限制 | |
| 262 | + if (count > product.getCount()) { | |
| 263 | + throw exception(POINT_ACTIVITY_JOIN_ACTIVITY_SINGLE_LIMIT_COUNT_EXCEED); | |
| 264 | + } | |
| 265 | + // 2.2 校验库存是否充足 | |
| 266 | + if (count > product.getStock()) { | |
| 267 | + throw exception(POINT_ACTIVITY_UPDATE_STOCK_FAIL); | |
| 268 | + } | |
| 269 | + return BeanUtils.toBean(product, PointValidateJoinRespDTO.class); | |
| 270 | + } | |
| 271 | + | |
| 247 | 272 | } |
| 248 | 273 | \ No newline at end of file | ... | ... |
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 { |
| 58 | 58 | |
| 59 | 59 | // ========== Price 相关 1-011-003-000 ============ |
| 60 | 60 | ErrorCode PRICE_CALCULATE_PAY_PRICE_ILLEGAL = new ErrorCode(1_011_003_000, "支付价格计算异常,原因:价格小于等于 0"); |
| 61 | - ErrorCode PRICE_CALCULATE_DELIVERY_PRICE_TEMPLATE_NOT_FOUND = new ErrorCode(1_011_003_002, "计算快递运费异常,找不到对应的运费模板"); | |
| 62 | - ErrorCode PRICE_CALCULATE_COUPON_NOT_MATCH_NORMAL_ORDER = new ErrorCode(1_011_003_004, "参与秒杀、拼团、砍价的营销商品,无法使用优惠劵"); | |
| 63 | - ErrorCode PRICE_CALCULATE_SECKILL_TOTAL_LIMIT_COUNT = new ErrorCode(1_011_003_005, "参与秒杀的商品,超过了秒杀总限购数量"); | |
| 64 | - ErrorCode PRICE_CALCULATE_DELIVERY_PRICE_TYPE_ILLEGAL = new ErrorCode(1_011_003_006, "计算快递运费异常,配送方式不匹配"); | |
| 65 | - ErrorCode PRICE_CALCULATE_COUPON_CAN_NOT_USE = new ErrorCode(1_011_003_007, "该优惠劵无法使用,原因:{}」"); | |
| 61 | + ErrorCode PRICE_CALCULATE_DELIVERY_PRICE_TEMPLATE_NOT_FOUND = new ErrorCode(1_011_003_001, "计算快递运费异常,找不到对应的运费模板"); | |
| 62 | + ErrorCode PRICE_CALCULATE_COUPON_NOT_MATCH_NORMAL_ORDER = new ErrorCode(1_011_003_002, "参与秒杀、拼团、砍价的营销商品,无法使用优惠劵"); | |
| 63 | + ErrorCode PRICE_CALCULATE_SECKILL_TOTAL_LIMIT_COUNT = new ErrorCode(1_011_003_003, "参与秒杀的商品,超过了秒杀总限购数量"); | |
| 64 | + ErrorCode PRICE_CALCULATE_POINT_TOTAL_LIMIT_COUNT = new ErrorCode(1_011_003_004, "参与积分活动的商品,超过了积分活动商品总限购数量"); | |
| 65 | + ErrorCode PRICE_CALCULATE_DELIVERY_PRICE_TYPE_ILLEGAL = new ErrorCode(1_011_003_005, "计算快递运费异常,配送方式不匹配"); | |
| 66 | + ErrorCode PRICE_CALCULATE_COUPON_CAN_NOT_USE = new ErrorCode(1_011_003_006, "该优惠劵无法使用,原因:{}」"); | |
| 66 | 67 | |
| 67 | 68 | // ========== 物流 Express 模块 1-011-004-000 ========== |
| 68 | 69 | ErrorCode EXPRESS_NOT_EXISTS = new ErrorCode(1_011_004_000, "快递公司不存在"); | ... | ... |
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 { |
| 20 | 20 | SECKILL(1, "秒杀订单"), |
| 21 | 21 | BARGAIN(2, "砍价订单"), |
| 22 | 22 | COMBINATION(3, "拼团订单"), |
| 23 | + POINT(4, "积分商城"), | |
| 23 | 24 | ; |
| 24 | 25 | |
| 25 | 26 | public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(TradeOrderTypeEnum::getType).toArray(); | ... | ... |
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; |
| 6 | 6 | import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum; |
| 7 | 7 | import com.fasterxml.jackson.annotation.JsonIgnore; |
| 8 | 8 | import io.swagger.v3.oas.annotations.media.Schema; |
| 9 | -import lombok.Data; | |
| 10 | - | |
| 11 | 9 | import jakarta.validation.Valid; |
| 12 | 10 | import jakarta.validation.constraints.AssertTrue; |
| 13 | 11 | import jakarta.validation.constraints.Min; |
| 14 | 12 | import jakarta.validation.constraints.NotEmpty; |
| 15 | 13 | import jakarta.validation.constraints.NotNull; |
| 14 | +import lombok.Data; | |
| 15 | + | |
| 16 | 16 | import java.util.List; |
| 17 | 17 | |
| 18 | 18 | @Schema(description = "用户 App - 交易订单结算 Request VO") |
| ... | ... | @@ -62,6 +62,10 @@ public class AppTradeOrderSettlementReqVO { |
| 62 | 62 | @Schema(description = "砍价记录编号", example = "123") |
| 63 | 63 | private Long bargainRecordId; |
| 64 | 64 | |
| 65 | + // ========== 积分商城活动相关字段 ========== | |
| 66 | + @Schema(description = "积分商城活动编号", example = "123") | |
| 67 | + private Long pointActivityId; | |
| 68 | + | |
| 65 | 69 | @AssertTrue(message = "活动商品每次只能购买一种规格") |
| 66 | 70 | @JsonIgnore |
| 67 | 71 | public boolean isValidActivityItems() { | ... | ... |
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 { |
| 219 | 219 | .setSeckillActivityId(settlementReqVO.getSeckillActivityId()) |
| 220 | 220 | .setBargainRecordId(settlementReqVO.getBargainRecordId()) |
| 221 | 221 | .setCombinationActivityId(settlementReqVO.getCombinationActivityId()) |
| 222 | - .setCombinationHeadId(settlementReqVO.getCombinationHeadId()); | |
| 222 | + .setCombinationHeadId(settlementReqVO.getCombinationHeadId()) | |
| 223 | + .setPointActivityId(settlementReqVO.getPointActivityId()); | |
| 223 | 224 | // 商品项的构建 |
| 224 | 225 | Map<Long, CartDO> cartMap = convertMap(cartList, CartDO::getId); |
| 225 | 226 | for (AppTradeOrderSettlementReqVO.Item item : settlementReqVO.getItems()) { | ... | ... |
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 { |
| 42 | 42 | /** |
| 43 | 43 | * 获得指定用户,指定活动,指定状态的交易订单 |
| 44 | 44 | * |
| 45 | - * @param userId 用户编号 | |
| 45 | + * @param userId 用户编号 | |
| 46 | 46 | * @param combinationActivityId 活动编号 |
| 47 | - * @param status 订单状态 | |
| 47 | + * @param status 订单状态 | |
| 48 | 48 | * @return 交易订单 |
| 49 | 49 | */ |
| 50 | 50 | TradeOrderDO getOrderByUserIdAndStatusAndCombination(Long userId, Long combinationActivityId, Integer status); |
| ... | ... | @@ -116,7 +116,7 @@ public interface TradeOrderQueryService { |
| 116 | 116 | * @param activityId 活动编号 |
| 117 | 117 | * @return 秒杀商品数量 |
| 118 | 118 | */ |
| 119 | - int getSeckillProductCount(Long userId, Long activityId); | |
| 119 | + int getActivityProductCount(Long userId, Long activityId); | |
| 120 | 120 | |
| 121 | 121 | // =================== Order Item =================== |
| 122 | 122 | ... | ... |
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 |
| 23 | 23 | import cn.iocoder.yudao.module.trade.framework.delivery.core.client.dto.ExpressTrackQueryReqDTO; |
| 24 | 24 | import cn.iocoder.yudao.module.trade.framework.delivery.core.client.dto.ExpressTrackRespDTO; |
| 25 | 25 | import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressService; |
| 26 | +import jakarta.annotation.Resource; | |
| 26 | 27 | import org.springframework.cache.annotation.Cacheable; |
| 27 | 28 | import org.springframework.stereotype.Service; |
| 28 | 29 | |
| 29 | -import jakarta.annotation.Resource; | |
| 30 | 30 | import java.util.*; |
| 31 | 31 | |
| 32 | 32 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| ... | ... | @@ -174,7 +174,7 @@ public class TradeOrderQueryServiceImpl implements TradeOrderQueryService { |
| 174 | 174 | } |
| 175 | 175 | |
| 176 | 176 | @Override |
| 177 | - public int getSeckillProductCount(Long userId, Long activityId) { | |
| 177 | + public int getActivityProductCount(Long userId, Long activityId) { | |
| 178 | 178 | // 获得订单列表 |
| 179 | 179 | List<TradeOrderDO> orders = tradeOrderMapper.selectListByUserIdAndSeckillActivityId(userId, activityId); |
| 180 | 180 | orders.removeIf(order -> TradeOrderStatusEnum.isCanceled(order.getStatus())); // 过滤掉【已取消】的订单 | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/bo/TradePriceCalculateReqBO.java
| 1 | 1 | package cn.iocoder.yudao.module.trade.service.price.bo; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum; |
| 4 | -import lombok.Data; | |
| 5 | - | |
| 6 | 4 | import jakarta.validation.Valid; |
| 7 | 5 | import jakarta.validation.constraints.Min; |
| 8 | 6 | import jakarta.validation.constraints.NotNull; |
| 7 | +import lombok.Data; | |
| 8 | + | |
| 9 | 9 | import java.util.List; |
| 10 | 10 | |
| 11 | 11 | /** |
| ... | ... | @@ -84,6 +84,12 @@ public class TradePriceCalculateReqBO { |
| 84 | 84 | */ |
| 85 | 85 | private Long bargainRecordId; |
| 86 | 86 | |
| 87 | + // ========== 积分商城活动相关字段 ========== | |
| 88 | + /** | |
| 89 | + * 积分商城活动编号 | |
| 90 | + */ | |
| 91 | + private Long pointActivityId; | |
| 92 | + | |
| 87 | 93 | /** |
| 88 | 94 | * 商品 SKU |
| 89 | 95 | */ | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePointActivityPriceCalculator.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.service.price.calculator; | |
| 2 | + | |
| 3 | +import cn.hutool.core.lang.Assert; | |
| 4 | +import cn.hutool.core.util.ObjectUtil; | |
| 5 | +import cn.hutool.core.util.StrUtil; | |
| 6 | +import cn.iocoder.yudao.module.promotion.api.point.PointActivityApi; | |
| 7 | +import cn.iocoder.yudao.module.promotion.api.point.dto.PointValidateJoinRespDTO; | |
| 8 | +import cn.iocoder.yudao.module.promotion.enums.common.PromotionTypeEnum; | |
| 9 | +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum; | |
| 10 | +import cn.iocoder.yudao.module.trade.service.order.TradeOrderQueryService; | |
| 11 | +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; | |
| 12 | +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; | |
| 13 | +import jakarta.annotation.Resource; | |
| 14 | +import lombok.extern.slf4j.Slf4j; | |
| 15 | +import org.springframework.core.annotation.Order; | |
| 16 | +import org.springframework.stereotype.Component; | |
| 17 | + | |
| 18 | +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | |
| 19 | +import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.PRICE_CALCULATE_POINT_TOTAL_LIMIT_COUNT; | |
| 20 | + | |
| 21 | +/** | |
| 22 | + * 积分商城的 {@link TradePriceCalculator} 实现类 | |
| 23 | + * | |
| 24 | + * @author owen | |
| 25 | + */ | |
| 26 | +@Component | |
| 27 | +@Order(TradePriceCalculator.ORDER_POINT_ACTIVITY) | |
| 28 | +@Slf4j | |
| 29 | +public class TradePointActivityPriceCalculator implements TradePriceCalculator { | |
| 30 | + | |
| 31 | + @Resource | |
| 32 | + private PointActivityApi pointActivityApi; | |
| 33 | + | |
| 34 | + @Resource | |
| 35 | + private TradeOrderQueryService tradeOrderQueryService; | |
| 36 | + | |
| 37 | + @Override | |
| 38 | + public void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) { | |
| 39 | + // 1. 判断订单类型是否为积分商城活动 | |
| 40 | + if (ObjectUtil.notEqual(result.getType(), TradeOrderTypeEnum.POINT.getType())) { | |
| 41 | + return; | |
| 42 | + } | |
| 43 | + | |
| 44 | + Assert.isTrue(param.getItems().size() == 1, "积分商城兑换商品时,只允许选择一个商品"); | |
| 45 | + // 2. 校验是否可以参与积分商城活动 | |
| 46 | + TradePriceCalculateRespBO.OrderItem orderItem = result.getItems().get(0); | |
| 47 | + PointValidateJoinRespDTO activity = validateJoinSeckill( | |
| 48 | + param.getUserId(), param.getPointActivityId(), | |
| 49 | + orderItem.getSkuId(), orderItem.getCount()); | |
| 50 | + | |
| 51 | + // 3.1 记录优惠明细 | |
| 52 | + int discountPrice = 0; | |
| 53 | + Assert.isTrue(activity.getPoint() >= 1, "积分商城商品兑换积分必须大于 1"); | |
| 54 | + // 情况一:单使用积分兑换 | |
| 55 | + if (activity.getPrice() == null || activity.getPrice() == 0) { | |
| 56 | + discountPrice = orderItem.getPayPrice(); | |
| 57 | + } else { // 情况二:积分 + 金额 | |
| 58 | + discountPrice = orderItem.getPayPrice() - activity.getPrice() * orderItem.getCount(); | |
| 59 | + } | |
| 60 | + TradePriceCalculatorHelper.addPromotion(result, orderItem, | |
| 61 | + param.getPointActivityId(), "积分商城活动", PromotionTypeEnum.POINT.getType(), | |
| 62 | + StrUtil.format("积分商城活动:省 {} 元", TradePriceCalculatorHelper.formatPrice(discountPrice)), | |
| 63 | + discountPrice); | |
| 64 | + // 3.2 更新 SKU 优惠金额 | |
| 65 | + orderItem.setDiscountPrice(orderItem.getDiscountPrice() + discountPrice); | |
| 66 | + TradePriceCalculatorHelper.recountPayPrice(orderItem); | |
| 67 | + TradePriceCalculatorHelper.recountAllPrice(result); | |
| 68 | + } | |
| 69 | + | |
| 70 | + private PointValidateJoinRespDTO validateJoinSeckill(Long userId, Long activityId, Long skuId, Integer count) { | |
| 71 | + // 1. 校验是否可以参与积分商城活动 | |
| 72 | + PointValidateJoinRespDTO pointValidateJoinRespDTO = pointActivityApi.validateJoinPointActivity(activityId, skuId, count); | |
| 73 | + // 2. 校验总限购数量,目前只有 trade 有具体下单的数据,需要交给 trade 价格计算使用 | |
| 74 | + int activityProductCount = tradeOrderQueryService.getActivityProductCount(userId, activityId); | |
| 75 | + if (activityProductCount + count > pointValidateJoinRespDTO.getCount()) { | |
| 76 | + throw exception(PRICE_CALCULATE_POINT_TOTAL_LIMIT_COUNT); | |
| 77 | + } | |
| 78 | + return pointValidateJoinRespDTO; | |
| 79 | + } | |
| 80 | + | |
| 81 | +} | ... | ... |
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 { |
| 16 | 16 | int ORDER_SECKILL_ACTIVITY = 8; |
| 17 | 17 | int ORDER_BARGAIN_ACTIVITY = 8; |
| 18 | 18 | int ORDER_COMBINATION_ACTIVITY = 8; |
| 19 | + int ORDER_POINT_ACTIVITY = 8; | |
| 19 | 20 | |
| 20 | 21 | int ORDER_DISCOUNT_ACTIVITY = 10; |
| 21 | 22 | int ORDER_REWARD_ACTIVITY = 20; | ... | ... |
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 { |
| 90 | 90 | if (param.getBargainRecordId() != null) { |
| 91 | 91 | return TradeOrderTypeEnum.BARGAIN.getType(); |
| 92 | 92 | } |
| 93 | + if (param.getPointActivityId() != null) { | |
| 94 | + return TradeOrderTypeEnum.POINT.getType(); | |
| 95 | + } | |
| 93 | 96 | return TradeOrderTypeEnum.NORMAL.getType(); |
| 94 | 97 | } |
| 95 | 98 | ... | ... |
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; |
| 8 | 8 | import cn.iocoder.yudao.module.trade.service.order.TradeOrderQueryService; |
| 9 | 9 | import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; |
| 10 | 10 | import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; |
| 11 | +import jakarta.annotation.Resource; | |
| 11 | 12 | import org.springframework.core.annotation.Order; |
| 12 | 13 | import org.springframework.stereotype.Component; |
| 13 | 14 | |
| 14 | -import jakarta.annotation.Resource; | |
| 15 | - | |
| 16 | 15 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| 17 | 16 | import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.PRICE_CALCULATE_SECKILL_TOTAL_LIMIT_COUNT; |
| 18 | 17 | |
| ... | ... | @@ -61,7 +60,7 @@ public class TradeSeckillActivityPriceCalculator implements TradePriceCalculator |
| 61 | 60 | // 1. 校验是否可以参与秒杀 |
| 62 | 61 | SeckillValidateJoinRespDTO seckillActivity = seckillActivityApi.validateJoinSeckill(activityId, skuId, count); |
| 63 | 62 | // 2. 校验总限购数量,目前只有 trade 有具体下单的数据,需要交给 trade 价格计算使用 |
| 64 | - int seckillProductCount = tradeOrderQueryService.getSeckillProductCount(userId, activityId); | |
| 63 | + int seckillProductCount = tradeOrderQueryService.getActivityProductCount(userId, activityId); | |
| 65 | 64 | if (seckillProductCount + count > seckillActivity.getTotalLimitCount()) { |
| 66 | 65 | throw exception(PRICE_CALCULATE_SECKILL_TOTAL_LIMIT_COUNT); |
| 67 | 66 | } | ... | ... |