Commit 6f740fab7cad2140b9bd15e65069dd8a8ba492b1
1 parent
20775791
【代码优化】商城:完善满减送的计算逻辑
Showing
7 changed files
with
125 additions
and
191 deletions
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 | 113 | Map<Long, ProductCategoryDO> categoryMap = CollectionUtils.convertMap(list, ProductCategoryDO::getId); |
| 114 | 114 | // 校验 |
| 115 | 115 | ids.forEach(id -> { |
| 116 | + // 校验分类是否存在 | |
| 116 | 117 | ProductCategoryDO category = categoryMap.get(id); |
| 117 | 118 | if (category == null) { |
| 118 | 119 | throw exception(CATEGORY_NOT_EXISTS); |
| 119 | 120 | } |
| 121 | + // 校验分类是否启用 | |
| 120 | 122 | if (!CommonStatusEnum.ENABLE.getStatus().equals(category.getStatus())) { |
| 121 | 123 | throw exception(CATEGORY_DISABLED, category.getName()); |
| 122 | 124 | } |
| 123 | - // 校验层级 | |
| 125 | + // 商品分类层级校验,必须使用第二级的商品分类 | |
| 124 | 126 | if (getCategoryLevel(id) < CATEGORY_LEVEL) { |
| 125 | 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 | 1 | package cn.iocoder.yudao.module.promotion.convert.discount; |
| 2 | 2 | |
| 3 | -import cn.hutool.core.util.ObjectUtil; | |
| 4 | 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 | 9 | import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountActivityDO; |
| 10 | 10 | import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO; |
| 11 | -import cn.iocoder.yudao.module.promotion.enums.common.PromotionDiscountTypeEnum; | |
| 12 | 11 | import org.mapstruct.Mapper; |
| 13 | 12 | import org.mapstruct.factory.Mappers; |
| 14 | 13 | |
| 15 | 14 | import java.util.List; |
| 16 | -import java.util.Map; | |
| 17 | 15 | |
| 18 | 16 | /** |
| 19 | 17 | * 限时折扣活动 Convert |
| ... | ... | @@ -32,105 +30,22 @@ public interface DiscountActivityConvert { |
| 32 | 30 | DiscountActivityRespVO convert(DiscountActivityDO bean); |
| 33 | 31 | |
| 34 | 32 | List<DiscountActivityRespVO> convertList(List<DiscountActivityDO> list); |
| 33 | + | |
| 35 | 34 | List<DiscountActivityBaseVO.Product> convertList2(List<DiscountProductDO> list); |
| 35 | + | |
| 36 | 36 | PageResult<DiscountActivityRespVO> convertPage(PageResult<DiscountActivityDO> page); |
| 37 | 37 | |
| 38 | 38 | default PageResult<DiscountActivityRespVO> convertPage(PageResult<DiscountActivityDO> page, |
| 39 | - List<DiscountProductDO> discountProductDOList, | |
| 40 | - List<ProductSpuRespDTO> spuList) { | |
| 39 | + List<DiscountProductDO> discountProductDOList) { | |
| 41 | 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 | 42 | return pageResult; |
| 56 | 43 | } |
| 57 | 44 | |
| 58 | 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 | 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 | 3 | import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; |
| 4 | 4 | import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; |
| 5 | 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 | 7 | import org.apache.ibatis.annotations.Mapper; |
| 8 | 8 | |
| 9 | 9 | import java.time.LocalDateTime; |
| 10 | 10 | import java.util.Collection; |
| 11 | 11 | import java.util.List; |
| 12 | -import java.util.Map; | |
| 13 | 12 | |
| 14 | 13 | /** |
| 15 | 14 | * 限时折扣商城 Mapper |
| ... | ... | @@ -23,8 +22,23 @@ public interface DiscountProductMapper extends BaseMapperX<DiscountProductDO> { |
| 23 | 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 | 44 | default List<DiscountProductDO> selectListBySkuIdsAndStatusAndNow(Collection<Long> skuIds, Integer status) { |
| ... | ... | @@ -36,19 +50,4 @@ public interface DiscountProductMapper extends BaseMapperX<DiscountProductDO> { |
| 36 | 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 | 89 | */ |
| 90 | 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 | 1 | package cn.iocoder.yudao.module.promotion.service.discount; |
| 2 | 2 | |
| 3 | 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 | 5 | import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; |
| 7 | 6 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 7 | +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | |
| 8 | 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 | 11 | import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityBaseVO; |
| 10 | 12 | import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityCreateReqVO; |
| 11 | 13 | import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityPageReqVO; |
| ... | ... | @@ -20,15 +22,15 @@ import org.springframework.stereotype.Service; |
| 20 | 22 | import org.springframework.transaction.annotation.Transactional; |
| 21 | 23 | import org.springframework.validation.annotation.Validated; |
| 22 | 24 | |
| 23 | -import java.time.LocalDateTime; | |
| 24 | 25 | import java.util.Collection; |
| 25 | -import java.util.Collections; | |
| 26 | 26 | import java.util.List; |
| 27 | 27 | import java.util.Map; |
| 28 | 28 | |
| 29 | +import static cn.hutool.core.collection.CollUtil.intersectionDistinct; | |
| 29 | 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 | 34 | import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*; |
| 33 | 35 | |
| 34 | 36 | /** |
| ... | ... | @@ -45,16 +47,16 @@ public class DiscountActivityServiceImpl implements DiscountActivityService { |
| 45 | 47 | @Resource |
| 46 | 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 | 53 | @Override |
| 54 | 54 | @Transactional(rollbackFor = Exception.class) |
| 55 | 55 | public Long createDiscountActivity(DiscountActivityCreateReqVO createReqVO) { |
| 56 | 56 | // 校验商品是否冲突 |
| 57 | 57 | validateDiscountActivityProductConflicts(null, createReqVO.getProducts()); |
| 58 | + // 校验商品是否存在 | |
| 59 | + validateProductExists(createReqVO.getProducts()); | |
| 58 | 60 | |
| 59 | 61 | // 插入活动 |
| 60 | 62 | DiscountActivityDO discountActivity = DiscountActivityConvert.INSTANCE.convert(createReqVO) |
| ... | ... | @@ -66,6 +68,7 @@ public class DiscountActivityServiceImpl implements DiscountActivityService { |
| 66 | 68 | .setActivityName(discountActivity.getName()).setActivityStatus(discountActivity.getStatus()) |
| 67 | 69 | .setActivityStartTime(createReqVO.getStartTime()).setActivityEndTime(createReqVO.getEndTime())); |
| 68 | 70 | discountProductMapper.insertBatch(discountProducts); |
| 71 | + // 返回 | |
| 69 | 72 | return discountActivity.getId(); |
| 70 | 73 | } |
| 71 | 74 | |
| ... | ... | @@ -79,36 +82,40 @@ public class DiscountActivityServiceImpl implements DiscountActivityService { |
| 79 | 82 | } |
| 80 | 83 | // 校验商品是否冲突 |
| 81 | 84 | validateDiscountActivityProductConflicts(updateReqVO.getId(), updateReqVO.getProducts()); |
| 85 | + // 校验商品是否存在 | |
| 86 | + validateProductExists(updateReqVO.getProducts()); | |
| 82 | 87 | |
| 83 | 88 | // 更新活动 |
| 84 | 89 | DiscountActivityDO updateObj = DiscountActivityConvert.INSTANCE.convert(updateReqVO); |
| 85 | 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 | 126 | * @param products 商品列表 |
| 120 | 127 | */ |
| 121 | 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 | 169 | @Override |
| ... | ... | @@ -143,9 +174,11 @@ public class DiscountActivityServiceImpl implements DiscountActivityService { |
| 143 | 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 | 184 | @Override |
| ... | ... | @@ -156,8 +189,10 @@ public class DiscountActivityServiceImpl implements DiscountActivityService { |
| 156 | 189 | throw exception(DISCOUNT_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED); |
| 157 | 190 | } |
| 158 | 191 | |
| 159 | - // 删除 | |
| 192 | + // 删除活动 | |
| 160 | 193 | discountActivityMapper.deleteById(id); |
| 194 | + // 删除活动商品 | |
| 195 | + discountProductMapper.deleteByActivityId(id); | |
| 161 | 196 | } |
| 162 | 197 | |
| 163 | 198 | private DiscountActivityDO validateDiscountActivityExists(Long id) { |
| ... | ... | @@ -185,21 +220,12 @@ public class DiscountActivityServiceImpl implements DiscountActivityService { |
| 185 | 220 | |
| 186 | 221 | @Override |
| 187 | 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 | 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 | 137 | if (PromotionProductScopeEnum.isAll(item.getProductScope()) || |
| 138 | 138 | PromotionProductScopeEnum.isAll(rewardActivity.getProductScope())) { |
| 139 | 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 | 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 | 2 | |
| 3 | 3 | import cn.hutool.core.util.ObjectUtil; |
| 4 | 4 | import cn.hutool.core.util.StrUtil; |
| 5 | -import cn.iocoder.yudao.framework.common.util.number.MoneyUtils; | |
| 6 | 5 | import cn.iocoder.yudao.module.member.api.level.MemberLevelApi; |
| 7 | 6 | import cn.iocoder.yudao.module.member.api.level.dto.MemberLevelRespDTO; |
| 8 | 7 | import cn.iocoder.yudao.module.member.api.user.MemberUserApi; |
| ... | ... | @@ -23,6 +22,7 @@ import java.util.Map; |
| 23 | 22 | |
| 24 | 23 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; |
| 25 | 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 | 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 | 125 | if (PromotionDiscountTypeEnum.PRICE.getType().equals(discount.getDiscountType())) { // 减价 |
| 126 | 126 | newPrice -= discount.getDiscountPrice() * orderItem.getCount(); |
| 127 | 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 | 129 | } else { |
| 130 | 130 | throw new IllegalArgumentException(String.format("优惠活动的商品(%s) 的优惠类型不正确", discount)); |
| 131 | 131 | } |
| ... | ... | @@ -144,7 +144,7 @@ public class TradeDiscountActivityPriceCalculator implements TradePriceCalculato |
| 144 | 144 | if (level == null || level.getDiscountPercent() == null) { |
| 145 | 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 | 148 | return orderItem.getPayPrice() - newPrice; |
| 149 | 149 | } |
| 150 | 150 | ... | ... |