Commit 78b3d2a20fc2357b0051b273ca17d7ddbfc7a723

Authored by puhui999
1 parent 41d996f7

fix:mall promotion Combination

Showing 12 changed files with 125 additions and 139 deletions
yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/sku/ProductSkuApi.java
@@ -30,14 +30,13 @@ public interface ProductSkuApi { @@ -30,14 +30,13 @@ public interface ProductSkuApi {
30 */ 30 */
31 List<ProductSkuRespDTO> getSkuList(Collection<Long> ids); 31 List<ProductSkuRespDTO> getSkuList(Collection<Long> ids);
32 32
33 - // TODO puhui999:入参用 Collection<Long> 更通用  
34 /** 33 /**
35 * 批量查询 SKU 数组 34 * 批量查询 SKU 数组
36 * 35 *
37 * @param spuIds SPU 编号列表 36 * @param spuIds SPU 编号列表
38 * @return SKU 数组 37 * @return SKU 数组
39 */ 38 */
40 - List<ProductSkuRespDTO> getSkuListBySpuId(List<Long> spuIds); 39 + List<ProductSkuRespDTO> getSkuListBySpuId(Collection<Long> spuIds);
41 40
42 /** 41 /**
43 * 更新 SKU 库存 42 * 更新 SKU 库存
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/api/sku/ProductSkuApiImpl.java
@@ -43,7 +43,7 @@ public class ProductSkuApiImpl implements ProductSkuApi { @@ -43,7 +43,7 @@ public class ProductSkuApiImpl implements ProductSkuApi {
43 } 43 }
44 44
45 @Override 45 @Override
46 - public List<ProductSkuRespDTO> getSkuListBySpuId(List<Long> spuIds) { 46 + public List<ProductSkuRespDTO> getSkuListBySpuId(Collection<Long> spuIds) {
47 if (CollUtil.isEmpty(spuIds)) { 47 if (CollUtil.isEmpty(spuIds)) {
48 return Collections.emptyList(); 48 return Collections.emptyList();
49 } 49 }
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java
@@ -4,7 +4,7 @@ import cn.iocoder.yudao.framework.common.exception.ErrorCode; @@ -4,7 +4,7 @@ import cn.iocoder.yudao.framework.common.exception.ErrorCode;
4 4
5 /** 5 /**
6 * Promotion 错误码枚举类 6 * Promotion 错误码枚举类
7 - * 7 + * <p>
8 * promotion 系统,使用 1-013-000-000 段 8 * promotion 系统,使用 1-013-000-000 段
9 */ 9 */
10 public interface ErrorCodeConstants { 10 public interface ErrorCodeConstants {
@@ -58,6 +58,7 @@ public interface ErrorCodeConstants { @@ -58,6 +58,7 @@ public interface ErrorCodeConstants {
58 ErrorCode SECKILL_TIME_CONFLICTS = new ErrorCode(1013009001, "秒杀时段冲突"); 58 ErrorCode SECKILL_TIME_CONFLICTS = new ErrorCode(1013009001, "秒杀时段冲突");
59 ErrorCode SECKILL_TIME_EQUAL = new ErrorCode(1013009002, "秒杀时段开始时间和结束时间不能相等"); 59 ErrorCode SECKILL_TIME_EQUAL = new ErrorCode(1013009002, "秒杀时段开始时间和结束时间不能相等");
60 ErrorCode SECKILL_START_TIME_BEFORE_END_TIME = new ErrorCode(1013009003, "秒杀时段开始时间不能在结束时间之后"); 60 ErrorCode SECKILL_START_TIME_BEFORE_END_TIME = new ErrorCode(1013009003, "秒杀时段开始时间不能在结束时间之后");
  61 + ErrorCode SECKILL_TIME_DISABLE = new ErrorCode(1013009004, "秒杀时段已关闭");
61 62
62 // ========== 拼团活动 1013010000 ========== 63 // ========== 拼团活动 1013010000 ==========
63 ErrorCode COMBINATION_ACTIVITY_NOT_EXISTS = new ErrorCode(1013010000, "拼团活动不存在"); 64 ErrorCode COMBINATION_ACTIVITY_NOT_EXISTS = new ErrorCode(1013010000, "拼团活动不存在");
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/activity/SeckillActivityBaseVO.java
@@ -20,10 +20,9 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_ @@ -20,10 +20,9 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_
20 @Data 20 @Data
21 public class SeckillActivityBaseVO { 21 public class SeckillActivityBaseVO {
22 22
23 - // TODO @puhui999:对应单 spuId 哈  
24 @Schema(description = "秒杀活动商品id", requiredMode = Schema.RequiredMode.REQUIRED, example = "[121,1212]") 23 @Schema(description = "秒杀活动商品id", requiredMode = Schema.RequiredMode.REQUIRED, example = "[121,1212]")
25 @NotNull(message = "秒杀活动商品不能为空") 24 @NotNull(message = "秒杀活动商品不能为空")
26 - private List<Long> spuIds; 25 + private Long spuId;
27 26
28 @Schema(description = "秒杀活动名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "618大促") 27 @Schema(description = "秒杀活动名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "618大促")
29 @NotNull(message = "秒杀活动名称不能为空") 28 @NotNull(message = "秒杀活动名称不能为空")
@@ -56,8 +55,4 @@ public class SeckillActivityBaseVO { @@ -56,8 +55,4 @@ public class SeckillActivityBaseVO {
56 @Schema(description = "单次限够数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "31683") 55 @Schema(description = "单次限够数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "31683")
57 private Integer singleLimitCount; 56 private Integer singleLimitCount;
58 57
59 - // TODO @puhui999:这个应该是计算出来的字段,只返回,create 和 update 不用哈  
60 - @Schema(description = "秒杀总库存", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")  
61 - private Integer totalStock;  
62 -  
63 } 58 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/activity/SeckillActivityRespVO.java
@@ -23,7 +23,7 @@ public class SeckillActivityRespVO extends SeckillActivityBaseVO { @@ -23,7 +23,7 @@ public class SeckillActivityRespVO extends SeckillActivityBaseVO {
23 private Long id; 23 private Long id;
24 24
25 @Schema(description = "秒杀商品", requiredMode = Schema.RequiredMode.REQUIRED) 25 @Schema(description = "秒杀商品", requiredMode = Schema.RequiredMode.REQUIRED)
26 - private List<SeckillProductRespVO> products; // TODO puhui: 考虑是否去除 26 + private List<SeckillProductRespVO> products;
27 27
28 @Schema(description = "活动状态 开启:0 禁用:1", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") 28 @Schema(description = "活动状态 开启:0 禁用:1", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
29 private Integer status; 29 private Integer status;
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/product/SeckillProductBaseVO.java
@@ -14,11 +14,6 @@ import javax.validation.constraints.NotNull; @@ -14,11 +14,6 @@ import javax.validation.constraints.NotNull;
14 @Data 14 @Data
15 public class SeckillProductBaseVO { 15 public class SeckillProductBaseVO {
16 16
17 - // TODO @puhui:spuId 不用传递;因为一个秒杀活动只对应一个 SPU 哈;  
18 - @Schema(description = "商品spu_id", requiredMode = Schema.RequiredMode.REQUIRED, example = "30563")  
19 - @NotNull(message = "商品spu_id不能为空")  
20 - private Long spuId;  
21 -  
22 @Schema(description = "商品sku_id", requiredMode = Schema.RequiredMode.REQUIRED, example = "30563") 17 @Schema(description = "商品sku_id", requiredMode = Schema.RequiredMode.REQUIRED, example = "30563")
23 @NotNull(message = "商品sku_id不能为空") 18 @NotNull(message = "商品sku_id不能为空")
24 private Long skuId; 19 private Long skuId;
@@ -31,5 +26,4 @@ public class SeckillProductBaseVO { @@ -31,5 +26,4 @@ public class SeckillProductBaseVO {
31 @NotNull(message = "秒杀库存不能为空") 26 @NotNull(message = "秒杀库存不能为空")
32 private Integer stock; 27 private Integer stock;
33 28
34 -  
35 } 29 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/product/SeckillProductUpdateReqVO.java
1 package cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product; 1 package cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product;
2 2
3 import io.swagger.v3.oas.annotations.media.Schema; 3 import io.swagger.v3.oas.annotations.media.Schema;
4 -import lombok.*;  
5 -import javax.validation.constraints.*; 4 +import lombok.Data;
  5 +import lombok.EqualsAndHashCode;
  6 +import lombok.ToString;
6 7
7 /** 8 /**
8 * 管理后台 - 秒杀参与商品更新 Request VO 9 * 管理后台 - 秒杀参与商品更新 Request VO
@@ -15,8 +16,4 @@ import javax.validation.constraints.*; @@ -15,8 +16,4 @@ import javax.validation.constraints.*;
15 @ToString(callSuper = true) 16 @ToString(callSuper = true)
16 public class SeckillProductUpdateReqVO extends SeckillProductBaseVO { 17 public class SeckillProductUpdateReqVO extends SeckillProductBaseVO {
17 18
18 - @Schema(description = "秒杀参与商品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "256")  
19 - @NotNull(message = "秒杀参与商品编号不能为空")  
20 - private Long id;  
21 -  
22 } 19 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/seckill/seckillactivity/SeckillActivityConvert.java
1 package cn.iocoder.yudao.module.promotion.convert.seckill.seckillactivity; 1 package cn.iocoder.yudao.module.promotion.convert.seckill.seckillactivity;
2 2
3 -import cn.hutool.core.util.ObjectUtil;  
4 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; 3 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
5 import cn.iocoder.yudao.framework.common.pojo.PageResult; 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  5 +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
6 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityCreateReqVO; 6 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityCreateReqVO;
7 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityDetailRespVO; 7 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityDetailRespVO;
8 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityRespVO; 8 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityRespVO;
9 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityUpdateReqVO; 9 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityUpdateReqVO;
10 -import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product.SeckillProductCreateReqVO; 10 +import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product.SeckillProductBaseVO;
  11 +import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product.SeckillProductUpdateReqVO;
11 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillActivityDO; 12 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillActivityDO;
12 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillProductDO; 13 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillProductDO;
13 import org.mapstruct.Mapper; 14 import org.mapstruct.Mapper;
  15 +import org.mapstruct.Mapping;
  16 +import org.mapstruct.Mappings;
14 import org.mapstruct.factory.Mappers; 17 import org.mapstruct.factory.Mappers;
15 18
16 import java.util.ArrayList; 19 import java.util.ArrayList;
17 import java.util.List; 20 import java.util.List;
  21 +import java.util.Map;
18 22
19 /** 23 /**
20 * 秒杀活动 Convert 24 * 秒杀活动 Convert
@@ -26,8 +30,6 @@ public interface SeckillActivityConvert { @@ -26,8 +30,6 @@ public interface SeckillActivityConvert {
26 30
27 SeckillActivityConvert INSTANCE = Mappers.getMapper(SeckillActivityConvert.class); 31 SeckillActivityConvert INSTANCE = Mappers.getMapper(SeckillActivityConvert.class);
28 32
29 - SeckillProductDO convert(SeckillProductCreateReqVO product);  
30 -  
31 SeckillActivityDO convert(SeckillActivityCreateReqVO bean); 33 SeckillActivityDO convert(SeckillActivityCreateReqVO bean);
32 34
33 SeckillActivityDO convert(SeckillActivityUpdateReqVO bean); 35 SeckillActivityDO convert(SeckillActivityUpdateReqVO bean);
@@ -40,51 +42,38 @@ public interface SeckillActivityConvert { @@ -40,51 +42,38 @@ public interface SeckillActivityConvert {
40 42
41 SeckillActivityDetailRespVO convert(SeckillActivityDO seckillActivity, List<SeckillProductDO> seckillProducts); 43 SeckillActivityDetailRespVO convert(SeckillActivityDO seckillActivity, List<SeckillProductDO> seckillProducts);
42 44
  45 + @Mappings({
  46 + @Mapping(target = "activityId", source = "activityDO.id"),
  47 + @Mapping(target = "configIds", source = "activityDO.configIds"),
  48 + @Mapping(target = "spuId", source = "activityDO.spuId"),
  49 + @Mapping(target = "skuId", source = "vo.skuId"),
  50 + @Mapping(target = "seckillPrice", source = "vo.seckillPrice"),
  51 + @Mapping(target = "stock", source = "vo.stock"),
  52 + @Mapping(target = "activityStartTime", source = "activityDO.startTime"),
  53 + @Mapping(target = "activityEndTime", source = "activityDO.endTime")
  54 + })
  55 + SeckillProductDO convert(SeckillActivityDO activityDO, SeckillProductBaseVO vo);
43 56
44 - /**  
45 - * 比较两个秒杀商品对象是否相等  
46 - *  
47 - * @param productDO 数据库中的商品  
48 - * @param productVO 前端传入的商品  
49 - * @return 是否匹配  
50 - */  
51 - default boolean isEquals(SeckillProductDO productDO, SeckillProductCreateReqVO productVO) {  
52 - return ObjectUtil.equals(productDO.getSpuId(), 1) // TODO puhui:再看看  
53 - && ObjectUtil.equals(productDO.getSkuId(), productVO.getSkuId())  
54 - && ObjectUtil.equals(productDO.getSeckillPrice(), productVO.getSeckillPrice());  
55 - //&& ObjectUtil.equals(productDO.getQuota(), productVO.getQuota())  
56 - //&& ObjectUtil.equals(productDO.getLimitCount(), productVO.getLimitCount());  
57 - }  
58 -  
59 - /**  
60 - * 比较两个秒杀商品对象是否相等  
61 - *  
62 - * @param productDO 商品1  
63 - * @param productVO 商品2  
64 - * @return 是否匹配  
65 - */  
66 - default boolean isEquals(SeckillProductDO productDO, SeckillProductDO productVO) {  
67 - return ObjectUtil.equals(productDO.getSpuId(), productVO.getSpuId())  
68 - && ObjectUtil.equals(productDO.getSkuId(), productVO.getSkuId())  
69 - && ObjectUtil.equals(productDO.getSeckillPrice(), productVO.getSeckillPrice());  
70 - //&& ObjectUtil.equals(productDO.getQuota(), productVO.getQuota())  
71 - //&& ObjectUtil.equals(productDO.getLimitCount(), productVO.getLimitCount()); 57 + default List<SeckillProductDO> convertList(SeckillActivityDO activityDO, List<? extends SeckillProductBaseVO> products) {
  58 + List<SeckillProductDO> list = new ArrayList<>();
  59 + products.forEach(sku -> {
  60 + SeckillProductDO productDO = convert(activityDO, sku);
  61 + productDO.setActivityStatus(CommonStatusEnum.ENABLE.getStatus());
  62 + list.add(productDO);
  63 + });
  64 + return list;
72 } 65 }
73 66
74 - default List<SeckillProductDO> convertList(SeckillActivityDO seckillActivity, List<SeckillProductCreateReqVO> products) { 67 + default List<SeckillProductDO> convertList1(SeckillActivityDO activityDO, List<SeckillProductUpdateReqVO> vos, List<SeckillProductDO> productDOs) {
  68 + Map<Long, Long> longMap = CollectionUtils.convertMap(productDOs, SeckillProductDO::getSkuId, SeckillProductDO::getId);
75 List<SeckillProductDO> list = new ArrayList<>(); 69 List<SeckillProductDO> list = new ArrayList<>();
76 - products.forEach(sku -> {  
77 - SeckillProductDO productDO = new SeckillProductDO();  
78 - productDO.setActivityId(seckillActivity.getId());  
79 - productDO.setConfigIds(seckillActivity.getConfigIds());  
80 - productDO.setSpuId(sku.getSpuId());  
81 - productDO.setSkuId(sku.getSkuId());  
82 - productDO.setSeckillPrice(sku.getSeckillPrice());  
83 - productDO.setStock(sku.getStock()); 70 + vos.forEach(sku -> {
  71 + SeckillProductDO productDO = convert(activityDO, sku);
  72 + productDO.setId(longMap.get(sku.getSkuId()));
84 productDO.setActivityStatus(CommonStatusEnum.ENABLE.getStatus()); 73 productDO.setActivityStatus(CommonStatusEnum.ENABLE.getStatus());
85 - productDO.setActivityStartTime(seckillActivity.getStartTime());  
86 - productDO.setActivityEndTime(seckillActivity.getEndTime()); 74 + list.add(productDO);
87 }); 75 });
88 return list; 76 return list;
89 } 77 }
  78 +
90 } 79 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/seckill/seckillactivity/SeckillActivityDO.java
@@ -34,8 +34,7 @@ public class SeckillActivityDO extends BaseDO { @@ -34,8 +34,7 @@ public class SeckillActivityDO extends BaseDO {
34 /** 34 /**
35 * 秒杀活动商品 35 * 秒杀活动商品
36 */ 36 */
37 - @TableField(typeHandler = LongListTypeHandler.class)  
38 - private List<Long> spuIds; 37 + private Long spuId;
39 /** 38 /**
40 * 秒杀活动名称 39 * 秒杀活动名称
41 */ 40 */
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/seckillactivity/SeckillActivityServiceImpl.java
@@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollUtil; @@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollUtil;
4 import cn.hutool.core.util.ObjectUtil; 4 import cn.hutool.core.util.ObjectUtil;
5 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; 5 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
6 import cn.iocoder.yudao.framework.common.pojo.PageResult; 6 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  7 +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
7 import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; 8 import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
8 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; 9 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
9 import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi; 10 import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
@@ -18,23 +19,21 @@ import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity. @@ -18,23 +19,21 @@ import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.
18 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillProductDO; 19 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillProductDO;
19 import cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckillactivity.SeckillActivityMapper; 20 import cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckillactivity.SeckillActivityMapper;
20 import cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckillactivity.SeckillProductMapper; 21 import cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckillactivity.SeckillProductMapper;
21 -import cn.iocoder.yudao.module.promotion.enums.common.PromotionActivityStatusEnum;  
22 import cn.iocoder.yudao.module.promotion.service.seckill.seckillconfig.SeckillConfigService; 22 import cn.iocoder.yudao.module.promotion.service.seckill.seckillconfig.SeckillConfigService;
23 import cn.iocoder.yudao.module.promotion.util.PromotionUtils; 23 import cn.iocoder.yudao.module.promotion.util.PromotionUtils;
24 import org.springframework.stereotype.Service; 24 import org.springframework.stereotype.Service;
  25 +import org.springframework.transaction.annotation.Transactional;
25 import org.springframework.validation.annotation.Validated; 26 import org.springframework.validation.annotation.Validated;
26 27
27 import javax.annotation.Resource; 28 import javax.annotation.Resource;
28 -import java.util.ArrayList;  
29 import java.util.Collection; 29 import java.util.Collection;
30 import java.util.List; 30 import java.util.List;
31 -import java.util.stream.Collectors; 31 +import java.util.Set;
32 32
33 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 33 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
34 import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SPU_NOT_EXISTS; 34 import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SPU_NOT_EXISTS;
35 import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*; 35 import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
36 import static cn.iocoder.yudao.module.promotion.util.PromotionUtils.validateProductSkuExistence; 36 import static cn.iocoder.yudao.module.promotion.util.PromotionUtils.validateProductSkuExistence;
37 -import static java.util.Arrays.asList;  
38 37
39 /** 38 /**
40 * 秒杀活动 Service 实现类 39 * 秒杀活动 Service 实现类
@@ -57,17 +56,19 @@ public class SeckillActivityServiceImpl implements SeckillActivityService { @@ -57,17 +56,19 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
57 private ProductSkuApi productSkuApi; 56 private ProductSkuApi productSkuApi;
58 57
59 @Override 58 @Override
  59 + @Transactional(rollbackFor = Exception.class)
60 public Long createSeckillActivity(SeckillActivityCreateReqVO createReqVO) { 60 public Long createSeckillActivity(SeckillActivityCreateReqVO createReqVO) {
61 // 校验商品秒秒杀时段是否冲突 61 // 校验商品秒秒杀时段是否冲突
62 - validateProductSpuSeckillConflict(createReqVO.getConfigIds(), createReqVO.getSpuIds()); 62 + validateProductSpuSeckillConflict(createReqVO.getConfigIds(), createReqVO.getSpuId(), null);
63 // 获取所选 spu下的所有 sku 63 // 获取所选 spu下的所有 sku
64 - List<ProductSkuRespDTO> skus = productSkuApi.getSkuListBySpuId(createReqVO.getSpuIds()); 64 + List<ProductSkuRespDTO> skus = productSkuApi.getSkuListBySpuId(CollUtil.newArrayList(createReqVO.getSpuId()));
65 // 校验商品 sku 是否存在 65 // 校验商品 sku 是否存在
66 validateProductSkuExistence(skus, createReqVO.getProducts(), SeckillProductCreateReqVO::getSkuId); 66 validateProductSkuExistence(skus, createReqVO.getProducts(), SeckillProductCreateReqVO::getSkuId);
67 67
68 // 插入秒杀活动 68 // 插入秒杀活动
69 SeckillActivityDO activity = SeckillActivityConvert.INSTANCE.convert(createReqVO) 69 SeckillActivityDO activity = SeckillActivityConvert.INSTANCE.convert(createReqVO)
70 - .setStatus(PromotionUtils.calculateActivityStatus(createReqVO.getEndTime())); 70 + .setStatus(PromotionUtils.calculateActivityStatus(createReqVO.getEndTime()))
  71 + .setTotalStock(CollectionUtils.getSumValue(createReqVO.getProducts(), SeckillProductCreateReqVO::getStock, Integer::sum));
71 seckillActivityMapper.insert(activity); 72 seckillActivityMapper.insert(activity);
72 // 插入商品 73 // 插入商品
73 List<SeckillProductDO> product = SeckillActivityConvert.INSTANCE.convertList(activity, createReqVO.getProducts()); 74 List<SeckillProductDO> product = SeckillActivityConvert.INSTANCE.convertList(activity, createReqVO.getProducts());
@@ -75,119 +76,124 @@ public class SeckillActivityServiceImpl implements SeckillActivityService { @@ -75,119 +76,124 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
75 return activity.getId(); 76 return activity.getId();
76 } 77 }
77 78
78 - private void validateProductSpuSeckillConflict(List<Long> configIds, List<Long> spuIds) { 79 + private void validateProductSpuSeckillConflict(List<Long> configIds, Long spuId, Long activityId) {
79 // 校验秒杀时段是否存在 80 // 校验秒杀时段是否存在
80 seckillConfigService.validateSeckillConfigExists(configIds); 81 seckillConfigService.validateSeckillConfigExists(configIds);
81 // 校验商品 spu 是否存在 82 // 校验商品 spu 是否存在
82 - List<ProductSpuRespDTO> spuList = productSpuApi.getSpuList(spuIds);  
83 - if (ObjectUtil.notEqual(spuIds.size(), spuList.size())) { 83 + List<ProductSpuRespDTO> spuList = productSpuApi.getSpuList(CollUtil.newArrayList(spuId));
  84 + if (CollUtil.isEmpty(spuList)) {
84 throw exception(SPU_NOT_EXISTS); 85 throw exception(SPU_NOT_EXISTS);
85 } 86 }
86 // 查询所有开启的秒杀活动 87 // 查询所有开启的秒杀活动
87 List<SeckillActivityDO> activityDOs = seckillActivityMapper.selectListByStatus(CommonStatusEnum.ENABLE.getStatus()); 88 List<SeckillActivityDO> activityDOs = seckillActivityMapper.selectListByStatus(CommonStatusEnum.ENABLE.getStatus());
88 - // 过滤出所有 spuIds 有交集的活动  
89 - List<SeckillActivityDO> doList = activityDOs.stream().filter(s -> {  
90 - // 判断 spu 是否有交集  
91 - ArrayList<Long> spuIdsClone = CollUtil.newArrayList(s.getSpuIds());  
92 - spuIdsClone.retainAll(spuIds);  
93 - if (CollUtil.isEmpty(spuIdsClone)) {  
94 - return false;  
95 - } 89 + if (activityId != null) {
  90 + // 更新时移除本活动
  91 + activityDOs.removeIf(item -> ObjectUtil.equal(item.getId(), activityId));
  92 + }
  93 + // 过滤出所有 spuId 有交集的活动
  94 + List<SeckillActivityDO> activityDOs1 = CollectionUtils.convertList(activityDOs, c -> c, s -> ObjectUtil.equal(s.getSpuId(), spuId));
  95 + if (CollUtil.isNotEmpty(activityDOs1)) {
  96 + throw exception(SECKILL_ACTIVITY_SPU_CONFLICTS);
  97 + }
  98 + List<SeckillActivityDO> activityDOs2 = CollectionUtils.convertList(activityDOs, c -> c, s -> {
96 // 判断秒杀时段是否有交集 99 // 判断秒杀时段是否有交集
97 List<Long> configIdsClone = CollUtil.newArrayList(s.getConfigIds()); 100 List<Long> configIdsClone = CollUtil.newArrayList(s.getConfigIds());
98 configIdsClone.retainAll(configIds); 101 configIdsClone.retainAll(configIds);
99 return CollUtil.isNotEmpty(configIdsClone); 102 return CollUtil.isNotEmpty(configIdsClone);
100 - }).collect(Collectors.toList());  
101 - if (CollUtil.isNotEmpty(doList)) {  
102 - throw exception(SECKILL_ACTIVITY_SPU_CONFLICTS); 103 + });
  104 + if (CollUtil.isNotEmpty(activityDOs2)) {
  105 + throw exception(SECKILL_TIME_CONFLICTS);
103 } 106 }
104 } 107 }
105 108
106 @Override 109 @Override
  110 + @Transactional(rollbackFor = Exception.class)
107 public void updateSeckillActivity(SeckillActivityUpdateReqVO updateReqVO) { 111 public void updateSeckillActivity(SeckillActivityUpdateReqVO updateReqVO) {
108 // 校验存在 112 // 校验存在
109 SeckillActivityDO seckillActivity = validateSeckillActivityExists(updateReqVO.getId()); 113 SeckillActivityDO seckillActivity = validateSeckillActivityExists(updateReqVO.getId());
110 - if (CommonStatusEnum.ENABLE.getStatus().equals(seckillActivity.getStatus())) { 114 + if (CommonStatusEnum.DISABLE.getStatus().equals(seckillActivity.getStatus())) {
111 throw exception(SECKILL_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED); 115 throw exception(SECKILL_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED);
112 } 116 }
113 // 校验商品是否冲突 117 // 校验商品是否冲突
114 - validateProductSpuSeckillConflict(updateReqVO.getConfigIds(), updateReqVO.getSpuIds()); 118 + validateProductSpuSeckillConflict(updateReqVO.getConfigIds(), updateReqVO.getSpuId(), updateReqVO.getId());
115 // 获取所选 spu下的所有 sku 119 // 获取所选 spu下的所有 sku
116 - List<ProductSkuRespDTO> skus = productSkuApi.getSkuListBySpuId(updateReqVO.getSpuIds()); 120 + List<ProductSkuRespDTO> skus = productSkuApi.getSkuListBySpuId(CollUtil.newArrayList(updateReqVO.getSpuId()));
117 // 校验商品 sku 是否存在 121 // 校验商品 sku 是否存在
118 validateProductSkuExistence(skus, updateReqVO.getProducts(), SeckillProductUpdateReqVO::getSkuId); 122 validateProductSkuExistence(skus, updateReqVO.getProducts(), SeckillProductUpdateReqVO::getSkuId);
119 123
120 // 更新活动 124 // 更新活动
121 SeckillActivityDO updateObj = SeckillActivityConvert.INSTANCE.convert(updateReqVO) 125 SeckillActivityDO updateObj = SeckillActivityConvert.INSTANCE.convert(updateReqVO)
122 - .setStatus(PromotionUtils.calculateActivityStatus(updateReqVO.getEndTime())); 126 + .setStatus(PromotionUtils.calculateActivityStatus(updateReqVO.getEndTime()))
  127 + .setTotalStock(CollectionUtils.getSumValue(updateReqVO.getProducts(), SeckillProductUpdateReqVO::getStock, Integer::sum));
123 seckillActivityMapper.updateById(updateObj); 128 seckillActivityMapper.updateById(updateObj);
124 // 更新商品 129 // 更新商品
125 - //updateSeckillProduct(updateReqVO); 130 + updateSeckillProduct(updateObj, updateReqVO.getProducts());
126 } 131 }
127 132
128 133
129 /** 134 /**
130 * 更新秒杀商品 135 * 更新秒杀商品
131 - * 后台查出的数据和前台查出的数据进行遍历,  
132 - * 1. 对前台数据进行遍历:如果不存在于后台的 sku 中需要新增  
133 - * 2. 对后台数据进行遍历:如果不存在于前台的 sku 中需要删除  
134 - * 3. 最后对当前活动商品全部更新,更新秒杀时段id列表  
135 * 136 *
136 - * @param updateReqVO 更新的请求VO 137 + * @param updateObj DO
  138 + * @param products 商品配置
137 */ 139 */
138 - private void updateSeckillProduct(SeckillActivityUpdateReqVO updateReqVO) {  
139 - // TODO puhui999:要不这里简单一点;删除原本的,插入新增的;不做的这么细致  
140 - // TODO puhui999:后续完善  
141 - //List<SeckillProductDO> seckillProductDOs = seckillProductMapper.selectListByActivityId(updateReqVO.getId());  
142 - //List<SeckillProductUpdateReqVO> products = updateReqVO.getProducts();  
143 -  
144 - ////计算需要删除的数据  
145 - //List<Long> deleteIds = CollectionUtils.convertList(seckillProductDOs, SeckillProductDO::getId,  
146 - // seckillProductDO -> products.stream()  
147 - // .noneMatch(product -> SeckillActivityConvert.INSTANCE.isEquals(seckillProductDO, product)));  
148 - //if (CollUtil.isNotEmpty(deleteIds)) {  
149 - // seckillProductMapper.deleteBatchIds(deleteIds);  
150 - //}  
151 - //  
152 - //// 计算需要新增的数据  
153 - //List<SeckillProductDO> newSeckillProductDOs = CollectionUtils.convertList(products,  
154 - // product -> SeckillActivityConvert.INSTANCE.convert(product).setActivityId(updateReqVO.getId()));  
155 - //newSeckillProductDOs.removeIf(product -> seckillProductDOs.stream()  
156 - // .anyMatch(seckillProduct -> SeckillActivityConvert.INSTANCE.isEquals(seckillProduct, product)));  
157 - //if (CollUtil.isNotEmpty(newSeckillProductDOs)) {  
158 - // seckillProductMapper.insertBatch(newSeckillProductDOs);  
159 - //}  
160 -  
161 - //全量更新当前活动商品的秒杀时段id列表(timeIds)  
162 - seckillProductMapper.updateTimeIdsByActivityId(updateReqVO.getId(), updateReqVO.getConfigIds()); 140 + private void updateSeckillProduct(SeckillActivityDO updateObj, List<SeckillProductUpdateReqVO> products) {
  141 + List<SeckillProductDO> seckillProductDOs = seckillProductMapper.selectListByActivityId(updateObj.getId());
  142 + // 数据库中的活动商品
  143 + Set<Long> convertSet = CollectionUtils.convertSet(seckillProductDOs, SeckillProductDO::getSkuId);
  144 + // 前端传过来的活动商品
  145 + Set<Long> convertSet1 = CollectionUtils.convertSet(products, SeckillProductUpdateReqVO::getSkuId);
  146 + // 删除后台存在的前端不存在的商品
  147 + List<Long> d = CollectionUtils.filterList(convertSet, item -> !convertSet1.contains(item));
  148 + if (CollUtil.isNotEmpty(d)) {
  149 + seckillProductMapper.deleteBatchIds(d);
  150 + }
  151 + // 前端存在的后端不存在的商品
  152 + List<Long> c = CollectionUtils.filterList(convertSet1, item -> !convertSet.contains(item));
  153 + if (CollUtil.isNotEmpty(c)) {
  154 + List<SeckillProductUpdateReqVO> vos = CollectionUtils.filterList(products, item -> c.contains(item.getSkuId()));
  155 + List<SeckillProductDO> productDOs = SeckillActivityConvert.INSTANCE.convertList(updateObj, vos);
  156 + seckillProductMapper.insertBatch(productDOs);
  157 + }
  158 + // 更新已存在的商品
  159 + List<Long> u = CollectionUtils.filterList(convertSet1, convertSet::contains);
  160 + if (CollUtil.isNotEmpty(u)) {
  161 + List<SeckillProductUpdateReqVO> vos = CollectionUtils.filterList(products, item -> u.contains(item.getSkuId()));
  162 + List<SeckillProductDO> productDOs = SeckillActivityConvert.INSTANCE.convertList1(updateObj, vos, seckillProductDOs);
  163 + seckillProductMapper.insertBatch(productDOs);
  164 + }
163 } 165 }
164 166
165 @Override 167 @Override
  168 + @Transactional(rollbackFor = Exception.class)
166 public void closeSeckillActivity(Long id) { 169 public void closeSeckillActivity(Long id) {
  170 + // TODO 待验证没使用过
167 // 校验存在 171 // 校验存在
168 - SeckillActivityDO seckillActivity = this.validateSeckillActivityExists(id);  
169 - if (PromotionActivityStatusEnum.CLOSE.getStatus().equals(seckillActivity.getStatus())) { 172 + SeckillActivityDO seckillActivity = validateSeckillActivityExists(id);
  173 + if (CommonStatusEnum.DISABLE.getStatus().equals(seckillActivity.getStatus())) {
170 throw exception(SECKILL_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED); 174 throw exception(SECKILL_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED);
171 } 175 }
172 - if (PromotionActivityStatusEnum.END.getStatus().equals(seckillActivity.getStatus())) {  
173 - throw exception(SECKILL_ACTIVITY_CLOSE_FAIL_STATUS_END);  
174 - } 176 +
175 // 更新 177 // 更新
176 - SeckillActivityDO updateObj = new SeckillActivityDO().setId(id).setStatus(PromotionActivityStatusEnum.CLOSE.getStatus()); 178 + SeckillActivityDO updateObj = new SeckillActivityDO().setId(id).setStatus(CommonStatusEnum.DISABLE.getStatus());
177 seckillActivityMapper.updateById(updateObj); 179 seckillActivityMapper.updateById(updateObj);
178 } 180 }
179 181
180 @Override 182 @Override
  183 + @Transactional(rollbackFor = Exception.class)
181 public void deleteSeckillActivity(Long id) { 184 public void deleteSeckillActivity(Long id) {
182 // 校验存在 185 // 校验存在
183 SeckillActivityDO seckillActivity = this.validateSeckillActivityExists(id); 186 SeckillActivityDO seckillActivity = this.validateSeckillActivityExists(id);
184 - List<Integer> statuses = asList(PromotionActivityStatusEnum.CLOSE.getStatus(), PromotionActivityStatusEnum.END.getStatus());  
185 - if (!statuses.contains(seckillActivity.getStatus())) { 187 + if (CommonStatusEnum.ENABLE.getStatus().equals(seckillActivity.getStatus())) {
186 throw exception(SECKILL_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END); 188 throw exception(SECKILL_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END);
187 } 189 }
188 190
189 - // 删除 191 + // 删除活动
190 seckillActivityMapper.deleteById(id); 192 seckillActivityMapper.deleteById(id);
  193 + // 删除活动商品
  194 + List<SeckillProductDO> productDOs = seckillProductMapper.selectListByActivityId(id);
  195 + Set<Long> convertSet = CollectionUtils.convertSet(productDOs, SeckillProductDO::getSkuId);
  196 + seckillProductMapper.deleteBatchIds(convertSet);
191 } 197 }
192 198
193 private SeckillActivityDO validateSeckillActivityExists(Long id) { 199 private SeckillActivityDO validateSeckillActivityExists(Long id) {
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/seckillconfig/SeckillConfigServiceImpl.java
1 package cn.iocoder.yudao.module.promotion.service.seckill.seckillconfig; 1 package cn.iocoder.yudao.module.promotion.service.seckill.seckillconfig;
2 2
3 import cn.hutool.core.collection.CollUtil; 3 import cn.hutool.core.collection.CollUtil;
  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;
  7 +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
6 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.SeckillConfigCreateReqVO; 8 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.SeckillConfigCreateReqVO;
7 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.SeckillConfigPageReqVO; 9 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.SeckillConfigPageReqVO;
8 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.SeckillConfigUpdateReqVO; 10 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.SeckillConfigUpdateReqVO;
@@ -127,10 +129,18 @@ public class SeckillConfigServiceImpl implements SeckillConfigService { @@ -127,10 +129,18 @@ public class SeckillConfigServiceImpl implements SeckillConfigService {
127 if (CollUtil.isEmpty(configIds)) { 129 if (CollUtil.isEmpty(configIds)) {
128 throw exception(SECKILL_TIME_NOT_EXISTS); 130 throw exception(SECKILL_TIME_NOT_EXISTS);
129 } 131 }
130 - if (seckillConfigMapper.selectBatchIds(configIds).size() != configIds.size()) { 132 + List<SeckillConfigDO> configDOs = seckillConfigMapper.selectBatchIds(configIds);
  133 + if (CollUtil.isEmpty(configDOs)) {
  134 + throw exception(SECKILL_TIME_NOT_EXISTS);
  135 + }
  136 + // 过滤出关闭的时段
  137 + List<SeckillConfigDO> filterList = CollectionUtils.filterList(configDOs, item -> ObjectUtil.equal(item.getStatus(), CommonStatusEnum.DISABLE.getStatus()));
  138 + if (CollUtil.isNotEmpty(filterList)) {
  139 + throw exception(SECKILL_TIME_DISABLE);
  140 + }
  141 + if (configDOs.size() != configIds.size()) {
131 throw exception(SECKILL_TIME_NOT_EXISTS); 142 throw exception(SECKILL_TIME_NOT_EXISTS);
132 } 143 }
133 - // TODO @puhui999:应该要校验个 status 哈;如果有禁用的,也不行  
134 } 144 }
135 145
136 @Override 146 @Override
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/util/PromotionUtils.java
1 package cn.iocoder.yudao.module.promotion.util; 1 package cn.iocoder.yudao.module.promotion.util;
2 2
3 -import cn.hutool.core.util.ObjectUtil;  
4 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; 3 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
5 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; 4 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
6 import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils; 5 import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
@@ -35,9 +34,6 @@ public class PromotionUtils { @@ -35,9 +34,6 @@ public class PromotionUtils {
35 // 校验 sku 个数是否一致 34 // 校验 sku 个数是否一致
36 Set<Long> skuIdsSet = CollectionUtils.convertSet(products, func); 35 Set<Long> skuIdsSet = CollectionUtils.convertSet(products, func);
37 Set<Long> skuIdsSet1 = CollectionUtils.convertSet(skus, ProductSkuRespDTO::getId); 36 Set<Long> skuIdsSet1 = CollectionUtils.convertSet(skus, ProductSkuRespDTO::getId);
38 - if (ObjectUtil.notEqual(skuIdsSet.size(), skuIdsSet1.size())) {  
39 - throw exception(SKU_NOT_EXISTS);  
40 - }  
41 // 校验 skuId 是否存在 37 // 校验 skuId 是否存在
42 if (!skuIdsSet1.containsAll(skuIdsSet) || !skuIdsSet.containsAll(skuIdsSet1)) { 38 if (!skuIdsSet1.containsAll(skuIdsSet) || !skuIdsSet.containsAll(skuIdsSet1)) {
43 throw exception(SKU_NOT_EXISTS); 39 throw exception(SKU_NOT_EXISTS);