Commit 6f740fab7cad2140b9bd15e65069dd8a8ba492b1

Authored by YunaiV
1 parent 20775791

【代码优化】商城:完善满减送的计算逻辑

yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/category/ProductCategoryServiceImpl.java
@@ -113,14 +113,16 @@ public class ProductCategoryServiceImpl implements ProductCategoryService { @@ -113,14 +113,16 @@ public class ProductCategoryServiceImpl implements ProductCategoryService {
113 Map<Long, ProductCategoryDO> categoryMap = CollectionUtils.convertMap(list, ProductCategoryDO::getId); 113 Map<Long, ProductCategoryDO> categoryMap = CollectionUtils.convertMap(list, ProductCategoryDO::getId);
114 // 校验 114 // 校验
115 ids.forEach(id -> { 115 ids.forEach(id -> {
  116 + // 校验分类是否存在
116 ProductCategoryDO category = categoryMap.get(id); 117 ProductCategoryDO category = categoryMap.get(id);
117 if (category == null) { 118 if (category == null) {
118 throw exception(CATEGORY_NOT_EXISTS); 119 throw exception(CATEGORY_NOT_EXISTS);
119 } 120 }
  121 + // 校验分类是否启用
120 if (!CommonStatusEnum.ENABLE.getStatus().equals(category.getStatus())) { 122 if (!CommonStatusEnum.ENABLE.getStatus().equals(category.getStatus())) {
121 throw exception(CATEGORY_DISABLED, category.getName()); 123 throw exception(CATEGORY_DISABLED, category.getName());
122 } 124 }
123 - // 校验层级 125 + // 商品分类层级校验,必须使用第二级的商品分类
124 if (getCategoryLevel(id) < CATEGORY_LEVEL) { 126 if (getCategoryLevel(id) < CATEGORY_LEVEL) {
125 throw exception(SPU_SAVE_FAIL_CATEGORY_LEVEL_ERROR); 127 throw exception(SPU_SAVE_FAIL_CATEGORY_LEVEL_ERROR);
126 } 128 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/discount/DiscountActivityConvert.java
1 package cn.iocoder.yudao.module.promotion.convert.discount; 1 package cn.iocoder.yudao.module.promotion.convert.discount;
2 2
3 -import cn.hutool.core.util.ObjectUtil;  
4 import cn.iocoder.yudao.framework.common.pojo.PageResult; 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;  
6 -import cn.iocoder.yudao.framework.common.util.collection.MapUtils;  
7 -import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;  
8 -import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.*; 4 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  5 +import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityBaseVO;
  6 +import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityCreateReqVO;
  7 +import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityRespVO;
  8 +import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityUpdateReqVO;
9 import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountActivityDO; 9 import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountActivityDO;
10 import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO; 10 import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO;
11 -import cn.iocoder.yudao.module.promotion.enums.common.PromotionDiscountTypeEnum;  
12 import org.mapstruct.Mapper; 11 import org.mapstruct.Mapper;
13 import org.mapstruct.factory.Mappers; 12 import org.mapstruct.factory.Mappers;
14 13
15 import java.util.List; 14 import java.util.List;
16 -import java.util.Map;  
17 15
18 /** 16 /**
19 * 限时折扣活动 Convert 17 * 限时折扣活动 Convert
@@ -32,105 +30,22 @@ public interface DiscountActivityConvert { @@ -32,105 +30,22 @@ public interface DiscountActivityConvert {
32 DiscountActivityRespVO convert(DiscountActivityDO bean); 30 DiscountActivityRespVO convert(DiscountActivityDO bean);
33 31
34 List<DiscountActivityRespVO> convertList(List<DiscountActivityDO> list); 32 List<DiscountActivityRespVO> convertList(List<DiscountActivityDO> list);
  33 +
35 List<DiscountActivityBaseVO.Product> convertList2(List<DiscountProductDO> list); 34 List<DiscountActivityBaseVO.Product> convertList2(List<DiscountProductDO> list);
  35 +
36 PageResult<DiscountActivityRespVO> convertPage(PageResult<DiscountActivityDO> page); 36 PageResult<DiscountActivityRespVO> convertPage(PageResult<DiscountActivityDO> page);
37 37
38 default PageResult<DiscountActivityRespVO> convertPage(PageResult<DiscountActivityDO> page, 38 default PageResult<DiscountActivityRespVO> convertPage(PageResult<DiscountActivityDO> page,
39 - List<DiscountProductDO> discountProductDOList,  
40 - List<ProductSpuRespDTO> spuList) { 39 + List<DiscountProductDO> discountProductDOList) {
41 PageResult<DiscountActivityRespVO> pageResult = convertPage(page); 40 PageResult<DiscountActivityRespVO> pageResult = convertPage(page);
42 -  
43 - // 拼接商品 TODO @zhangshuai:类似空行的问题,也可以看看  
44 - Map<Long, DiscountProductDO> discountActivityMap = CollectionUtils.convertMap(discountProductDOList, DiscountProductDO::getActivityId);  
45 - Map<Long, ProductSpuRespDTO> spuMap = CollectionUtils.convertMap(spuList, ProductSpuRespDTO::getId);  
46 - pageResult.getList().forEach(item -> {  
47 - item.setProducts(convertList2(discountProductDOList));  
48 - item.setSpuId(discountActivityMap.get(item.getId())==null?null: discountActivityMap.get(item.getId()).getSpuId());  
49 - if (item.getSpuId() != null) {  
50 - MapUtils.findAndThen(spuMap, item.getSpuId(),  
51 - spu -> item.setSpuName(spu.getName()).setPicUrl(spu.getPicUrl()).setMarketPrice(spu.getMarketPrice()));  
52 - }  
53 -  
54 - }); 41 + pageResult.getList().forEach(item -> item.setProducts(convertList2(discountProductDOList)));
55 return pageResult; 42 return pageResult;
56 } 43 }
57 44
58 DiscountProductDO convert(DiscountActivityBaseVO.Product bean); 45 DiscountProductDO convert(DiscountActivityBaseVO.Product bean);
59 46
60 - default DiscountActivityDetailRespVO convert(DiscountActivityDO activity, List<DiscountProductDO> products){  
61 - if ( activity == null && products == null ) {  
62 - return null;  
63 - }  
64 -  
65 - DiscountActivityDetailRespVO discountActivityDetailRespVO = new DiscountActivityDetailRespVO();  
66 -  
67 - if ( activity != null ) {  
68 - discountActivityDetailRespVO.setName( activity.getName() );  
69 - discountActivityDetailRespVO.setStartTime( activity.getStartTime() );  
70 - discountActivityDetailRespVO.setEndTime( activity.getEndTime() );  
71 - discountActivityDetailRespVO.setRemark( activity.getRemark() );  
72 - discountActivityDetailRespVO.setId( activity.getId() );  
73 - discountActivityDetailRespVO.setStatus( activity.getStatus() );  
74 - discountActivityDetailRespVO.setCreateTime( activity.getCreateTime() );  
75 - }  
76 - if (!products.isEmpty()) {  
77 - discountActivityDetailRespVO.setSpuId(products.get(0).getSpuId());  
78 - }  
79 - discountActivityDetailRespVO.setProducts( convertList2( products ) );  
80 -  
81 - return discountActivityDetailRespVO;  
82 - }  
83 -  
84 - // =========== 比较是否相等 ==========  
85 - /**  
86 - * 比较两个限时折扣商品是否相等  
87 - *  
88 - * @param productDO 数据库中的商品  
89 - * @param productVO 前端传入的商品  
90 - * @return 是否匹配  
91 - */  
92 - @SuppressWarnings("DuplicatedCode")  
93 - default boolean isEquals(DiscountProductDO productDO, DiscountActivityBaseVO.Product productVO) {  
94 - if (ObjectUtil.notEqual(productDO.getSpuId(), productVO.getSpuId())  
95 - || ObjectUtil.notEqual(productDO.getSkuId(), productVO.getSkuId())  
96 - || ObjectUtil.notEqual(productDO.getDiscountType(), productVO.getDiscountType())) {  
97 - return false;  
98 - }  
99 - if (productDO.getDiscountType().equals(PromotionDiscountTypeEnum.PRICE.getType())) {  
100 - return ObjectUtil.equal(productDO.getDiscountPrice(), productVO.getDiscountPrice());  
101 - }  
102 - if (productDO.getDiscountType().equals(PromotionDiscountTypeEnum.PERCENT.getType())) {  
103 - return ObjectUtil.equal(productDO.getDiscountPercent(), productVO.getDiscountPercent());  
104 - }  
105 - return true; 47 + default DiscountActivityRespVO convert(DiscountActivityDO activity, List<DiscountProductDO> products) {
  48 + return BeanUtils.toBean(activity, DiscountActivityRespVO.class).setProducts(convertList2(products));
106 } 49 }
107 50
108 - /**  
109 - * 比较两个限时折扣商品是否相等  
110 - * 注意,比较时忽略 id 编号  
111 - *  
112 - * @param productDO 商品 1  
113 - * @param productVO 商品 2  
114 - * @return 是否匹配  
115 - */  
116 - @SuppressWarnings("DuplicatedCode")  
117 - default boolean isEquals(DiscountProductDO productDO, DiscountProductDO productVO) {  
118 - if (ObjectUtil.notEqual(productDO.getSpuId(), productVO.getSpuId())  
119 - || ObjectUtil.notEqual(productDO.getSkuId(), productVO.getSkuId())  
120 - || ObjectUtil.notEqual(productDO.getDiscountType(), productVO.getDiscountType())  
121 - || ObjectUtil.notEqual(productDO.getActivityEndTime(), productVO.getActivityEndTime())  
122 - || ObjectUtil.notEqual(productDO.getActivityStartTime(), productVO.getActivityStartTime())  
123 - || ObjectUtil.notEqual(productDO.getActivityStatus(), productVO.getActivityStatus())) {  
124 - return false;  
125 - }  
126 - if (productDO.getDiscountType().equals(PromotionDiscountTypeEnum.PRICE.getType())) {  
127 - return ObjectUtil.equal(productDO.getDiscountPrice(), productVO.getDiscountPrice());  
128 - }  
129 - if (productDO.getDiscountType().equals(PromotionDiscountTypeEnum.PERCENT.getType())) {  
130 - return ObjectUtil.equal(productDO.getDiscountPercent(), productVO.getDiscountPercent());  
131 - }  
132 - return true;  
133 - }  
134 -  
135 -  
136 -} 51 +}
137 \ No newline at end of file 52 \ No newline at end of file
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/discount/DiscountProductMapper.java
@@ -3,13 +3,12 @@ package cn.iocoder.yudao.module.promotion.dal.mysql.discount; @@ -3,13 +3,12 @@ package cn.iocoder.yudao.module.promotion.dal.mysql.discount;
3 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; 3 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
4 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; 4 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
5 import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO; 5 import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO;
6 -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; 6 +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
7 import org.apache.ibatis.annotations.Mapper; 7 import org.apache.ibatis.annotations.Mapper;
8 8
9 import java.time.LocalDateTime; 9 import java.time.LocalDateTime;
10 import java.util.Collection; 10 import java.util.Collection;
11 import java.util.List; 11 import java.util.List;
12 -import java.util.Map;  
13 12
14 /** 13 /**
15 * 限时折扣商城 Mapper 14 * 限时折扣商城 Mapper
@@ -23,8 +22,23 @@ public interface DiscountProductMapper extends BaseMapperX&lt;DiscountProductDO&gt; { @@ -23,8 +22,23 @@ public interface DiscountProductMapper extends BaseMapperX&lt;DiscountProductDO&gt; {
23 return selectList(DiscountProductDO::getActivityId, activityId); 22 return selectList(DiscountProductDO::getActivityId, activityId);
24 } 23 }
25 24
26 - default List<DiscountProductDO> selectListBySkuIds(Collection<Long> skuIds) {  
27 - return selectList(DiscountProductDO::getSkuId, skuIds); 25 + default List<DiscountProductDO> selectListByActivityId(Collection<Long> activityIds) {
  26 + return selectList(DiscountProductDO::getActivityId, activityIds);
  27 + }
  28 +
  29 + default List<DiscountProductDO> selectListBySpuIdsAndStatus(Collection<Long> spuIds, Integer status) {
  30 + return selectList(new LambdaQueryWrapperX<DiscountProductDO>()
  31 + .in(DiscountProductDO::getSpuId, spuIds)
  32 + .eq(DiscountProductDO::getActivityStatus, status));
  33 + }
  34 +
  35 + default void updateByActivityId(DiscountProductDO discountProductDO) {
  36 + update(discountProductDO, new LambdaUpdateWrapper<DiscountProductDO>()
  37 + .eq(DiscountProductDO::getActivityId, discountProductDO.getActivityId()));
  38 + }
  39 +
  40 + default void deleteByActivityId(Long activityId) {
  41 + delete(DiscountProductDO::getActivityId, activityId);
28 } 42 }
29 43
30 default List<DiscountProductDO> selectListBySkuIdsAndStatusAndNow(Collection<Long> skuIds, Integer status) { 44 default List<DiscountProductDO> selectListBySkuIdsAndStatusAndNow(Collection<Long> skuIds, Integer status) {
@@ -36,19 +50,4 @@ public interface DiscountProductMapper extends BaseMapperX&lt;DiscountProductDO&gt; { @@ -36,19 +50,4 @@ public interface DiscountProductMapper extends BaseMapperX&lt;DiscountProductDO&gt; {
36 .gt(DiscountProductDO::getActivityEndTime, now)); 50 .gt(DiscountProductDO::getActivityEndTime, now));
37 } 51 }
38 52
39 - /**  
40 - * 查询出指定 spuId 的 spu 参加的活动最接近现在的一条记录。多个的话,一个 spuId 对应一个最近的活动编号  
41 - *  
42 - * @param spuIds spu 编号  
43 - * @param status 状态  
44 - * @return 包含 spuId 和 activityId 的 map 对象列表  
45 - */  
46 - default List<Map<String, Object>> selectSpuIdAndActivityIdMapsBySpuIdsAndStatus(Collection<Long> spuIds, Integer status) {  
47 - return selectMaps(new QueryWrapper<DiscountProductDO>()  
48 - .select("spu_id AS spuId, MAX(DISTINCT(activity_id)) AS activityId")  
49 - .in("spu_id", spuIds)  
50 - .eq("activity_status", status)  
51 - .groupBy("spu_id"));  
52 - }  
53 -  
54 } 53 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/discount/DiscountActivityService.java
@@ -89,12 +89,4 @@ public interface DiscountActivityService { @@ -89,12 +89,4 @@ public interface DiscountActivityService {
89 */ 89 */
90 List<DiscountProductDO> getDiscountProductsByActivityId(Collection<Long> activityIds); 90 List<DiscountProductDO> getDiscountProductsByActivityId(Collection<Long> activityIds);
91 91
92 - /**  
93 - * 获取指定 SPU 编号最近参加的活动,每个 spuId 只返回一条记录  
94 - *  
95 - * @param spuIds SPU 编号数组  
96 - * @return 折扣活动列表  
97 - */  
98 - List<DiscountActivityDO> getDiscountActivityListBySpuIds(Collection<Long> spuIds);  
99 -  
100 } 92 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/discount/DiscountActivityServiceImpl.java
1 package cn.iocoder.yudao.module.promotion.service.discount; 1 package cn.iocoder.yudao.module.promotion.service.discount;
2 2
3 import cn.hutool.core.collection.CollUtil; 3 import cn.hutool.core.collection.CollUtil;
4 -import cn.hutool.core.collection.CollectionUtil;  
5 -import cn.hutool.core.map.MapUtil; 4 +import cn.hutool.core.util.ObjectUtil;
6 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; 5 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
7 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;
8 import cn.iocoder.yudao.framework.common.util.object.BeanUtils; 8 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  9 +import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
  10 +import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
9 import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityBaseVO; 11 import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityBaseVO;
10 import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityCreateReqVO; 12 import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityCreateReqVO;
11 import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityPageReqVO; 13 import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityPageReqVO;
@@ -20,15 +22,15 @@ import org.springframework.stereotype.Service; @@ -20,15 +22,15 @@ import org.springframework.stereotype.Service;
20 import org.springframework.transaction.annotation.Transactional; 22 import org.springframework.transaction.annotation.Transactional;
21 import org.springframework.validation.annotation.Validated; 23 import org.springframework.validation.annotation.Validated;
22 24
23 -import java.time.LocalDateTime;  
24 import java.util.Collection; 25 import java.util.Collection;
25 -import java.util.Collections;  
26 import java.util.List; 26 import java.util.List;
27 import java.util.Map; 27 import java.util.Map;
28 28
  29 +import static cn.hutool.core.collection.CollUtil.intersectionDistinct;
29 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 30 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
30 -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;  
31 -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; 31 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
  32 +import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen;
  33 +import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_NOT_EXISTS;
32 import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*; 34 import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
33 35
34 /** 36 /**
@@ -45,16 +47,16 @@ public class DiscountActivityServiceImpl implements DiscountActivityService { @@ -45,16 +47,16 @@ public class DiscountActivityServiceImpl implements DiscountActivityService {
45 @Resource 47 @Resource
46 private DiscountProductMapper discountProductMapper; 48 private DiscountProductMapper discountProductMapper;
47 49
48 - @Override  
49 - public List<DiscountProductDO> getMatchDiscountProductListBySkuIds(Collection<Long> skuIds) {  
50 - return discountProductMapper.selectListBySkuIdsAndStatusAndNow(skuIds, CommonStatusEnum.ENABLE.getStatus());  
51 - } 50 + @Resource
  51 + private ProductSkuApi productSkuApi;
52 52
53 @Override 53 @Override
54 @Transactional(rollbackFor = Exception.class) 54 @Transactional(rollbackFor = Exception.class)
55 public Long createDiscountActivity(DiscountActivityCreateReqVO createReqVO) { 55 public Long createDiscountActivity(DiscountActivityCreateReqVO createReqVO) {
56 // 校验商品是否冲突 56 // 校验商品是否冲突
57 validateDiscountActivityProductConflicts(null, createReqVO.getProducts()); 57 validateDiscountActivityProductConflicts(null, createReqVO.getProducts());
  58 + // 校验商品是否存在
  59 + validateProductExists(createReqVO.getProducts());
58 60
59 // 插入活动 61 // 插入活动
60 DiscountActivityDO discountActivity = DiscountActivityConvert.INSTANCE.convert(createReqVO) 62 DiscountActivityDO discountActivity = DiscountActivityConvert.INSTANCE.convert(createReqVO)
@@ -66,6 +68,7 @@ public class DiscountActivityServiceImpl implements DiscountActivityService { @@ -66,6 +68,7 @@ public class DiscountActivityServiceImpl implements DiscountActivityService {
66 .setActivityName(discountActivity.getName()).setActivityStatus(discountActivity.getStatus()) 68 .setActivityName(discountActivity.getName()).setActivityStatus(discountActivity.getStatus())
67 .setActivityStartTime(createReqVO.getStartTime()).setActivityEndTime(createReqVO.getEndTime())); 69 .setActivityStartTime(createReqVO.getStartTime()).setActivityEndTime(createReqVO.getEndTime()));
68 discountProductMapper.insertBatch(discountProducts); 70 discountProductMapper.insertBatch(discountProducts);
  71 + // 返回
69 return discountActivity.getId(); 72 return discountActivity.getId();
70 } 73 }
71 74
@@ -79,36 +82,40 @@ public class DiscountActivityServiceImpl implements DiscountActivityService { @@ -79,36 +82,40 @@ public class DiscountActivityServiceImpl implements DiscountActivityService {
79 } 82 }
80 // 校验商品是否冲突 83 // 校验商品是否冲突
81 validateDiscountActivityProductConflicts(updateReqVO.getId(), updateReqVO.getProducts()); 84 validateDiscountActivityProductConflicts(updateReqVO.getId(), updateReqVO.getProducts());
  85 + // 校验商品是否存在
  86 + validateProductExists(updateReqVO.getProducts());
82 87
83 // 更新活动 88 // 更新活动
84 DiscountActivityDO updateObj = DiscountActivityConvert.INSTANCE.convert(updateReqVO); 89 DiscountActivityDO updateObj = DiscountActivityConvert.INSTANCE.convert(updateReqVO);
85 discountActivityMapper.updateById(updateObj); 90 discountActivityMapper.updateById(updateObj);
86 // 更新商品 91 // 更新商品
87 - updateDiscountProduct(updateReqVO); 92 + updateDiscountProduct(updateObj, updateReqVO.getProducts());
88 } 93 }
89 94
90 - private void updateDiscountProduct(DiscountActivityUpdateReqVO updateReqVO) {  
91 - // TODO @zhangshuai:这里的逻辑,可以优化下哈;参考 CombinationActivityServiceImpl 的 updateCombinationProduct,主要是 CollectionUtils.diffList 的使用哈;  
92 - // 然后原先是使用 DiscountActivityConvert.INSTANCE.isEquals 对比,现在看看是不是简化就基于 skuId 对比就完事了;之前写的太精细,意义不大;  
93 - List<DiscountProductDO> dbDiscountProducts = discountProductMapper.selectListByActivityId(updateReqVO.getId());  
94 - // 计算要删除的记录  
95 - List<Long> deleteIds = convertList(dbDiscountProducts, DiscountProductDO::getId,  
96 - discountProductDO -> updateReqVO.getProducts().stream()  
97 - .noneMatch(product -> DiscountActivityConvert.INSTANCE.isEquals(discountProductDO, product)));  
98 - if (CollUtil.isNotEmpty(deleteIds)) {  
99 - discountProductMapper.deleteByIds(deleteIds); 95 + private void updateDiscountProduct(DiscountActivityDO activity, List<DiscountActivityCreateReqVO.Product> products) {
  96 + // 第一步,对比新老数据,获得添加、修改、删除的列表
  97 + List<DiscountProductDO> newList = BeanUtils.toBean(products, DiscountProductDO.class,
  98 + product -> product.setActivityId(activity.getId())
  99 + .setActivityName(activity.getName()).setActivityStatus(activity.getStatus())
  100 + .setActivityStartTime(activity.getStartTime()).setActivityEndTime(activity.getEndTime()));
  101 + List<DiscountProductDO> oldList = discountProductMapper.selectListByActivityId(activity.getId());
  102 + List<List<DiscountProductDO>> diffList = CollectionUtils.diffList(oldList, newList, (oldVal, newVal) -> {
  103 + boolean same = ObjectUtil.equal(oldVal.getSkuId(), newVal.getSkuId());
  104 + if (same) {
  105 + newVal.setId(oldVal.getId());
  106 + }
  107 + return same;
  108 + });
  109 +
  110 + // 第二步,批量添加、修改、删除
  111 + if (CollUtil.isNotEmpty(diffList.get(0))) {
  112 + discountProductMapper.insertBatch(diffList.get(0));
100 } 113 }
101 - // 计算新增的记录  
102 - List<DiscountProductDO> newDiscountProducts = convertList(updateReqVO.getProducts(),  
103 - product -> DiscountActivityConvert.INSTANCE.convert(product)  
104 - .setActivityId(updateReqVO.getId())  
105 - .setActivityName(updateReqVO.getName())  
106 - .setActivityStartTime(updateReqVO.getStartTime())  
107 - .setActivityEndTime(updateReqVO.getEndTime()));  
108 - newDiscountProducts.removeIf(product -> dbDiscountProducts.stream().anyMatch(  
109 - dbProduct -> DiscountActivityConvert.INSTANCE.isEquals(dbProduct, product))); // 如果匹配到,说明是更新的  
110 - if (CollectionUtil.isNotEmpty(newDiscountProducts)) {  
111 - discountProductMapper.insertBatch(newDiscountProducts); 114 + if (CollUtil.isNotEmpty(diffList.get(1))) {
  115 + discountProductMapper.updateBatch(diffList.get(1));
  116 + }
  117 + if (CollUtil.isNotEmpty(diffList.get(2))) {
  118 + discountProductMapper.deleteByIds(convertList(diffList.get(2), DiscountProductDO::getId));
112 } 119 }
113 } 120 }
114 121
@@ -119,20 +126,44 @@ public class DiscountActivityServiceImpl implements DiscountActivityService { @@ -119,20 +126,44 @@ public class DiscountActivityServiceImpl implements DiscountActivityService {
119 * @param products 商品列表 126 * @param products 商品列表
120 */ 127 */
121 private void validateDiscountActivityProductConflicts(Long id, List<DiscountActivityBaseVO.Product> products) { 128 private void validateDiscountActivityProductConflicts(Long id, List<DiscountActivityBaseVO.Product> products) {
122 - if (CollUtil.isEmpty(products)) {  
123 - return;  
124 - }  
125 - // 查询商品参加的活动  
126 - List<DiscountProductDO> list = discountProductMapper.selectListByActivityId(id);  
127 - List<DiscountProductDO> matchDiscountProductList = discountProductMapper.selectListBySkuIds(  
128 - convertSet(list, DiscountProductDO::getSkuId));  
129 - if (id != null) { // 排除自己这个活动  
130 - matchDiscountProductList.removeIf(product -> id.equals(product.getActivityId()));  
131 - }  
132 - // 如果非空,则说明冲突  
133 - if (CollUtil.isNotEmpty(matchDiscountProductList)) {  
134 - throw exception(DISCOUNT_ACTIVITY_SPU_CONFLICTS); 129 + // 1.1 查询所有开启的折扣活动
  130 + List<DiscountActivityDO> activityList = discountActivityMapper.selectList(DiscountActivityDO::getStatus,
  131 + CommonStatusEnum.ENABLE.getStatus());
  132 + if (id != null) { // 时排除自己
  133 + activityList.removeIf(item -> ObjectUtil.equal(item.getId(), id));
135 } 134 }
  135 + // 1.2 查询活动下的所有商品
  136 + List<DiscountProductDO> productList = discountProductMapper.selectListByActivityId(
  137 + convertList(activityList, DiscountActivityDO::getId));
  138 + Map<Long, List<DiscountProductDO>> productListMap = convertMultiMap(productList, DiscountProductDO::getActivityId);
  139 +
  140 + // 2. 校验商品是否冲突
  141 + activityList.forEach(item -> {
  142 + findAndThen(productListMap, item.getId(), discountProducts -> {
  143 + if (!intersectionDistinct(convertList(discountProducts, DiscountProductDO::getSpuId),
  144 + convertList(products, DiscountActivityBaseVO.Product::getSpuId)).isEmpty()) {
  145 + throw exception(DISCOUNT_ACTIVITY_SPU_CONFLICTS, item.getName());
  146 + }
  147 + });
  148 + });
  149 + }
  150 +
  151 + /**
  152 + * 校验活动商品是否都存在
  153 + *
  154 + * @param products 活动商品
  155 + */
  156 + private void validateProductExists(List<DiscountActivityBaseVO.Product> products) {
  157 + // 1.获得商品所有的 sku
  158 + List<ProductSkuRespDTO> skus = productSkuApi.getSkuListBySpuId(
  159 + convertList(products, DiscountActivityBaseVO.Product::getSpuId));
  160 + Map<Long, ProductSkuRespDTO> skuMap = convertMap(skus, ProductSkuRespDTO::getId);
  161 + // 2. 校验商品 sku 都存在
  162 + products.forEach(product -> {
  163 + if (!skuMap.containsKey(product.getSkuId())) {
  164 + throw exception(SKU_NOT_EXISTS);
  165 + }
  166 + });
136 } 167 }
137 168
138 @Override 169 @Override
@@ -143,9 +174,11 @@ public class DiscountActivityServiceImpl implements DiscountActivityService { @@ -143,9 +174,11 @@ public class DiscountActivityServiceImpl implements DiscountActivityService {
143 throw exception(DISCOUNT_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED); 174 throw exception(DISCOUNT_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED);
144 } 175 }
145 176
146 - // 更新  
147 - DiscountActivityDO updateObj = new DiscountActivityDO().setId(id).setStatus(CommonStatusEnum.DISABLE.getStatus());  
148 - discountActivityMapper.updateById(updateObj); 177 + // 更新活动状态
  178 + discountActivityMapper.updateById(new DiscountActivityDO().setId(id).setStatus(CommonStatusEnum.DISABLE.getStatus()));
  179 + // 更新活动商品状态
  180 + discountProductMapper.updateByActivityId(new DiscountProductDO().setActivityId(id).setActivityStatus(
  181 + CommonStatusEnum.DISABLE.getStatus()));
149 } 182 }
150 183
151 @Override 184 @Override
@@ -156,8 +189,10 @@ public class DiscountActivityServiceImpl implements DiscountActivityService { @@ -156,8 +189,10 @@ public class DiscountActivityServiceImpl implements DiscountActivityService {
156 throw exception(DISCOUNT_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED); 189 throw exception(DISCOUNT_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED);
157 } 190 }
158 191
159 - // 删除 192 + // 删除活动
160 discountActivityMapper.deleteById(id); 193 discountActivityMapper.deleteById(id);
  194 + // 删除活动商品
  195 + discountProductMapper.deleteByActivityId(id);
161 } 196 }
162 197
163 private DiscountActivityDO validateDiscountActivityExists(Long id) { 198 private DiscountActivityDO validateDiscountActivityExists(Long id) {
@@ -185,21 +220,12 @@ public class DiscountActivityServiceImpl implements DiscountActivityService { @@ -185,21 +220,12 @@ public class DiscountActivityServiceImpl implements DiscountActivityService {
185 220
186 @Override 221 @Override
187 public List<DiscountProductDO> getDiscountProductsByActivityId(Collection<Long> activityIds) { 222 public List<DiscountProductDO> getDiscountProductsByActivityId(Collection<Long> activityIds) {
188 - return discountProductMapper.selectList("activity_id", activityIds); 223 + return discountProductMapper.selectList(DiscountProductDO::getActivityId, activityIds);
189 } 224 }
190 225
191 @Override 226 @Override
192 - public List<DiscountActivityDO> getDiscountActivityListBySpuIds(Collection<Long> spuIds) {  
193 - // 1. 查询出指定 spuId 的 spu 参加的活动最接近现在的一条记录。多个的话,一个 spuId 对应一个最近的活动编号  
194 - List<Map<String, Object>> spuIdAndActivityIdMaps = discountProductMapper.selectSpuIdAndActivityIdMapsBySpuIdsAndStatus(  
195 - spuIds, CommonStatusEnum.ENABLE.getStatus());  
196 - if (CollUtil.isEmpty(spuIdAndActivityIdMaps)) {  
197 - return Collections.emptyList();  
198 - }  
199 -  
200 - // 2. 查询活动详情  
201 - return discountActivityMapper.selectListByIdsAndDateTimeLt(  
202 - convertSet(spuIdAndActivityIdMaps, map -> MapUtil.getLong(map, "activityId")), LocalDateTime.now()); 227 + public List<DiscountProductDO> getMatchDiscountProductListBySkuIds(Collection<Long> skuIds) {
  228 + return discountProductMapper.selectListBySkuIdsAndStatusAndNow(skuIds, CommonStatusEnum.ENABLE.getStatus());
203 } 229 }
204 230
205 } 231 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/reward/RewardActivityServiceImpl.java
@@ -137,8 +137,8 @@ public class RewardActivityServiceImpl implements RewardActivityService { @@ -137,8 +137,8 @@ public class RewardActivityServiceImpl implements RewardActivityService {
137 if (PromotionProductScopeEnum.isAll(item.getProductScope()) || 137 if (PromotionProductScopeEnum.isAll(item.getProductScope()) ||
138 PromotionProductScopeEnum.isAll(rewardActivity.getProductScope())) { 138 PromotionProductScopeEnum.isAll(rewardActivity.getProductScope())) {
139 throw exception(REWARD_ACTIVITY_SCOPE_EXISTS, item.getName(), 139 throw exception(REWARD_ACTIVITY_SCOPE_EXISTS, item.getName(),
140 - PromotionProductScopeEnum.isAll(item.getProductScope()) ? "该活动商品范围为全部已覆盖包含本活动范围" :  
141 - "本活动商品范围为全部已覆盖包含了该活动商品范围"); 140 + PromotionProductScopeEnum.isAll(item.getProductScope()) ?
  141 + "该活动商品范围为全部已覆盖包含本活动范围" : "本活动商品范围为全部已覆盖包含了该活动商品范围");
142 } 142 }
143 // 情况二:如果与该时间段内商品范围为类别的活动冲突 143 // 情况二:如果与该时间段内商品范围为类别的活动冲突
144 if (PromotionProductScopeEnum.isCategory(item.getProductScope())) { 144 if (PromotionProductScopeEnum.isCategory(item.getProductScope())) {
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeDiscountActivityPriceCalculator.java
@@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.trade.service.price.calculator; @@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.trade.service.price.calculator;
2 2
3 import cn.hutool.core.util.ObjectUtil; 3 import cn.hutool.core.util.ObjectUtil;
4 import cn.hutool.core.util.StrUtil; 4 import cn.hutool.core.util.StrUtil;
5 -import cn.iocoder.yudao.framework.common.util.number.MoneyUtils;  
6 import cn.iocoder.yudao.module.member.api.level.MemberLevelApi; 5 import cn.iocoder.yudao.module.member.api.level.MemberLevelApi;
7 import cn.iocoder.yudao.module.member.api.level.dto.MemberLevelRespDTO; 6 import cn.iocoder.yudao.module.member.api.level.dto.MemberLevelRespDTO;
8 import cn.iocoder.yudao.module.member.api.user.MemberUserApi; 7 import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
@@ -23,6 +22,7 @@ import java.util.Map; @@ -23,6 +22,7 @@ import java.util.Map;
23 22
24 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; 23 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
25 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; 24 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
  25 +import static cn.iocoder.yudao.framework.common.util.number.MoneyUtils.calculateRatePrice;
26 import static cn.iocoder.yudao.module.trade.service.price.calculator.TradePriceCalculatorHelper.formatPrice; 26 import static cn.iocoder.yudao.module.trade.service.price.calculator.TradePriceCalculatorHelper.formatPrice;
27 27
28 /** 28 /**
@@ -125,7 +125,7 @@ public class TradeDiscountActivityPriceCalculator implements TradePriceCalculato @@ -125,7 +125,7 @@ public class TradeDiscountActivityPriceCalculator implements TradePriceCalculato
125 if (PromotionDiscountTypeEnum.PRICE.getType().equals(discount.getDiscountType())) { // 减价 125 if (PromotionDiscountTypeEnum.PRICE.getType().equals(discount.getDiscountType())) { // 减价
126 newPrice -= discount.getDiscountPrice() * orderItem.getCount(); 126 newPrice -= discount.getDiscountPrice() * orderItem.getCount();
127 } else if (PromotionDiscountTypeEnum.PERCENT.getType().equals(discount.getDiscountType())) { // 打折 127 } else if (PromotionDiscountTypeEnum.PERCENT.getType().equals(discount.getDiscountType())) { // 打折
128 - newPrice = newPrice * discount.getDiscountPercent() / 100; 128 + newPrice = calculateRatePrice(orderItem.getPayPrice(), discount.getDiscountPercent() / 100.0);
129 } else { 129 } else {
130 throw new IllegalArgumentException(String.format("优惠活动的商品(%s) 的优惠类型不正确", discount)); 130 throw new IllegalArgumentException(String.format("优惠活动的商品(%s) 的优惠类型不正确", discount));
131 } 131 }
@@ -144,7 +144,7 @@ public class TradeDiscountActivityPriceCalculator implements TradePriceCalculato @@ -144,7 +144,7 @@ public class TradeDiscountActivityPriceCalculator implements TradePriceCalculato
144 if (level == null || level.getDiscountPercent() == null) { 144 if (level == null || level.getDiscountPercent() == null) {
145 return 0; 145 return 0;
146 } 146 }
147 - Integer newPrice = MoneyUtils.calculateRatePrice(orderItem.getPayPrice(), level.getDiscountPercent().doubleValue()); 147 + Integer newPrice = calculateRatePrice(orderItem.getPayPrice(), level.getDiscountPercent().doubleValue());
148 return orderItem.getPayPrice() - newPrice; 148 return orderItem.getPayPrice() - newPrice;
149 } 149 }
150 150