Commit c4943e97c7b447d75776cd6c1d50023236d243f2
Committed by
Gitee
!1057 完善满减送活动 CRUD 部分
Merge pull request !1057 from puhui999/develop
Showing
17 changed files
with
248 additions
and
193 deletions
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/reward/dto/RewardActivityMatchRespDTO.java
| 1 | 1 | package cn.iocoder.yudao.module.promotion.api.reward.dto; |
| 2 | 2 | |
| 3 | +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | |
| 3 | 4 | import cn.iocoder.yudao.module.promotion.enums.common.PromotionConditionTypeEnum; |
| 5 | +import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum; | |
| 4 | 6 | import lombok.Data; |
| 5 | 7 | |
| 8 | +import java.io.Serializable; | |
| 9 | +import java.time.LocalDateTime; | |
| 6 | 10 | import java.util.List; |
| 7 | 11 | |
| 8 | 12 | /** |
| ... | ... | @@ -22,27 +26,49 @@ public class RewardActivityMatchRespDTO { |
| 22 | 26 | */ |
| 23 | 27 | private String name; |
| 24 | 28 | /** |
| 29 | + * 状态 | |
| 30 | + * | |
| 31 | + * 枚举 {@link CommonStatusEnum} | |
| 32 | + */ | |
| 33 | + private Integer status; | |
| 34 | + /** | |
| 35 | + * 开始时间 | |
| 36 | + */ | |
| 37 | + private LocalDateTime startTime; | |
| 38 | + /** | |
| 39 | + * 结束时间 | |
| 40 | + */ | |
| 41 | + private LocalDateTime endTime; | |
| 42 | + /** | |
| 43 | + * 备注 | |
| 44 | + */ | |
| 45 | + private String remark; | |
| 46 | + /** | |
| 25 | 47 | * 条件类型 |
| 26 | 48 | * |
| 27 | 49 | * 枚举 {@link PromotionConditionTypeEnum} |
| 28 | 50 | */ |
| 29 | 51 | private Integer conditionType; |
| 30 | 52 | /** |
| 31 | - * 优惠规则的数组 | |
| 53 | + * 商品范围 | |
| 54 | + * | |
| 55 | + * 枚举 {@link PromotionProductScopeEnum} | |
| 32 | 56 | */ |
| 33 | - private List<Rule> rules; | |
| 34 | - | |
| 57 | + private Integer productScope; | |
| 35 | 58 | /** |
| 36 | 59 | * 商品 SPU 编号的数组 |
| 37 | 60 | */ |
| 38 | - private List<Long> spuIds; | |
| 61 | + private List<Long> productScopeValues; | |
| 62 | + /** | |
| 63 | + * 优惠规则的数组 | |
| 64 | + */ | |
| 65 | + private List<Rule> rules; | |
| 39 | 66 | |
| 40 | - // TODO 芋艿:后面 RewardActivityRespDTO 有了之后,Rule 可以放过去 | |
| 41 | 67 | /** |
| 42 | 68 | * 优惠规则 |
| 43 | 69 | */ |
| 44 | 70 | @Data |
| 45 | - public static class Rule { | |
| 71 | + public static class Rule implements Serializable { | |
| 46 | 72 | |
| 47 | 73 | /** |
| 48 | 74 | * 优惠门槛 |
| ... | ... | @@ -60,10 +86,18 @@ public class RewardActivityMatchRespDTO { |
| 60 | 86 | */ |
| 61 | 87 | private Boolean freeDelivery; |
| 62 | 88 | /** |
| 89 | + * 是否赠送积分 | |
| 90 | + */ | |
| 91 | + private Boolean givePoint; | |
| 92 | + /** | |
| 63 | 93 | * 赠送的积分 |
| 64 | 94 | */ |
| 65 | 95 | private Integer point; |
| 66 | 96 | /** |
| 97 | + * 是否赠送优惠券 | |
| 98 | + */ | |
| 99 | + private Boolean giveCoupon; | |
| 100 | + /** | |
| 67 | 101 | * 赠送的优惠劵编号的数组 |
| 68 | 102 | */ |
| 69 | 103 | private List<Long> couponIds; | ... | ... |
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java
| ... | ... | @@ -44,7 +44,8 @@ public interface ErrorCodeConstants { |
| 44 | 44 | ErrorCode REWARD_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED = new ErrorCode(1_013_006_002, "满减送活动已关闭,不能修改"); |
| 45 | 45 | ErrorCode REWARD_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED = new ErrorCode(1_013_006_003, "满减送活动未关闭,不能删除"); |
| 46 | 46 | ErrorCode REWARD_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED = new ErrorCode(1_013_006_004, "满减送活动已关闭,不能重复关闭"); |
| 47 | - ErrorCode REWARD_ACTIVITY_CLOSE_FAIL_STATUS_END = new ErrorCode(1_013_006_005, "满减送活动已结束,不能关闭"); | |
| 47 | + ErrorCode REWARD_ACTIVITY_SCOPE_ALL_EXISTS = new ErrorCode(1_013_006_005, "已存在商品范围为全场的满减送活动"); | |
| 48 | + ErrorCode REWARD_ACTIVITY_SCOPE_CATEGORY_EXISTS = new ErrorCode(1_013_006_006, "存在商品类型参加了其它满减送活动"); | |
| 48 | 49 | |
| 49 | 50 | // ========== TODO 空着 1-013-007-000 ============ |
| 50 | 51 | ... | ... |
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/common/PromotionProductScopeEnum.java
| 1 | 1 | package cn.iocoder.yudao.module.promotion.enums.common; |
| 2 | 2 | |
| 3 | +import cn.hutool.core.util.ObjUtil; | |
| 3 | 4 | import cn.iocoder.yudao.framework.common.core.IntArrayValuable; |
| 4 | 5 | import lombok.AllArgsConstructor; |
| 5 | 6 | import lombok.Getter; |
| ... | ... | @@ -35,4 +36,16 @@ public enum PromotionProductScopeEnum implements IntArrayValuable { |
| 35 | 36 | return ARRAYS; |
| 36 | 37 | } |
| 37 | 38 | |
| 39 | + public static boolean isAll(Integer scope) { | |
| 40 | + return ObjUtil.equal(scope, ALL.scope); | |
| 41 | + } | |
| 42 | + | |
| 43 | + public static boolean isSpu(Integer scope) { | |
| 44 | + return ObjUtil.equal(scope, SPU.scope); | |
| 45 | + } | |
| 46 | + | |
| 47 | + public static boolean isCategory(Integer scope) { | |
| 48 | + return ObjUtil.equal(scope, CATEGORY.scope); | |
| 49 | + } | |
| 50 | + | |
| 38 | 51 | } | ... | ... |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/activity/AppActivityController.java
| ... | ... | @@ -2,14 +2,19 @@ package cn.iocoder.yudao.module.promotion.controller.app.activity; |
| 2 | 2 | |
| 3 | 3 | import cn.hutool.core.collection.CollUtil; |
| 4 | 4 | import cn.hutool.core.map.MapUtil; |
| 5 | +import cn.hutool.core.util.ObjUtil; | |
| 5 | 6 | import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; |
| 6 | 7 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 8 | +import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi; | |
| 9 | +import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; | |
| 7 | 10 | import cn.iocoder.yudao.module.promotion.controller.app.activity.vo.AppActivityRespVO; |
| 8 | 11 | import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainActivityDO; |
| 9 | 12 | import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO; |
| 10 | 13 | import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountActivityDO; |
| 11 | 14 | import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO; |
| 15 | +import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO; | |
| 12 | 16 | import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillActivityDO; |
| 17 | +import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum; | |
| 13 | 18 | import cn.iocoder.yudao.module.promotion.enums.common.PromotionTypeEnum; |
| 14 | 19 | import cn.iocoder.yudao.module.promotion.service.bargain.BargainActivityService; |
| 15 | 20 | import cn.iocoder.yudao.module.promotion.service.combination.CombinationActivityService; |
| ... | ... | @@ -48,6 +53,8 @@ public class AppActivityController { |
| 48 | 53 | private DiscountActivityService discountActivityService; |
| 49 | 54 | @Resource |
| 50 | 55 | private RewardActivityService rewardActivityService; |
| 56 | + @Resource | |
| 57 | + private ProductSpuApi productSpuApi; | |
| 51 | 58 | |
| 52 | 59 | @GetMapping("/list-by-spu-id") |
| 53 | 60 | @Operation(summary = "获得单个商品,近期参与的每个活动") |
| ... | ... | @@ -141,29 +148,52 @@ public class AppActivityController { |
| 141 | 148 | item.getName(), productMap.get(item.getId()), item.getStartTime(), item.getEndTime()))); |
| 142 | 149 | } |
| 143 | 150 | |
| 151 | + private static void buildAppActivityRespVO(RewardActivityDO rewardActivity, Collection<Long> spuIds, | |
| 152 | + List<AppActivityRespVO> activityList) { | |
| 153 | + for (Long spuId : spuIds) { | |
| 154 | + // 校验商品是否已经加入过活动 | |
| 155 | + if (anyMatch(activityList, appActivity -> ObjUtil.equal(appActivity.getId(), rewardActivity.getId()) && | |
| 156 | + ObjUtil.equal(appActivity.getSpuId(), spuId))) { | |
| 157 | + continue; | |
| 158 | + } | |
| 159 | + activityList.add(new AppActivityRespVO(rewardActivity.getId(), | |
| 160 | + PromotionTypeEnum.REWARD_ACTIVITY.getType(), rewardActivity.getName(), spuId, | |
| 161 | + rewardActivity.getStartTime(), rewardActivity.getEndTime())); | |
| 162 | + } | |
| 163 | + } | |
| 164 | + | |
| 144 | 165 | private void getRewardActivities(Collection<Long> spuIds, LocalDateTime now, List<AppActivityRespVO> activityList) { |
| 145 | - // TODO @puhui999:有 3 范围,不只 spuId,还有 categoryId,全部,下次 fix | |
| 146 | - //List<RewardActivityDO> rewardActivityList = rewardActivityService.getRewardActivityBySpuIdsAndStatusAndDateTimeLt( | |
| 147 | - // spuIds, PromotionActivityStatusEnum.RUN.getStatus(), now); | |
| 148 | - //if (CollUtil.isEmpty(rewardActivityList)) { | |
| 149 | - // return; | |
| 150 | - //} | |
| 151 | - // | |
| 152 | - //Map<Long, Optional<RewardActivityDO>> spuIdAndActivityMap = spuIds.stream() | |
| 153 | - // .collect(Collectors.toMap( | |
| 154 | - // spuId -> spuId, | |
| 155 | - // spuId -> rewardActivityList.stream() | |
| 156 | - // .filter(activity -> activity.getProductSpuIds().contains(spuId)) | |
| 157 | - // .max(Comparator.comparing(RewardActivityDO::getCreateTime)))); | |
| 158 | - //for (Long supId : spuIdAndActivityMap.keySet()) { | |
| 159 | - // if (spuIdAndActivityMap.get(supId).isEmpty()) { | |
| 160 | - // continue; | |
| 161 | - // } | |
| 162 | - // | |
| 163 | - // RewardActivityDO rewardActivityDO = spuIdAndActivityMap.get(supId).get(); | |
| 164 | - // activityList.add(new AppActivityRespVO(rewardActivityDO.getId(), PromotionTypeEnum.REWARD_ACTIVITY.getType(), | |
| 165 | - // rewardActivityDO.getName(), supId, rewardActivityDO.getStartTime(), rewardActivityDO.getEndTime())); | |
| 166 | - //} | |
| 166 | + // 1.1 获得所有的活动 | |
| 167 | + List<RewardActivityDO> rewardActivityList = rewardActivityService.getRewardActivityByStatusAndDateTimeLt( | |
| 168 | + CommonStatusEnum.ENABLE.getStatus(), now); | |
| 169 | + if (CollUtil.isEmpty(rewardActivityList)) { | |
| 170 | + return; | |
| 171 | + } | |
| 172 | + // 1.2 获得所有的商品信息 | |
| 173 | + List<ProductSpuRespDTO> spuList = productSpuApi.getSpuList(spuIds); | |
| 174 | + if (CollUtil.isEmpty(spuList)) { | |
| 175 | + return; | |
| 176 | + } | |
| 177 | + | |
| 178 | + // 2. 构建活动 | |
| 179 | + for (RewardActivityDO rewardActivity : rewardActivityList) { | |
| 180 | + // 情况一:所有商品都能参加 | |
| 181 | + if (PromotionProductScopeEnum.isAll(rewardActivity.getProductScope())) { | |
| 182 | + buildAppActivityRespVO(rewardActivity, spuIds, activityList); | |
| 183 | + } | |
| 184 | + // 情况二:指定商品参加 | |
| 185 | + if (PromotionProductScopeEnum.isSpu(rewardActivity.getProductScope())) { | |
| 186 | + List<Long> fSpuIds = spuList.stream().map(ProductSpuRespDTO::getId).filter(id -> | |
| 187 | + rewardActivity.getProductScopeValues().contains(id)).toList(); | |
| 188 | + buildAppActivityRespVO(rewardActivity, fSpuIds, activityList); | |
| 189 | + } | |
| 190 | + // 情况三:指定商品类型参加 | |
| 191 | + if (PromotionProductScopeEnum.isCategory(rewardActivity.getProductScope())) { | |
| 192 | + List<Long> fSpuIds = spuList.stream().filter(spuItem -> rewardActivity.getProductScopeValues() | |
| 193 | + .contains(spuItem.getCategoryId())).map(ProductSpuRespDTO::getId).toList(); | |
| 194 | + buildAppActivityRespVO(rewardActivity, fSpuIds, activityList); | |
| 195 | + } | |
| 196 | + } | |
| 167 | 197 | } |
| 168 | 198 | |
| 169 | 199 | } | ... | ... |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/reward/RewardActivityDO.java
| 1 | 1 | package cn.iocoder.yudao.module.promotion.dal.dataobject.reward; |
| 2 | 2 | |
| 3 | +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | |
| 3 | 4 | import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; |
| 4 | 5 | import cn.iocoder.yudao.framework.mybatis.core.type.LongListTypeHandler; |
| 5 | -import cn.iocoder.yudao.module.promotion.enums.common.PromotionActivityStatusEnum; | |
| 6 | 6 | import cn.iocoder.yudao.module.promotion.enums.common.PromotionConditionTypeEnum; |
| 7 | 7 | import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum; |
| 8 | 8 | import com.baomidou.mybatisplus.annotation.KeySequence; |
| ... | ... | @@ -40,7 +40,7 @@ public class RewardActivityDO extends BaseDO { |
| 40 | 40 | /** |
| 41 | 41 | * 状态 |
| 42 | 42 | * |
| 43 | - * 枚举 {@link PromotionActivityStatusEnum} | |
| 43 | + * 枚举 {@link CommonStatusEnum} | |
| 44 | 44 | */ |
| 45 | 45 | private Integer status; |
| 46 | 46 | /** | ... | ... |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/reward/RewardActivityMapper.java
| ... | ... | @@ -30,10 +30,6 @@ public interface RewardActivityMapper extends BaseMapperX<RewardActivityDO> { |
| 30 | 30 | .orderByDesc(RewardActivityDO::getId)); |
| 31 | 31 | } |
| 32 | 32 | |
| 33 | - default List<RewardActivityDO> selectListByStatus(Collection<Integer> statuses) { | |
| 34 | - return selectList(RewardActivityDO::getStatus, statuses); | |
| 35 | - } | |
| 36 | - | |
| 37 | 33 | default List<RewardActivityDO> selectListByProductScopeAndStatus(Integer productScope, Integer status) { |
| 38 | 34 | return selectList(new LambdaQueryWrapperX<RewardActivityDO>() |
| 39 | 35 | .eq(RewardActivityDO::getProductScope, productScope) |
| ... | ... | @@ -53,16 +49,16 @@ public interface RewardActivityMapper extends BaseMapperX<RewardActivityDO> { |
| 53 | 49 | * 获取指定活动编号的活动列表且 |
| 54 | 50 | * 开始时间和结束时间小于给定时间 dateTime 的活动列表 |
| 55 | 51 | * |
| 56 | - * @param ids 活动编号 | |
| 52 | + * @param status 状态 | |
| 57 | 53 | * @param dateTime 指定日期 |
| 58 | 54 | * @return 活动列表 |
| 59 | 55 | */ |
| 60 | - default List<RewardActivityDO> selectListByIdsAndDateTimeLt(Collection<Long> ids, LocalDateTime dateTime) { | |
| 56 | + default List<RewardActivityDO> selectListByStatusAndDateTimeLt(Integer status, LocalDateTime dateTime) { | |
| 61 | 57 | return selectList(new LambdaQueryWrapperX<RewardActivityDO>() |
| 62 | - .in(RewardActivityDO::getId, ids) | |
| 58 | + .eq(RewardActivityDO::getStatus, status) | |
| 63 | 59 | .lt(RewardActivityDO::getStartTime, dateTime) |
| 64 | 60 | .gt(RewardActivityDO::getEndTime, dateTime)// 开始时间 < 指定时间 < 结束时间,也就是说获取指定时间段的活动 |
| 65 | - .orderByDesc(RewardActivityDO::getCreateTime) | |
| 61 | + .orderByAsc(RewardActivityDO::getStartTime) | |
| 66 | 62 | ); |
| 67 | 63 | } |
| 68 | 64 | ... | ... |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationRecordServiceImpl.java
| ... | ... | @@ -27,6 +27,7 @@ import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStat |
| 27 | 27 | import cn.iocoder.yudao.module.system.api.social.SocialClientApi; |
| 28 | 28 | import cn.iocoder.yudao.module.system.api.social.dto.SocialWxaSubscribeMessageSendReqDTO; |
| 29 | 29 | import cn.iocoder.yudao.module.trade.api.order.TradeOrderApi; |
| 30 | +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderCancelTypeEnum; | |
| 30 | 31 | import jakarta.annotation.Nullable; |
| 31 | 32 | import jakarta.annotation.Resource; |
| 32 | 33 | import lombok.extern.slf4j.Slf4j; |
| ... | ... | @@ -37,7 +38,10 @@ import org.springframework.transaction.annotation.Transactional; |
| 37 | 38 | import org.springframework.validation.annotation.Validated; |
| 38 | 39 | |
| 39 | 40 | import java.time.LocalDateTime; |
| 40 | -import java.util.*; | |
| 41 | +import java.util.ArrayList; | |
| 42 | +import java.util.Collection; | |
| 43 | +import java.util.List; | |
| 44 | +import java.util.Map; | |
| 41 | 45 | |
| 42 | 46 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| 43 | 47 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; |
| ... | ... | @@ -335,7 +339,8 @@ public class CombinationRecordServiceImpl implements CombinationRecordService { |
| 335 | 339 | List<CombinationRecordDO> headAndRecords = updateBatchCombinationRecords(headRecord, |
| 336 | 340 | CombinationRecordStatusEnum.FAILED); |
| 337 | 341 | // 2. 订单取消 |
| 338 | - headAndRecords.forEach(item -> tradeOrderApi.cancelPaidOrder(item.getUserId(), item.getOrderId())); | |
| 342 | + headAndRecords.forEach(item -> tradeOrderApi.cancelPaidOrder(item.getUserId(), item.getOrderId(), | |
| 343 | + TradeOrderCancelTypeEnum.COMBINATION_CLOSE)); | |
| 339 | 344 | } |
| 340 | 345 | |
| 341 | 346 | /** | ... | ... |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/reward/RewardActivityService.java
| ... | ... | @@ -75,11 +75,10 @@ public interface RewardActivityService { |
| 75 | 75 | /** |
| 76 | 76 | * 获取指定 spu 编号最近参加的活动,每个 spuId 只返回一条记录 |
| 77 | 77 | * |
| 78 | - * @param spuIds spu 编号 | |
| 79 | 78 | * @param status 状态 |
| 80 | 79 | * @param dateTime 当前日期时间 |
| 81 | 80 | * @return 满减送活动列表 |
| 82 | 81 | */ |
| 83 | - List<RewardActivityDO> getRewardActivityBySpuIdsAndStatusAndDateTimeLt(Collection<Long> spuIds, Integer status, LocalDateTime dateTime); | |
| 82 | + List<RewardActivityDO> getRewardActivityByStatusAndDateTimeLt(Integer status, LocalDateTime dateTime); | |
| 84 | 83 | |
| 85 | 84 | } | ... | ... |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/reward/RewardActivityServiceImpl.java
| 1 | 1 | package cn.iocoder.yudao.module.promotion.service.reward; |
| 2 | 2 | |
| 3 | -import cn.hutool.core.collection.CollUtil; | |
| 3 | +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | |
| 4 | 4 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 5 | +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | |
| 5 | 6 | import cn.iocoder.yudao.module.product.api.category.ProductCategoryApi; |
| 6 | 7 | import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi; |
| 7 | 8 | import cn.iocoder.yudao.module.promotion.api.reward.dto.RewardActivityMatchRespDTO; |
| 9 | +import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityBaseVO; | |
| 8 | 10 | import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityCreateReqVO; |
| 9 | 11 | import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityPageReqVO; |
| 10 | 12 | import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityUpdateReqVO; |
| 11 | 13 | import cn.iocoder.yudao.module.promotion.convert.reward.RewardActivityConvert; |
| 12 | 14 | import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO; |
| 13 | 15 | import cn.iocoder.yudao.module.promotion.dal.mysql.reward.RewardActivityMapper; |
| 14 | -import cn.iocoder.yudao.module.promotion.enums.common.PromotionActivityStatusEnum; | |
| 15 | 16 | import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum; |
| 16 | 17 | import cn.iocoder.yudao.module.promotion.util.PromotionUtils; |
| 17 | 18 | import jakarta.annotation.Resource; |
| ... | ... | @@ -20,14 +21,13 @@ import org.springframework.validation.annotation.Validated; |
| 20 | 21 | |
| 21 | 22 | import java.time.LocalDateTime; |
| 22 | 23 | import java.util.Collection; |
| 23 | -import java.util.Collections; | |
| 24 | 24 | import java.util.List; |
| 25 | 25 | import java.util.Objects; |
| 26 | 26 | |
| 27 | +import static cn.hutool.core.collection.CollUtil.intersectionDistinct; | |
| 27 | 28 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| 28 | -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; | |
| 29 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.anyMatch; | |
| 29 | 30 | import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*; |
| 30 | -import static java.util.Arrays.asList; | |
| 31 | 31 | |
| 32 | 32 | /** |
| 33 | 33 | * 满减送活动 Service 实现类 |
| ... | ... | @@ -51,7 +51,7 @@ public class RewardActivityServiceImpl implements RewardActivityService { |
| 51 | 51 | // 1.1 校验商品范围 |
| 52 | 52 | validateProductScope(createReqVO.getProductScope(), createReqVO.getProductScopeValues()); |
| 53 | 53 | // 1.2 校验商品是否冲突 |
| 54 | - //validateRewardActivitySpuConflicts(null, createReqVO.getProductSpuIds()); | |
| 54 | + validateRewardActivitySpuConflicts(null, createReqVO); | |
| 55 | 55 | |
| 56 | 56 | // 2. 插入 |
| 57 | 57 | RewardActivityDO rewardActivity = RewardActivityConvert.INSTANCE.convert(createReqVO) |
| ... | ... | @@ -65,13 +65,13 @@ public class RewardActivityServiceImpl implements RewardActivityService { |
| 65 | 65 | public void updateRewardActivity(RewardActivityUpdateReqVO updateReqVO) { |
| 66 | 66 | // 1.1 校验存在 |
| 67 | 67 | RewardActivityDO dbRewardActivity = validateRewardActivityExists(updateReqVO.getId()); |
| 68 | - if (dbRewardActivity.getStatus().equals(PromotionActivityStatusEnum.CLOSE.getStatus())) { // 已关闭的活动,不能修改噢 | |
| 68 | + if (dbRewardActivity.getStatus().equals(CommonStatusEnum.DISABLE.getStatus())) { // 已关闭的活动,不能修改噢 | |
| 69 | 69 | throw exception(REWARD_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED); |
| 70 | 70 | } |
| 71 | 71 | // 1.2 校验商品范围 |
| 72 | 72 | validateProductScope(updateReqVO.getProductScope(), updateReqVO.getProductScopeValues()); |
| 73 | 73 | // 1.3 校验商品是否冲突 |
| 74 | - //validateRewardActivitySpuConflicts(updateReqVO.getId(), updateReqVO.getProductSpuIds()); | |
| 74 | + validateRewardActivitySpuConflicts(updateReqVO.getId(), updateReqVO); | |
| 75 | 75 | |
| 76 | 76 | // 2. 更新 |
| 77 | 77 | RewardActivityDO updateObj = RewardActivityConvert.INSTANCE.convert(updateReqVO) |
| ... | ... | @@ -82,17 +82,13 @@ public class RewardActivityServiceImpl implements RewardActivityService { |
| 82 | 82 | @Override |
| 83 | 83 | public void closeRewardActivity(Long id) { |
| 84 | 84 | // 校验存在 |
| 85 | - // TODO @puhui999:去掉 PromotionActivityStatusEnum,使用 CommonStatus 作为状态哈。开启,关闭 | |
| 86 | 85 | RewardActivityDO dbRewardActivity = validateRewardActivityExists(id); |
| 87 | - if (dbRewardActivity.getStatus().equals(PromotionActivityStatusEnum.CLOSE.getStatus())) { // 已关闭的活动,不能关闭噢 | |
| 86 | + if (dbRewardActivity.getStatus().equals(CommonStatusEnum.DISABLE.getStatus())) { // 已关闭的活动,不能关闭噢 | |
| 88 | 87 | throw exception(REWARD_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED); |
| 89 | 88 | } |
| 90 | - if (dbRewardActivity.getStatus().equals(PromotionActivityStatusEnum.END.getStatus())) { // 已关闭的活动,不能关闭噢 | |
| 91 | - throw exception(REWARD_ACTIVITY_CLOSE_FAIL_STATUS_END); | |
| 92 | - } | |
| 93 | 89 | |
| 94 | 90 | // 更新 |
| 95 | - RewardActivityDO updateObj = new RewardActivityDO().setId(id).setStatus(PromotionActivityStatusEnum.CLOSE.getStatus()); | |
| 91 | + RewardActivityDO updateObj = new RewardActivityDO().setId(id).setStatus(CommonStatusEnum.DISABLE.getStatus()); | |
| 96 | 92 | rewardActivityMapper.updateById(updateObj); |
| 97 | 93 | } |
| 98 | 94 | |
| ... | ... | @@ -100,7 +96,7 @@ public class RewardActivityServiceImpl implements RewardActivityService { |
| 100 | 96 | public void deleteRewardActivity(Long id) { |
| 101 | 97 | // 校验存在 |
| 102 | 98 | RewardActivityDO dbRewardActivity = validateRewardActivityExists(id); |
| 103 | - if (!dbRewardActivity.getStatus().equals(PromotionActivityStatusEnum.CLOSE.getStatus())) { // 未关闭的活动,不能删除噢 | |
| 99 | + if (dbRewardActivity.getStatus().equals(CommonStatusEnum.ENABLE.getStatus())) { // 未关闭的活动,不能删除噢 | |
| 104 | 100 | throw exception(REWARD_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED); |
| 105 | 101 | } |
| 106 | 102 | |
| ... | ... | @@ -116,27 +112,30 @@ public class RewardActivityServiceImpl implements RewardActivityService { |
| 116 | 112 | return activity; |
| 117 | 113 | } |
| 118 | 114 | |
| 119 | - // TODO @芋艿:逻辑有问题,需要优化;要分成全场、和指定来校验; | |
| 120 | - // TODO @puhui999: 下次提交 fix | |
| 121 | 115 | /** |
| 122 | 116 | * 校验商品参加的活动是否冲突 |
| 123 | 117 | * |
| 124 | - * @param id 活动编号 | |
| 125 | - * @param spuIds 商品 SPU 编号数组 | |
| 118 | + * @param id 活动编号 | |
| 119 | + * @param rewardActivity 请求 | |
| 126 | 120 | */ |
| 127 | - private void validateRewardActivitySpuConflicts(Long id, Collection<Long> spuIds) { | |
| 128 | - if (CollUtil.isEmpty(spuIds)) { | |
| 129 | - return; | |
| 130 | - } | |
| 131 | - // 查询商品参加的活动 | |
| 132 | - List<RewardActivityDO> rewardActivityList = getRewardActivityListBySpuIds(spuIds, | |
| 133 | - asList(PromotionActivityStatusEnum.WAIT.getStatus(), PromotionActivityStatusEnum.RUN.getStatus())); | |
| 121 | + private void validateRewardActivitySpuConflicts(Long id, RewardActivityBaseVO rewardActivity) { | |
| 122 | + List<RewardActivityDO> list = rewardActivityMapper.selectList(RewardActivityDO::getProductScope, | |
| 123 | + rewardActivity.getProductScope(), RewardActivityDO::getStatus, CommonStatusEnum.ENABLE.getStatus()); | |
| 134 | 124 | if (id != null) { // 排除自己这个活动 |
| 135 | - rewardActivityList.removeIf(activity -> id.equals(activity.getId())); | |
| 125 | + list.removeIf(activity -> id.equals(activity.getId())); | |
| 126 | + } | |
| 127 | + | |
| 128 | + // 情况一:全部商品参加 | |
| 129 | + if (PromotionProductScopeEnum.isAll(rewardActivity.getProductScope()) && !list.isEmpty()) { | |
| 130 | + throw exception(REWARD_ACTIVITY_SCOPE_ALL_EXISTS); | |
| 136 | 131 | } |
| 137 | - // 如果非空,则说明冲突 | |
| 138 | - if (CollUtil.isNotEmpty(rewardActivityList)) { | |
| 139 | - throw exception(REWARD_ACTIVITY_SPU_CONFLICTS); | |
| 132 | + if (PromotionProductScopeEnum.isSpu(rewardActivity.getProductScope()) || // 情况二:指定商品参加 | |
| 133 | + PromotionProductScopeEnum.isCategory(rewardActivity.getProductScope())) { // 情况三:指定商品类型参加 | |
| 134 | + if (anyMatch(list, item -> !intersectionDistinct(item.getProductScopeValues(), | |
| 135 | + rewardActivity.getProductScopeValues()).isEmpty())) { | |
| 136 | + throw exception(PromotionProductScopeEnum.isSpu(rewardActivity.getProductScope()) ? | |
| 137 | + REWARD_ACTIVITY_SPU_CONFLICTS : REWARD_ACTIVITY_SCOPE_CATEGORY_EXISTS); | |
| 138 | + } | |
| 140 | 139 | } |
| 141 | 140 | } |
| 142 | 141 | |
| ... | ... | @@ -148,21 +147,6 @@ public class RewardActivityServiceImpl implements RewardActivityService { |
| 148 | 147 | } |
| 149 | 148 | } |
| 150 | 149 | |
| 151 | - /** | |
| 152 | - * 获得商品参加的满减送活动的数组 | |
| 153 | - * | |
| 154 | - * @param spuIds 商品 SPU 编号数组 | |
| 155 | - * @param statuses 活动状态数组 | |
| 156 | - * @return 商品参加的满减送活动的数组 | |
| 157 | - */ | |
| 158 | - private List<RewardActivityDO> getRewardActivityListBySpuIds(Collection<Long> spuIds, | |
| 159 | - Collection<Integer> statuses) { | |
| 160 | - // TODO @puhui999: 下次 fix | |
| 161 | - //List<RewardActivityDO> list = rewardActivityMapper.selectListByStatus(statuses); | |
| 162 | - //return CollUtil.filter(list, activity -> CollUtil.containsAny(activity.getProductSpuIds(), spuIds)); | |
| 163 | - return List.of(); | |
| 164 | - } | |
| 165 | - | |
| 166 | 150 | @Override |
| 167 | 151 | public RewardActivityDO getRewardActivity(Long id) { |
| 168 | 152 | return rewardActivityMapper.selectById(id); |
| ... | ... | @@ -176,31 +160,13 @@ public class RewardActivityServiceImpl implements RewardActivityService { |
| 176 | 160 | @Override |
| 177 | 161 | public List<RewardActivityMatchRespDTO> getMatchRewardActivityList(Collection<Long> spuIds) { |
| 178 | 162 | // TODO 芋艿:待实现;先指定,然后再全局的; |
| 179 | -// // 如果有全局活动,则直接选择它 | |
| 180 | -// List<RewardActivityDO> allActivities = rewardActivityMapper.selectListByProductScopeAndStatus( | |
| 181 | -// PromotionProductScopeEnum.ALL.getScope(), PromotionActivityStatusEnum.RUN.getStatus()); | |
| 182 | -// if (CollUtil.isNotEmpty(allActivities)) { | |
| 183 | -// return MapUtil.builder(allActivities.get(0), spuIds).build(); | |
| 184 | -// } | |
| 185 | -// | |
| 186 | -// // 查询某个活动参加的活动 | |
| 187 | -// List<RewardActivityDO> productActivityList = getRewardActivityListBySpuIds(spuIds, | |
| 188 | -// singleton(PromotionActivityStatusEnum.RUN.getStatus())); | |
| 189 | -// return convertMap(productActivityList, activity -> activity, | |
| 190 | -// rewardActivityDO -> intersectionDistinct(rewardActivityDO.getProductSpuIds(), spuIds)); // 求交集返回 | |
| 191 | - return null; | |
| 163 | + List<RewardActivityDO> list = rewardActivityMapper.selectListBySpuIdsAndStatus(spuIds, CommonStatusEnum.ENABLE.getStatus()); | |
| 164 | + return BeanUtils.toBean(list, RewardActivityMatchRespDTO.class); | |
| 192 | 165 | } |
| 193 | 166 | |
| 194 | 167 | @Override |
| 195 | - public List<RewardActivityDO> getRewardActivityBySpuIdsAndStatusAndDateTimeLt(Collection<Long> spuIds, Integer status, LocalDateTime dateTime) { | |
| 196 | - // 1. 查询出指定 spuId 的 spu 参加的活动 | |
| 197 | - List<RewardActivityDO> rewardActivityList = rewardActivityMapper.selectListBySpuIdsAndStatus(spuIds, status); | |
| 198 | - if (CollUtil.isEmpty(rewardActivityList)) { | |
| 199 | - return Collections.emptyList(); | |
| 200 | - } | |
| 201 | - | |
| 202 | - // 2. 查询活动详情 | |
| 203 | - return rewardActivityMapper.selectListByIdsAndDateTimeLt(convertSet(rewardActivityList, RewardActivityDO::getId), dateTime); | |
| 168 | + public List<RewardActivityDO> getRewardActivityByStatusAndDateTimeLt(Integer status, LocalDateTime dateTime) { | |
| 169 | + return rewardActivityMapper.selectListByStatusAndDateTimeLt(status, dateTime); | |
| 204 | 170 | } |
| 205 | 171 | |
| 206 | 172 | } | ... | ... |
yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/reward/RewardActivityServiceImplTest.java
| 1 | 1 | package cn.iocoder.yudao.module.promotion.service.reward; |
| 2 | 2 | |
| 3 | +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | |
| 3 | 4 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 4 | 5 | import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; |
| 6 | +import cn.iocoder.yudao.module.promotion.api.reward.dto.RewardActivityMatchRespDTO; | |
| 5 | 7 | import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityCreateReqVO; |
| 6 | 8 | import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityPageReqVO; |
| 7 | 9 | import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityUpdateReqVO; |
| 8 | 10 | import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO; |
| 9 | 11 | import cn.iocoder.yudao.module.promotion.dal.mysql.reward.RewardActivityMapper; |
| 10 | -import cn.iocoder.yudao.module.promotion.enums.common.PromotionActivityStatusEnum; | |
| 11 | 12 | import cn.iocoder.yudao.module.promotion.enums.common.PromotionConditionTypeEnum; |
| 12 | 13 | import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum; |
| 14 | +import jakarta.annotation.Resource; | |
| 13 | 15 | import org.junit.jupiter.api.Disabled; |
| 14 | 16 | import org.junit.jupiter.api.Test; |
| 15 | 17 | import org.springframework.context.annotation.Import; |
| 16 | 18 | |
| 17 | -import jakarta.annotation.Resource; | |
| 18 | 19 | import java.time.Duration; |
| 20 | +import java.util.List; | |
| 19 | 21 | import java.util.Set; |
| 20 | 22 | |
| 21 | 23 | import static cn.hutool.core.util.RandomUtil.randomEle; |
| ... | ... | @@ -27,15 +29,15 @@ import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServic |
| 27 | 29 | import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId; |
| 28 | 30 | import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; |
| 29 | 31 | import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.REWARD_ACTIVITY_NOT_EXISTS; |
| 30 | -import static java.util.Arrays.asList; | |
| 32 | +import static com.google.common.primitives.Longs.asList; | |
| 31 | 33 | import static java.util.Collections.singletonList; |
| 32 | 34 | import static org.junit.jupiter.api.Assertions.*; |
| 33 | 35 | |
| 34 | 36 | /** |
| 35 | -* {@link RewardActivityServiceImpl} 的单元测试类 | |
| 36 | -* | |
| 37 | -* @author 芋道源码 | |
| 38 | -*/ | |
| 37 | + * {@link RewardActivityServiceImpl} 的单元测试类 | |
| 38 | + * | |
| 39 | + * @author 芋道源码 | |
| 40 | + */ | |
| 39 | 41 | @Disabled // TODO 芋艿:后续 fix 补充的单测 |
| 40 | 42 | @Import(RewardActivityServiceImpl.class) |
| 41 | 43 | public class RewardActivityServiceImplTest extends BaseDbUnitTest { |
| ... | ... | @@ -63,7 +65,7 @@ public class RewardActivityServiceImplTest extends BaseDbUnitTest { |
| 63 | 65 | // 校验记录的属性是否正确 |
| 64 | 66 | RewardActivityDO rewardActivity = rewardActivityMapper.selectById(rewardActivityId); |
| 65 | 67 | assertPojoEquals(reqVO, rewardActivity, "rules"); |
| 66 | - assertEquals(rewardActivity.getStatus(), PromotionActivityStatusEnum.WAIT.getStatus()); | |
| 68 | + assertEquals(rewardActivity.getStatus(), CommonStatusEnum.DISABLE.getStatus()); | |
| 67 | 69 | for (int i = 0; i < reqVO.getRules().size(); i++) { |
| 68 | 70 | assertPojoEquals(reqVO.getRules().get(i), rewardActivity.getRules().get(i)); |
| 69 | 71 | } |
| ... | ... | @@ -72,7 +74,7 @@ public class RewardActivityServiceImplTest extends BaseDbUnitTest { |
| 72 | 74 | @Test |
| 73 | 75 | public void testUpdateRewardActivity_success() { |
| 74 | 76 | // mock 数据 |
| 75 | - RewardActivityDO dbRewardActivity = randomPojo(RewardActivityDO.class, o -> o.setStatus(PromotionActivityStatusEnum.WAIT.getStatus())); | |
| 77 | + RewardActivityDO dbRewardActivity = randomPojo(RewardActivityDO.class, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())); | |
| 76 | 78 | rewardActivityMapper.insert(dbRewardActivity);// @Sql: 先插入出一条存在的数据 |
| 77 | 79 | // 准备参数 |
| 78 | 80 | RewardActivityUpdateReqVO reqVO = randomPojo(RewardActivityUpdateReqVO.class, o -> { |
| ... | ... | @@ -88,7 +90,7 @@ public class RewardActivityServiceImplTest extends BaseDbUnitTest { |
| 88 | 90 | // 校验是否更新正确 |
| 89 | 91 | RewardActivityDO rewardActivity = rewardActivityMapper.selectById(reqVO.getId()); // 获取最新的 |
| 90 | 92 | assertPojoEquals(reqVO, rewardActivity, "rules"); |
| 91 | - assertEquals(rewardActivity.getStatus(), PromotionActivityStatusEnum.WAIT.getStatus()); | |
| 93 | + assertEquals(rewardActivity.getStatus(), CommonStatusEnum.DISABLE.getStatus()); | |
| 92 | 94 | for (int i = 0; i < reqVO.getRules().size(); i++) { |
| 93 | 95 | assertPojoEquals(reqVO.getRules().get(i), rewardActivity.getRules().get(i)); |
| 94 | 96 | } |
| ... | ... | @@ -97,7 +99,7 @@ public class RewardActivityServiceImplTest extends BaseDbUnitTest { |
| 97 | 99 | @Test |
| 98 | 100 | public void testCloseRewardActivity() { |
| 99 | 101 | // mock 数据 |
| 100 | - RewardActivityDO dbRewardActivity = randomPojo(RewardActivityDO.class, o -> o.setStatus(PromotionActivityStatusEnum.WAIT.getStatus())); | |
| 102 | + RewardActivityDO dbRewardActivity = randomPojo(RewardActivityDO.class, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())); | |
| 101 | 103 | rewardActivityMapper.insert(dbRewardActivity);// @Sql: 先插入出一条存在的数据 |
| 102 | 104 | // 准备参数 |
| 103 | 105 | Long id = dbRewardActivity.getId(); |
| ... | ... | @@ -106,7 +108,7 @@ public class RewardActivityServiceImplTest extends BaseDbUnitTest { |
| 106 | 108 | rewardActivityService.closeRewardActivity(id); |
| 107 | 109 | // 校验状态 |
| 108 | 110 | RewardActivityDO rewardActivity = rewardActivityMapper.selectById(id); |
| 109 | - assertEquals(rewardActivity.getStatus(), PromotionActivityStatusEnum.CLOSE.getStatus()); | |
| 111 | + assertEquals(rewardActivity.getStatus(), CommonStatusEnum.DISABLE.getStatus()); | |
| 110 | 112 | } |
| 111 | 113 | |
| 112 | 114 | @Test |
| ... | ... | @@ -121,15 +123,15 @@ public class RewardActivityServiceImplTest extends BaseDbUnitTest { |
| 121 | 123 | @Test |
| 122 | 124 | public void testDeleteRewardActivity_success() { |
| 123 | 125 | // mock 数据 |
| 124 | - RewardActivityDO dbRewardActivity = randomPojo(RewardActivityDO.class, o -> o.setStatus(PromotionActivityStatusEnum.CLOSE.getStatus())); | |
| 126 | + RewardActivityDO dbRewardActivity = randomPojo(RewardActivityDO.class, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())); | |
| 125 | 127 | rewardActivityMapper.insert(dbRewardActivity);// @Sql: 先插入出一条存在的数据 |
| 126 | 128 | // 准备参数 |
| 127 | 129 | Long id = dbRewardActivity.getId(); |
| 128 | 130 | |
| 129 | 131 | // 调用 |
| 130 | 132 | rewardActivityService.deleteRewardActivity(id); |
| 131 | - // 校验数据不存在了 | |
| 132 | - assertNull(rewardActivityMapper.selectById(id)); | |
| 133 | + // 校验数据不存在了 | |
| 134 | + assertNull(rewardActivityMapper.selectById(id)); | |
| 133 | 135 | } |
| 134 | 136 | |
| 135 | 137 | @Test |
| ... | ... | @@ -143,78 +145,82 @@ public class RewardActivityServiceImplTest extends BaseDbUnitTest { |
| 143 | 145 | |
| 144 | 146 | @Test |
| 145 | 147 | public void testGetRewardActivityPage() { |
| 146 | - // mock 数据 | |
| 147 | - RewardActivityDO dbRewardActivity = randomPojo(RewardActivityDO.class, o -> { // 等会查询到 | |
| 148 | - o.setName("芋艿"); | |
| 149 | - o.setStatus(PromotionActivityStatusEnum.CLOSE.getStatus()); | |
| 150 | - }); | |
| 151 | - rewardActivityMapper.insert(dbRewardActivity); | |
| 152 | - // 测试 name 不匹配 | |
| 153 | - rewardActivityMapper.insert(cloneIgnoreId(dbRewardActivity, o -> o.setName("土豆"))); | |
| 154 | - // 测试 status 不匹配 | |
| 155 | - rewardActivityMapper.insert(cloneIgnoreId(dbRewardActivity, o -> o.setStatus(PromotionActivityStatusEnum.RUN.getStatus()))); | |
| 156 | - // 准备参数 | |
| 157 | - RewardActivityPageReqVO reqVO = new RewardActivityPageReqVO(); | |
| 158 | - reqVO.setName("芋艿"); | |
| 159 | - reqVO.setStatus(PromotionActivityStatusEnum.CLOSE.getStatus()); | |
| 160 | - | |
| 161 | - // 调用 | |
| 162 | - PageResult<RewardActivityDO> pageResult = rewardActivityService.getRewardActivityPage(reqVO); | |
| 163 | - // 断言 | |
| 164 | - assertEquals(1, pageResult.getTotal()); | |
| 165 | - assertEquals(1, pageResult.getList().size()); | |
| 166 | - assertPojoEquals(dbRewardActivity, pageResult.getList().get(0), "rules"); | |
| 148 | + // mock 数据 | |
| 149 | + RewardActivityDO dbRewardActivity = randomPojo(RewardActivityDO.class, o -> { // 等会查询到 | |
| 150 | + o.setName("芋艿"); | |
| 151 | + o.setStatus(CommonStatusEnum.DISABLE.getStatus()); | |
| 152 | + }); | |
| 153 | + rewardActivityMapper.insert(dbRewardActivity); | |
| 154 | + // 测试 name 不匹配 | |
| 155 | + rewardActivityMapper.insert(cloneIgnoreId(dbRewardActivity, o -> o.setName("土豆"))); | |
| 156 | + // 测试 status 不匹配 | |
| 157 | + rewardActivityMapper.insert(cloneIgnoreId(dbRewardActivity, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus()))); | |
| 158 | + // 准备参数 | |
| 159 | + RewardActivityPageReqVO reqVO = new RewardActivityPageReqVO(); | |
| 160 | + reqVO.setName("芋艿"); | |
| 161 | + reqVO.setStatus(CommonStatusEnum.DISABLE.getStatus()); | |
| 162 | + | |
| 163 | + // 调用 | |
| 164 | + PageResult<RewardActivityDO> pageResult = rewardActivityService.getRewardActivityPage(reqVO); | |
| 165 | + // 断言 | |
| 166 | + assertEquals(1, pageResult.getTotal()); | |
| 167 | + assertEquals(1, pageResult.getList().size()); | |
| 168 | + assertPojoEquals(dbRewardActivity, pageResult.getList().get(0), "rules"); | |
| 167 | 169 | } |
| 168 | 170 | |
| 169 | 171 | @Test |
| 170 | 172 | public void testGetRewardActivities_all() { |
| 171 | 173 | // mock 数据 |
| 172 | - RewardActivityDO allActivity = randomPojo(RewardActivityDO.class, o -> o.setStatus(PromotionActivityStatusEnum.RUN.getStatus()) | |
| 174 | + RewardActivityDO allActivity = randomPojo(RewardActivityDO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus()) | |
| 173 | 175 | .setProductScope(PromotionProductScopeEnum.ALL.getScope())); |
| 174 | 176 | rewardActivityMapper.insert(allActivity); |
| 175 | - RewardActivityDO productActivity = randomPojo(RewardActivityDO.class, o -> o.setStatus(PromotionActivityStatusEnum.RUN.getStatus()) | |
| 176 | - .setProductScope(PromotionProductScopeEnum.SPU.getScope()).setProductSpuIds(asList(1L, 2L))); | |
| 177 | + RewardActivityDO productActivity = randomPojo(RewardActivityDO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus()) | |
| 178 | + .setProductScope(PromotionProductScopeEnum.SPU.getScope()).setProductScopeValues(asList(1L, 2L))); | |
| 177 | 179 | rewardActivityMapper.insert(productActivity); |
| 178 | 180 | // 准备参数 |
| 179 | 181 | Set<Long> spuIds = asSet(1L, 2L); |
| 180 | 182 | |
| 181 | 183 | // 调用 TODO getMatchRewardActivities 没有这个方法,但是找到了 getMatchRewardActivityList |
| 182 | - //Map<RewardActivityDO, Set<Long>> matchRewardActivities = rewardActivityService.getMatchRewardActivities(spuIds); | |
| 184 | + List<RewardActivityMatchRespDTO> matchRewardActivityList = rewardActivityService.getMatchRewardActivityList(spuIds); | |
| 183 | 185 | // 断言 |
| 184 | - //assertEquals(matchRewardActivities.size(), 1); | |
| 185 | - //Map.Entry<RewardActivityDO, Set<Long>> next = matchRewardActivities.entrySet().iterator().next(); | |
| 186 | - //assertPojoEquals(next.getKey(), allActivity); | |
| 187 | - //assertEquals(next.getValue(), spuIds); | |
| 186 | + assertEquals(matchRewardActivityList.size(), 1); | |
| 187 | + matchRewardActivityList.forEach((activity) -> { | |
| 188 | + if (activity.getId().equals(productActivity.getId())) { | |
| 189 | + assertPojoEquals(activity, productActivity); | |
| 190 | + assertEquals(activity.getProductScopeValues(), asList(1L, 2L)); | |
| 191 | + } else { | |
| 192 | + fail(); | |
| 193 | + } | |
| 194 | + }); | |
| 188 | 195 | } |
| 189 | 196 | |
| 190 | 197 | @Test |
| 191 | 198 | public void testGetRewardActivities_product() { |
| 192 | 199 | // mock 数据 |
| 193 | - // TODO @puhui999:有单测的问题,也一起瞅瞅 | |
| 194 | - RewardActivityDO productActivity01 = randomPojo(RewardActivityDO.class, o -> o.setStatus(PromotionActivityStatusEnum.RUN.getStatus()) | |
| 195 | - .setProductScope(PromotionProductScopeEnum.SPU.getScope()).setProductSpuIds(asList(1L, 2L))); | |
| 200 | + RewardActivityDO productActivity01 = randomPojo(RewardActivityDO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus()) | |
| 201 | + .setProductScope(PromotionProductScopeEnum.SPU.getScope()).setProductScopeValues(asList(1L, 2L))); | |
| 196 | 202 | rewardActivityMapper.insert(productActivity01); |
| 197 | - RewardActivityDO productActivity02 = randomPojo(RewardActivityDO.class, o -> o.setStatus(PromotionActivityStatusEnum.RUN.getStatus()) | |
| 198 | - .setProductScope(PromotionProductScopeEnum.SPU.getScope()).setProductSpuIds(singletonList(3L))); | |
| 203 | + RewardActivityDO productActivity02 = randomPojo(RewardActivityDO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus()) | |
| 204 | + .setProductScope(PromotionProductScopeEnum.SPU.getScope()).setProductScopeValues(singletonList(3L))); | |
| 199 | 205 | rewardActivityMapper.insert(productActivity02); |
| 200 | 206 | // 准备参数 |
| 201 | 207 | Set<Long> spuIds = asSet(1L, 2L, 3L); |
| 202 | 208 | |
| 203 | 209 | // 调用 TODO getMatchRewardActivities 没有这个方法,但是找到了 getMatchRewardActivityList |
| 204 | - //Map<RewardActivityDO, Set<Long>> matchRewardActivities = rewardActivityService.getMatchRewardActivities(spuIds); | |
| 210 | + List<RewardActivityMatchRespDTO> matchRewardActivityList = rewardActivityService.getMatchRewardActivityList(spuIds); | |
| 205 | 211 | // 断言 |
| 206 | - //assertEquals(matchRewardActivities.size(), 2); | |
| 207 | - //matchRewardActivities.forEach((activity, activitySpuIds) -> { | |
| 208 | - // if (activity.getId().equals(productActivity01.getId())) { | |
| 209 | - // assertPojoEquals(activity, productActivity01); | |
| 210 | - // assertEquals(activitySpuIds, asSet(1L, 2L)); | |
| 211 | - // } else if (activity.getId().equals(productActivity02.getId())) { | |
| 212 | - // assertPojoEquals(activity, productActivity02); | |
| 213 | - // assertEquals(activitySpuIds, asSet(3L)); | |
| 214 | - // } else { | |
| 215 | - // fail(); | |
| 216 | - // } | |
| 217 | - //}); | |
| 212 | + assertEquals(matchRewardActivityList.size(), 2); | |
| 213 | + matchRewardActivityList.forEach((activity) -> { | |
| 214 | + if (activity.getId().equals(productActivity01.getId())) { | |
| 215 | + assertPojoEquals(activity, productActivity01); | |
| 216 | + assertEquals(activity.getProductScopeValues(), asList(1L, 2L)); | |
| 217 | + } else if (activity.getId().equals(productActivity02.getId())) { | |
| 218 | + assertPojoEquals(activity, productActivity02); | |
| 219 | + assertEquals(activity.getProductScopeValues(), singletonList(3L)); | |
| 220 | + } else { | |
| 221 | + fail(); | |
| 222 | + } | |
| 223 | + }); | |
| 218 | 224 | } |
| 219 | 225 | |
| 220 | 226 | } | ... | ... |
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/api/order/TradeOrderApi.java
| 1 | 1 | package cn.iocoder.yudao.module.trade.api.order; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.module.trade.api.order.dto.TradeOrderRespDTO; |
| 4 | +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderCancelTypeEnum; | |
| 4 | 5 | |
| 5 | 6 | import java.util.Collection; |
| 6 | 7 | import java.util.List; |
| ... | ... | @@ -31,9 +32,10 @@ public interface TradeOrderApi { |
| 31 | 32 | /** |
| 32 | 33 | * 取消支付订单 |
| 33 | 34 | * |
| 34 | - * @param userId 用户编号 | |
| 35 | - * @param orderId 订单编号 | |
| 35 | + * @param userId 用户编号 | |
| 36 | + * @param orderId 订单编号 | |
| 37 | + * @param cancelTypeEnum 取消类型 | |
| 36 | 38 | */ |
| 37 | - void cancelPaidOrder(Long userId, Long orderId); | |
| 39 | + void cancelPaidOrder(Long userId, Long orderId, TradeOrderCancelTypeEnum cancelTypeEnum); | |
| 38 | 40 | |
| 39 | 41 | } | ... | ... |
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderCancelTypeEnum.java
| ... | ... | @@ -17,7 +17,8 @@ public enum TradeOrderCancelTypeEnum implements IntArrayValuable { |
| 17 | 17 | |
| 18 | 18 | PAY_TIMEOUT(10, "超时未支付"), |
| 19 | 19 | AFTER_SALE_CLOSE(20, "退款关闭"), |
| 20 | - MEMBER_CANCEL(30, "买家取消"); | |
| 20 | + MEMBER_CANCEL(30, "买家取消"), | |
| 21 | + COMBINATION_CLOSE(40, "拼团关闭"); | |
| 21 | 22 | |
| 22 | 23 | public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(TradeOrderCancelTypeEnum::getType).toArray(); |
| 23 | 24 | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/api/order/TradeOrderApiImpl.java
| ... | ... | @@ -2,12 +2,13 @@ package cn.iocoder.yudao.module.trade.api.order; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.module.trade.api.order.dto.TradeOrderRespDTO; |
| 4 | 4 | import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert; |
| 5 | +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderCancelTypeEnum; | |
| 5 | 6 | import cn.iocoder.yudao.module.trade.service.order.TradeOrderQueryService; |
| 6 | 7 | import cn.iocoder.yudao.module.trade.service.order.TradeOrderUpdateService; |
| 8 | +import jakarta.annotation.Resource; | |
| 7 | 9 | import org.springframework.stereotype.Service; |
| 8 | 10 | import org.springframework.validation.annotation.Validated; |
| 9 | 11 | |
| 10 | -import jakarta.annotation.Resource; | |
| 11 | 12 | import java.util.Collection; |
| 12 | 13 | import java.util.List; |
| 13 | 14 | |
| ... | ... | @@ -36,8 +37,8 @@ public class TradeOrderApiImpl implements TradeOrderApi { |
| 36 | 37 | } |
| 37 | 38 | |
| 38 | 39 | @Override |
| 39 | - public void cancelPaidOrder(Long userId, Long orderId) { | |
| 40 | - tradeOrderUpdateService.cancelPaidOrder(userId, orderId); | |
| 40 | + public void cancelPaidOrder(Long userId, Long orderId, TradeOrderCancelTypeEnum cancelTypeEnum) { | |
| 41 | + tradeOrderUpdateService.cancelPaidOrder(userId, orderId, cancelTypeEnum); | |
| 41 | 42 | } |
| 42 | 43 | |
| 43 | 44 | } | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateService.java
| 1 | 1 | package cn.iocoder.yudao.module.trade.service.order; |
| 2 | 2 | |
| 3 | -import cn.iocoder.yudao.framework.common.enums.TerminalEnum; | |
| 4 | 3 | import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderDeliveryReqVO; |
| 5 | 4 | import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderRemarkReqVO; |
| 6 | 5 | import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderUpdateAddressReqVO; |
| ... | ... | @@ -10,7 +9,7 @@ import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderSettle |
| 10 | 9 | import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderSettlementRespVO; |
| 11 | 10 | import cn.iocoder.yudao.module.trade.controller.app.order.vo.item.AppTradeOrderItemCommentCreateReqVO; |
| 12 | 11 | import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; |
| 13 | - | |
| 12 | +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderCancelTypeEnum; | |
| 14 | 13 | import jakarta.validation.constraints.NotNull; |
| 15 | 14 | |
| 16 | 15 | /** |
| ... | ... | @@ -188,12 +187,14 @@ public interface TradeOrderUpdateService { |
| 188 | 187 | void updateOrderCombinationInfo(Long orderId, Long activityId, Long combinationRecordId, Long headId); |
| 189 | 188 | |
| 190 | 189 | // TODO 芋艿:拼团取消,不调这个接口哈; |
| 190 | + | |
| 191 | 191 | /** |
| 192 | 192 | * 取消支付订单 |
| 193 | 193 | * |
| 194 | - * @param userId 用户编号 | |
| 195 | - * @param orderId 订单编号 | |
| 194 | + * @param userId 用户编号 | |
| 195 | + * @param orderId 订单编号 | |
| 196 | + * @param cancelTypeEnum 取消类型 | |
| 196 | 197 | */ |
| 197 | - void cancelPaidOrder(Long userId, Long orderId); | |
| 198 | + void cancelPaidOrder(Long userId, Long orderId, TradeOrderCancelTypeEnum cancelTypeEnum); | |
| 198 | 199 | |
| 199 | 200 | } | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java
| ... | ... | @@ -858,13 +858,13 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { |
| 858 | 858 | |
| 859 | 859 | @Override |
| 860 | 860 | @Transactional(rollbackFor = Exception.class) |
| 861 | - public void cancelPaidOrder(Long userId, Long orderId) { | |
| 862 | - // TODO @puhui999:可能要加一个拼团取消;TradeOrderCancelTypeEnum.AFTER_SALE_CLOSE;然后参数传入下; | |
| 861 | + public void cancelPaidOrder(Long userId, Long orderId, TradeOrderCancelTypeEnum cancelTypeEnum) { | |
| 863 | 862 | // 1.1 检验订单存在 |
| 864 | 863 | TradeOrderDO order = tradeOrderMapper.selectOrderByIdAndUserId(orderId, userId); |
| 865 | 864 | if (order == null) { |
| 866 | 865 | throw exception(ORDER_NOT_FOUND); |
| 867 | 866 | } |
| 867 | + | |
| 868 | 868 | // 1.2 校验订单是否支付 |
| 869 | 869 | if (!order.getPayStatus()) { |
| 870 | 870 | throw exception(ORDER_CANCEL_PAID_FAIL, "已支付"); |
| ... | ... | @@ -875,13 +875,13 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { |
| 875 | 875 | } |
| 876 | 876 | |
| 877 | 877 | // 2.1 取消订单 |
| 878 | - cancelOrder0(order, TradeOrderCancelTypeEnum.AFTER_SALE_CLOSE); | |
| 878 | + cancelOrder0(order, cancelTypeEnum); | |
| 879 | 879 | // 2.2 创建退款单 |
| 880 | 880 | payRefundApi.createRefund(new PayRefundCreateReqDTO() |
| 881 | 881 | .setAppKey(tradeOrderProperties.getPayAppKey()).setUserIp(getClientIP()) // 支付应用 |
| 882 | 882 | .setMerchantOrderId(String.valueOf(order.getId())) // 支付单号 |
| 883 | 883 | .setMerchantRefundId(String.valueOf(order.getId())) |
| 884 | - .setReason("取消支付订单").setPrice(order.getPayPrice()));// 价格信息 | |
| 884 | + .setReason(cancelTypeEnum.getName()).setPrice(order.getPayPrice()));// 价格信息 | |
| 885 | 885 | } |
| 886 | 886 | |
| 887 | 887 | /** | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeRewardActivityPriceCalculator.java
| ... | ... | @@ -10,10 +10,10 @@ import cn.iocoder.yudao.module.promotion.enums.common.PromotionTypeEnum; |
| 10 | 10 | import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum; |
| 11 | 11 | import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; |
| 12 | 12 | import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; |
| 13 | +import jakarta.annotation.Resource; | |
| 13 | 14 | import org.springframework.core.annotation.Order; |
| 14 | 15 | import org.springframework.stereotype.Component; |
| 15 | 16 | |
| 16 | -import jakarta.annotation.Resource; | |
| 17 | 17 | import java.util.List; |
| 18 | 18 | |
| 19 | 19 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; |
| ... | ... | @@ -96,7 +96,7 @@ public class TradeRewardActivityPriceCalculator implements TradePriceCalculator |
| 96 | 96 | private List<TradePriceCalculateRespBO.OrderItem> filterMatchCouponOrderItems(TradePriceCalculateRespBO result, |
| 97 | 97 | RewardActivityMatchRespDTO rewardActivity) { |
| 98 | 98 | return filterList(result.getItems(), |
| 99 | - orderItem -> CollUtil.contains(rewardActivity.getSpuIds(), orderItem.getSpuId())); | |
| 99 | + orderItem -> CollUtil.contains(rewardActivity.getProductScopeValues(), orderItem.getSpuId())); | |
| 100 | 100 | } |
| 101 | 101 | |
| 102 | 102 | /** | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeRewardActivityPriceCalculatorTest.java
| ... | ... | @@ -63,10 +63,10 @@ public class TradeRewardActivityPriceCalculatorTest extends BaseMockitoUnitTest |
| 63 | 63 | // mock 方法(限时折扣 DiscountActivity 信息) |
| 64 | 64 | when(rewardActivityApi.getMatchRewardActivityList(eq(asSet(1L, 2L, 3L)))).thenReturn(asList( |
| 65 | 65 | randomPojo(RewardActivityMatchRespDTO.class, o -> o.setId(1000L).setName("活动 1000 号") |
| 66 | - .setSpuIds(asList(1L, 2L)).setConditionType(PromotionConditionTypeEnum.PRICE.getType()) | |
| 66 | + .setProductScopeValues(asList(1L, 2L)).setConditionType(PromotionConditionTypeEnum.PRICE.getType()) | |
| 67 | 67 | .setRules(singletonList(new RewardActivityMatchRespDTO.Rule().setLimit(200).setDiscountPrice(70)))), |
| 68 | 68 | randomPojo(RewardActivityMatchRespDTO.class, o -> o.setId(2000L).setName("活动 2000 号") |
| 69 | - .setSpuIds(singletonList(3L)).setConditionType(PromotionConditionTypeEnum.COUNT.getType()) | |
| 69 | + .setProductScopeValues(singletonList(3L)).setConditionType(PromotionConditionTypeEnum.COUNT.getType()) | |
| 70 | 70 | .setRules(asList(new RewardActivityMatchRespDTO.Rule().setLimit(1).setDiscountPrice(10), |
| 71 | 71 | new RewardActivityMatchRespDTO.Rule().setLimit(2).setDiscountPrice(60), // 最大可满足,因为是 4 个 |
| 72 | 72 | new RewardActivityMatchRespDTO.Rule().setLimit(10).setDiscountPrice(100)))) |
| ... | ... | @@ -175,7 +175,7 @@ public class TradeRewardActivityPriceCalculatorTest extends BaseMockitoUnitTest |
| 175 | 175 | // mock 方法(限时折扣 DiscountActivity 信息) |
| 176 | 176 | when(rewardActivityApi.getMatchRewardActivityList(eq(asSet(1L, 2L)))).thenReturn(singletonList( |
| 177 | 177 | randomPojo(RewardActivityMatchRespDTO.class, o -> o.setId(1000L).setName("活动 1000 号") |
| 178 | - .setSpuIds(asList(1L, 2L)).setConditionType(PromotionConditionTypeEnum.PRICE.getType()) | |
| 178 | + .setProductScopeValues(asList(1L, 2L)).setConditionType(PromotionConditionTypeEnum.PRICE.getType()) | |
| 179 | 179 | .setRules(singletonList(new RewardActivityMatchRespDTO.Rule().setLimit(351).setDiscountPrice(70)))) |
| 180 | 180 | )); |
| 181 | 181 | ... | ... |