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 30 */
31 31 List<ProductSkuRespDTO> getSkuList(Collection<Long> ids);
32 32  
33   - // TODO puhui999:入参用 Collection<Long> 更通用
34 33 /**
35 34 * 批量查询 SKU 数组
36 35 *
37 36 * @param spuIds SPU 编号列表
38 37 * @return SKU 数组
39 38 */
40   - List<ProductSkuRespDTO> getSkuListBySpuId(List<Long> spuIds);
  39 + List<ProductSkuRespDTO> getSkuListBySpuId(Collection<Long> spuIds);
41 40  
42 41 /**
43 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 43 }
44 44  
45 45 @Override
46   - public List<ProductSkuRespDTO> getSkuListBySpuId(List<Long> spuIds) {
  46 + public List<ProductSkuRespDTO> getSkuListBySpuId(Collection<Long> spuIds) {
47 47 if (CollUtil.isEmpty(spuIds)) {
48 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 4  
5 5 /**
6 6 * Promotion 错误码枚举类
7   - *
  7 + * <p>
8 8 * promotion 系统,使用 1-013-000-000 段
9 9 */
10 10 public interface ErrorCodeConstants {
... ... @@ -58,6 +58,7 @@ public interface ErrorCodeConstants {
58 58 ErrorCode SECKILL_TIME_CONFLICTS = new ErrorCode(1013009001, "秒杀时段冲突");
59 59 ErrorCode SECKILL_TIME_EQUAL = new ErrorCode(1013009002, "秒杀时段开始时间和结束时间不能相等");
60 60 ErrorCode SECKILL_START_TIME_BEFORE_END_TIME = new ErrorCode(1013009003, "秒杀时段开始时间不能在结束时间之后");
  61 + ErrorCode SECKILL_TIME_DISABLE = new ErrorCode(1013009004, "秒杀时段已关闭");
61 62  
62 63 // ========== 拼团活动 1013010000 ==========
63 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 20 @Data
21 21 public class SeckillActivityBaseVO {
22 22  
23   - // TODO @puhui999:对应单 spuId 哈
24 23 @Schema(description = "秒杀活动商品id", requiredMode = Schema.RequiredMode.REQUIRED, example = "[121,1212]")
25 24 @NotNull(message = "秒杀活动商品不能为空")
26   - private List<Long> spuIds;
  25 + private Long spuId;
27 26  
28 27 @Schema(description = "秒杀活动名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "618大促")
29 28 @NotNull(message = "秒杀活动名称不能为空")
... ... @@ -56,8 +55,4 @@ public class SeckillActivityBaseVO {
56 55 @Schema(description = "单次限够数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "31683")
57 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 23 private Long id;
24 24  
25 25 @Schema(description = "秒杀商品", requiredMode = Schema.RequiredMode.REQUIRED)
26   - private List<SeckillProductRespVO> products; // TODO puhui: 考虑是否去除
  26 + private List<SeckillProductRespVO> products;
27 27  
28 28 @Schema(description = "活动状态 开启:0 禁用:1", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
29 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 14 @Data
15 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 17 @Schema(description = "商品sku_id", requiredMode = Schema.RequiredMode.REQUIRED, example = "30563")
23 18 @NotNull(message = "商品sku_id不能为空")
24 19 private Long skuId;
... ... @@ -31,5 +26,4 @@ public class SeckillProductBaseVO {
31 26 @NotNull(message = "秒杀库存不能为空")
32 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 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 javax.validation.constraints.*;
  4 +import lombok.Data;
  5 +import lombok.EqualsAndHashCode;
  6 +import lombok.ToString;
6 7  
7 8 /**
8 9 * 管理后台 - 秒杀参与商品更新 Request VO
... ... @@ -15,8 +16,4 @@ import javax.validation.constraints.*;
15 16 @ToString(callSuper = true)
16 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 1 package cn.iocoder.yudao.module.promotion.convert.seckill.seckillactivity;
2 2  
3   -import cn.hutool.core.util.ObjectUtil;
4 3 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
5 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  5 +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
6 6 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityCreateReqVO;
7 7 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityDetailRespVO;
8 8 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityRespVO;
9 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 12 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillActivityDO;
12 13 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillProductDO;
13 14 import org.mapstruct.Mapper;
  15 +import org.mapstruct.Mapping;
  16 +import org.mapstruct.Mappings;
14 17 import org.mapstruct.factory.Mappers;
15 18  
16 19 import java.util.ArrayList;
17 20 import java.util.List;
  21 +import java.util.Map;
18 22  
19 23 /**
20 24 * 秒杀活动 Convert
... ... @@ -26,8 +30,6 @@ public interface SeckillActivityConvert {
26 30  
27 31 SeckillActivityConvert INSTANCE = Mappers.getMapper(SeckillActivityConvert.class);
28 32  
29   - SeckillProductDO convert(SeckillProductCreateReqVO product);
30   -
31 33 SeckillActivityDO convert(SeckillActivityCreateReqVO bean);
32 34  
33 35 SeckillActivityDO convert(SeckillActivityUpdateReqVO bean);
... ... @@ -40,51 +42,38 @@ public interface SeckillActivityConvert {
40 42  
41 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 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 73 productDO.setActivityStatus(CommonStatusEnum.ENABLE.getStatus());
85   - productDO.setActivityStartTime(seckillActivity.getStartTime());
86   - productDO.setActivityEndTime(seckillActivity.getEndTime());
  74 + list.add(productDO);
87 75 });
88 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 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 4 import cn.hutool.core.util.ObjectUtil;
5 5 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
6 6 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  7 +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
7 8 import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
8 9 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
9 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 19 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillProductDO;
19 20 import cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckillactivity.SeckillActivityMapper;
20 21 import cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckillactivity.SeckillProductMapper;
21   -import cn.iocoder.yudao.module.promotion.enums.common.PromotionActivityStatusEnum;
22 22 import cn.iocoder.yudao.module.promotion.service.seckill.seckillconfig.SeckillConfigService;
23 23 import cn.iocoder.yudao.module.promotion.util.PromotionUtils;
24 24 import org.springframework.stereotype.Service;
  25 +import org.springframework.transaction.annotation.Transactional;
25 26 import org.springframework.validation.annotation.Validated;
26 27  
27 28 import javax.annotation.Resource;
28   -import java.util.ArrayList;
29 29 import java.util.Collection;
30 30 import java.util.List;
31   -import java.util.stream.Collectors;
  31 +import java.util.Set;
32 32  
33 33 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
34 34 import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SPU_NOT_EXISTS;
35 35 import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
36 36 import static cn.iocoder.yudao.module.promotion.util.PromotionUtils.validateProductSkuExistence;
37   -import static java.util.Arrays.asList;
38 37  
39 38 /**
40 39 * 秒杀活动 Service 实现类
... ... @@ -57,17 +56,19 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
57 56 private ProductSkuApi productSkuApi;
58 57  
59 58 @Override
  59 + @Transactional(rollbackFor = Exception.class)
60 60 public Long createSeckillActivity(SeckillActivityCreateReqVO createReqVO) {
61 61 // 校验商品秒秒杀时段是否冲突
62   - validateProductSpuSeckillConflict(createReqVO.getConfigIds(), createReqVO.getSpuIds());
  62 + validateProductSpuSeckillConflict(createReqVO.getConfigIds(), createReqVO.getSpuId(), null);
63 63 // 获取所选 spu下的所有 sku
64   - List<ProductSkuRespDTO> skus = productSkuApi.getSkuListBySpuId(createReqVO.getSpuIds());
  64 + List<ProductSkuRespDTO> skus = productSkuApi.getSkuListBySpuId(CollUtil.newArrayList(createReqVO.getSpuId()));
65 65 // 校验商品 sku 是否存在
66 66 validateProductSkuExistence(skus, createReqVO.getProducts(), SeckillProductCreateReqVO::getSkuId);
67 67  
68 68 // 插入秒杀活动
69 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 72 seckillActivityMapper.insert(activity);
72 73 // 插入商品
73 74 List<SeckillProductDO> product = SeckillActivityConvert.INSTANCE.convertList(activity, createReqVO.getProducts());
... ... @@ -75,119 +76,124 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
75 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 81 seckillConfigService.validateSeckillConfigExists(configIds);
81 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 85 throw exception(SPU_NOT_EXISTS);
85 86 }
86 87 // 查询所有开启的秒杀活动
87 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 100 List<Long> configIdsClone = CollUtil.newArrayList(s.getConfigIds());
98 101 configIdsClone.retainAll(configIds);
99 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 109 @Override
  110 + @Transactional(rollbackFor = Exception.class)
107 111 public void updateSeckillActivity(SeckillActivityUpdateReqVO updateReqVO) {
108 112 // 校验存在
109 113 SeckillActivityDO seckillActivity = validateSeckillActivityExists(updateReqVO.getId());
110   - if (CommonStatusEnum.ENABLE.getStatus().equals(seckillActivity.getStatus())) {
  114 + if (CommonStatusEnum.DISABLE.getStatus().equals(seckillActivity.getStatus())) {
111 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 119 // 获取所选 spu下的所有 sku
116   - List<ProductSkuRespDTO> skus = productSkuApi.getSkuListBySpuId(updateReqVO.getSpuIds());
  120 + List<ProductSkuRespDTO> skus = productSkuApi.getSkuListBySpuId(CollUtil.newArrayList(updateReqVO.getSpuId()));
117 121 // 校验商品 sku 是否存在
118 122 validateProductSkuExistence(skus, updateReqVO.getProducts(), SeckillProductUpdateReqVO::getSkuId);
119 123  
120 124 // 更新活动
121 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 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 167 @Override
  168 + @Transactional(rollbackFor = Exception.class)
166 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 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 179 seckillActivityMapper.updateById(updateObj);
178 180 }
179 181  
180 182 @Override
  183 + @Transactional(rollbackFor = Exception.class)
181 184 public void deleteSeckillActivity(Long id) {
182 185 // 校验存在
183 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 188 throw exception(SECKILL_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END);
187 189 }
188 190  
189   - // 删除
  191 + // 删除活动
190 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 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 1 package cn.iocoder.yudao.module.promotion.service.seckill.seckillconfig;
2 2  
3 3 import cn.hutool.core.collection.CollUtil;
  4 +import cn.hutool.core.util.ObjectUtil;
4 5 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
5 6 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  7 +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
6 8 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.SeckillConfigCreateReqVO;
7 9 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.SeckillConfigPageReqVO;
8 10 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.SeckillConfigUpdateReqVO;
... ... @@ -127,10 +129,18 @@ public class SeckillConfigServiceImpl implements SeckillConfigService {
127 129 if (CollUtil.isEmpty(configIds)) {
128 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 142 throw exception(SECKILL_TIME_NOT_EXISTS);
132 143 }
133   - // TODO @puhui999:应该要校验个 status 哈;如果有禁用的,也不行
134 144 }
135 145  
136 146 @Override
... ...
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.hutool.core.util.ObjectUtil;
4 3 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
5 4 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
6 5 import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
... ... @@ -35,9 +34,6 @@ public class PromotionUtils {
35 34 // 校验 sku 个数是否一致
36 35 Set<Long> skuIdsSet = CollectionUtils.convertSet(products, func);
37 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 37 // 校验 skuId 是否存在
42 38 if (!skuIdsSet1.containsAll(skuIdsSet) || !skuIdsSet.containsAll(skuIdsSet1)) {
43 39 throw exception(SKU_NOT_EXISTS);
... ...