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

This commit is contained in:
YunaiV 2024-09-15 20:57:37 +08:00
parent 20775791d9
commit 6f740fab7c
7 changed files with 125 additions and 191 deletions

View File

@ -113,14 +113,16 @@ public class ProductCategoryServiceImpl implements ProductCategoryService {
Map<Long, ProductCategoryDO> categoryMap = CollectionUtils.convertMap(list, ProductCategoryDO::getId); Map<Long, ProductCategoryDO> categoryMap = CollectionUtils.convertMap(list, ProductCategoryDO::getId);
// 校验 // 校验
ids.forEach(id -> { ids.forEach(id -> {
// 校验分类是否存在
ProductCategoryDO category = categoryMap.get(id); ProductCategoryDO category = categoryMap.get(id);
if (category == null) { if (category == null) {
throw exception(CATEGORY_NOT_EXISTS); throw exception(CATEGORY_NOT_EXISTS);
} }
// 校验分类是否启用
if (!CommonStatusEnum.ENABLE.getStatus().equals(category.getStatus())) { if (!CommonStatusEnum.ENABLE.getStatus().equals(category.getStatus())) {
throw exception(CATEGORY_DISABLED, category.getName()); throw exception(CATEGORY_DISABLED, category.getName());
} }
// 校验层级 // 商品分类层级校验必须使用第二级的商品分类
if (getCategoryLevel(id) < CATEGORY_LEVEL) { if (getCategoryLevel(id) < CATEGORY_LEVEL) {
throw exception(SPU_SAVE_FAIL_CATEGORY_LEVEL_ERROR); throw exception(SPU_SAVE_FAIL_CATEGORY_LEVEL_ERROR);
} }

View File

@ -1,19 +1,17 @@
package cn.iocoder.yudao.module.promotion.convert.discount; package cn.iocoder.yudao.module.promotion.convert.discount;
import cn.hutool.core.util.ObjectUtil;
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.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.common.util.collection.MapUtils; import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityBaseVO;
import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityCreateReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.*; import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityRespVO;
import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityUpdateReqVO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountActivityDO; import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountActivityDO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO; import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO;
import cn.iocoder.yudao.module.promotion.enums.common.PromotionDiscountTypeEnum;
import org.mapstruct.Mapper; import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers; import org.mapstruct.factory.Mappers;
import java.util.List; import java.util.List;
import java.util.Map;
/** /**
* 限时折扣活动 Convert * 限时折扣活动 Convert
@ -32,105 +30,22 @@ public interface DiscountActivityConvert {
DiscountActivityRespVO convert(DiscountActivityDO bean); DiscountActivityRespVO convert(DiscountActivityDO bean);
List<DiscountActivityRespVO> convertList(List<DiscountActivityDO> list); List<DiscountActivityRespVO> convertList(List<DiscountActivityDO> list);
List<DiscountActivityBaseVO.Product> convertList2(List<DiscountProductDO> list); List<DiscountActivityBaseVO.Product> convertList2(List<DiscountProductDO> list);
PageResult<DiscountActivityRespVO> convertPage(PageResult<DiscountActivityDO> page); PageResult<DiscountActivityRespVO> convertPage(PageResult<DiscountActivityDO> page);
default PageResult<DiscountActivityRespVO> convertPage(PageResult<DiscountActivityDO> page, default PageResult<DiscountActivityRespVO> convertPage(PageResult<DiscountActivityDO> page,
List<DiscountProductDO> discountProductDOList, List<DiscountProductDO> discountProductDOList) {
List<ProductSpuRespDTO> spuList) {
PageResult<DiscountActivityRespVO> pageResult = convertPage(page); PageResult<DiscountActivityRespVO> pageResult = convertPage(page);
pageResult.getList().forEach(item -> item.setProducts(convertList2(discountProductDOList)));
// 拼接商品 TODO @zhangshuai类似空行的问题也可以看看
Map<Long, DiscountProductDO> discountActivityMap = CollectionUtils.convertMap(discountProductDOList, DiscountProductDO::getActivityId);
Map<Long, ProductSpuRespDTO> spuMap = CollectionUtils.convertMap(spuList, ProductSpuRespDTO::getId);
pageResult.getList().forEach(item -> {
item.setProducts(convertList2(discountProductDOList));
item.setSpuId(discountActivityMap.get(item.getId())==null?null: discountActivityMap.get(item.getId()).getSpuId());
if (item.getSpuId() != null) {
MapUtils.findAndThen(spuMap, item.getSpuId(),
spu -> item.setSpuName(spu.getName()).setPicUrl(spu.getPicUrl()).setMarketPrice(spu.getMarketPrice()));
}
});
return pageResult; return pageResult;
} }
DiscountProductDO convert(DiscountActivityBaseVO.Product bean); DiscountProductDO convert(DiscountActivityBaseVO.Product bean);
default DiscountActivityDetailRespVO convert(DiscountActivityDO activity, List<DiscountProductDO> products){ default DiscountActivityRespVO convert(DiscountActivityDO activity, List<DiscountProductDO> products) {
if ( activity == null && products == null ) { return BeanUtils.toBean(activity, DiscountActivityRespVO.class).setProducts(convertList2(products));
return null;
}
DiscountActivityDetailRespVO discountActivityDetailRespVO = new DiscountActivityDetailRespVO();
if ( activity != null ) {
discountActivityDetailRespVO.setName( activity.getName() );
discountActivityDetailRespVO.setStartTime( activity.getStartTime() );
discountActivityDetailRespVO.setEndTime( activity.getEndTime() );
discountActivityDetailRespVO.setRemark( activity.getRemark() );
discountActivityDetailRespVO.setId( activity.getId() );
discountActivityDetailRespVO.setStatus( activity.getStatus() );
discountActivityDetailRespVO.setCreateTime( activity.getCreateTime() );
}
if (!products.isEmpty()) {
discountActivityDetailRespVO.setSpuId(products.get(0).getSpuId());
}
discountActivityDetailRespVO.setProducts( convertList2( products ) );
return discountActivityDetailRespVO;
} }
// =========== 比较是否相等 ========== }
/**
* 比较两个限时折扣商品是否相等
*
* @param productDO 数据库中的商品
* @param productVO 前端传入的商品
* @return 是否匹配
*/
@SuppressWarnings("DuplicatedCode")
default boolean isEquals(DiscountProductDO productDO, DiscountActivityBaseVO.Product productVO) {
if (ObjectUtil.notEqual(productDO.getSpuId(), productVO.getSpuId())
|| ObjectUtil.notEqual(productDO.getSkuId(), productVO.getSkuId())
|| ObjectUtil.notEqual(productDO.getDiscountType(), productVO.getDiscountType())) {
return false;
}
if (productDO.getDiscountType().equals(PromotionDiscountTypeEnum.PRICE.getType())) {
return ObjectUtil.equal(productDO.getDiscountPrice(), productVO.getDiscountPrice());
}
if (productDO.getDiscountType().equals(PromotionDiscountTypeEnum.PERCENT.getType())) {
return ObjectUtil.equal(productDO.getDiscountPercent(), productVO.getDiscountPercent());
}
return true;
}
/**
* 比较两个限时折扣商品是否相等
* 注意比较时忽略 id 编号
*
* @param productDO 商品 1
* @param productVO 商品 2
* @return 是否匹配
*/
@SuppressWarnings("DuplicatedCode")
default boolean isEquals(DiscountProductDO productDO, DiscountProductDO productVO) {
if (ObjectUtil.notEqual(productDO.getSpuId(), productVO.getSpuId())
|| ObjectUtil.notEqual(productDO.getSkuId(), productVO.getSkuId())
|| ObjectUtil.notEqual(productDO.getDiscountType(), productVO.getDiscountType())
|| ObjectUtil.notEqual(productDO.getActivityEndTime(), productVO.getActivityEndTime())
|| ObjectUtil.notEqual(productDO.getActivityStartTime(), productVO.getActivityStartTime())
|| ObjectUtil.notEqual(productDO.getActivityStatus(), productVO.getActivityStatus())) {
return false;
}
if (productDO.getDiscountType().equals(PromotionDiscountTypeEnum.PRICE.getType())) {
return ObjectUtil.equal(productDO.getDiscountPrice(), productVO.getDiscountPrice());
}
if (productDO.getDiscountType().equals(PromotionDiscountTypeEnum.PERCENT.getType())) {
return ObjectUtil.equal(productDO.getDiscountPercent(), productVO.getDiscountPercent());
}
return true;
}
}

View File

@ -3,13 +3,12 @@ package cn.iocoder.yudao.module.promotion.dal.mysql.discount;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO; import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Map;
/** /**
* 限时折扣商城 Mapper * 限时折扣商城 Mapper
@ -23,8 +22,23 @@ public interface DiscountProductMapper extends BaseMapperX<DiscountProductDO> {
return selectList(DiscountProductDO::getActivityId, activityId); return selectList(DiscountProductDO::getActivityId, activityId);
} }
default List<DiscountProductDO> selectListBySkuIds(Collection<Long> skuIds) { default List<DiscountProductDO> selectListByActivityId(Collection<Long> activityIds) {
return selectList(DiscountProductDO::getSkuId, skuIds); return selectList(DiscountProductDO::getActivityId, activityIds);
}
default List<DiscountProductDO> selectListBySpuIdsAndStatus(Collection<Long> spuIds, Integer status) {
return selectList(new LambdaQueryWrapperX<DiscountProductDO>()
.in(DiscountProductDO::getSpuId, spuIds)
.eq(DiscountProductDO::getActivityStatus, status));
}
default void updateByActivityId(DiscountProductDO discountProductDO) {
update(discountProductDO, new LambdaUpdateWrapper<DiscountProductDO>()
.eq(DiscountProductDO::getActivityId, discountProductDO.getActivityId()));
}
default void deleteByActivityId(Long activityId) {
delete(DiscountProductDO::getActivityId, activityId);
} }
default List<DiscountProductDO> selectListBySkuIdsAndStatusAndNow(Collection<Long> skuIds, Integer status) { default List<DiscountProductDO> selectListBySkuIdsAndStatusAndNow(Collection<Long> skuIds, Integer status) {
@ -36,19 +50,4 @@ public interface DiscountProductMapper extends BaseMapperX<DiscountProductDO> {
.gt(DiscountProductDO::getActivityEndTime, now)); .gt(DiscountProductDO::getActivityEndTime, now));
} }
/**
* 查询出指定 spuId spu 参加的活动最接近现在的一条记录多个的话一个 spuId 对应一个最近的活动编号
*
* @param spuIds spu 编号
* @param status 状态
* @return 包含 spuId activityId map 对象列表
*/
default List<Map<String, Object>> selectSpuIdAndActivityIdMapsBySpuIdsAndStatus(Collection<Long> spuIds, Integer status) {
return selectMaps(new QueryWrapper<DiscountProductDO>()
.select("spu_id AS spuId, MAX(DISTINCT(activity_id)) AS activityId")
.in("spu_id", spuIds)
.eq("activity_status", status)
.groupBy("spu_id"));
}
} }

View File

@ -89,12 +89,4 @@ public interface DiscountActivityService {
*/ */
List<DiscountProductDO> getDiscountProductsByActivityId(Collection<Long> activityIds); List<DiscountProductDO> getDiscountProductsByActivityId(Collection<Long> activityIds);
/**
* 获取指定 SPU 编号最近参加的活动每个 spuId 只返回一条记录
*
* @param spuIds SPU 编号数组
* @return 折扣活动列表
*/
List<DiscountActivityDO> getDiscountActivityListBySpuIds(Collection<Long> spuIds);
} }

View File

@ -1,11 +1,13 @@
package cn.iocoder.yudao.module.promotion.service.discount; package cn.iocoder.yudao.module.promotion.service.discount;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.map.MapUtil;
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.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityBaseVO; import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityBaseVO;
import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityCreateReqVO; import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityCreateReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityPageReqVO; import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityPageReqVO;
@ -20,15 +22,15 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import java.time.LocalDateTime;
import java.util.Collection; import java.util.Collection;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import static cn.hutool.core.collection.CollUtil.intersectionDistinct;
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.framework.common.util.collection.CollectionUtils.convertList; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen;
import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_NOT_EXISTS;
import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*; import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
/** /**
@ -45,16 +47,16 @@ public class DiscountActivityServiceImpl implements DiscountActivityService {
@Resource @Resource
private DiscountProductMapper discountProductMapper; private DiscountProductMapper discountProductMapper;
@Override @Resource
public List<DiscountProductDO> getMatchDiscountProductListBySkuIds(Collection<Long> skuIds) { private ProductSkuApi productSkuApi;
return discountProductMapper.selectListBySkuIdsAndStatusAndNow(skuIds, CommonStatusEnum.ENABLE.getStatus());
}
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public Long createDiscountActivity(DiscountActivityCreateReqVO createReqVO) { public Long createDiscountActivity(DiscountActivityCreateReqVO createReqVO) {
// 校验商品是否冲突 // 校验商品是否冲突
validateDiscountActivityProductConflicts(null, createReqVO.getProducts()); validateDiscountActivityProductConflicts(null, createReqVO.getProducts());
// 校验商品是否存在
validateProductExists(createReqVO.getProducts());
// 插入活动 // 插入活动
DiscountActivityDO discountActivity = DiscountActivityConvert.INSTANCE.convert(createReqVO) DiscountActivityDO discountActivity = DiscountActivityConvert.INSTANCE.convert(createReqVO)
@ -66,6 +68,7 @@ public class DiscountActivityServiceImpl implements DiscountActivityService {
.setActivityName(discountActivity.getName()).setActivityStatus(discountActivity.getStatus()) .setActivityName(discountActivity.getName()).setActivityStatus(discountActivity.getStatus())
.setActivityStartTime(createReqVO.getStartTime()).setActivityEndTime(createReqVO.getEndTime())); .setActivityStartTime(createReqVO.getStartTime()).setActivityEndTime(createReqVO.getEndTime()));
discountProductMapper.insertBatch(discountProducts); discountProductMapper.insertBatch(discountProducts);
// 返回
return discountActivity.getId(); return discountActivity.getId();
} }
@ -79,36 +82,40 @@ public class DiscountActivityServiceImpl implements DiscountActivityService {
} }
// 校验商品是否冲突 // 校验商品是否冲突
validateDiscountActivityProductConflicts(updateReqVO.getId(), updateReqVO.getProducts()); validateDiscountActivityProductConflicts(updateReqVO.getId(), updateReqVO.getProducts());
// 校验商品是否存在
validateProductExists(updateReqVO.getProducts());
// 更新活动 // 更新活动
DiscountActivityDO updateObj = DiscountActivityConvert.INSTANCE.convert(updateReqVO); DiscountActivityDO updateObj = DiscountActivityConvert.INSTANCE.convert(updateReqVO);
discountActivityMapper.updateById(updateObj); discountActivityMapper.updateById(updateObj);
// 更新商品 // 更新商品
updateDiscountProduct(updateReqVO); updateDiscountProduct(updateObj, updateReqVO.getProducts());
} }
private void updateDiscountProduct(DiscountActivityUpdateReqVO updateReqVO) { private void updateDiscountProduct(DiscountActivityDO activity, List<DiscountActivityCreateReqVO.Product> products) {
// TODO @zhangshuai这里的逻辑可以优化下哈参考 CombinationActivityServiceImpl updateCombinationProduct主要是 CollectionUtils.diffList 的使用哈 // 第一步对比新老数据获得添加修改删除的列表
// 然后原先是使用 DiscountActivityConvert.INSTANCE.isEquals 对比现在看看是不是简化就基于 skuId 对比就完事了之前写的太精细意义不大 List<DiscountProductDO> newList = BeanUtils.toBean(products, DiscountProductDO.class,
List<DiscountProductDO> dbDiscountProducts = discountProductMapper.selectListByActivityId(updateReqVO.getId()); product -> product.setActivityId(activity.getId())
// 计算要删除的记录 .setActivityName(activity.getName()).setActivityStatus(activity.getStatus())
List<Long> deleteIds = convertList(dbDiscountProducts, DiscountProductDO::getId, .setActivityStartTime(activity.getStartTime()).setActivityEndTime(activity.getEndTime()));
discountProductDO -> updateReqVO.getProducts().stream() List<DiscountProductDO> oldList = discountProductMapper.selectListByActivityId(activity.getId());
.noneMatch(product -> DiscountActivityConvert.INSTANCE.isEquals(discountProductDO, product))); List<List<DiscountProductDO>> diffList = CollectionUtils.diffList(oldList, newList, (oldVal, newVal) -> {
if (CollUtil.isNotEmpty(deleteIds)) { boolean same = ObjectUtil.equal(oldVal.getSkuId(), newVal.getSkuId());
discountProductMapper.deleteByIds(deleteIds); if (same) {
newVal.setId(oldVal.getId());
}
return same;
});
// 第二步批量添加修改删除
if (CollUtil.isNotEmpty(diffList.get(0))) {
discountProductMapper.insertBatch(diffList.get(0));
} }
// 计算新增的记录 if (CollUtil.isNotEmpty(diffList.get(1))) {
List<DiscountProductDO> newDiscountProducts = convertList(updateReqVO.getProducts(), discountProductMapper.updateBatch(diffList.get(1));
product -> DiscountActivityConvert.INSTANCE.convert(product) }
.setActivityId(updateReqVO.getId()) if (CollUtil.isNotEmpty(diffList.get(2))) {
.setActivityName(updateReqVO.getName()) discountProductMapper.deleteByIds(convertList(diffList.get(2), DiscountProductDO::getId));
.setActivityStartTime(updateReqVO.getStartTime())
.setActivityEndTime(updateReqVO.getEndTime()));
newDiscountProducts.removeIf(product -> dbDiscountProducts.stream().anyMatch(
dbProduct -> DiscountActivityConvert.INSTANCE.isEquals(dbProduct, product))); // 如果匹配到说明是更新的
if (CollectionUtil.isNotEmpty(newDiscountProducts)) {
discountProductMapper.insertBatch(newDiscountProducts);
} }
} }
@ -119,20 +126,44 @@ public class DiscountActivityServiceImpl implements DiscountActivityService {
* @param products 商品列表 * @param products 商品列表
*/ */
private void validateDiscountActivityProductConflicts(Long id, List<DiscountActivityBaseVO.Product> products) { private void validateDiscountActivityProductConflicts(Long id, List<DiscountActivityBaseVO.Product> products) {
if (CollUtil.isEmpty(products)) { // 1.1 查询所有开启的折扣活动
return; List<DiscountActivityDO> activityList = discountActivityMapper.selectList(DiscountActivityDO::getStatus,
} CommonStatusEnum.ENABLE.getStatus());
// 查询商品参加的活动 if (id != null) { // 时排除自己
List<DiscountProductDO> list = discountProductMapper.selectListByActivityId(id); activityList.removeIf(item -> ObjectUtil.equal(item.getId(), id));
List<DiscountProductDO> matchDiscountProductList = discountProductMapper.selectListBySkuIds(
convertSet(list, DiscountProductDO::getSkuId));
if (id != null) { // 排除自己这个活动
matchDiscountProductList.removeIf(product -> id.equals(product.getActivityId()));
}
// 如果非空则说明冲突
if (CollUtil.isNotEmpty(matchDiscountProductList)) {
throw exception(DISCOUNT_ACTIVITY_SPU_CONFLICTS);
} }
// 1.2 查询活动下的所有商品
List<DiscountProductDO> productList = discountProductMapper.selectListByActivityId(
convertList(activityList, DiscountActivityDO::getId));
Map<Long, List<DiscountProductDO>> productListMap = convertMultiMap(productList, DiscountProductDO::getActivityId);
// 2. 校验商品是否冲突
activityList.forEach(item -> {
findAndThen(productListMap, item.getId(), discountProducts -> {
if (!intersectionDistinct(convertList(discountProducts, DiscountProductDO::getSpuId),
convertList(products, DiscountActivityBaseVO.Product::getSpuId)).isEmpty()) {
throw exception(DISCOUNT_ACTIVITY_SPU_CONFLICTS, item.getName());
}
});
});
}
/**
* 校验活动商品是否都存在
*
* @param products 活动商品
*/
private void validateProductExists(List<DiscountActivityBaseVO.Product> products) {
// 1.获得商品所有的 sku
List<ProductSkuRespDTO> skus = productSkuApi.getSkuListBySpuId(
convertList(products, DiscountActivityBaseVO.Product::getSpuId));
Map<Long, ProductSkuRespDTO> skuMap = convertMap(skus, ProductSkuRespDTO::getId);
// 2. 校验商品 sku 都存在
products.forEach(product -> {
if (!skuMap.containsKey(product.getSkuId())) {
throw exception(SKU_NOT_EXISTS);
}
});
} }
@Override @Override
@ -143,9 +174,11 @@ public class DiscountActivityServiceImpl implements DiscountActivityService {
throw exception(DISCOUNT_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED); throw exception(DISCOUNT_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED);
} }
// 更新 // 更新活动状态
DiscountActivityDO updateObj = new DiscountActivityDO().setId(id).setStatus(CommonStatusEnum.DISABLE.getStatus()); discountActivityMapper.updateById(new DiscountActivityDO().setId(id).setStatus(CommonStatusEnum.DISABLE.getStatus()));
discountActivityMapper.updateById(updateObj); // 更新活动商品状态
discountProductMapper.updateByActivityId(new DiscountProductDO().setActivityId(id).setActivityStatus(
CommonStatusEnum.DISABLE.getStatus()));
} }
@Override @Override
@ -156,8 +189,10 @@ public class DiscountActivityServiceImpl implements DiscountActivityService {
throw exception(DISCOUNT_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED); throw exception(DISCOUNT_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED);
} }
// 删除 // 删除活动
discountActivityMapper.deleteById(id); discountActivityMapper.deleteById(id);
// 删除活动商品
discountProductMapper.deleteByActivityId(id);
} }
private DiscountActivityDO validateDiscountActivityExists(Long id) { private DiscountActivityDO validateDiscountActivityExists(Long id) {
@ -185,21 +220,12 @@ public class DiscountActivityServiceImpl implements DiscountActivityService {
@Override @Override
public List<DiscountProductDO> getDiscountProductsByActivityId(Collection<Long> activityIds) { public List<DiscountProductDO> getDiscountProductsByActivityId(Collection<Long> activityIds) {
return discountProductMapper.selectList("activity_id", activityIds); return discountProductMapper.selectList(DiscountProductDO::getActivityId, activityIds);
} }
@Override @Override
public List<DiscountActivityDO> getDiscountActivityListBySpuIds(Collection<Long> spuIds) { public List<DiscountProductDO> getMatchDiscountProductListBySkuIds(Collection<Long> skuIds) {
// 1. 查询出指定 spuId spu 参加的活动最接近现在的一条记录多个的话一个 spuId 对应一个最近的活动编号 return discountProductMapper.selectListBySkuIdsAndStatusAndNow(skuIds, CommonStatusEnum.ENABLE.getStatus());
List<Map<String, Object>> spuIdAndActivityIdMaps = discountProductMapper.selectSpuIdAndActivityIdMapsBySpuIdsAndStatus(
spuIds, CommonStatusEnum.ENABLE.getStatus());
if (CollUtil.isEmpty(spuIdAndActivityIdMaps)) {
return Collections.emptyList();
}
// 2. 查询活动详情
return discountActivityMapper.selectListByIdsAndDateTimeLt(
convertSet(spuIdAndActivityIdMaps, map -> MapUtil.getLong(map, "activityId")), LocalDateTime.now());
} }
} }

View File

@ -137,8 +137,8 @@ public class RewardActivityServiceImpl implements RewardActivityService {
if (PromotionProductScopeEnum.isAll(item.getProductScope()) || if (PromotionProductScopeEnum.isAll(item.getProductScope()) ||
PromotionProductScopeEnum.isAll(rewardActivity.getProductScope())) { PromotionProductScopeEnum.isAll(rewardActivity.getProductScope())) {
throw exception(REWARD_ACTIVITY_SCOPE_EXISTS, item.getName(), throw exception(REWARD_ACTIVITY_SCOPE_EXISTS, item.getName(),
PromotionProductScopeEnum.isAll(item.getProductScope()) ? "该活动商品范围为全部已覆盖包含本活动范围" : PromotionProductScopeEnum.isAll(item.getProductScope()) ?
"本活动商品范围为全部已覆盖包含了该活动商品范围"); "该活动商品范围为全部已覆盖包含本活动范围" : "本活动商品范围为全部已覆盖包含了该活动商品范围");
} }
// 情况二如果与该时间段内商品范围为类别的活动冲突 // 情况二如果与该时间段内商品范围为类别的活动冲突
if (PromotionProductScopeEnum.isCategory(item.getProductScope())) { if (PromotionProductScopeEnum.isCategory(item.getProductScope())) {

View File

@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.trade.service.price.calculator;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.util.number.MoneyUtils;
import cn.iocoder.yudao.module.member.api.level.MemberLevelApi; import cn.iocoder.yudao.module.member.api.level.MemberLevelApi;
import cn.iocoder.yudao.module.member.api.level.dto.MemberLevelRespDTO; import cn.iocoder.yudao.module.member.api.level.dto.MemberLevelRespDTO;
import cn.iocoder.yudao.module.member.api.user.MemberUserApi; import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
@ -23,6 +22,7 @@ import java.util.Map;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
import static cn.iocoder.yudao.framework.common.util.number.MoneyUtils.calculateRatePrice;
import static cn.iocoder.yudao.module.trade.service.price.calculator.TradePriceCalculatorHelper.formatPrice; import static cn.iocoder.yudao.module.trade.service.price.calculator.TradePriceCalculatorHelper.formatPrice;
/** /**
@ -125,7 +125,7 @@ public class TradeDiscountActivityPriceCalculator implements TradePriceCalculato
if (PromotionDiscountTypeEnum.PRICE.getType().equals(discount.getDiscountType())) { // 减价 if (PromotionDiscountTypeEnum.PRICE.getType().equals(discount.getDiscountType())) { // 减价
newPrice -= discount.getDiscountPrice() * orderItem.getCount(); newPrice -= discount.getDiscountPrice() * orderItem.getCount();
} else if (PromotionDiscountTypeEnum.PERCENT.getType().equals(discount.getDiscountType())) { // 打折 } else if (PromotionDiscountTypeEnum.PERCENT.getType().equals(discount.getDiscountType())) { // 打折
newPrice = newPrice * discount.getDiscountPercent() / 100; newPrice = calculateRatePrice(orderItem.getPayPrice(), discount.getDiscountPercent() / 100.0);
} else { } else {
throw new IllegalArgumentException(String.format("优惠活动的商品(%s) 的优惠类型不正确", discount)); throw new IllegalArgumentException(String.format("优惠活动的商品(%s) 的优惠类型不正确", discount));
} }
@ -144,7 +144,7 @@ public class TradeDiscountActivityPriceCalculator implements TradePriceCalculato
if (level == null || level.getDiscountPercent() == null) { if (level == null || level.getDiscountPercent() == null) {
return 0; return 0;
} }
Integer newPrice = MoneyUtils.calculateRatePrice(orderItem.getPayPrice(), level.getDiscountPercent().doubleValue()); Integer newPrice = calculateRatePrice(orderItem.getPayPrice(), level.getDiscountPercent().doubleValue());
return orderItem.getPayPrice() - newPrice; return orderItem.getPayPrice() - newPrice;
} }