Commit 42c47d9b4481366f03ec16612bacd874f3f67aaa

Authored by puhui999
1 parent 8060aeb5

秒回活动:订单金额计算初步设计

Showing 11 changed files with 207 additions and 7 deletions
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/seckill/SeckillActivityApi.java
1 package cn.iocoder.yudao.module.promotion.api.seckill; 1 package cn.iocoder.yudao.module.promotion.api.seckill;
2 2
  3 +import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillActivityProductRespDTO;
  4 +
  5 +import java.util.Collection;
  6 +import java.util.List;
  7 +
3 /** 8 /**
4 * 秒杀活动 API 接口 9 * 秒杀活动 API 接口
5 * 10 *
@@ -16,4 +21,13 @@ public interface SeckillActivityApi { @@ -16,4 +21,13 @@ public interface SeckillActivityApi {
16 */ 21 */
17 void updateSeckillStock(Long id, Long skuId, Integer count); 22 void updateSeckillStock(Long id, Long skuId, Integer count);
18 23
  24 + /**
  25 + * 获取秒杀活动商品信息
  26 + *
  27 + * @param id 活动编号
  28 + * @param skuIds sku 编号
  29 + * @return 秒杀活动商品信息列表
  30 + */
  31 + List<SeckillActivityProductRespDTO> getSeckillActivityProductList(Long id, Collection<Long> skuIds);
  32 +
19 } 33 }
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/seckill/dto/SeckillActivityProductRespDTO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.promotion.api.seckill.dto;
  2 +
  3 +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
  4 +import lombok.Data;
  5 +
  6 +import java.time.LocalDateTime;
  7 +import java.util.List;
  8 +
  9 +/**
  10 + * 秒杀活动商品 Response DTO
  11 + *
  12 + * @author HUIHUI
  13 + */
  14 +@Data
  15 +public class SeckillActivityProductRespDTO {
  16 +
  17 + /**
  18 + * 秒杀参与商品编号
  19 + */
  20 + private Long id;
  21 + /**
  22 + * 秒杀活动 id
  23 + *
  24 + * 关联 SeckillActivityDO#getId()
  25 + */
  26 + private Long activityId;
  27 + /**
  28 + * 秒杀时段 id
  29 + *
  30 + * 关联 SeckillConfigDO#getId()
  31 + */
  32 + private List<Long> configIds;
  33 + /**
  34 + * 商品 SPU 编号
  35 + */
  36 + private Long spuId;
  37 + /**
  38 + * 商品 SKU 编号
  39 + */
  40 + private Long skuId;
  41 + /**
  42 + * 秒杀金额,单位:分
  43 + */
  44 + private Integer seckillPrice;
  45 + /**
  46 + * 秒杀库存
  47 + */
  48 + private Integer stock;
  49 +
  50 + /**
  51 + * 秒杀商品状态
  52 + *
  53 + * 枚举 {@link CommonStatusEnum 对应的类}
  54 + */
  55 + private Integer activityStatus;
  56 + /**
  57 + * 活动开始时间点
  58 + */
  59 + private LocalDateTime activityStartTime;
  60 + /**
  61 + * 活动结束时间点
  62 + */
  63 + private LocalDateTime activityEndTime;
  64 +
  65 +}
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/seckill/SeckillActivityApiImpl.java
1 package cn.iocoder.yudao.module.promotion.api.seckill; 1 package cn.iocoder.yudao.module.promotion.api.seckill;
2 2
  3 +import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillActivityProductRespDTO;
  4 +import cn.iocoder.yudao.module.promotion.convert.seckill.seckillactivity.SeckillActivityConvert;
3 import cn.iocoder.yudao.module.promotion.service.seckill.SeckillActivityService; 5 import cn.iocoder.yudao.module.promotion.service.seckill.SeckillActivityService;
4 import org.springframework.stereotype.Service; 6 import org.springframework.stereotype.Service;
5 7
6 import javax.annotation.Resource; 8 import javax.annotation.Resource;
  9 +import java.util.Collection;
  10 +import java.util.List;
7 11
8 /** 12 /**
9 * 秒杀活动接口 Api 接口实现类 13 * 秒杀活动接口 Api 接口实现类
@@ -21,4 +25,9 @@ public class SeckillActivityApiImpl implements SeckillActivityApi { @@ -21,4 +25,9 @@ public class SeckillActivityApiImpl implements SeckillActivityApi {
21 activityService.updateSeckillStock(id, skuId, count); 25 activityService.updateSeckillStock(id, skuId, count);
22 } 26 }
23 27
  28 + @Override
  29 + public List<SeckillActivityProductRespDTO> getSeckillActivityProductList(Long id, Collection<Long> skuIds) {
  30 + return SeckillActivityConvert.INSTANCE.convertList4(activityService.getSeckillActivityProductList(id, skuIds));
  31 + }
  32 +
24 } 33 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/seckill/seckillactivity/SeckillActivityConvert.java
@@ -7,6 +7,7 @@ import cn.iocoder.yudao.framework.common.util.collection.MapUtils; @@ -7,6 +7,7 @@ import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
7 import cn.iocoder.yudao.framework.dict.core.util.DictFrameworkUtils; 7 import cn.iocoder.yudao.framework.dict.core.util.DictFrameworkUtils;
8 import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; 8 import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
9 import cn.iocoder.yudao.module.product.enums.DictTypeConstants; 9 import cn.iocoder.yudao.module.product.enums.DictTypeConstants;
  10 +import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillActivityProductRespDTO;
10 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityCreateReqVO; 11 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityCreateReqVO;
11 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityDetailRespVO; 12 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityDetailRespVO;
12 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityRespVO; 13 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityRespVO;
@@ -137,4 +138,6 @@ public interface SeckillActivityConvert { @@ -137,4 +138,6 @@ public interface SeckillActivityConvert {
137 "yyyy-MM-dd HH:mm:ss")); // 活动结束日期和时段结合 138 "yyyy-MM-dd HH:mm:ss")); // 活动结束日期和时段结合
138 } 139 }
139 140
  141 + List<SeckillActivityProductRespDTO> convertList4(List<SeckillProductDO> seckillActivityProductList);
  142 +
140 } 143 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityService.java
@@ -37,9 +37,9 @@ public interface SeckillActivityService { @@ -37,9 +37,9 @@ public interface SeckillActivityService {
37 /** 37 /**
38 * 更新秒杀库存 38 * 更新秒杀库存
39 * 39 *
40 - * @param id 活动编号  
41 - * @param skuId sku 编号  
42 - * @param count 数量 40 + * @param id 活动编号
  41 + * @param skuId sku 编号
  42 + * @param count 数量
43 */ 43 */
44 void updateSeckillStock(Long id, Long skuId, Integer count); 44 void updateSeckillStock(Long id, Long skuId, Integer count);
45 45
@@ -114,4 +114,13 @@ public interface SeckillActivityService { @@ -114,4 +114,13 @@ public interface SeckillActivityService {
114 */ 114 */
115 PageResult<SeckillActivityDO> getSeckillActivityAppPageByConfigId(AppSeckillActivityPageReqVO pageReqVO); 115 PageResult<SeckillActivityDO> getSeckillActivityAppPageByConfigId(AppSeckillActivityPageReqVO pageReqVO);
116 116
  117 + /**
  118 + * 获取秒杀活动商品信息
  119 + *
  120 + * @param id 活动编号
  121 + * @param skuIds sku 编号
  122 + * @return 秒杀活动商品信息列表
  123 + */
  124 + List<SeckillProductDO> getSeckillActivityProductList(Long id, Collection<Long> skuIds);
  125 +
117 } 126 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityServiceImpl.java
1 package cn.iocoder.yudao.module.promotion.service.seckill; 1 package cn.iocoder.yudao.module.promotion.service.seckill;
2 2
  3 +import cn.hutool.core.collection.CollectionUtil;
3 import cn.hutool.core.util.ObjectUtil; 4 import cn.hutool.core.util.ObjectUtil;
4 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; 5 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
5 import cn.iocoder.yudao.framework.common.pojo.PageResult; 6 import cn.iocoder.yudao.framework.common.pojo.PageResult;
@@ -284,4 +285,18 @@ public class SeckillActivityServiceImpl implements SeckillActivityService { @@ -284,4 +285,18 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
284 return seckillActivityMapper.selectPage(pageReqVO, CommonStatusEnum.ENABLE.getStatus()); 285 return seckillActivityMapper.selectPage(pageReqVO, CommonStatusEnum.ENABLE.getStatus());
285 } 286 }
286 287
  288 + @Override
  289 + public List<SeckillProductDO> getSeckillActivityProductList(Long id, Collection<Long> skuIds) {
  290 + // 1、校验秒杀活动是否存在
  291 + validateSeckillActivityExists(id);
  292 + // 2、校验活动商品是否存在
  293 + List<SeckillProductDO> productList = filterList(seckillProductMapper.selectListByActivityId(id),
  294 + item -> skuIds.contains(item.getSkuId()));
  295 + if (CollectionUtil.isEmpty(productList)) {
  296 + throw exception(SKU_NOT_EXISTS);
  297 + }
  298 +
  299 + return productList;
  300 + }
  301 +
287 } 302 }
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java
@@ -216,11 +216,11 @@ public interface TradeOrderConvert { @@ -216,11 +216,11 @@ public interface TradeOrderConvert {
216 }) 216 })
217 ProductCommentCreateReqDTO convert04(AppTradeOrderItemCommentCreateReqVO createReqVO, TradeOrderItemDO tradeOrderItemDO); 217 ProductCommentCreateReqDTO convert04(AppTradeOrderItemCommentCreateReqVO createReqVO, TradeOrderItemDO tradeOrderItemDO);
218 218
  219 + TradePriceCalculateReqBO convert(AppTradeOrderSettlementReqVO settlementReqVO);
  220 +
219 default TradePriceCalculateReqBO convert(Long userId, AppTradeOrderSettlementReqVO settlementReqVO, 221 default TradePriceCalculateReqBO convert(Long userId, AppTradeOrderSettlementReqVO settlementReqVO,
220 List<CartDO> cartList) { 222 List<CartDO> cartList) {
221 - TradePriceCalculateReqBO reqBO = new TradePriceCalculateReqBO();  
222 - reqBO.setUserId(userId).setCouponId(settlementReqVO.getCouponId()).setAddressId(settlementReqVO.getAddressId())  
223 - .setItems(new ArrayList<>(settlementReqVO.getItems().size())); 223 + TradePriceCalculateReqBO reqBO = convert(settlementReqVO).setUserId(userId).setItems(new ArrayList<>(settlementReqVO.getItems().size()));
224 // 商品项的构建 224 // 商品项的构建
225 Map<Long, CartDO> cartMap = convertMap(cartList, CartDO::getId); 225 Map<Long, CartDO> cartMap = convertMap(cartList, CartDO::getId);
226 for (AppTradeOrderSettlementReqVO.Item item : settlementReqVO.getItems()) { 226 for (AppTradeOrderSettlementReqVO.Item item : settlementReqVO.getItems()) {
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/bo/TradePriceCalculateReqBO.java
@@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.trade.service.price.bo; @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.trade.service.price.bo;
2 2
3 import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum; 3 import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum;
4 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum; 4 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
  5 +import io.swagger.v3.oas.annotations.media.Schema;
5 import lombok.Data; 6 import lombok.Data;
6 7
7 import javax.validation.Valid; 8 import javax.validation.Valid;
@@ -52,6 +53,23 @@ public class TradePriceCalculateReqBO { @@ -52,6 +53,23 @@ public class TradePriceCalculateReqBO {
52 */ 53 */
53 private Integer deliveryType; 54 private Integer deliveryType;
54 55
  56 + // ========== 秒杀活动相关字段 ==========
  57 + @Schema(description = "秒杀活动编号", example = "1024")
  58 + private Long seckillActivityId;
  59 +
  60 + // ========== 拼团活动相关字段 ==========
  61 + // TODO @puhui999:是不是拼团记录的编号哈?
  62 + @Schema(description = "拼团活动编号", example = "1024")
  63 + private Long combinationActivityId;
  64 +
  65 + @Schema(description = "拼团团长编号", example = "2048")
  66 + private Long combinationHeadId;
  67 +
  68 + // ========== 砍价活动相关字段 ==========
  69 + // TODO @puhui999:是不是砍价记录的编号哈?
  70 + @Schema(description = "砍价活动编号", example = "123")
  71 + private Long bargainActivityId;
  72 +
55 /** 73 /**
56 * 商品 SKU 数组 74 * 商品 SKU 数组
57 */ 75 */
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/bo/TradePriceCalculateRespBO.java
@@ -85,8 +85,18 @@ public class TradePriceCalculateRespBO { @@ -85,8 +85,18 @@ public class TradePriceCalculateRespBO {
85 */ 85 */
86 private Integer pointPrice; 86 private Integer pointPrice;
87 /** 87 /**
  88 + * 秒杀、拼团、砍价活动商品的总金额,单位:分
  89 + *
  90 + * 基于 {@link OrderItem#getActivityPrice()} ()} * {@link OrderItem#getCount()} 求和
  91 + */
  92 + private Integer activityPrice;
  93 + /**
88 * 最终购买金额(总),单位:分 94 * 最终购买金额(总),单位:分
89 * 95 *
  96 + * ==========活动情况===========
  97 + * = {@link #activityPrice}
  98 + * + {@link #deliveryPrice}
  99 + * ==========正常情况===========
90 * = {@link #totalPrice} 100 * = {@link #totalPrice}
91 * - {@link #couponPrice} 101 * - {@link #couponPrice}
92 * - {@link #pointPrice} 102 * - {@link #pointPrice}
@@ -154,8 +164,15 @@ public class TradePriceCalculateRespBO { @@ -154,8 +164,15 @@ public class TradePriceCalculateRespBO {
154 */ 164 */
155 private Integer pointPrice; 165 private Integer pointPrice;
156 /** 166 /**
  167 + * 秒杀、拼团、砍价活动商品的金额,单位:分
  168 + */
  169 + private Integer activityPrice;
  170 + /**
157 * 应付金额(总),单位:分 171 * 应付金额(总),单位:分
158 - * 172 + * ==========活动情况===========
  173 + * = {@link #activityPrice} * {@link #count}
  174 + * + {@link #deliveryPrice}
  175 + * ==========正常情况===========
159 * = {@link #price} * {@link #count} 176 * = {@link #price} * {@link #count}
160 * - {@link #couponPrice} 177 * - {@link #couponPrice}
161 * - {@link #pointPrice} 178 * - {@link #pointPrice}
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePriceCalculatorHelper.java
@@ -84,6 +84,9 @@ public class TradePriceCalculatorHelper { @@ -84,6 +84,9 @@ public class TradePriceCalculatorHelper {
84 if (!item.getSelected()) { 84 if (!item.getSelected()) {
85 return; 85 return;
86 } 86 }
  87 + // TODO puhui: 需要在这里计算活动的价格
  88 + // ========== 一、活动情况 ==========
  89 + // ========== 二、正常情况 ==========
87 price.setTotalPrice(price.getTotalPrice() + item.getPrice() * item.getCount()); 90 price.setTotalPrice(price.getTotalPrice() + item.getPrice() * item.getCount());
88 price.setDiscountPrice(price.getDiscountPrice() + item.getDiscountPrice()); 91 price.setDiscountPrice(price.getDiscountPrice() + item.getDiscountPrice());
89 price.setDeliveryPrice(price.getDeliveryPrice() + item.getDeliveryPrice()); 92 price.setDeliveryPrice(price.getDeliveryPrice() + item.getDeliveryPrice());
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeSeckillActivityPriceCalculator.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.service.price.calculator;
  2 +
  3 +import cn.hutool.core.util.ObjectUtil;
  4 +import cn.iocoder.yudao.module.promotion.api.seckill.SeckillActivityApi;
  5 +import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillActivityProductRespDTO;
  6 +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
  7 +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO;
  8 +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO;
  9 +import org.springframework.core.annotation.Order;
  10 +import org.springframework.stereotype.Component;
  11 +
  12 +import javax.annotation.Resource;
  13 +import java.util.List;
  14 +import java.util.Map;
  15 +
  16 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
  17 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
  18 +
  19 +/**
  20 + * 秒杀活动的 {@link TradePriceCalculator} 实现类
  21 + *
  22 + * @author HUIHUI
  23 + */
  24 +@Component
  25 +@Order(TradePriceCalculator.ORDER_DISCOUNT_ACTIVITY)
  26 +public class TradeSeckillActivityPriceCalculator implements TradePriceCalculator {
  27 +
  28 + @Resource
  29 + private SeckillActivityApi activityApi;
  30 +
  31 + @Override
  32 + public void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) {
  33 + // 1、判断订单类型和是否具有秒杀活动编号
  34 + if (ObjectUtil.notEqual(param.getType(), TradeOrderTypeEnum.SECKILL.getType()) && param.getSeckillActivityId() == null) {
  35 + return;
  36 + }
  37 + // 2、获取秒杀活动商品信息
  38 + List<SeckillActivityProductRespDTO> productList = activityApi.getSeckillActivityProductList(param.getSeckillActivityId(), convertSet(param.getItems(),
  39 + TradePriceCalculateReqBO.Item::getSkuId));
  40 + Map<Long, SeckillActivityProductRespDTO> productMap = convertMap(productList, SeckillActivityProductRespDTO::getSkuId);
  41 + result.getItems().forEach(item -> {
  42 + SeckillActivityProductRespDTO product = productMap.get(item.getSkuId());
  43 + item.setActivityPrice(product.getSeckillPrice()); // 设置活动金额
  44 + });
  45 + }
  46 +
  47 +}