Commit ab30ff64804ee892cadccaa36ed70fac48abf590

Authored by puhui999
1 parent b44ad3a0

fix:完善 mall seckill 相关 ②

Showing 15 changed files with 166 additions and 119 deletions
yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/sku/ProductSkuApi.java
1 1 package cn.iocoder.yudao.module.product.api.sku;
2 2  
3   -import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO;
4 3 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
  4 +import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO;
5 5  
6 6 import java.util.Collection;
7 7 import java.util.List;
... ... @@ -31,6 +31,14 @@ public interface ProductSkuApi {
31 31 List<ProductSkuRespDTO> getSkuList(Collection<Long> ids);
32 32  
33 33 /**
  34 + * 批量查询 SKU 数组
  35 + *
  36 + * @param spuIds SPU 编号列表
  37 + * @return SKU 数组
  38 + */
  39 + List<ProductSkuRespDTO> getSkuListBySpuId(List<Long> spuIds);
  40 +
  41 + /**
34 42 * 更新 SKU 库存
35 43 *
36 44 * @param updateStockReqDTO 更新请求
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/api/sku/ProductSkuApiImpl.java
... ... @@ -43,6 +43,15 @@ public class ProductSkuApiImpl implements ProductSkuApi {
43 43 }
44 44  
45 45 @Override
  46 + public List<ProductSkuRespDTO> getSkuListBySpuId(List<Long> spuIds) {
  47 + if (CollUtil.isEmpty(spuIds)) {
  48 + return Collections.emptyList();
  49 + }
  50 + List<ProductSkuDO> skus = productSkuService.getSkuListBySpuId(spuIds);
  51 + return ProductSkuConvert.INSTANCE.convertList04(skus);
  52 + }
  53 +
  54 + @Override
46 55 public void updateSkuStock(ProductSkuUpdateStockReqDTO updateStockReqDTO) {
47 56 productSkuService.updateSkuStock(updateStockReqDTO);
48 57 }
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/api/spu/ProductSpuApiImpl.java
1 1 package cn.iocoder.yudao.module.product.api.spu;
2 2  
3   -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
  3 +import cn.hutool.core.collection.CollectionUtil;
4 4 import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
5 5 import cn.iocoder.yudao.module.product.convert.spu.ProductSpuConvert;
6 6 import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO;
... ... @@ -14,7 +14,7 @@ import java.util.Collections;
14 14 import java.util.List;
15 15  
16 16 /**
17   - * TODO LeeYan9: 类注释;
  17 + * 商品 SPU API 接口实现类
18 18 *
19 19 * @author LeeYan9
20 20 * @since 2022-09-06
... ... @@ -28,11 +28,12 @@ public class ProductSpuApiImpl implements ProductSpuApi {
28 28  
29 29 @Override
30 30 public List<ProductSpuRespDTO> getSpuList(Collection<Long> spuIds) {
31   - // TODO TODO LeeYan9: AllEmpty?
32   - if (CollectionUtils.isAnyEmpty(spuIds)) {
  31 + // TODO 需不需要判断集合中是否有 null 值
  32 + if (CollectionUtil.isEmpty(spuIds)) {
33 33 return Collections.emptyList();
34 34 }
35 35 List<ProductSpuDO> productSpuDOList = productSpuMapper.selectBatchIds(spuIds);
36 36 return ProductSpuConvert.INSTANCE.convertList2(productSpuDOList);
37 37 }
  38 +
38 39 }
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuService.java
... ... @@ -55,7 +55,7 @@ public interface ProductSkuService {
55 55 * 批量创建 SKU
56 56 *
57 57 * @param spuId 商品 SPU 编号
58   - * @param list SKU 对象集合
  58 + * @param list SKU 对象集合
59 59 */
60 60 void createSkuList(Long spuId, List<ProductSkuCreateOrUpdateReqVO> list);
61 61  
... ... @@ -63,13 +63,13 @@ public interface ProductSkuService {
63 63 * 根据 SPU 编号,批量更新它的 SKU 信息
64 64 *
65 65 * @param spuId SPU 编码
66   - * @param skus SKU 的集合
  66 + * @param skus SKU 的集合
67 67 */
68 68 void updateSkuList(Long spuId, List<ProductSkuCreateOrUpdateReqVO> skus);
69 69  
70 70 /**
71 71 * 更新 SKU 库存(增量)
72   - *
  72 + * <p>
73 73 * 如果更新的库存不足,会抛出异常
74 74 *
75 75 * @param updateStockReqDTO 更行请求
... ... @@ -88,7 +88,7 @@ public interface ProductSkuService {
88 88 * 获得 spu 对应的 SKU 集合
89 89 *
90 90 * @param spuIds spu 编码集合
91   - * @return 商品 sku 集合
  91 + * @return 商品 sku 集合
92 92 */
93 93 List<ProductSkuDO> getSkuListBySpuId(List<Long> spuIds);
94 94  
... ... @@ -123,4 +123,5 @@ public interface ProductSkuService {
123 123 * @return int 影响的行数
124 124 */
125 125 int updateSkuPropertyValue(Long propertyValueId, String propertyValueName);
  126 +
126 127 }
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/activity/SeckillActivityBaseVO.java
1 1 package cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity;
2 2  
3   -import com.fasterxml.jackson.annotation.JsonFormat;
4 3 import io.swagger.v3.oas.annotations.media.Schema;
5 4 import lombok.Data;
6 5 import org.springframework.format.annotation.DateTimeFormat;
7 6  
8   -import javax.validation.constraints.Min;
9 7 import javax.validation.constraints.NotNull;
10 8 import java.time.LocalDateTime;
11 9 import java.util.List;
12 10  
13 11 import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
14   -import static cn.iocoder.yudao.framework.common.util.date.DateUtils.TIME_ZONE_DEFAULT;
15 12  
16 13 /**
17 14 * 秒杀活动基地签证官
... ... @@ -23,18 +20,14 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.TIME_ZONE_DE
23 20 @Data
24 21 public class SeckillActivityBaseVO {
25 22  
26   - @Schema(description = "秒杀活动商品", requiredMode = Schema.RequiredMode.REQUIRED, example = "121")
  23 + @Schema(description = "秒杀活动商品id", requiredMode = Schema.RequiredMode.REQUIRED, example = "[121,1212]")
27 24 @NotNull(message = "秒杀活动商品不能为空")
28   - private Long spuId;
  25 + private List<Long> spuIds;
29 26  
30 27 @Schema(description = "秒杀活动名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "618大促")
31 28 @NotNull(message = "秒杀活动名称不能为空")
32 29 private String name;
33 30  
34   - @Schema(description = "活动状态 开启:0 禁用:1", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
35   - @NotNull(message = "活动状态 开启:0 禁用:1不能为空")
36   - private Integer status;
37   -
38 31 @Schema(description = "备注", example = "清仓大甩卖割韭菜")
39 32 private String remark;
40 33  
... ... @@ -52,8 +45,8 @@ public class SeckillActivityBaseVO {
52 45 @NotNull(message = "排序不能为空")
53 46 private Integer sort;
54 47  
55   - @Schema(description = "秒杀时段id", requiredMode = Schema.RequiredMode.REQUIRED)
56   - @NotNull(message = "秒杀时段id不能为空")
  48 + @Schema(description = "秒杀时段id", requiredMode = Schema.RequiredMode.REQUIRED, example = "[1,2,3]")
  49 + @NotNull(message = "秒杀时段不能为空")
57 50 private List<Long> configIds;
58 51  
59 52 @Schema(description = "总限购数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "12877")
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/activity/SeckillActivityRespVO.java
... ... @@ -6,7 +6,6 @@ import lombok.Data;
6 6 import lombok.EqualsAndHashCode;
7 7 import lombok.ToString;
8 8  
9   -import java.time.LocalDateTime;
10 9 import java.util.List;
11 10  
12 11 /**
... ... @@ -24,8 +23,10 @@ public class SeckillActivityRespVO extends SeckillActivityBaseVO {
24 23 private Long id;
25 24  
26 25 @Schema(description = "秒杀商品", requiredMode = Schema.RequiredMode.REQUIRED)
27   - private List<SeckillProductRespVO> products;
  26 + private List<SeckillProductRespVO> products; // TODO puhui: 考虑是否去除
28 27  
  28 + @Schema(description = "活动状态 开启:0 禁用:1", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
  29 + private Integer status;
29 30  
30 31  
31 32 }
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/product/SeckillProductBaseVO.java
1 1 package cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product;
2 2  
3 3 import io.swagger.v3.oas.annotations.media.Schema;
4   -import lombok.*;
5   -import java.time.LocalDateTime;
6   -import javax.validation.constraints.*;
7   -import org.springframework.format.annotation.DateTimeFormat;
  4 +import lombok.Data;
8 5  
9   -import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  6 +import javax.validation.constraints.NotNull;
10 7  
11 8 /**
12 9 * 秒杀参与商品 Base VO,提供给添加、修改、详细的子 VO 使用
... ... @@ -17,15 +14,7 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_
17 14 @Data
18 15 public class SeckillProductBaseVO {
19 16  
20   - @Schema(description = "秒杀活动id", requiredMode = Schema.RequiredMode.REQUIRED, example = "20173")
21   - @NotNull(message = "秒杀活动id不能为空")
22   - private Long activityId;
23   -
24   - @Schema(description = "秒杀时段id", requiredMode = Schema.RequiredMode.REQUIRED)
25   - @NotNull(message = "秒杀时段id不能为空")
26   - private String configIds;
27   -
28   - @Schema(description = "商品spu_id", requiredMode = Schema.RequiredMode.REQUIRED, example = "10290")
  17 + @Schema(description = "商品spu_id", requiredMode = Schema.RequiredMode.REQUIRED, example = "30563")
29 18 @NotNull(message = "商品spu_id不能为空")
30 19 private Long spuId;
31 20  
... ... @@ -41,18 +30,5 @@ public class SeckillProductBaseVO {
41 30 @NotNull(message = "秒杀库存不能为空")
42 31 private Integer stock;
43 32  
44   - @Schema(description = "秒杀商品状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
45   - @NotNull(message = "秒杀商品状态不能为空")
46   - private Integer activityStatus;
47   -
48   - @Schema(description = "活动开始时间点", requiredMode = Schema.RequiredMode.REQUIRED)
49   - @NotNull(message = "活动开始时间点不能为空")
50   - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
51   - private LocalDateTime activityStartTime;
52   -
53   - @Schema(description = "活动结束时间点", requiredMode = Schema.RequiredMode.REQUIRED)
54   - @NotNull(message = "活动结束时间点不能为空")
55   - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
56   - private LocalDateTime activityEndTime;
57 33  
58 34 }
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/seckill/seckillactivity/SeckillActivityConvert.java
1 1 package cn.iocoder.yudao.module.promotion.convert.seckill.seckillactivity;
2 2  
3 3 import cn.hutool.core.util.ObjectUtil;
  4 +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
4 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 6 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityCreateReqVO;
6 7 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityDetailRespVO;
... ... @@ -12,6 +13,7 @@ import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.
12 13 import org.mapstruct.Mapper;
13 14 import org.mapstruct.factory.Mappers;
14 15  
  16 +import java.util.ArrayList;
15 17 import java.util.List;
16 18  
17 19 /**
... ... @@ -47,7 +49,7 @@ public interface SeckillActivityConvert {
47 49 * @return 是否匹配
48 50 */
49 51 default boolean isEquals(SeckillProductDO productDO, SeckillProductCreateReqVO productVO) {
50   - return ObjectUtil.equals(productDO.getSpuId(), productVO.getSpuId())
  52 + return ObjectUtil.equals(productDO.getSpuId(), 1) // TODO puhui:再看看
51 53 && ObjectUtil.equals(productDO.getSkuId(), productVO.getSkuId())
52 54 && ObjectUtil.equals(productDO.getSeckillPrice(), productVO.getSeckillPrice());
53 55 //&& ObjectUtil.equals(productDO.getQuota(), productVO.getQuota())
... ... @@ -65,9 +67,25 @@ public interface SeckillActivityConvert {
65 67 return ObjectUtil.equals(productDO.getSpuId(), productVO.getSpuId())
66 68 && ObjectUtil.equals(productDO.getSkuId(), productVO.getSkuId())
67 69 && ObjectUtil.equals(productDO.getSeckillPrice(), productVO.getSeckillPrice());
68   - //&& ObjectUtil.equals(productDO.getQuota(), productVO.getQuota())
69   - //&& ObjectUtil.equals(productDO.getLimitCount(), productVO.getLimitCount());
  70 + //&& ObjectUtil.equals(productDO.getQuota(), productVO.getQuota())
  71 + //&& ObjectUtil.equals(productDO.getLimitCount(), productVO.getLimitCount());
70 72  
71 73 }
72 74  
  75 + default List<SeckillProductDO> convertList(SeckillActivityDO seckillActivity, List<SeckillProductCreateReqVO> products) {
  76 + List<SeckillProductDO> list = new ArrayList<>();
  77 + products.forEach(sku -> {
  78 + SeckillProductDO productDO = new SeckillProductDO();
  79 + productDO.setActivityId(seckillActivity.getId());
  80 + productDO.setConfigIds(seckillActivity.getConfigIds());
  81 + productDO.setSpuId(sku.getSpuId());
  82 + productDO.setSkuId(sku.getSkuId());
  83 + productDO.setSeckillPrice(sku.getSeckillPrice());
  84 + productDO.setStock(sku.getStock());
  85 + productDO.setActivityStatus(CommonStatusEnum.ENABLE.getStatus());
  86 + productDO.setActivityStartTime(seckillActivity.getStartTime());
  87 + productDO.setActivityEndTime(seckillActivity.getEndTime());
  88 + });
  89 + return list;
  90 + }
73 91 }
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/seckill/seckillactivity/SeckillActivityDO.java
... ... @@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity
3 3 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
4 4 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
5 5 import cn.iocoder.yudao.framework.mybatis.core.type.LongListTypeHandler;
6   -import cn.iocoder.yudao.module.promotion.enums.common.PromotionActivityStatusEnum;
7 6 import com.baomidou.mybatisplus.annotation.KeySequence;
8 7 import com.baomidou.mybatisplus.annotation.TableField;
9 8 import com.baomidou.mybatisplus.annotation.TableId;
... ... @@ -35,7 +34,8 @@ public class SeckillActivityDO extends BaseDO {
35 34 /**
36 35 * 秒杀活动商品
37 36 */
38   - private Long spuId;
  37 + @TableField(typeHandler = LongListTypeHandler.class)
  38 + private List<Long> spuIds;
39 39 /**
40 40 * 秒杀活动名称
41 41 */
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/seckill/seckillactivity/SeckillProductDO.java
1 1 package cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity;
2 2  
  3 +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
  4 +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  5 +import cn.iocoder.yudao.framework.mybatis.core.type.LongListTypeHandler;
  6 +import com.baomidou.mybatisplus.annotation.KeySequence;
  7 +import com.baomidou.mybatisplus.annotation.TableField;
  8 +import com.baomidou.mybatisplus.annotation.TableId;
  9 +import com.baomidou.mybatisplus.annotation.TableName;
3 10 import lombok.*;
  11 +
4 12 import java.time.LocalDateTime;
5   -import com.baomidou.mybatisplus.annotation.*;
6   -import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  13 +import java.util.List;
7 14  
8 15 /**
9 16 * 秒杀参与商品 DO
... ... @@ -32,7 +39,8 @@ public class SeckillProductDO extends BaseDO {
32 39 /**
33 40 * 秒杀时段 id
34 41 */
35   - private String configIds;
  42 + @TableField(typeHandler = LongListTypeHandler.class)
  43 + private List<Long> configIds;
36 44 /**
37 45 * 商品 spu_id
38 46 */
... ... @@ -51,6 +59,7 @@ public class SeckillProductDO extends BaseDO {
51 59 private Integer stock;
52 60 /**
53 61 * 秒杀商品状态
  62 + * 枚举 {@link CommonStatusEnum 对应的类}
54 63 */
55 64 private Integer activityStatus;
56 65 /**
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/seckill/seckillactivity/SeckillActivityMapper.java
... ... @@ -8,6 +8,8 @@ import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.Se
8 8 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillActivityDO;
9 9 import org.apache.ibatis.annotations.Mapper;
10 10  
  11 +import java.util.List;
  12 +
11 13 /**
12 14 * 秒杀活动 Mapper
13 15 *
... ... @@ -23,4 +25,9 @@ public interface SeckillActivityMapper extends BaseMapperX&lt;SeckillActivityDO&gt; {
23 25 .apply(ObjectUtil.isNotNull(reqVO.getConfigId()), "FIND_IN_SET(" + reqVO.getConfigId() + ",time_ids) > 0")
24 26 .orderByDesc(SeckillActivityDO::getId));
25 27 }
  28 +
  29 + default List<SeckillActivityDO> selectListByStatus(Integer status) {
  30 + return selectList(new LambdaQueryWrapperX<SeckillActivityDO>()
  31 + .eqIfPresent(SeckillActivityDO::getStatus, status));
  32 + }
26 33 }
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/discount/DiscountActivityServiceImpl.java
... ... @@ -52,7 +52,7 @@ public class DiscountActivityServiceImpl implements DiscountActivityService {
52 52  
53 53 // 插入活动
54 54 DiscountActivityDO discountActivity = DiscountActivityConvert.INSTANCE.convert(createReqVO)
55   - .setStatus(PromotionUtils.calculateActivityStatus(createReqVO.getStartTime(), createReqVO.getEndTime()));
  55 + .setStatus(PromotionUtils.calculateActivityStatus(createReqVO.getEndTime()));
56 56 discountActivityMapper.insert(discountActivity);
57 57 // 插入商品
58 58 List<DiscountProductDO> discountProducts = convertList(createReqVO.getProducts(),
... ... @@ -74,7 +74,7 @@ public class DiscountActivityServiceImpl implements DiscountActivityService {
74 74  
75 75 // 更新活动
76 76 DiscountActivityDO updateObj = DiscountActivityConvert.INSTANCE.convert(updateReqVO)
77   - .setStatus(PromotionUtils.calculateActivityStatus(updateReqVO.getStartTime(), updateReqVO.getEndTime()));
  77 + .setStatus(PromotionUtils.calculateActivityStatus(updateReqVO.getEndTime()));
78 78 discountActivityMapper.updateById(updateObj);
79 79 // 更新商品
80 80 updateDiscountProduct(updateReqVO);
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/reward/RewardActivityServiceImpl.java
... ... @@ -41,7 +41,7 @@ public class RewardActivityServiceImpl implements RewardActivityService {
41 41  
42 42 // 插入
43 43 RewardActivityDO rewardActivity = RewardActivityConvert.INSTANCE.convert(createReqVO)
44   - .setStatus(PromotionUtils.calculateActivityStatus(createReqVO.getStartTime(), createReqVO.getEndTime()));
  44 + .setStatus(PromotionUtils.calculateActivityStatus(createReqVO.getEndTime()));
45 45 rewardActivityMapper.insert(rewardActivity);
46 46 // 返回
47 47 return rewardActivity.getId();
... ... @@ -59,7 +59,7 @@ public class RewardActivityServiceImpl implements RewardActivityService {
59 59  
60 60 // 更新
61 61 RewardActivityDO updateObj = RewardActivityConvert.INSTANCE.convert(updateReqVO)
62   - .setStatus(PromotionUtils.calculateActivityStatus(updateReqVO.getStartTime(), updateReqVO.getEndTime()));
  62 + .setStatus(PromotionUtils.calculateActivityStatus(updateReqVO.getEndTime()));
63 63 rewardActivityMapper.updateById(updateObj);
64 64 }
65 65  
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/seckillactivity/SeckillActivityServiceImpl.java
1 1 package cn.iocoder.yudao.module.promotion.service.seckill.seckillactivity;
2 2  
3 3 import cn.hutool.core.collection.CollUtil;
  4 +import cn.hutool.core.util.ArrayUtil;
4 5 import cn.hutool.core.util.ObjectUtil;
5 6 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
6 7 import cn.iocoder.yudao.framework.common.pojo.PageResult;
7 8 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
8   -import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityBaseVO;
  9 +import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
  10 +import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
  11 +import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
  12 +import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
9 13 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityCreateReqVO;
10 14 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityPageReqVO;
11 15 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityUpdateReqVO;
12 16 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product.SeckillProductBaseVO;
13   -import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product.SeckillProductCreateReqVO;
14 17 import cn.iocoder.yudao.module.promotion.convert.seckill.seckillactivity.SeckillActivityConvert;
15 18 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillActivityDO;
16 19 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillProductDO;
... ... @@ -25,8 +28,12 @@ import org.springframework.validation.annotation.Validated;
25 28 import javax.annotation.Resource;
26 29 import java.util.Collection;
27 30 import java.util.List;
  31 +import java.util.Set;
  32 +import java.util.stream.Collectors;
28 33  
29 34 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  35 +import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_NOT_EXISTS;
  36 +import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SPU_NOT_EXISTS;
30 37 import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
31 38 import static java.util.Arrays.asList;
32 39  
... ... @@ -45,40 +52,94 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
45 52 private SeckillProductMapper seckillProductMapper;
46 53 @Resource
47 54 private SeckillConfigService seckillConfigService;
  55 + @Resource
  56 + private ProductSpuApi productSpuApi;
  57 + @Resource
  58 + private ProductSkuApi productSkuApi;
48 59  
49 60 @Override
50 61 public Long createSeckillActivity(SeckillActivityCreateReqVO createReqVO) {
51   - // 校验商品是否冲突
52   - validateSeckillActivityProductConflicts(null, createReqVO.getProducts());
53   - // 校验秒杀时段是否存在
54   - seckillConfigService.validateSeckillConfigExists(createReqVO.getConfigIds());
  62 + // 校验商品秒秒杀时段是否冲突
  63 + validateProductSpuSeckillConflict(createReqVO.getConfigIds(), createReqVO.getSpuIds());
  64 + // 校验商品 sku 是否存在
  65 + validateProductSkuExistence(createReqVO.getSpuIds(), createReqVO.getProducts());
55 66  
56   - // 插入秒杀活动 TODO 活动日期拼接上秒杀时段 -> 2023-06-08 09:00:00
  67 + // 插入秒杀活动
57 68 SeckillActivityDO seckillActivity = SeckillActivityConvert.INSTANCE.convert(createReqVO)
58   - .setStatus(PromotionUtils.calculateActivityStatus(createReqVO.getStartTime(), createReqVO.getEndTime()));
  69 + .setStatus(PromotionUtils.calculateActivityStatus(createReqVO.getEndTime()));
59 70 seckillActivityMapper.insert(seckillActivity);
60 71 // 插入商品
61   - //List<SeckillProductDO> productDOs = SeckillActivityConvert.INSTANCE.convertList(createReqVO.getProducts(), seckillActivity);
62   - //seckillProductMapper.insertBatch(productDOs);
  72 + List<SeckillProductDO> productDOs = SeckillActivityConvert.INSTANCE.convertList(seckillActivity, createReqVO.getProducts());
  73 + seckillProductMapper.insertBatch(productDOs);
63 74 return seckillActivity.getId();
64 75 }
65 76  
  77 + private <T extends SeckillProductBaseVO> void validateProductSkuExistence(List<Long> spuIds, List<T> products) {
  78 + Set<Long> convertedSpuIds = CollectionUtils.convertSet(products, T::getSpuId);
  79 + // 校验 spu 个数是否相等
  80 + if (ObjectUtil.notEqual(spuIds.size(), convertedSpuIds.size())) {
  81 + throw exception(SKU_NOT_EXISTS);
  82 + }
  83 + // 获取所选 spu下的所有 sku
  84 + List<ProductSkuRespDTO> skuRespDTOs = productSkuApi.getSkuListBySpuId(spuIds);
  85 + // 校验 sku 个数是否一致
  86 + Set<Long> skuIdsSet = CollectionUtils.convertSet(products, T::getSkuId);
  87 + Set<Long> skuIdsSet1 = CollectionUtils.convertSet(skuRespDTOs, ProductSkuRespDTO::getId);
  88 + if (ObjectUtil.notEqual(skuIdsSet.size(), skuIdsSet1.size())) {
  89 + throw exception(SKU_NOT_EXISTS);
  90 + }
  91 + // 校验 skuId 是否存在
  92 + if (!skuIdsSet1.containsAll(skuIdsSet) || !skuIdsSet.containsAll(skuIdsSet1)) {
  93 + throw exception(SKU_NOT_EXISTS);
  94 + }
  95 + }
  96 +
  97 + private void validateProductSpuSeckillConflict(List<Long> configIds, List<Long> spuIds) {
  98 + // 校验秒杀时段是否存在
  99 + seckillConfigService.validateSeckillConfigExists(configIds);
  100 + // 校验商品 spu 是否存在
  101 + List<ProductSpuRespDTO> spuList = productSpuApi.getSpuList(spuIds);
  102 + if (ObjectUtil.notEqual(spuIds.size(), spuList.size())) {
  103 + throw exception(SPU_NOT_EXISTS);
  104 + }
  105 + // 查询所有开启的秒杀活动
  106 + List<SeckillActivityDO> activityDOs = seckillActivityMapper.selectListByStatus(CommonStatusEnum.ENABLE.getStatus());
  107 + // 过滤出所有 spuIds 有交集的活动
  108 + List<SeckillActivityDO> doList = activityDOs.stream().filter(s -> {
  109 + // 判断 spu 是否有交集
  110 + List<Long> spuIdsClone = ArrayUtil.clone(s.getSpuIds());
  111 + spuIdsClone.retainAll(spuIds);
  112 + if (CollUtil.isEmpty(spuIdsClone)) {
  113 + return false;
  114 + }
  115 + // 判断秒杀时段是否有交集
  116 + List<Long> configIdsClone = ArrayUtil.clone(s.getConfigIds());
  117 + configIdsClone.retainAll(configIds);
  118 + return CollUtil.isNotEmpty(configIdsClone);
  119 + }).collect(Collectors.toList());
  120 + if (CollUtil.isNotEmpty(doList)) {
  121 + throw exception(SECKILL_ACTIVITY_SPU_CONFLICTS);
  122 + }
  123 + }
  124 +
66 125 @Override
67 126 public void updateSeckillActivity(SeckillActivityUpdateReqVO updateReqVO) {
68 127 // 校验存在
69 128 SeckillActivityDO seckillActivity = validateSeckillActivityExists(updateReqVO.getId());
70   - if (PromotionActivityStatusEnum.CLOSE.getStatus().equals(seckillActivity.getStatus())) {
  129 + if (CommonStatusEnum.ENABLE.getStatus().equals(seckillActivity.getStatus())) {
71 130 throw exception(SECKILL_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED);
72 131 }
73 132 // 校验商品是否冲突
74   - validateSeckillActivityProductConflicts(updateReqVO.getId(), updateReqVO.getProducts());
  133 + validateProductSpuSeckillConflict(updateReqVO.getConfigIds(), updateReqVO.getSpuIds());
  134 + // 校验商品 sku 是否存在
  135 + validateProductSkuExistence(updateReqVO.getSpuIds(), updateReqVO.getProducts());
75 136  
76 137 // 更新活动
77 138 SeckillActivityDO updateObj = SeckillActivityConvert.INSTANCE.convert(updateReqVO)
78   - .setStatus(PromotionUtils.calculateActivityStatus(updateReqVO.getStartTime(), updateReqVO.getEndTime()));
  139 + .setStatus(PromotionUtils.calculateActivityStatus(updateReqVO.getEndTime()));
79 140 seckillActivityMapper.updateById(updateObj);
80 141 // 更新商品
81   - updateSeckillProduct(updateReqVO);
  142 + //updateSeckillProduct(updateReqVO);
82 143 }
83 144  
84 145  
... ... @@ -92,10 +153,11 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
92 153 * @param updateReqVO 更新的请求VO
93 154 */
94 155 private void updateSeckillProduct(SeckillActivityUpdateReqVO updateReqVO) {
95   - List<SeckillProductDO> seckillProductDOs = seckillProductMapper.selectListByActivityId(updateReqVO.getId());
96   - //List<SeckillActivityBaseVO.Product> products = updateReqVO.getProducts();
  156 + // TODO puhui999:后续完善
  157 + //List<SeckillProductDO> seckillProductDOs = seckillProductMapper.selectListByActivityId(updateReqVO.getId());
  158 + //List<SeckillProductUpdateReqVO> products = updateReqVO.getProducts();
97 159  
98   - // 计算需要删除的数据
  160 + ////计算需要删除的数据
99 161 //List<Long> deleteIds = CollectionUtils.convertList(seckillProductDOs, SeckillProductDO::getId,
100 162 // seckillProductDO -> products.stream()
101 163 // .noneMatch(product -> SeckillActivityConvert.INSTANCE.isEquals(seckillProductDO, product)));
... ... @@ -116,37 +178,6 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
116 178 seckillProductMapper.updateTimeIdsByActivityId(updateReqVO.getId(), updateReqVO.getConfigIds());
117 179 }
118 180  
119   - /**
120   - * 校验商品是否冲突
121   - *
122   - * @param id 秒杀活动编号
123   - * @param products 商品列表
124   - */
125   - private <T extends SeckillProductBaseVO> void validateSeckillActivityProductConflicts(Long id, List<T> products) {
126   - if (CollUtil.isEmpty(products)) {
127   - return;
128   - }
129   - // 校验秒杀商品是否存在
130   - List<SeckillProductDO> seckillProductDOs = seckillProductMapper
131   - .selectListBySkuIds(CollectionUtils.convertSet(products, T::getSkuId));
132   - if (CollUtil.isEmpty(seckillProductDOs)) {
133   - return;
134   - }
135   - // 获取秒杀商品所在活动
136   - List<SeckillActivityDO> seckillActivityDOs = seckillActivityMapper
137   - .selectBatchIds(CollectionUtils.convertSet(seckillProductDOs, SeckillProductDO::getActivityId));
138   - if (id != null) {
139   - // 排除自己这个活动
140   - seckillActivityDOs.removeIf(item -> id.equals(item.getId()));
141   - }
142   - // 排除关闭了的活动
143   - seckillActivityDOs.removeIf(item -> ObjectUtil.equal(item.getStatus(), CommonStatusEnum.DISABLE.getStatus()));
144   - // 如果非空,则说明冲突
145   - if (CollUtil.isNotEmpty(seckillActivityDOs)) {
146   - throw exception(SECKILL_ACTIVITY_SPU_CONFLICTS);
147   - }
148   - }
149   -
150 181 @Override
151 182 public void closeSeckillActivity(Long id) {
152 183 // 校验存在
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/util/PromotionUtils.java
1 1 package cn.iocoder.yudao.module.promotion.util;
2 2  
  3 +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
3 4 import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
4   -import cn.iocoder.yudao.module.promotion.enums.common.PromotionActivityStatusEnum;
5 5  
6 6 import java.time.LocalDateTime;
7 7  
... ... @@ -15,18 +15,11 @@ public class PromotionUtils {
15 15 /**
16 16 * 根据时间,计算活动状态
17 17 *
18   - * @param startTime 开始时间
19 18 * @param endTime 结束时间
20 19 * @return 活动状态
21 20 */
22   - public static Integer calculateActivityStatus(LocalDateTime startTime, LocalDateTime endTime) {
23   - if (LocalDateTimeUtils.beforeNow(endTime)) {
24   - return PromotionActivityStatusEnum.END.getStatus();
25   - }
26   - if (LocalDateTimeUtils.afterNow(startTime)) {
27   - return PromotionActivityStatusEnum.WAIT.getStatus();
28   - }
29   - return PromotionActivityStatusEnum.RUN.getStatus();
  21 + public static Integer calculateActivityStatus(LocalDateTime endTime) {
  22 + return LocalDateTimeUtils.beforeNow(endTime) ? CommonStatusEnum.DISABLE.getStatus() : CommonStatusEnum.ENABLE.getStatus();
30 23 }
31 24  
32 25 }
... ...