fix:mall promotion Combination

This commit is contained in:
puhui999 2023-07-05 11:31:16 +08:00
parent 41d996f7f3
commit 78b3d2a20f
12 changed files with 126 additions and 140 deletions

View File

@ -30,14 +30,13 @@ public interface ProductSkuApi {
*/ */
List<ProductSkuRespDTO> getSkuList(Collection<Long> ids); List<ProductSkuRespDTO> getSkuList(Collection<Long> ids);
// TODO puhui999入参用 Collection<Long> 更通用
/** /**
* 批量查询 SKU 数组 * 批量查询 SKU 数组
* *
* @param spuIds SPU 编号列表 * @param spuIds SPU 编号列表
* @return SKU 数组 * @return SKU 数组
*/ */
List<ProductSkuRespDTO> getSkuListBySpuId(List<Long> spuIds); List<ProductSkuRespDTO> getSkuListBySpuId(Collection<Long> spuIds);
/** /**
* 更新 SKU 库存 * 更新 SKU 库存

View File

@ -43,7 +43,7 @@ public class ProductSkuApiImpl implements ProductSkuApi {
} }
@Override @Override
public List<ProductSkuRespDTO> getSkuListBySpuId(List<Long> spuIds) { public List<ProductSkuRespDTO> getSkuListBySpuId(Collection<Long> spuIds) {
if (CollUtil.isEmpty(spuIds)) { if (CollUtil.isEmpty(spuIds)) {
return Collections.emptyList(); return Collections.emptyList();
} }

View File

@ -4,7 +4,7 @@ import cn.iocoder.yudao.framework.common.exception.ErrorCode;
/** /**
* Promotion 错误码枚举类 * Promotion 错误码枚举类
* * <p>
* promotion 系统使用 1-013-000-000 * promotion 系统使用 1-013-000-000
*/ */
public interface ErrorCodeConstants { public interface ErrorCodeConstants {
@ -58,6 +58,7 @@ public interface ErrorCodeConstants {
ErrorCode SECKILL_TIME_CONFLICTS = new ErrorCode(1013009001, "秒杀时段冲突"); ErrorCode SECKILL_TIME_CONFLICTS = new ErrorCode(1013009001, "秒杀时段冲突");
ErrorCode SECKILL_TIME_EQUAL = new ErrorCode(1013009002, "秒杀时段开始时间和结束时间不能相等"); ErrorCode SECKILL_TIME_EQUAL = new ErrorCode(1013009002, "秒杀时段开始时间和结束时间不能相等");
ErrorCode SECKILL_START_TIME_BEFORE_END_TIME = new ErrorCode(1013009003, "秒杀时段开始时间不能在结束时间之后"); ErrorCode SECKILL_START_TIME_BEFORE_END_TIME = new ErrorCode(1013009003, "秒杀时段开始时间不能在结束时间之后");
ErrorCode SECKILL_TIME_DISABLE = new ErrorCode(1013009004, "秒杀时段已关闭");
// ========== 拼团活动 1013010000 ========== // ========== 拼团活动 1013010000 ==========
ErrorCode COMBINATION_ACTIVITY_NOT_EXISTS = new ErrorCode(1013010000, "拼团活动不存在"); ErrorCode COMBINATION_ACTIVITY_NOT_EXISTS = new ErrorCode(1013010000, "拼团活动不存在");

View File

@ -20,10 +20,9 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_
@Data @Data
public class SeckillActivityBaseVO { public class SeckillActivityBaseVO {
// TODO @puhui999对应单 spuId
@Schema(description = "秒杀活动商品id", requiredMode = Schema.RequiredMode.REQUIRED, example = "[121,1212]") @Schema(description = "秒杀活动商品id", requiredMode = Schema.RequiredMode.REQUIRED, example = "[121,1212]")
@NotNull(message = "秒杀活动商品不能为空") @NotNull(message = "秒杀活动商品不能为空")
private List<Long> spuIds; private Long spuId;
@Schema(description = "秒杀活动名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "618大促") @Schema(description = "秒杀活动名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "618大促")
@NotNull(message = "秒杀活动名称不能为空") @NotNull(message = "秒杀活动名称不能为空")
@ -56,8 +55,4 @@ public class SeckillActivityBaseVO {
@Schema(description = "单次限够数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "31683") @Schema(description = "单次限够数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "31683")
private Integer singleLimitCount; private Integer singleLimitCount;
// TODO @puhui999这个应该是计算出来的字段只返回create update 不用哈
@Schema(description = "秒杀总库存", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
private Integer totalStock;
} }

View File

@ -23,7 +23,7 @@ public class SeckillActivityRespVO extends SeckillActivityBaseVO {
private Long id; private Long id;
@Schema(description = "秒杀商品", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "秒杀商品", requiredMode = Schema.RequiredMode.REQUIRED)
private List<SeckillProductRespVO> products; // TODO puhui: 考虑是否去除 private List<SeckillProductRespVO> products;
@Schema(description = "活动状态 开启0 禁用1", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") @Schema(description = "活动状态 开启0 禁用1", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
private Integer status; private Integer status;

View File

@ -14,11 +14,6 @@ import javax.validation.constraints.NotNull;
@Data @Data
public class SeckillProductBaseVO { public class SeckillProductBaseVO {
// TODO @puhuispuId 不用传递因为一个秒杀活动只对应一个 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") @Schema(description = "商品sku_id", requiredMode = Schema.RequiredMode.REQUIRED, example = "30563")
@NotNull(message = "商品sku_id不能为空") @NotNull(message = "商品sku_id不能为空")
private Long skuId; private Long skuId;
@ -31,5 +26,4 @@ public class SeckillProductBaseVO {
@NotNull(message = "秒杀库存不能为空") @NotNull(message = "秒杀库存不能为空")
private Integer stock; private Integer stock;
} }

View File

@ -1,8 +1,9 @@
package cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product; package cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*; import lombok.Data;
import javax.validation.constraints.*; import lombok.EqualsAndHashCode;
import lombok.ToString;
/** /**
* 管理后台 - 秒杀参与商品更新 Request VO * 管理后台 - 秒杀参与商品更新 Request VO
@ -15,8 +16,4 @@ import javax.validation.constraints.*;
@ToString(callSuper = true) @ToString(callSuper = true)
public class SeckillProductUpdateReqVO extends SeckillProductBaseVO { public class SeckillProductUpdateReqVO extends SeckillProductBaseVO {
@Schema(description = "秒杀参与商品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "256")
@NotNull(message = "秒杀参与商品编号不能为空")
private Long id;
} }

View File

@ -1,20 +1,24 @@
package cn.iocoder.yudao.module.promotion.convert.seckill.seckillactivity; 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.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.pojo.PageResult; 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.SeckillActivityCreateReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityDetailRespVO; 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.SeckillActivityRespVO;
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityUpdateReqVO; 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.SeckillActivityDO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillProductDO; import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillProductDO;
import org.mapstruct.Mapper; import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers; import org.mapstruct.factory.Mappers;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map;
/** /**
* 秒杀活动 Convert * 秒杀活动 Convert
@ -26,8 +30,6 @@ public interface SeckillActivityConvert {
SeckillActivityConvert INSTANCE = Mappers.getMapper(SeckillActivityConvert.class); SeckillActivityConvert INSTANCE = Mappers.getMapper(SeckillActivityConvert.class);
SeckillProductDO convert(SeckillProductCreateReqVO product);
SeckillActivityDO convert(SeckillActivityCreateReqVO bean); SeckillActivityDO convert(SeckillActivityCreateReqVO bean);
SeckillActivityDO convert(SeckillActivityUpdateReqVO bean); SeckillActivityDO convert(SeckillActivityUpdateReqVO bean);
@ -40,51 +42,38 @@ public interface SeckillActivityConvert {
SeckillActivityDetailRespVO convert(SeckillActivityDO seckillActivity, List<SeckillProductDO> seckillProducts); SeckillActivityDetailRespVO convert(SeckillActivityDO seckillActivity, List<SeckillProductDO> 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);
/** default List<SeckillProductDO> convertList(SeckillActivityDO activityDO, List<? extends SeckillProductBaseVO> products) {
* 比较两个秒杀商品对象是否相等
*
* @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<SeckillProductDO> convertList(SeckillActivityDO seckillActivity, List<SeckillProductCreateReqVO> products) {
List<SeckillProductDO> list = new ArrayList<>(); List<SeckillProductDO> list = new ArrayList<>();
products.forEach(sku -> { products.forEach(sku -> {
SeckillProductDO productDO = new SeckillProductDO(); SeckillProductDO productDO = convert(activityDO, sku);
productDO.setActivityId(seckillActivity.getId());
productDO.setConfigIds(seckillActivity.getConfigIds());
productDO.setSpuId(sku.getSpuId());
productDO.setSkuId(sku.getSkuId());
productDO.setSeckillPrice(sku.getSeckillPrice());
productDO.setStock(sku.getStock());
productDO.setActivityStatus(CommonStatusEnum.ENABLE.getStatus()); productDO.setActivityStatus(CommonStatusEnum.ENABLE.getStatus());
productDO.setActivityStartTime(seckillActivity.getStartTime()); list.add(productDO);
productDO.setActivityEndTime(seckillActivity.getEndTime());
}); });
return list; return list;
} }
default List<SeckillProductDO> convertList1(SeckillActivityDO activityDO, List<SeckillProductUpdateReqVO> vos, List<SeckillProductDO> productDOs) {
Map<Long, Long> longMap = CollectionUtils.convertMap(productDOs, SeckillProductDO::getSkuId, SeckillProductDO::getId);
List<SeckillProductDO> 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;
}
} }

View File

@ -34,8 +34,7 @@ public class SeckillActivityDO extends BaseDO {
/** /**
* 秒杀活动商品 * 秒杀活动商品
*/ */
@TableField(typeHandler = LongListTypeHandler.class) private Long spuId;
private List<Long> spuIds;
/** /**
* 秒杀活动名称 * 秒杀活动名称
*/ */

View File

@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.pojo.PageResult; 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.ProductSkuApi;
import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi; 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.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.SeckillActivityMapper;
import cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckillactivity.SeckillProductMapper; 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.service.seckill.seckillconfig.SeckillConfigService;
import cn.iocoder.yudao.module.promotion.util.PromotionUtils; import cn.iocoder.yudao.module.promotion.util.PromotionUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List; 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.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SPU_NOT_EXISTS; 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.enums.ErrorCodeConstants.*;
import static cn.iocoder.yudao.module.promotion.util.PromotionUtils.validateProductSkuExistence; import static cn.iocoder.yudao.module.promotion.util.PromotionUtils.validateProductSkuExistence;
import static java.util.Arrays.asList;
/** /**
* 秒杀活动 Service 实现类 * 秒杀活动 Service 实现类
@ -57,17 +56,19 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
private ProductSkuApi productSkuApi; private ProductSkuApi productSkuApi;
@Override @Override
@Transactional(rollbackFor = Exception.class)
public Long createSeckillActivity(SeckillActivityCreateReqVO createReqVO) { public Long createSeckillActivity(SeckillActivityCreateReqVO createReqVO) {
// 校验商品秒秒杀时段是否冲突 // 校验商品秒秒杀时段是否冲突
validateProductSpuSeckillConflict(createReqVO.getConfigIds(), createReqVO.getSpuIds()); validateProductSpuSeckillConflict(createReqVO.getConfigIds(), createReqVO.getSpuId(), null);
// 获取所选 spu下的所有 sku // 获取所选 spu下的所有 sku
List<ProductSkuRespDTO> skus = productSkuApi.getSkuListBySpuId(createReqVO.getSpuIds()); List<ProductSkuRespDTO> skus = productSkuApi.getSkuListBySpuId(CollUtil.newArrayList(createReqVO.getSpuId()));
// 校验商品 sku 是否存在 // 校验商品 sku 是否存在
validateProductSkuExistence(skus, createReqVO.getProducts(), SeckillProductCreateReqVO::getSkuId); validateProductSkuExistence(skus, createReqVO.getProducts(), SeckillProductCreateReqVO::getSkuId);
// 插入秒杀活动 // 插入秒杀活动
SeckillActivityDO activity = SeckillActivityConvert.INSTANCE.convert(createReqVO) 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); seckillActivityMapper.insert(activity);
// 插入商品 // 插入商品
List<SeckillProductDO> product = SeckillActivityConvert.INSTANCE.convertList(activity, createReqVO.getProducts()); List<SeckillProductDO> product = SeckillActivityConvert.INSTANCE.convertList(activity, createReqVO.getProducts());
@ -75,119 +76,124 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
return activity.getId(); return activity.getId();
} }
private void validateProductSpuSeckillConflict(List<Long> configIds, List<Long> spuIds) { private void validateProductSpuSeckillConflict(List<Long> configIds, Long spuId, Long activityId) {
// 校验秒杀时段是否存在 // 校验秒杀时段是否存在
seckillConfigService.validateSeckillConfigExists(configIds); seckillConfigService.validateSeckillConfigExists(configIds);
// 校验商品 spu 是否存在 // 校验商品 spu 是否存在
List<ProductSpuRespDTO> spuList = productSpuApi.getSpuList(spuIds); List<ProductSpuRespDTO> spuList = productSpuApi.getSpuList(CollUtil.newArrayList(spuId));
if (ObjectUtil.notEqual(spuIds.size(), spuList.size())) { if (CollUtil.isEmpty(spuList)) {
throw exception(SPU_NOT_EXISTS); throw exception(SPU_NOT_EXISTS);
} }
// 查询所有开启的秒杀活动 // 查询所有开启的秒杀活动
List<SeckillActivityDO> activityDOs = seckillActivityMapper.selectListByStatus(CommonStatusEnum.ENABLE.getStatus()); List<SeckillActivityDO> activityDOs = seckillActivityMapper.selectListByStatus(CommonStatusEnum.ENABLE.getStatus());
// 过滤出所有 spuIds 有交集的活动 if (activityId != null) {
List<SeckillActivityDO> doList = activityDOs.stream().filter(s -> { // 更新时移除本活动
// 判断 spu 是否有交集 activityDOs.removeIf(item -> ObjectUtil.equal(item.getId(), activityId));
ArrayList<Long> spuIdsClone = CollUtil.newArrayList(s.getSpuIds());
spuIdsClone.retainAll(spuIds);
if (CollUtil.isEmpty(spuIdsClone)) {
return false;
} }
// 过滤出所有 spuId 有交集的活动
List<SeckillActivityDO> activityDOs1 = CollectionUtils.convertList(activityDOs, c -> c, s -> ObjectUtil.equal(s.getSpuId(), spuId));
if (CollUtil.isNotEmpty(activityDOs1)) {
throw exception(SECKILL_ACTIVITY_SPU_CONFLICTS);
}
List<SeckillActivityDO> activityDOs2 = CollectionUtils.convertList(activityDOs, c -> c, s -> {
// 判断秒杀时段是否有交集 // 判断秒杀时段是否有交集
List<Long> configIdsClone = CollUtil.newArrayList(s.getConfigIds()); List<Long> configIdsClone = CollUtil.newArrayList(s.getConfigIds());
configIdsClone.retainAll(configIds); configIdsClone.retainAll(configIds);
return CollUtil.isNotEmpty(configIdsClone); return CollUtil.isNotEmpty(configIdsClone);
}).collect(Collectors.toList()); });
if (CollUtil.isNotEmpty(doList)) { if (CollUtil.isNotEmpty(activityDOs2)) {
throw exception(SECKILL_ACTIVITY_SPU_CONFLICTS); throw exception(SECKILL_TIME_CONFLICTS);
} }
} }
@Override @Override
@Transactional(rollbackFor = Exception.class)
public void updateSeckillActivity(SeckillActivityUpdateReqVO updateReqVO) { public void updateSeckillActivity(SeckillActivityUpdateReqVO updateReqVO) {
// 校验存在 // 校验存在
SeckillActivityDO seckillActivity = validateSeckillActivityExists(updateReqVO.getId()); 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); throw exception(SECKILL_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED);
} }
// 校验商品是否冲突 // 校验商品是否冲突
validateProductSpuSeckillConflict(updateReqVO.getConfigIds(), updateReqVO.getSpuIds()); validateProductSpuSeckillConflict(updateReqVO.getConfigIds(), updateReqVO.getSpuId(), updateReqVO.getId());
// 获取所选 spu下的所有 sku // 获取所选 spu下的所有 sku
List<ProductSkuRespDTO> skus = productSkuApi.getSkuListBySpuId(updateReqVO.getSpuIds()); List<ProductSkuRespDTO> skus = productSkuApi.getSkuListBySpuId(CollUtil.newArrayList(updateReqVO.getSpuId()));
// 校验商品 sku 是否存在 // 校验商品 sku 是否存在
validateProductSkuExistence(skus, updateReqVO.getProducts(), SeckillProductUpdateReqVO::getSkuId); validateProductSkuExistence(skus, updateReqVO.getProducts(), SeckillProductUpdateReqVO::getSkuId);
// 更新活动 // 更新活动
SeckillActivityDO updateObj = SeckillActivityConvert.INSTANCE.convert(updateReqVO) 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); 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) { private void updateSeckillProduct(SeckillActivityDO updateObj, List<SeckillProductUpdateReqVO> products) {
// TODO puhui999要不这里简单一点删除原本的插入新增的不做的这么细致 List<SeckillProductDO> seckillProductDOs = seckillProductMapper.selectListByActivityId(updateObj.getId());
// TODO puhui999后续完善 // 数据库中的活动商品
//List<SeckillProductDO> seckillProductDOs = seckillProductMapper.selectListByActivityId(updateReqVO.getId()); Set<Long> convertSet = CollectionUtils.convertSet(seckillProductDOs, SeckillProductDO::getSkuId);
//List<SeckillProductUpdateReqVO> products = updateReqVO.getProducts(); // 前端传过来的活动商品
Set<Long> convertSet1 = CollectionUtils.convertSet(products, SeckillProductUpdateReqVO::getSkuId);
////计算需要删除的数据 // 删除后台存在的前端不存在的商品
//List<Long> deleteIds = CollectionUtils.convertList(seckillProductDOs, SeckillProductDO::getId, List<Long> d = CollectionUtils.filterList(convertSet, item -> !convertSet1.contains(item));
// seckillProductDO -> products.stream() if (CollUtil.isNotEmpty(d)) {
// .noneMatch(product -> SeckillActivityConvert.INSTANCE.isEquals(seckillProductDO, product))); seckillProductMapper.deleteBatchIds(d);
//if (CollUtil.isNotEmpty(deleteIds)) { }
// seckillProductMapper.deleteBatchIds(deleteIds); // 前端存在的后端不存在的商品
//} List<Long> c = CollectionUtils.filterList(convertSet1, item -> !convertSet.contains(item));
// if (CollUtil.isNotEmpty(c)) {
//// 计算需要新增的数据 List<SeckillProductUpdateReqVO> vos = CollectionUtils.filterList(products, item -> c.contains(item.getSkuId()));
//List<SeckillProductDO> newSeckillProductDOs = CollectionUtils.convertList(products, List<SeckillProductDO> productDOs = SeckillActivityConvert.INSTANCE.convertList(updateObj, vos);
// product -> SeckillActivityConvert.INSTANCE.convert(product).setActivityId(updateReqVO.getId())); seckillProductMapper.insertBatch(productDOs);
//newSeckillProductDOs.removeIf(product -> seckillProductDOs.stream() }
// .anyMatch(seckillProduct -> SeckillActivityConvert.INSTANCE.isEquals(seckillProduct, product))); // 更新已存在的商品
//if (CollUtil.isNotEmpty(newSeckillProductDOs)) { List<Long> u = CollectionUtils.filterList(convertSet1, convertSet::contains);
// seckillProductMapper.insertBatch(newSeckillProductDOs); if (CollUtil.isNotEmpty(u)) {
//} List<SeckillProductUpdateReqVO> vos = CollectionUtils.filterList(products, item -> u.contains(item.getSkuId()));
List<SeckillProductDO> productDOs = SeckillActivityConvert.INSTANCE.convertList1(updateObj, vos, seckillProductDOs);
//全量更新当前活动商品的秒杀时段id列表timeIds seckillProductMapper.insertBatch(productDOs);
seckillProductMapper.updateTimeIdsByActivityId(updateReqVO.getId(), updateReqVO.getConfigIds()); }
} }
@Override @Override
@Transactional(rollbackFor = Exception.class)
public void closeSeckillActivity(Long id) { public void closeSeckillActivity(Long id) {
// TODO 待验证没使用过
// 校验存在 // 校验存在
SeckillActivityDO seckillActivity = this.validateSeckillActivityExists(id); SeckillActivityDO seckillActivity = validateSeckillActivityExists(id);
if (PromotionActivityStatusEnum.CLOSE.getStatus().equals(seckillActivity.getStatus())) { if (CommonStatusEnum.DISABLE.getStatus().equals(seckillActivity.getStatus())) {
throw exception(SECKILL_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED); 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); seckillActivityMapper.updateById(updateObj);
} }
@Override @Override
@Transactional(rollbackFor = Exception.class)
public void deleteSeckillActivity(Long id) { public void deleteSeckillActivity(Long id) {
// 校验存在 // 校验存在
SeckillActivityDO seckillActivity = this.validateSeckillActivityExists(id); SeckillActivityDO seckillActivity = this.validateSeckillActivityExists(id);
List<Integer> statuses = asList(PromotionActivityStatusEnum.CLOSE.getStatus(), PromotionActivityStatusEnum.END.getStatus()); if (CommonStatusEnum.ENABLE.getStatus().equals(seckillActivity.getStatus())) {
if (!statuses.contains(seckillActivity.getStatus())) {
throw exception(SECKILL_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END); throw exception(SECKILL_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END);
} }
// 删除 // 删除活动
seckillActivityMapper.deleteById(id); seckillActivityMapper.deleteById(id);
// 删除活动商品
List<SeckillProductDO> productDOs = seckillProductMapper.selectListByActivityId(id);
Set<Long> convertSet = CollectionUtils.convertSet(productDOs, SeckillProductDO::getSkuId);
seckillProductMapper.deleteBatchIds(convertSet);
} }
private SeckillActivityDO validateSeckillActivityExists(Long id) { private SeckillActivityDO validateSeckillActivityExists(Long id) {

View File

@ -1,8 +1,10 @@
package cn.iocoder.yudao.module.promotion.service.seckill.seckillconfig; package cn.iocoder.yudao.module.promotion.service.seckill.seckillconfig;
import cn.hutool.core.collection.CollUtil; 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.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.pojo.PageResult; 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.SeckillConfigCreateReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.SeckillConfigPageReqVO; import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.SeckillConfigPageReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.SeckillConfigUpdateReqVO; 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)) { if (CollUtil.isEmpty(configIds)) {
throw exception(SECKILL_TIME_NOT_EXISTS); throw exception(SECKILL_TIME_NOT_EXISTS);
} }
if (seckillConfigMapper.selectBatchIds(configIds).size() != configIds.size()) { List<SeckillConfigDO> configDOs = seckillConfigMapper.selectBatchIds(configIds);
if (CollUtil.isEmpty(configDOs)) {
throw exception(SECKILL_TIME_NOT_EXISTS);
}
// 过滤出关闭的时段
List<SeckillConfigDO> 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); throw exception(SECKILL_TIME_NOT_EXISTS);
} }
// TODO @puhui999应该要校验个 status 如果有禁用的也不行
} }
@Override @Override

View File

@ -1,6 +1,5 @@
package cn.iocoder.yudao.module.promotion.util; 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.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils; import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
@ -35,9 +34,6 @@ public class PromotionUtils {
// 校验 sku 个数是否一致 // 校验 sku 个数是否一致
Set<Long> skuIdsSet = CollectionUtils.convertSet(products, func); Set<Long> skuIdsSet = CollectionUtils.convertSet(products, func);
Set<Long> skuIdsSet1 = CollectionUtils.convertSet(skus, ProductSkuRespDTO::getId); Set<Long> skuIdsSet1 = CollectionUtils.convertSet(skus, ProductSkuRespDTO::getId);
if (ObjectUtil.notEqual(skuIdsSet.size(), skuIdsSet1.size())) {
throw exception(SKU_NOT_EXISTS);
}
// 校验 skuId 是否存在 // 校验 skuId 是否存在
if (!skuIdsSet1.containsAll(skuIdsSet) || !skuIdsSet.containsAll(skuIdsSet1)) { if (!skuIdsSet1.containsAll(skuIdsSet) || !skuIdsSet.containsAll(skuIdsSet1)) {
throw exception(SKU_NOT_EXISTS); throw exception(SKU_NOT_EXISTS);