From 78b3d2a20fc2357b0051b273ca17d7ddbfc7a723 Mon Sep 17 00:00:00 2001 From: puhui999 Date: Wed, 5 Jul 2023 11:31:16 +0800 Subject: [PATCH] =?UTF-8?q?fix=EF=BC=9Amall=20promotion=20Combination?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/product/api/sku/ProductSkuApi.java | 3 +- .../product/api/sku/ProductSkuApiImpl.java | 2 +- .../promotion/enums/ErrorCodeConstants.java | 3 +- .../vo/activity/SeckillActivityBaseVO.java | 7 +- .../vo/activity/SeckillActivityRespVO.java | 2 +- .../vo/product/SeckillProductBaseVO.java | 6 - .../vo/product/SeckillProductUpdateReqVO.java | 9 +- .../SeckillActivityConvert.java | 77 +++++----- .../seckillactivity/SeckillActivityDO.java | 3 +- .../SeckillActivityServiceImpl.java | 136 +++++++++--------- .../SeckillConfigServiceImpl.java | 14 +- .../module/promotion/util/PromotionUtils.java | 4 - 12 files changed, 126 insertions(+), 140 deletions(-) diff --git a/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/sku/ProductSkuApi.java b/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/sku/ProductSkuApi.java index 21fcf7d969..2ed262cded 100644 --- a/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/sku/ProductSkuApi.java +++ b/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 { */ List getSkuList(Collection ids); - // TODO puhui999:入参用 Collection 更通用 /** * 批量查询 SKU 数组 * * @param spuIds SPU 编号列表 * @return SKU 数组 */ - List getSkuListBySpuId(List spuIds); + List getSkuListBySpuId(Collection spuIds); /** * 更新 SKU 库存 diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/api/sku/ProductSkuApiImpl.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/api/sku/ProductSkuApiImpl.java index 4a8425f61d..bd0258efad 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/api/sku/ProductSkuApiImpl.java +++ b/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 { } @Override - public List getSkuListBySpuId(List spuIds) { + public List getSkuListBySpuId(Collection spuIds) { if (CollUtil.isEmpty(spuIds)) { return Collections.emptyList(); } diff --git a/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java index 21d464fb59..ca3f36af10 100644 --- a/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java +++ b/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; /** * Promotion 错误码枚举类 - * + *

* promotion 系统,使用 1-013-000-000 段 */ public interface ErrorCodeConstants { @@ -58,6 +58,7 @@ public interface ErrorCodeConstants { ErrorCode SECKILL_TIME_CONFLICTS = new ErrorCode(1013009001, "秒杀时段冲突"); ErrorCode SECKILL_TIME_EQUAL = new ErrorCode(1013009002, "秒杀时段开始时间和结束时间不能相等"); ErrorCode SECKILL_START_TIME_BEFORE_END_TIME = new ErrorCode(1013009003, "秒杀时段开始时间不能在结束时间之后"); + ErrorCode SECKILL_TIME_DISABLE = new ErrorCode(1013009004, "秒杀时段已关闭"); // ========== 拼团活动 1013010000 ========== ErrorCode COMBINATION_ACTIVITY_NOT_EXISTS = new ErrorCode(1013010000, "拼团活动不存在"); diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/activity/SeckillActivityBaseVO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/activity/SeckillActivityBaseVO.java index ac1126d8c9..504d4a057f 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/activity/SeckillActivityBaseVO.java +++ b/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_ @Data public class SeckillActivityBaseVO { - // TODO @puhui999:对应单 spuId 哈 @Schema(description = "秒杀活动商品id", requiredMode = Schema.RequiredMode.REQUIRED, example = "[121,1212]") @NotNull(message = "秒杀活动商品不能为空") - private List spuIds; + private Long spuId; @Schema(description = "秒杀活动名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "618大促") @NotNull(message = "秒杀活动名称不能为空") @@ -56,8 +55,4 @@ public class SeckillActivityBaseVO { @Schema(description = "单次限够数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "31683") private Integer singleLimitCount; - // TODO @puhui999:这个应该是计算出来的字段,只返回,create 和 update 不用哈 - @Schema(description = "秒杀总库存", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") - private Integer totalStock; - } diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/activity/SeckillActivityRespVO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/activity/SeckillActivityRespVO.java index 64f5c301a7..37ae289a5e 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/activity/SeckillActivityRespVO.java +++ b/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 { private Long id; @Schema(description = "秒杀商品", requiredMode = Schema.RequiredMode.REQUIRED) - private List products; // TODO puhui: 考虑是否去除 + private List products; @Schema(description = "活动状态 开启:0 禁用:1", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") private Integer status; diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/product/SeckillProductBaseVO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/product/SeckillProductBaseVO.java index 4dba74fe1a..a11d789302 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/product/SeckillProductBaseVO.java +++ b/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; @Data public class SeckillProductBaseVO { - // TODO @puhui:spuId 不用传递;因为一个秒杀活动只对应一个 SPU 哈; - @Schema(description = "商品spu_id", requiredMode = Schema.RequiredMode.REQUIRED, example = "30563") - @NotNull(message = "商品spu_id不能为空") - private Long spuId; - @Schema(description = "商品sku_id", requiredMode = Schema.RequiredMode.REQUIRED, example = "30563") @NotNull(message = "商品sku_id不能为空") private Long skuId; @@ -31,5 +26,4 @@ public class SeckillProductBaseVO { @NotNull(message = "秒杀库存不能为空") private Integer stock; - } diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/product/SeckillProductUpdateReqVO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/product/SeckillProductUpdateReqVO.java index 3f964255a6..b0b14d044a 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/product/SeckillProductUpdateReqVO.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/product/SeckillProductUpdateReqVO.java @@ -1,8 +1,9 @@ package cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product; import io.swagger.v3.oas.annotations.media.Schema; -import lombok.*; -import javax.validation.constraints.*; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; /** * 管理后台 - 秒杀参与商品更新 Request VO @@ -15,8 +16,4 @@ import javax.validation.constraints.*; @ToString(callSuper = true) public class SeckillProductUpdateReqVO extends SeckillProductBaseVO { - @Schema(description = "秒杀参与商品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "256") - @NotNull(message = "秒杀参与商品编号不能为空") - private Long id; - } diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/seckill/seckillactivity/SeckillActivityConvert.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/seckill/seckillactivity/SeckillActivityConvert.java index 7d62b4f2da..53e5b5e3d3 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/seckill/seckillactivity/SeckillActivityConvert.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/seckill/seckillactivity/SeckillActivityConvert.java @@ -1,20 +1,24 @@ package cn.iocoder.yudao.module.promotion.convert.seckill.seckillactivity; -import cn.hutool.core.util.ObjectUtil; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityCreateReqVO; import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityDetailRespVO; import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityRespVO; import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityUpdateReqVO; -import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product.SeckillProductCreateReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product.SeckillProductBaseVO; +import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product.SeckillProductUpdateReqVO; import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillActivityDO; import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillProductDO; import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.Mappings; import org.mapstruct.factory.Mappers; import java.util.ArrayList; import java.util.List; +import java.util.Map; /** * 秒杀活动 Convert @@ -26,8 +30,6 @@ public interface SeckillActivityConvert { SeckillActivityConvert INSTANCE = Mappers.getMapper(SeckillActivityConvert.class); - SeckillProductDO convert(SeckillProductCreateReqVO product); - SeckillActivityDO convert(SeckillActivityCreateReqVO bean); SeckillActivityDO convert(SeckillActivityUpdateReqVO bean); @@ -40,51 +42,38 @@ public interface SeckillActivityConvert { SeckillActivityDetailRespVO convert(SeckillActivityDO seckillActivity, List seckillProducts); + @Mappings({ + @Mapping(target = "activityId", source = "activityDO.id"), + @Mapping(target = "configIds", source = "activityDO.configIds"), + @Mapping(target = "spuId", source = "activityDO.spuId"), + @Mapping(target = "skuId", source = "vo.skuId"), + @Mapping(target = "seckillPrice", source = "vo.seckillPrice"), + @Mapping(target = "stock", source = "vo.stock"), + @Mapping(target = "activityStartTime", source = "activityDO.startTime"), + @Mapping(target = "activityEndTime", source = "activityDO.endTime") + }) + SeckillProductDO convert(SeckillActivityDO activityDO, SeckillProductBaseVO vo); - /** - * 比较两个秒杀商品对象是否相等 - * - * @param productDO 数据库中的商品 - * @param productVO 前端传入的商品 - * @return 是否匹配 - */ - default boolean isEquals(SeckillProductDO productDO, SeckillProductCreateReqVO productVO) { - return ObjectUtil.equals(productDO.getSpuId(), 1) // TODO puhui:再看看 - && ObjectUtil.equals(productDO.getSkuId(), productVO.getSkuId()) - && ObjectUtil.equals(productDO.getSeckillPrice(), productVO.getSeckillPrice()); - //&& ObjectUtil.equals(productDO.getQuota(), productVO.getQuota()) - //&& ObjectUtil.equals(productDO.getLimitCount(), productVO.getLimitCount()); - } - - /** - * 比较两个秒杀商品对象是否相等 - * - * @param productDO 商品1 - * @param productVO 商品2 - * @return 是否匹配 - */ - default boolean isEquals(SeckillProductDO productDO, SeckillProductDO productVO) { - return ObjectUtil.equals(productDO.getSpuId(), productVO.getSpuId()) - && ObjectUtil.equals(productDO.getSkuId(), productVO.getSkuId()) - && ObjectUtil.equals(productDO.getSeckillPrice(), productVO.getSeckillPrice()); - //&& ObjectUtil.equals(productDO.getQuota(), productVO.getQuota()) - //&& ObjectUtil.equals(productDO.getLimitCount(), productVO.getLimitCount()); - } - - default List convertList(SeckillActivityDO seckillActivity, List products) { + default List convertList(SeckillActivityDO activityDO, List products) { List list = new ArrayList<>(); products.forEach(sku -> { - SeckillProductDO productDO = new SeckillProductDO(); - productDO.setActivityId(seckillActivity.getId()); - productDO.setConfigIds(seckillActivity.getConfigIds()); - productDO.setSpuId(sku.getSpuId()); - productDO.setSkuId(sku.getSkuId()); - productDO.setSeckillPrice(sku.getSeckillPrice()); - productDO.setStock(sku.getStock()); + SeckillProductDO productDO = convert(activityDO, sku); productDO.setActivityStatus(CommonStatusEnum.ENABLE.getStatus()); - productDO.setActivityStartTime(seckillActivity.getStartTime()); - productDO.setActivityEndTime(seckillActivity.getEndTime()); + list.add(productDO); }); return list; } + + default List convertList1(SeckillActivityDO activityDO, List vos, List productDOs) { + Map longMap = CollectionUtils.convertMap(productDOs, SeckillProductDO::getSkuId, SeckillProductDO::getId); + List list = new ArrayList<>(); + vos.forEach(sku -> { + SeckillProductDO productDO = convert(activityDO, sku); + productDO.setId(longMap.get(sku.getSkuId())); + productDO.setActivityStatus(CommonStatusEnum.ENABLE.getStatus()); + list.add(productDO); + }); + return list; + } + } diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/seckill/seckillactivity/SeckillActivityDO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/seckill/seckillactivity/SeckillActivityDO.java index be6663592c..a8c7eb265f 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/seckill/seckillactivity/SeckillActivityDO.java +++ b/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 { /** * 秒杀活动商品 */ - @TableField(typeHandler = LongListTypeHandler.class) - private List spuIds; + private Long spuId; /** * 秒杀活动名称 */ diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/seckillactivity/SeckillActivityServiceImpl.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/seckillactivity/SeckillActivityServiceImpl.java index 9c9e559b29..ffc68c4bc8 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/seckillactivity/SeckillActivityServiceImpl.java +++ b/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; import cn.hutool.core.util.ObjectUtil; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi; @@ -18,23 +19,21 @@ import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity. import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillProductDO; import cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckillactivity.SeckillActivityMapper; import cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckillactivity.SeckillProductMapper; -import cn.iocoder.yudao.module.promotion.enums.common.PromotionActivityStatusEnum; import cn.iocoder.yudao.module.promotion.service.seckill.seckillconfig.SeckillConfigService; import cn.iocoder.yudao.module.promotion.util.PromotionUtils; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; -import java.util.ArrayList; import java.util.Collection; import java.util.List; -import java.util.stream.Collectors; +import java.util.Set; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SPU_NOT_EXISTS; import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*; import static cn.iocoder.yudao.module.promotion.util.PromotionUtils.validateProductSkuExistence; -import static java.util.Arrays.asList; /** * 秒杀活动 Service 实现类 @@ -57,17 +56,19 @@ public class SeckillActivityServiceImpl implements SeckillActivityService { private ProductSkuApi productSkuApi; @Override + @Transactional(rollbackFor = Exception.class) public Long createSeckillActivity(SeckillActivityCreateReqVO createReqVO) { // 校验商品秒秒杀时段是否冲突 - validateProductSpuSeckillConflict(createReqVO.getConfigIds(), createReqVO.getSpuIds()); + validateProductSpuSeckillConflict(createReqVO.getConfigIds(), createReqVO.getSpuId(), null); // 获取所选 spu下的所有 sku - List skus = productSkuApi.getSkuListBySpuId(createReqVO.getSpuIds()); + List skus = productSkuApi.getSkuListBySpuId(CollUtil.newArrayList(createReqVO.getSpuId())); // 校验商品 sku 是否存在 validateProductSkuExistence(skus, createReqVO.getProducts(), SeckillProductCreateReqVO::getSkuId); // 插入秒杀活动 SeckillActivityDO activity = SeckillActivityConvert.INSTANCE.convert(createReqVO) - .setStatus(PromotionUtils.calculateActivityStatus(createReqVO.getEndTime())); + .setStatus(PromotionUtils.calculateActivityStatus(createReqVO.getEndTime())) + .setTotalStock(CollectionUtils.getSumValue(createReqVO.getProducts(), SeckillProductCreateReqVO::getStock, Integer::sum)); seckillActivityMapper.insert(activity); // 插入商品 List product = SeckillActivityConvert.INSTANCE.convertList(activity, createReqVO.getProducts()); @@ -75,119 +76,124 @@ public class SeckillActivityServiceImpl implements SeckillActivityService { return activity.getId(); } - private void validateProductSpuSeckillConflict(List configIds, List spuIds) { + private void validateProductSpuSeckillConflict(List configIds, Long spuId, Long activityId) { // 校验秒杀时段是否存在 seckillConfigService.validateSeckillConfigExists(configIds); // 校验商品 spu 是否存在 - List spuList = productSpuApi.getSpuList(spuIds); - if (ObjectUtil.notEqual(spuIds.size(), spuList.size())) { + List spuList = productSpuApi.getSpuList(CollUtil.newArrayList(spuId)); + if (CollUtil.isEmpty(spuList)) { throw exception(SPU_NOT_EXISTS); } // 查询所有开启的秒杀活动 List activityDOs = seckillActivityMapper.selectListByStatus(CommonStatusEnum.ENABLE.getStatus()); - // 过滤出所有 spuIds 有交集的活动 - List doList = activityDOs.stream().filter(s -> { - // 判断 spu 是否有交集 - ArrayList spuIdsClone = CollUtil.newArrayList(s.getSpuIds()); - spuIdsClone.retainAll(spuIds); - if (CollUtil.isEmpty(spuIdsClone)) { - return false; - } + if (activityId != null) { + // 更新时移除本活动 + activityDOs.removeIf(item -> ObjectUtil.equal(item.getId(), activityId)); + } + // 过滤出所有 spuId 有交集的活动 + List activityDOs1 = CollectionUtils.convertList(activityDOs, c -> c, s -> ObjectUtil.equal(s.getSpuId(), spuId)); + if (CollUtil.isNotEmpty(activityDOs1)) { + throw exception(SECKILL_ACTIVITY_SPU_CONFLICTS); + } + List activityDOs2 = CollectionUtils.convertList(activityDOs, c -> c, s -> { // 判断秒杀时段是否有交集 List configIdsClone = CollUtil.newArrayList(s.getConfigIds()); configIdsClone.retainAll(configIds); return CollUtil.isNotEmpty(configIdsClone); - }).collect(Collectors.toList()); - if (CollUtil.isNotEmpty(doList)) { - throw exception(SECKILL_ACTIVITY_SPU_CONFLICTS); + }); + if (CollUtil.isNotEmpty(activityDOs2)) { + throw exception(SECKILL_TIME_CONFLICTS); } } @Override + @Transactional(rollbackFor = Exception.class) public void updateSeckillActivity(SeckillActivityUpdateReqVO updateReqVO) { // 校验存在 SeckillActivityDO seckillActivity = validateSeckillActivityExists(updateReqVO.getId()); - if (CommonStatusEnum.ENABLE.getStatus().equals(seckillActivity.getStatus())) { + if (CommonStatusEnum.DISABLE.getStatus().equals(seckillActivity.getStatus())) { throw exception(SECKILL_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED); } // 校验商品是否冲突 - validateProductSpuSeckillConflict(updateReqVO.getConfigIds(), updateReqVO.getSpuIds()); + validateProductSpuSeckillConflict(updateReqVO.getConfigIds(), updateReqVO.getSpuId(), updateReqVO.getId()); // 获取所选 spu下的所有 sku - List skus = productSkuApi.getSkuListBySpuId(updateReqVO.getSpuIds()); + List skus = productSkuApi.getSkuListBySpuId(CollUtil.newArrayList(updateReqVO.getSpuId())); // 校验商品 sku 是否存在 validateProductSkuExistence(skus, updateReqVO.getProducts(), SeckillProductUpdateReqVO::getSkuId); // 更新活动 SeckillActivityDO updateObj = SeckillActivityConvert.INSTANCE.convert(updateReqVO) - .setStatus(PromotionUtils.calculateActivityStatus(updateReqVO.getEndTime())); + .setStatus(PromotionUtils.calculateActivityStatus(updateReqVO.getEndTime())) + .setTotalStock(CollectionUtils.getSumValue(updateReqVO.getProducts(), SeckillProductUpdateReqVO::getStock, Integer::sum)); seckillActivityMapper.updateById(updateObj); // 更新商品 - //updateSeckillProduct(updateReqVO); + updateSeckillProduct(updateObj, updateReqVO.getProducts()); } /** * 更新秒杀商品 - * 后台查出的数据和前台查出的数据进行遍历, - * 1. 对前台数据进行遍历:如果不存在于后台的 sku 中需要新增 - * 2. 对后台数据进行遍历:如果不存在于前台的 sku 中需要删除 - * 3. 最后对当前活动商品全部更新,更新秒杀时段id列表 * - * @param updateReqVO 更新的请求VO + * @param updateObj DO + * @param products 商品配置 */ - private void updateSeckillProduct(SeckillActivityUpdateReqVO updateReqVO) { - // TODO puhui999:要不这里简单一点;删除原本的,插入新增的;不做的这么细致 - // TODO puhui999:后续完善 - //List seckillProductDOs = seckillProductMapper.selectListByActivityId(updateReqVO.getId()); - //List products = updateReqVO.getProducts(); - - ////计算需要删除的数据 - //List deleteIds = CollectionUtils.convertList(seckillProductDOs, SeckillProductDO::getId, - // seckillProductDO -> products.stream() - // .noneMatch(product -> SeckillActivityConvert.INSTANCE.isEquals(seckillProductDO, product))); - //if (CollUtil.isNotEmpty(deleteIds)) { - // seckillProductMapper.deleteBatchIds(deleteIds); - //} - // - //// 计算需要新增的数据 - //List newSeckillProductDOs = CollectionUtils.convertList(products, - // product -> SeckillActivityConvert.INSTANCE.convert(product).setActivityId(updateReqVO.getId())); - //newSeckillProductDOs.removeIf(product -> seckillProductDOs.stream() - // .anyMatch(seckillProduct -> SeckillActivityConvert.INSTANCE.isEquals(seckillProduct, product))); - //if (CollUtil.isNotEmpty(newSeckillProductDOs)) { - // seckillProductMapper.insertBatch(newSeckillProductDOs); - //} - - //全量更新当前活动商品的秒杀时段id列表(timeIds) - seckillProductMapper.updateTimeIdsByActivityId(updateReqVO.getId(), updateReqVO.getConfigIds()); + private void updateSeckillProduct(SeckillActivityDO updateObj, List products) { + List seckillProductDOs = seckillProductMapper.selectListByActivityId(updateObj.getId()); + // 数据库中的活动商品 + Set convertSet = CollectionUtils.convertSet(seckillProductDOs, SeckillProductDO::getSkuId); + // 前端传过来的活动商品 + Set convertSet1 = CollectionUtils.convertSet(products, SeckillProductUpdateReqVO::getSkuId); + // 删除后台存在的前端不存在的商品 + List d = CollectionUtils.filterList(convertSet, item -> !convertSet1.contains(item)); + if (CollUtil.isNotEmpty(d)) { + seckillProductMapper.deleteBatchIds(d); + } + // 前端存在的后端不存在的商品 + List c = CollectionUtils.filterList(convertSet1, item -> !convertSet.contains(item)); + if (CollUtil.isNotEmpty(c)) { + List vos = CollectionUtils.filterList(products, item -> c.contains(item.getSkuId())); + List productDOs = SeckillActivityConvert.INSTANCE.convertList(updateObj, vos); + seckillProductMapper.insertBatch(productDOs); + } + // 更新已存在的商品 + List u = CollectionUtils.filterList(convertSet1, convertSet::contains); + if (CollUtil.isNotEmpty(u)) { + List vos = CollectionUtils.filterList(products, item -> u.contains(item.getSkuId())); + List productDOs = SeckillActivityConvert.INSTANCE.convertList1(updateObj, vos, seckillProductDOs); + seckillProductMapper.insertBatch(productDOs); + } } @Override + @Transactional(rollbackFor = Exception.class) public void closeSeckillActivity(Long id) { + // TODO 待验证没使用过 // 校验存在 - SeckillActivityDO seckillActivity = this.validateSeckillActivityExists(id); - if (PromotionActivityStatusEnum.CLOSE.getStatus().equals(seckillActivity.getStatus())) { + SeckillActivityDO seckillActivity = validateSeckillActivityExists(id); + if (CommonStatusEnum.DISABLE.getStatus().equals(seckillActivity.getStatus())) { throw exception(SECKILL_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED); } - if (PromotionActivityStatusEnum.END.getStatus().equals(seckillActivity.getStatus())) { - throw exception(SECKILL_ACTIVITY_CLOSE_FAIL_STATUS_END); - } + // 更新 - SeckillActivityDO updateObj = new SeckillActivityDO().setId(id).setStatus(PromotionActivityStatusEnum.CLOSE.getStatus()); + SeckillActivityDO updateObj = new SeckillActivityDO().setId(id).setStatus(CommonStatusEnum.DISABLE.getStatus()); seckillActivityMapper.updateById(updateObj); } @Override + @Transactional(rollbackFor = Exception.class) public void deleteSeckillActivity(Long id) { // 校验存在 SeckillActivityDO seckillActivity = this.validateSeckillActivityExists(id); - List statuses = asList(PromotionActivityStatusEnum.CLOSE.getStatus(), PromotionActivityStatusEnum.END.getStatus()); - if (!statuses.contains(seckillActivity.getStatus())) { + if (CommonStatusEnum.ENABLE.getStatus().equals(seckillActivity.getStatus())) { throw exception(SECKILL_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END); } - // 删除 + // 删除活动 seckillActivityMapper.deleteById(id); + // 删除活动商品 + List productDOs = seckillProductMapper.selectListByActivityId(id); + Set convertSet = CollectionUtils.convertSet(productDOs, SeckillProductDO::getSkuId); + seckillProductMapper.deleteBatchIds(convertSet); } private SeckillActivityDO validateSeckillActivityExists(Long id) { diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/seckillconfig/SeckillConfigServiceImpl.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/seckillconfig/SeckillConfigServiceImpl.java index 599973d5b0..d233a2d389 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/seckillconfig/SeckillConfigServiceImpl.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/seckillconfig/SeckillConfigServiceImpl.java @@ -1,8 +1,10 @@ package cn.iocoder.yudao.module.promotion.service.seckill.seckillconfig; import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.SeckillConfigCreateReqVO; import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.SeckillConfigPageReqVO; import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.SeckillConfigUpdateReqVO; @@ -127,10 +129,18 @@ public class SeckillConfigServiceImpl implements SeckillConfigService { if (CollUtil.isEmpty(configIds)) { throw exception(SECKILL_TIME_NOT_EXISTS); } - if (seckillConfigMapper.selectBatchIds(configIds).size() != configIds.size()) { + List configDOs = seckillConfigMapper.selectBatchIds(configIds); + if (CollUtil.isEmpty(configDOs)) { + throw exception(SECKILL_TIME_NOT_EXISTS); + } + // 过滤出关闭的时段 + List filterList = CollectionUtils.filterList(configDOs, item -> ObjectUtil.equal(item.getStatus(), CommonStatusEnum.DISABLE.getStatus())); + if (CollUtil.isNotEmpty(filterList)) { + throw exception(SECKILL_TIME_DISABLE); + } + if (configDOs.size() != configIds.size()) { throw exception(SECKILL_TIME_NOT_EXISTS); } - // TODO @puhui999:应该要校验个 status 哈;如果有禁用的,也不行 } @Override diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/util/PromotionUtils.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/util/PromotionUtils.java index d21d6abf30..96da508412 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/util/PromotionUtils.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/util/PromotionUtils.java @@ -1,6 +1,5 @@ package cn.iocoder.yudao.module.promotion.util; -import cn.hutool.core.util.ObjectUtil; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils; @@ -35,9 +34,6 @@ public class PromotionUtils { // 校验 sku 个数是否一致 Set skuIdsSet = CollectionUtils.convertSet(products, func); Set skuIdsSet1 = CollectionUtils.convertSet(skus, ProductSkuRespDTO::getId); - if (ObjectUtil.notEqual(skuIdsSet.size(), skuIdsSet1.size())) { - throw exception(SKU_NOT_EXISTS); - } // 校验 skuId 是否存在 if (!skuIdsSet1.containsAll(skuIdsSet) || !skuIdsSet.containsAll(skuIdsSet1)) { throw exception(SKU_NOT_EXISTS);