瀏覽代碼

!1080 【代码优化】商城: 满减送活动
Merge pull request !1080 from puhui999/develop

芋道源码 7 月之前
父節點
當前提交
b094c35eaa

+ 5 - 5
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/reward/RewardActivityApi.java

@@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.promotion.api.reward;
 
 import cn.iocoder.yudao.module.promotion.api.reward.dto.RewardActivityMatchRespDTO;
 
-import java.util.Collection;
+import java.time.LocalDateTime;
 import java.util.List;
 
 /**
@@ -12,13 +12,13 @@ import java.util.List;
  */
 public interface RewardActivityApi {
 
-
     /**
-     * 基于指定的 SPU 编号数组,获得它们匹配的满减送活动
+     * 获得当前时间内开启的满减送活动
      *
-     * @param spuIds SPU 编号数组
+     * @param status   状态
+     * @param dateTime 时间
      * @return 满减送活动列表
      */
-    List<RewardActivityMatchRespDTO> getMatchRewardActivityList(Collection<Long> spuIds);
+    List<RewardActivityMatchRespDTO> getRewardActivityListByStatusAndNow(Integer status, LocalDateTime dateTime);
 
 }

+ 3 - 3
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java

@@ -40,12 +40,12 @@ public interface ErrorCodeConstants {
 
     // ========== 满减送活动 1-013-006-000 ==========
     ErrorCode REWARD_ACTIVITY_NOT_EXISTS = new ErrorCode(1_013_006_000, "满减送活动不存在");
-    ErrorCode REWARD_ACTIVITY_SPU_CONFLICTS = new ErrorCode(1_013_006_001, "存在商品参加了其它满减送活动");
+    ErrorCode REWARD_ACTIVITY_SPU_CONFLICTS = new ErrorCode(1_013_006_001, "该时间段存在商品参加了其它满减送活动");
     ErrorCode REWARD_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED = new ErrorCode(1_013_006_002, "满减送活动已关闭,不能修改");
     ErrorCode REWARD_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED = new ErrorCode(1_013_006_003, "满减送活动未关闭,不能删除");
     ErrorCode REWARD_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED = new ErrorCode(1_013_006_004, "满减送活动已关闭,不能重复关闭");
-    ErrorCode REWARD_ACTIVITY_SCOPE_ALL_EXISTS = new ErrorCode(1_013_006_005, "已存在商品范围为全场的满减送活动");
-    ErrorCode REWARD_ACTIVITY_SCOPE_CATEGORY_EXISTS = new ErrorCode(1_013_006_006, "存在商品类型参加了其它满减送活动");
+    ErrorCode REWARD_ACTIVITY_SCOPE_ALL_EXISTS = new ErrorCode(1_013_006_005, "该时间段已存在商品范围为全场的满减送活动");
+    ErrorCode REWARD_ACTIVITY_SCOPE_CATEGORY_EXISTS = new ErrorCode(1_013_006_006, "该时间段存在商品类型参加了其它满减送活动");
 
     // ========== TODO 空着 1-013-007-000 ============
 

+ 7 - 4
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/reward/RewardActivityApiImpl.java

@@ -1,12 +1,14 @@
 package cn.iocoder.yudao.module.promotion.api.reward;
 
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
 import cn.iocoder.yudao.module.promotion.api.reward.dto.RewardActivityMatchRespDTO;
+import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO;
 import cn.iocoder.yudao.module.promotion.service.reward.RewardActivityService;
+import jakarta.annotation.Resource;
 import org.springframework.stereotype.Service;
 import org.springframework.validation.annotation.Validated;
 
-import jakarta.annotation.Resource;
-import java.util.Collection;
+import java.time.LocalDateTime;
 import java.util.List;
 
 /**
@@ -22,8 +24,9 @@ public class RewardActivityApiImpl implements RewardActivityApi {
     private RewardActivityService rewardActivityService;
 
     @Override
-    public List<RewardActivityMatchRespDTO> getMatchRewardActivityList(Collection<Long> spuIds) {
-        return rewardActivityService.getMatchRewardActivityList(spuIds);
+    public List<RewardActivityMatchRespDTO> getRewardActivityListByStatusAndNow(Integer status, LocalDateTime dateTime) {
+        List<RewardActivityDO> list = rewardActivityService.getRewardActivityListByStatusAndDateTimeLt(status, dateTime);
+        return BeanUtils.toBean(list, RewardActivityMatchRespDTO.class);
     }
 
 }

+ 0 - 28
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/reward/RewardActivityMapper.java

@@ -1,19 +1,14 @@
 package cn.iocoder.yudao.module.promotion.dal.mysql.reward;
 
-import cn.hutool.core.util.StrUtil;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
 import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityPageReqVO;
 import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO;
-import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import org.apache.ibatis.annotations.Mapper;
 
 import java.time.LocalDateTime;
-import java.util.Collection;
 import java.util.List;
-import java.util.function.Function;
-import java.util.stream.Collectors;
 
 /**
  * 满减送活动 Mapper
@@ -30,29 +25,6 @@ public interface RewardActivityMapper extends BaseMapperX<RewardActivityDO> {
                 .orderByDesc(RewardActivityDO::getId));
     }
 
-    default List<RewardActivityDO> selectListByProductScopeAndStatus(Integer productScope, Integer status) {
-        return selectList(new LambdaQueryWrapperX<RewardActivityDO>()
-                .eq(RewardActivityDO::getProductScope, productScope)
-                .eq(RewardActivityDO::getStatus, status));
-    }
-
-    default List<RewardActivityDO> selectListBySpuIdsAndStatus(Collection<Long> spuIds, Integer status) {
-        Function<Collection<Long>, String> productScopeValuesFindInSetFunc = ids -> ids.stream()
-                .map(id -> StrUtil.format("FIND_IN_SET({}, product_spu_ids) ", id))
-                .collect(Collectors.joining(" OR "));
-        return selectList(new QueryWrapper<RewardActivityDO>()
-                .eq("status", status)
-                .apply(productScopeValuesFindInSetFunc.apply(spuIds)));
-    }
-
-    /**
-     * 获取指定活动编号的活动列表且
-     * 开始时间和结束时间小于给定时间 dateTime 的活动列表
-     *
-     * @param status   状态
-     * @param dateTime 指定日期
-     * @return 活动列表
-     */
     default List<RewardActivityDO> selectListByStatusAndDateTimeLt(Integer status, LocalDateTime dateTime) {
         return selectList(new LambdaQueryWrapperX<RewardActivityDO>()
                 .eq(RewardActivityDO::getStatus, status)

+ 1 - 11
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/reward/RewardActivityService.java

@@ -1,7 +1,6 @@
 package cn.iocoder.yudao.module.promotion.service.reward;
 
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.module.promotion.api.reward.dto.RewardActivityMatchRespDTO;
 import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityCreateReqVO;
 import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityPageReqVO;
 import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityUpdateReqVO;
@@ -9,7 +8,6 @@ import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO;
 import jakarta.validation.Valid;
 
 import java.time.LocalDateTime;
-import java.util.Collection;
 import java.util.List;
 
 /**
@@ -65,15 +63,7 @@ public interface RewardActivityService {
     PageResult<RewardActivityDO> getRewardActivityPage(RewardActivityPageReqVO pageReqVO);
 
     /**
-     * 基于指定的 SPU 编号数组,获得它们匹配的满减送活动
-     *
-     * @param spuIds SPU 编号数组
-     * @return 满减送活动列表
-     */
-    List<RewardActivityMatchRespDTO> getMatchRewardActivityList(Collection<Long> spuIds);
-
-    /**
-     * 获取指定 spu 编号最近参加的活动,每个 spuId 只返回一条记录
+     * 开始时间 < 指定时间 < 结束时间,也就是说获取指定时间段的活动
      *
      * @param status   状态
      * @param dateTime 当前日期时间

+ 21 - 23
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/reward/RewardActivityServiceImpl.java

@@ -1,11 +1,11 @@
 package cn.iocoder.yudao.module.promotion.service.reward;
 
+import cn.hutool.core.date.LocalDateTimeUtil;
 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
 import cn.iocoder.yudao.module.product.api.category.ProductCategoryApi;
 import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
-import cn.iocoder.yudao.module.promotion.api.reward.dto.RewardActivityMatchRespDTO;
 import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityBaseVO;
 import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityCreateReqVO;
 import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityPageReqVO;
@@ -19,13 +19,11 @@ import org.springframework.stereotype.Service;
 import org.springframework.validation.annotation.Validated;
 
 import java.time.LocalDateTime;
-import java.util.Collection;
 import java.util.List;
 import java.util.Objects;
 
 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.util.collection.CollectionUtils.anyMatch;
 import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
 
 /**
@@ -87,8 +85,7 @@ public class RewardActivityServiceImpl implements RewardActivityService {
         }
 
         // 更新
-        RewardActivityDO updateObj = new RewardActivityDO().setId(id).setStatus(CommonStatusEnum.DISABLE.getStatus());
-        rewardActivityMapper.updateById(updateObj);
+        rewardActivityMapper.updateById(new RewardActivityDO().setId(id).setStatus(CommonStatusEnum.DISABLE.getStatus()));
     }
 
     @Override
@@ -118,22 +115,29 @@ public class RewardActivityServiceImpl implements RewardActivityService {
      * @param rewardActivity 请求
      */
     private void validateRewardActivitySpuConflicts(Long id, RewardActivityBaseVO rewardActivity) {
-        List<RewardActivityDO> list = rewardActivityMapper.selectList(RewardActivityDO::getProductScope,
-                rewardActivity.getProductScope(), RewardActivityDO::getStatus, CommonStatusEnum.ENABLE.getStatus());
+        // 0. 获得开启的所有的活动
+        List<RewardActivityDO> list = rewardActivityMapper.selectList(RewardActivityDO::getStatus, CommonStatusEnum.ENABLE.getStatus());
         if (id != null) { // 排除自己这个活动
             list.removeIf(activity -> id.equals(activity.getId()));
         }
 
-        // 情况一:全部商品参加
-        if (PromotionProductScopeEnum.isAll(rewardActivity.getProductScope()) && !list.isEmpty()) {
-            throw exception(REWARD_ACTIVITY_SCOPE_ALL_EXISTS);
-        }
-        if (PromotionProductScopeEnum.isSpu(rewardActivity.getProductScope()) ||  // 情况二:指定商品参加
-                PromotionProductScopeEnum.isCategory(rewardActivity.getProductScope())) {  // 情况三:指定商品类型参加
-            if (anyMatch(list, item -> !intersectionDistinct(item.getProductScopeValues(),
-                    rewardActivity.getProductScopeValues()).isEmpty())) {
-                throw exception(PromotionProductScopeEnum.isSpu(rewardActivity.getProductScope()) ?
-                        REWARD_ACTIVITY_SPU_CONFLICTS : REWARD_ACTIVITY_SCOPE_CATEGORY_EXISTS);
+        for (RewardActivityDO item : list) {
+            // 1.1 校验满减送活动时间是否冲突,如果时段不冲突那么不同的时间段内则可以存在相同的商品范围
+            if (!LocalDateTimeUtil.isOverlap(item.getStartTime(), item.getEndTime(),
+                    rewardActivity.getStartTime(), rewardActivity.getEndTime())) {
+                continue;
+            }
+            // 1.2 校验商品范围是否重叠
+            if (PromotionProductScopeEnum.isAll(rewardActivity.getProductScope()) &&
+                    PromotionProductScopeEnum.isAll(item.getProductScope())) { // 情况一:全部商品参加
+                throw exception(REWARD_ACTIVITY_SCOPE_ALL_EXISTS);
+            }
+            if (PromotionProductScopeEnum.isSpu(rewardActivity.getProductScope()) ||  // 情况二:指定商品参加
+                    PromotionProductScopeEnum.isCategory(rewardActivity.getProductScope())) {  // 情况三:指定商品类型参加
+                if (!intersectionDistinct(item.getProductScopeValues(), rewardActivity.getProductScopeValues()).isEmpty()) {
+                    throw exception(PromotionProductScopeEnum.isSpu(rewardActivity.getProductScope()) ?
+                            REWARD_ACTIVITY_SPU_CONFLICTS : REWARD_ACTIVITY_SCOPE_CATEGORY_EXISTS);
+                }
             }
         }
     }
@@ -156,12 +160,6 @@ public class RewardActivityServiceImpl implements RewardActivityService {
         return rewardActivityMapper.selectPage(pageReqVO);
     }
 
-    @Override
-    public List<RewardActivityMatchRespDTO> getMatchRewardActivityList(Collection<Long> spuIds) {
-        List<RewardActivityDO> list = rewardActivityMapper.selectListBySpuIdsAndStatus(spuIds, CommonStatusEnum.ENABLE.getStatus());
-        return BeanUtils.toBean(list, RewardActivityMatchRespDTO.class);
-    }
-
     @Override
     public List<RewardActivityDO> getRewardActivityListByStatusAndDateTimeLt(Integer status, LocalDateTime dateTime) {
         return rewardActivityMapper.selectListByStatusAndDateTimeLt(status, dateTime);

+ 63 - 24
yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/reward/RewardActivityServiceImplTest.java

@@ -2,8 +2,9 @@ package cn.iocoder.yudao.module.promotion.service.reward;
 
 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
-import cn.iocoder.yudao.module.promotion.api.reward.dto.RewardActivityMatchRespDTO;
+import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
+import cn.iocoder.yudao.module.product.api.category.ProductCategoryApi;
+import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
 import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityCreateReqVO;
 import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityPageReqVO;
 import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityUpdateReqVO;
@@ -11,15 +12,19 @@ import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO;
 import cn.iocoder.yudao.module.promotion.dal.mysql.reward.RewardActivityMapper;
 import cn.iocoder.yudao.module.promotion.enums.common.PromotionConditionTypeEnum;
 import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum;
-import jakarta.annotation.Resource;
 import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.Test;
-import org.springframework.context.annotation.Import;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
 
 import java.time.Duration;
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.Collection;
 import java.util.List;
 import java.util.Set;
 
+import static cn.hutool.core.collection.CollUtil.intersectionDistinct;
 import static cn.hutool.core.util.RandomUtil.randomEle;
 import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet;
 import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.addTime;
@@ -39,14 +44,17 @@ import static org.junit.jupiter.api.Assertions.*;
  * @author 芋道源码
  */
 @Disabled // TODO 芋艿:后续 fix 补充的单测
-@Import(RewardActivityServiceImpl.class)
-public class RewardActivityServiceImplTest extends BaseDbUnitTest {
+public class RewardActivityServiceImplTest extends BaseMockitoUnitTest {
 
-    @Resource
-    private RewardActivityServiceImpl rewardActivityService;
+    @InjectMocks
+    private RewardActivityServiceImpl rewardActivityServiceImpl;
 
-    @Resource
+    @Mock
     private RewardActivityMapper rewardActivityMapper;
+    @Mock
+    private ProductCategoryApi productCategoryApi;
+    @Mock
+    private ProductSpuApi productSpuApi;
 
     @Test
     public void testCreateRewardActivity_success() {
@@ -59,7 +67,7 @@ public class RewardActivityServiceImplTest extends BaseDbUnitTest {
         });
 
         // 调用
-        Long rewardActivityId = rewardActivityService.createRewardActivity(reqVO);
+        Long rewardActivityId = rewardActivityServiceImpl.createRewardActivity(reqVO);
         // 断言
         assertNotNull(rewardActivityId);
         // 校验记录的属性是否正确
@@ -86,7 +94,7 @@ public class RewardActivityServiceImplTest extends BaseDbUnitTest {
         });
 
         // 调用
-        rewardActivityService.updateRewardActivity(reqVO);
+        rewardActivityServiceImpl.updateRewardActivity(reqVO);
         // 校验是否更新正确
         RewardActivityDO rewardActivity = rewardActivityMapper.selectById(reqVO.getId()); // 获取最新的
         assertPojoEquals(reqVO, rewardActivity, "rules");
@@ -105,7 +113,7 @@ public class RewardActivityServiceImplTest extends BaseDbUnitTest {
         Long id = dbRewardActivity.getId();
 
         // 调用
-        rewardActivityService.closeRewardActivity(id);
+        rewardActivityServiceImpl.closeRewardActivity(id);
         // 校验状态
         RewardActivityDO rewardActivity = rewardActivityMapper.selectById(id);
         assertEquals(rewardActivity.getStatus(), CommonStatusEnum.DISABLE.getStatus());
@@ -117,7 +125,7 @@ public class RewardActivityServiceImplTest extends BaseDbUnitTest {
         RewardActivityUpdateReqVO reqVO = randomPojo(RewardActivityUpdateReqVO.class);
 
         // 调用, 并断言异常
-        assertServiceException(() -> rewardActivityService.updateRewardActivity(reqVO), REWARD_ACTIVITY_NOT_EXISTS);
+        assertServiceException(() -> rewardActivityServiceImpl.updateRewardActivity(reqVO), REWARD_ACTIVITY_NOT_EXISTS);
     }
 
     @Test
@@ -129,7 +137,7 @@ public class RewardActivityServiceImplTest extends BaseDbUnitTest {
         Long id = dbRewardActivity.getId();
 
         // 调用
-        rewardActivityService.deleteRewardActivity(id);
+        rewardActivityServiceImpl.deleteRewardActivity(id);
         // 校验数据不存在了
         assertNull(rewardActivityMapper.selectById(id));
     }
@@ -140,7 +148,7 @@ public class RewardActivityServiceImplTest extends BaseDbUnitTest {
         Long id = randomLongId();
 
         // 调用, 并断言异常
-        assertServiceException(() -> rewardActivityService.deleteRewardActivity(id), REWARD_ACTIVITY_NOT_EXISTS);
+        assertServiceException(() -> rewardActivityServiceImpl.deleteRewardActivity(id), REWARD_ACTIVITY_NOT_EXISTS);
     }
 
     @Test
@@ -161,7 +169,7 @@ public class RewardActivityServiceImplTest extends BaseDbUnitTest {
         reqVO.setStatus(CommonStatusEnum.DISABLE.getStatus());
 
         // 调用
-        PageResult<RewardActivityDO> pageResult = rewardActivityService.getRewardActivityPage(reqVO);
+        PageResult<RewardActivityDO> pageResult = rewardActivityServiceImpl.getRewardActivityPage(reqVO);
         // 断言
         assertEquals(1, pageResult.getTotal());
         assertEquals(1, pageResult.getList().size());
@@ -170,18 +178,22 @@ public class RewardActivityServiceImplTest extends BaseDbUnitTest {
 
     @Test
     public void testGetRewardActivities_all() {
+        LocalDateTime now = LocalDateTime.now();
         // mock 数据
         RewardActivityDO allActivity = randomPojo(RewardActivityDO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus())
-                .setProductScope(PromotionProductScopeEnum.ALL.getScope()));
+                .setProductScope(PromotionProductScopeEnum.ALL.getScope()).setStartTime(now.minusDays(1)).setEndTime(now.plusDays(1)));
         rewardActivityMapper.insert(allActivity);
         RewardActivityDO productActivity = randomPojo(RewardActivityDO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus())
-                .setProductScope(PromotionProductScopeEnum.SPU.getScope()).setProductScopeValues(asList(1L, 2L)));
+                .setProductScope(PromotionProductScopeEnum.SPU.getScope()).setProductScopeValues(asList(1L, 2L))
+                .setStartTime(now.minusDays(1)).setEndTime(now.plusDays(1)));
         rewardActivityMapper.insert(productActivity);
         // 准备参数
         Set<Long> spuIds = asSet(1L, 2L);
 
-        // 调用 TODO getMatchRewardActivities 没有这个方法,但是找到了 getMatchRewardActivityList
-        List<RewardActivityMatchRespDTO> matchRewardActivityList = rewardActivityService.getMatchRewardActivityList(spuIds);
+        // 调用
+        List<RewardActivityDO> activityList = rewardActivityServiceImpl.getRewardActivityListByStatusAndDateTimeLt(
+                CommonStatusEnum.ENABLE.getStatus(), now);
+        List<RewardActivityDO> matchRewardActivityList = filterMatchActivity(spuIds, activityList);
         // 断言
         assertEquals(matchRewardActivityList.size(), 1);
         matchRewardActivityList.forEach((activity) -> {
@@ -196,18 +208,22 @@ public class RewardActivityServiceImplTest extends BaseDbUnitTest {
 
     @Test
     public void testGetRewardActivities_product() {
+        LocalDateTime now = LocalDateTime.now();
         // mock 数据
         RewardActivityDO productActivity01 = randomPojo(RewardActivityDO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus())
-                .setProductScope(PromotionProductScopeEnum.SPU.getScope()).setProductScopeValues(asList(1L, 2L)));
+                .setProductScope(PromotionProductScopeEnum.SPU.getScope()).setProductScopeValues(asList(1L, 2L))
+                .setStartTime(now.minusDays(1)).setEndTime(now.plusDays(1)));
         rewardActivityMapper.insert(productActivity01);
         RewardActivityDO productActivity02 = randomPojo(RewardActivityDO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus())
-                .setProductScope(PromotionProductScopeEnum.SPU.getScope()).setProductScopeValues(singletonList(3L)));
+                .setProductScope(PromotionProductScopeEnum.SPU.getScope()).setProductScopeValues(singletonList(3L))
+                .setStartTime(now.minusDays(1)).setEndTime(now.plusDays(1)));
         rewardActivityMapper.insert(productActivity02);
         // 准备参数
         Set<Long> spuIds = asSet(1L, 2L, 3L);
 
-        // 调用  TODO getMatchRewardActivities 没有这个方法,但是找到了 getMatchRewardActivityList
-        List<RewardActivityMatchRespDTO> matchRewardActivityList = rewardActivityService.getMatchRewardActivityList(spuIds);
+        List<RewardActivityDO> activityList = rewardActivityServiceImpl.getRewardActivityListByStatusAndDateTimeLt(
+                CommonStatusEnum.ENABLE.getStatus(), now);
+        List<RewardActivityDO> matchRewardActivityList = filterMatchActivity(spuIds, activityList);
         // 断言
         assertEquals(matchRewardActivityList.size(), 2);
         matchRewardActivityList.forEach((activity) -> {
@@ -223,4 +239,27 @@ public class RewardActivityServiceImplTest extends BaseDbUnitTest {
         });
     }
 
+    /**
+     * 获得满减送的订单项(商品)列表
+     *
+     * @param spuIds       商品编号
+     * @param activityList 活动列表
+     * @return 订单项(商品)列表
+     */
+    private List<RewardActivityDO> filterMatchActivity(Collection<Long> spuIds, List<RewardActivityDO> activityList) {
+        List<RewardActivityDO> resultActivityList = new ArrayList<>();
+        for (RewardActivityDO activity : activityList) {
+            // 情况一:全部商品都可以参与
+            if (PromotionProductScopeEnum.isAll(activity.getProductScope())) {
+                resultActivityList.add(activity);
+            }
+            // 情况二:指定商品参与
+            if (PromotionProductScopeEnum.isSpu(activity.getProductScope()) &&
+                    !intersectionDistinct(activity.getProductScopeValues(), spuIds).isEmpty()) {
+                resultActivityList.add(activity);
+            }
+        }
+        return resultActivityList;
+    }
+
 }

+ 8 - 15
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeRewardActivityPriceCalculator.java

@@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.trade.service.price.calculator;
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.StrUtil;
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
 import cn.iocoder.yudao.framework.common.util.number.MoneyUtils;
 import cn.iocoder.yudao.module.promotion.api.reward.RewardActivityApi;
 import cn.iocoder.yudao.module.promotion.api.reward.dto.RewardActivityMatchRespDTO;
@@ -16,12 +17,12 @@ import jakarta.annotation.Resource;
 import org.springframework.core.annotation.Order;
 import org.springframework.stereotype.Component;
 
+import java.time.LocalDateTime;
 import java.util.ArrayList;
 import java.util.Comparator;
 import java.util.List;
 import java.util.Map;
 
-import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList;
 import static cn.iocoder.yudao.module.trade.service.price.calculator.TradePriceCalculatorHelper.formatPrice;
 
@@ -46,8 +47,8 @@ public class TradeRewardActivityPriceCalculator implements TradePriceCalculator
             return;
         }
         // 获得 SKU 对应的满减送活动
-        List<RewardActivityMatchRespDTO> rewardActivities = rewardActivityApi.getMatchRewardActivityList(
-                convertSet(result.getItems(), TradePriceCalculateRespBO.OrderItem::getSpuId));
+        List<RewardActivityMatchRespDTO> rewardActivities = rewardActivityApi.getRewardActivityListByStatusAndNow(
+                CommonStatusEnum.ENABLE.getStatus(), LocalDateTime.now());
         if (CollUtil.isEmpty(rewardActivities)) {
             return;
         }
@@ -109,16 +110,8 @@ public class TradeRewardActivityPriceCalculator implements TradePriceCalculator
         // 4.3 记录赠送的优惠券
         if (CollUtil.isNotEmpty(rule.getGiveCouponTemplateCounts())) {
             for (Map.Entry<Long, Integer> entry : rule.getGiveCouponTemplateCounts().entrySet()) {
-                Map<Long, Integer> giveCouponTemplateCounts = result.getGiveCouponTemplateCounts();
-                // TODO @puhui999:是不是有一种可能性,这个 key 没有,别的 key 有哈。
-                // TODO 这里还有一种简化的写法。就是下面,大概两行就可以啦
-//                result.getGiveCouponTemplateCounts().put(entry.getKey(),
-//                        result.getGiveCouponTemplateCounts().getOrDefault(entry.getKey(), 0) + entry.getValue());
-                if (giveCouponTemplateCounts.get(entry.getKey()) == null) { // 情况一:还没有赠送的优惠券
-                    result.setGiveCouponTemplateCounts(rule.getGiveCouponTemplateCounts());
-                } else { // 情况二:别的满减活动送过同类优惠券,则直接增加数量
-                    giveCouponTemplateCounts.put(entry.getKey(), giveCouponTemplateCounts.get(entry.getKey()) + entry.getValue());
-                }
+                result.getGiveCouponTemplateCounts().put(entry.getKey(),
+                        result.getGiveCouponTemplateCounts().getOrDefault(entry.getKey(), 0) + entry.getValue());
             }
         }
     }
@@ -126,7 +119,7 @@ public class TradeRewardActivityPriceCalculator implements TradePriceCalculator
     /**
      * 获得满减送的订单项(商品)列表
      *
-     * @param result 计算结果
+     * @param result         计算结果
      * @param rewardActivity 满减送活动
      * @return 订单项(商品)列表
      */
@@ -153,7 +146,7 @@ public class TradeRewardActivityPriceCalculator implements TradePriceCalculator
      * 获得最大匹配的满减送活动的规则
      *
      * @param rewardActivity 满减送活动
-     * @param orderItems 商品项
+     * @param orderItems     商品项
      * @return 匹配的活动规则
      */
     private RewardActivityMatchRespDTO.Rule getMaxMatchRewardActivityRule(RewardActivityMatchRespDTO rewardActivity,

+ 25 - 23
yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeRewardActivityPriceCalculatorTest.java

@@ -1,5 +1,6 @@
 package cn.iocoder.yudao.module.trade.service.price.calculator;
 
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
 import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
 import cn.iocoder.yudao.module.promotion.api.reward.RewardActivityApi;
 import cn.iocoder.yudao.module.promotion.api.reward.dto.RewardActivityMatchRespDTO;
@@ -13,15 +14,14 @@ import org.junit.jupiter.api.Test;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
 
+import java.time.LocalDateTime;
 import java.util.ArrayList;
 import java.util.LinkedHashMap;
 
-import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet;
 import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
 import static java.util.Arrays.asList;
 import static java.util.Collections.singletonList;
 import static org.junit.jupiter.api.Assertions.*;
-import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.when;
 
 /**
@@ -63,22 +63,23 @@ public class TradeRewardActivityPriceCalculatorTest extends BaseMockitoUnitTest
         TradePriceCalculatorHelper.recountAllPrice(result);
 
         // mock 方法(满减送 RewardActivity 信息)
-        when(rewardActivityApi.getMatchRewardActivityList(eq(asSet(1L, 2L, 3L)))).thenReturn(asList(
-                randomPojo(RewardActivityMatchRespDTO.class, o -> o.setId(1000L).setName("活动 1000 号")
-                        .setConditionType(PromotionConditionTypeEnum.PRICE.getType())
-                        .setProductScope(PromotionProductScopeEnum.SPU.getScope()).setProductScopeValues(asList(1L, 2L))
-                        .setRules(singletonList(new RewardActivityMatchRespDTO.Rule().setLimit(20).setDiscountPrice(70)
-                                .setFreeDelivery(false)))),
-                randomPojo(RewardActivityMatchRespDTO.class, o -> o.setId(2000L).setName("活动 2000 号")
-                        .setConditionType(PromotionConditionTypeEnum.COUNT.getType())
-                        .setProductScope(PromotionProductScopeEnum.SPU.getScope()).setProductScopeValues(singletonList(3L))
-                        .setRules(asList(new RewardActivityMatchRespDTO.Rule().setLimit(1).setDiscountPrice(10)
-                                        .setPoint(50).setFreeDelivery(false),
-                                new RewardActivityMatchRespDTO.Rule().setLimit(2).setDiscountPrice(60)
-                                        .setPoint(100).setFreeDelivery(false), // 最大可满足,因为是 4 个
-                                new RewardActivityMatchRespDTO.Rule().setLimit(10).setDiscountPrice(100)
-                                        .setFreeDelivery(false))))
-        ));
+        when(rewardActivityApi.getRewardActivityListByStatusAndNow(CommonStatusEnum.ENABLE.getStatus(), LocalDateTime.now()))
+                .thenReturn(asList(
+                        randomPojo(RewardActivityMatchRespDTO.class, o -> o.setId(1000L).setName("活动 1000 号")
+                                .setConditionType(PromotionConditionTypeEnum.PRICE.getType())
+                                .setProductScope(PromotionProductScopeEnum.SPU.getScope()).setProductScopeValues(asList(1L, 2L))
+                                .setRules(singletonList(new RewardActivityMatchRespDTO.Rule().setLimit(20).setDiscountPrice(70)
+                                        .setFreeDelivery(false)))),
+                        randomPojo(RewardActivityMatchRespDTO.class, o -> o.setId(2000L).setName("活动 2000 号")
+                                .setConditionType(PromotionConditionTypeEnum.COUNT.getType())
+                                .setProductScope(PromotionProductScopeEnum.SPU.getScope()).setProductScopeValues(singletonList(3L))
+                                .setRules(asList(new RewardActivityMatchRespDTO.Rule().setLimit(1).setDiscountPrice(10)
+                                                .setPoint(50).setFreeDelivery(false),
+                                        new RewardActivityMatchRespDTO.Rule().setLimit(2).setDiscountPrice(60)
+                                                .setPoint(100).setFreeDelivery(false), // 最大可满足,因为是 4 个
+                                        new RewardActivityMatchRespDTO.Rule().setLimit(10).setDiscountPrice(100)
+                                                .setFreeDelivery(false))))
+                ));
 
         // 调用
         tradeRewardActivityPriceCalculator.calculate(param, result);
@@ -184,11 +185,12 @@ public class TradeRewardActivityPriceCalculatorTest extends BaseMockitoUnitTest
         TradePriceCalculatorHelper.recountAllPrice(result);
 
         // mock 方法(限时折扣 DiscountActivity 信息)
-        when(rewardActivityApi.getMatchRewardActivityList(eq(asSet(1L, 2L)))).thenReturn(singletonList(
-                randomPojo(RewardActivityMatchRespDTO.class, o -> o.setId(1000L).setName("活动 1000 号")
-                        .setProductScopeValues(asList(1L, 2L)).setConditionType(PromotionConditionTypeEnum.PRICE.getType())
-                        .setRules(singletonList(new RewardActivityMatchRespDTO.Rule().setLimit(351).setDiscountPrice(70))))
-        ));
+        when(rewardActivityApi.getRewardActivityListByStatusAndNow(CommonStatusEnum.ENABLE.getStatus(), LocalDateTime.now()))
+                .thenReturn(singletonList(
+                        randomPojo(RewardActivityMatchRespDTO.class, o -> o.setId(1000L).setName("活动 1000 号")
+                                .setProductScopeValues(asList(1L, 2L)).setConditionType(PromotionConditionTypeEnum.PRICE.getType())
+                                .setRules(singletonList(new RewardActivityMatchRespDTO.Rule().setLimit(351).setDiscountPrice(70))))
+                ));
 
         // 调用
         tradeRewardActivityPriceCalculator.calculate(param, result);