Commit 32e25cf4a24dd855a741832d98677863dff2091e

Authored by puhui999
1 parent 2b681f90

【代码优化】商城: 满减送活动

yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/common/PromotionProductScopeEnum.java
... ... @@ -15,10 +15,9 @@ import java.util.Arrays;
15 15 @AllArgsConstructor
16 16 public enum PromotionProductScopeEnum implements IntArrayValuable {
17 17  
18   - ALL(1, "通用券"), // 全部商品
19   - SPU(2, "商品券"), // 指定商品
20   - CATEGORY(3, "品类券"), // 指定品类
21   - ;
  18 + ALL(1, "全部商品"),
  19 + SPU(2, "指定商品"),
  20 + CATEGORY(3, "指定品类");
22 21  
23 22 public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(PromotionProductScopeEnum::getScope).toArray();
24 23  
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/reward/vo/RewardActivityBaseVO.java
1 1 package cn.iocoder.yudao.module.promotion.controller.admin.reward.vo;
2 2  
3 3 import cn.hutool.core.collection.CollUtil;
  4 +import cn.hutool.core.util.BooleanUtil;
4 5 import cn.iocoder.yudao.framework.common.validation.InEnum;
5 6 import cn.iocoder.yudao.module.promotion.enums.common.PromotionConditionTypeEnum;
6 7 import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum;
7 8 import com.fasterxml.jackson.annotation.JsonIgnore;
8 9 import io.swagger.v3.oas.annotations.media.Schema;
9   -import lombok.Data;
10   -import org.springframework.format.annotation.DateTimeFormat;
11   -
12 10 import jakarta.validation.Valid;
13 11 import jakarta.validation.constraints.AssertTrue;
14 12 import jakarta.validation.constraints.Future;
15 13 import jakarta.validation.constraints.Min;
16 14 import jakarta.validation.constraints.NotNull;
  15 +import lombok.Data;
  16 +
17 17 import java.time.LocalDateTime;
18 18 import java.util.List;
19   -
20   -import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  19 +import java.util.Objects;
21 20  
22 21 /**
23 22 * 满减送活动 Base VO,提供给添加、修改、详细的子 VO 使用
... ... @@ -32,12 +31,10 @@ public class RewardActivityBaseVO {
32 31  
33 32 @Schema(description = "开始时间", requiredMode = Schema.RequiredMode.REQUIRED)
34 33 @NotNull(message = "开始时间不能为空")
35   - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
36 34 private LocalDateTime startTime;
37 35  
38 36 @Schema(description = "结束时间", requiredMode = Schema.RequiredMode.REQUIRED)
39 37 @NotNull(message = "结束时间不能为空")
40   - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
41 38 @Future(message = "结束时间必须大于当前时间")
42 39 private LocalDateTime endTime;
43 40  
... ... @@ -54,8 +51,8 @@ public class RewardActivityBaseVO {
54 51 @InEnum(value = PromotionProductScopeEnum.class, message = "商品范围必须是 {value}")
55 52 private Integer productScope;
56 53  
57   - @Schema(description = "商品 SPU 编号的数组", example = "1,2,3")
58   - private List<Long> productSpuIds;
  54 + @Schema(description = "商品范围编号的数组", example = "[1, 3]")
  55 + private List<Long> productScopeValues;
59 56  
60 57 /**
61 58 * 优惠规则的数组
... ... @@ -63,6 +60,13 @@ public class RewardActivityBaseVO {
63 60 @Valid // 校验下子对象
64 61 private List<Rule> rules;
65 62  
  63 + @AssertTrue(message = "商品范围编号的数组不能为空")
  64 + @JsonIgnore
  65 + public boolean isProductScopeValuesValid() {
  66 + return Objects.equals(productScope, PromotionProductScopeEnum.ALL.getScope()) // 全部范围时,可以为空
  67 + || CollUtil.isNotEmpty(productScopeValues);
  68 + }
  69 +
66 70 @Schema(description = "优惠规则")
67 71 @Data
68 72 public static class Rule {
... ... @@ -76,12 +80,20 @@ public class RewardActivityBaseVO {
76 80 private Integer discountPrice;
77 81  
78 82 @Schema(description = "是否包邮", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
  83 + @NotNull(message = "规则是否包邮不能为空")
79 84 private Boolean freeDelivery;
80 85  
  86 + @Schema(description = "是否赠送积分", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
  87 + @NotNull(message = "规则是否赠送积分不能为空")
  88 + private Boolean givePoint;
  89 +
81 90 @Schema(description = "赠送的积分", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
82   - @Min(value = 1L, message = "赠送的积分必须大于等于 1")
83 91 private Integer point;
84 92  
  93 + @Schema(description = "是否赠送优惠券", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
  94 + @NotNull(message = "规则是否赠送优惠券不能为空")
  95 + private Boolean giveCoupon;
  96 +
85 97 @Schema(description = "赠送的优惠劵编号的数组", example = "1,2,3")
86 98 private List<Long> couponIds;
87 99  
... ... @@ -91,7 +103,13 @@ public class RewardActivityBaseVO {
91 103 @AssertTrue(message = "优惠劵和数量必须一一对应")
92 104 @JsonIgnore
93 105 public boolean isCouponCountsValid() {
94   - return CollUtil.size(couponCounts) == CollUtil.size(couponCounts);
  106 + return BooleanUtil.isFalse(givePoint) || CollUtil.size(couponIds) == CollUtil.size(couponCounts);
  107 + }
  108 +
  109 + @AssertTrue(message = "赠送的积分不能小于 1")
  110 + @JsonIgnore
  111 + public boolean isPointValid() {
  112 + return BooleanUtil.isFalse(givePoint) || (point != null && point >= 1);
95 113 }
96 114  
97 115 }
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/activity/AppActivityController.java
... ... @@ -9,9 +9,7 @@ import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainActivityD
9 9 import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO;
10 10 import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountActivityDO;
11 11 import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO;
12   -import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO;
13 12 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillActivityDO;
14   -import cn.iocoder.yudao.module.promotion.enums.common.PromotionActivityStatusEnum;
15 13 import cn.iocoder.yudao.module.promotion.enums.common.PromotionTypeEnum;
16 14 import cn.iocoder.yudao.module.promotion.service.bargain.BargainActivityService;
17 15 import cn.iocoder.yudao.module.promotion.service.combination.CombinationActivityService;
... ... @@ -30,7 +28,6 @@ import org.springframework.web.bind.annotation.RestController;
30 28  
31 29 import java.time.LocalDateTime;
32 30 import java.util.*;
33   -import java.util.stream.Collectors;
34 31  
35 32 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
36 33 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
... ... @@ -145,28 +142,28 @@ public class AppActivityController {
145 142 }
146 143  
147 144 private void getRewardActivities(Collection<Long> spuIds, LocalDateTime now, List<AppActivityRespVO> activityList) {
148   - // TODO @puhui999:有 3 范围,不只 spuId,还有 categoryId,全部
149   - List<RewardActivityDO> rewardActivityList = rewardActivityService.getRewardActivityBySpuIdsAndStatusAndDateTimeLt(
150   - spuIds, PromotionActivityStatusEnum.RUN.getStatus(), now);
151   - if (CollUtil.isEmpty(rewardActivityList)) {
152   - return;
153   - }
154   -
155   - Map<Long, Optional<RewardActivityDO>> spuIdAndActivityMap = spuIds.stream()
156   - .collect(Collectors.toMap(
157   - spuId -> spuId,
158   - spuId -> rewardActivityList.stream()
159   - .filter(activity -> activity.getProductSpuIds().contains(spuId))
160   - .max(Comparator.comparing(RewardActivityDO::getCreateTime))));
161   - for (Long supId : spuIdAndActivityMap.keySet()) {
162   - if (spuIdAndActivityMap.get(supId).isEmpty()) {
163   - continue;
164   - }
165   -
166   - RewardActivityDO rewardActivityDO = spuIdAndActivityMap.get(supId).get();
167   - activityList.add(new AppActivityRespVO(rewardActivityDO.getId(), PromotionTypeEnum.REWARD_ACTIVITY.getType(),
168   - rewardActivityDO.getName(), supId, rewardActivityDO.getStartTime(), rewardActivityDO.getEndTime()));
169   - }
  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 + //}
170 167 }
171 168  
172 169 }
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/reward/RewardActivityDO.java
... ... @@ -71,7 +71,7 @@ public class RewardActivityDO extends BaseDO {
71 71 * 商品 SPU 编号的数组
72 72 */
73 73 @TableField(typeHandler = LongListTypeHandler.class)
74   - private List<Long> productSpuIds;
  74 + private List<Long> productScopeValues;
75 75 /**
76 76 * 优惠规则的数组
77 77 */
... ... @@ -100,10 +100,18 @@ public class RewardActivityDO extends BaseDO {
100 100 */
101 101 private Boolean freeDelivery;
102 102 /**
  103 + * 是否赠送积分
  104 + */
  105 + private Boolean givePoint;
  106 + /**
103 107 * 赠送的积分
104 108 */
105 109 private Integer point;
106 110 /**
  111 + * 是否赠送优惠券
  112 + */
  113 + private Boolean giveCoupon;
  114 + /**
107 115 * 赠送的优惠劵编号的数组
108 116 */
109 117 private List<Long> couponIds;
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/reward/RewardActivityServiceImpl.java
... ... @@ -2,6 +2,8 @@ package cn.iocoder.yudao.module.promotion.service.reward;
2 2  
3 3 import cn.hutool.core.collection.CollUtil;
4 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  5 +import cn.iocoder.yudao.module.product.api.category.ProductCategoryApi;
  6 +import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
5 7 import cn.iocoder.yudao.module.promotion.api.reward.dto.RewardActivityMatchRespDTO;
6 8 import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityCreateReqVO;
7 9 import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityPageReqVO;
... ... @@ -10,6 +12,7 @@ import cn.iocoder.yudao.module.promotion.convert.reward.RewardActivityConvert;
10 12 import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO;
11 13 import cn.iocoder.yudao.module.promotion.dal.mysql.reward.RewardActivityMapper;
12 14 import cn.iocoder.yudao.module.promotion.enums.common.PromotionActivityStatusEnum;
  15 +import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum;
13 16 import cn.iocoder.yudao.module.promotion.util.PromotionUtils;
14 17 import jakarta.annotation.Resource;
15 18 import org.springframework.stereotype.Service;
... ... @@ -19,6 +22,7 @@ import java.time.LocalDateTime;
19 22 import java.util.Collection;
20 23 import java.util.Collections;
21 24 import java.util.List;
  25 +import java.util.Objects;
22 26  
23 27 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
24 28 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
... ... @@ -37,12 +41,19 @@ public class RewardActivityServiceImpl implements RewardActivityService {
37 41 @Resource
38 42 private RewardActivityMapper rewardActivityMapper;
39 43  
  44 + @Resource
  45 + private ProductCategoryApi productCategoryApi;
  46 + @Resource
  47 + private ProductSpuApi productSpuApi;
  48 +
40 49 @Override
41 50 public Long createRewardActivity(RewardActivityCreateReqVO createReqVO) {
42   - // 校验商品是否冲突
43   - validateRewardActivitySpuConflicts(null, createReqVO.getProductSpuIds());
  51 + // 1.1 校验商品范围
  52 + validateProductScope(createReqVO.getProductScope(), createReqVO.getProductScopeValues());
  53 + // 1.2 校验商品是否冲突
  54 + //validateRewardActivitySpuConflicts(null, createReqVO.getProductSpuIds());
44 55  
45   - // 插入
  56 + // 2. 插入
46 57 RewardActivityDO rewardActivity = RewardActivityConvert.INSTANCE.convert(createReqVO)
47 58 .setStatus(PromotionUtils.calculateActivityStatus(createReqVO.getEndTime()));
48 59 rewardActivityMapper.insert(rewardActivity);
... ... @@ -52,15 +63,17 @@ public class RewardActivityServiceImpl implements RewardActivityService {
52 63  
53 64 @Override
54 65 public void updateRewardActivity(RewardActivityUpdateReqVO updateReqVO) {
55   - // 校验存在
  66 + // 1.1 校验存在
56 67 RewardActivityDO dbRewardActivity = validateRewardActivityExists(updateReqVO.getId());
57 68 if (dbRewardActivity.getStatus().equals(PromotionActivityStatusEnum.CLOSE.getStatus())) { // 已关闭的活动,不能修改噢
58 69 throw exception(REWARD_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED);
59 70 }
60   - // 校验商品是否冲突
61   - validateRewardActivitySpuConflicts(updateReqVO.getId(), updateReqVO.getProductSpuIds());
  71 + // 1.2 校验商品范围
  72 + validateProductScope(updateReqVO.getProductScope(), updateReqVO.getProductScopeValues());
  73 + // 1.3 校验商品是否冲突
  74 + //validateRewardActivitySpuConflicts(updateReqVO.getId(), updateReqVO.getProductSpuIds());
62 75  
63   - // 更新
  76 + // 2. 更新
64 77 RewardActivityDO updateObj = RewardActivityConvert.INSTANCE.convert(updateReqVO)
65 78 .setStatus(PromotionUtils.calculateActivityStatus(updateReqVO.getEndTime()));
66 79 rewardActivityMapper.updateById(updateObj);
... ... @@ -103,7 +116,7 @@ public class RewardActivityServiceImpl implements RewardActivityService {
103 116 }
104 117  
105 118 // TODO @芋艿:逻辑有问题,需要优化;要分成全场、和指定来校验;
106   -
  119 + // TODO @puhui999: 下次提交 fix
107 120 /**
108 121 * 校验商品参加的活动是否冲突
109 122 *
... ... @@ -126,6 +139,14 @@ public class RewardActivityServiceImpl implements RewardActivityService {
126 139 }
127 140 }
128 141  
  142 + private void validateProductScope(Integer productScope, List<Long> productScopeValues) {
  143 + if (Objects.equals(PromotionProductScopeEnum.SPU.getScope(), productScope)) {
  144 + productSpuApi.validateSpuList(productScopeValues);
  145 + } else if (Objects.equals(PromotionProductScopeEnum.CATEGORY.getScope(), productScope)) {
  146 + productCategoryApi.validateCategoryList(productScopeValues);
  147 + }
  148 + }
  149 +
129 150 /**
130 151 * 获得商品参加的满减送活动的数组
131 152 *
... ... @@ -135,8 +156,10 @@ public class RewardActivityServiceImpl implements RewardActivityService {
135 156 */
136 157 private List<RewardActivityDO> getRewardActivityListBySpuIds(Collection<Long> spuIds,
137 158 Collection<Integer> statuses) {
138   - List<RewardActivityDO> list = rewardActivityMapper.selectListByStatus(statuses);
139   - return CollUtil.filter(list, activity -> CollUtil.containsAny(activity.getProductSpuIds(), spuIds));
  159 + // TODO @puhui999: 下次 fix
  160 + //List<RewardActivityDO> list = rewardActivityMapper.selectListByStatus(statuses);
  161 + //return CollUtil.filter(list, activity -> CollUtil.containsAny(activity.getProductSpuIds(), spuIds));
  162 + return List.of();
140 163 }
141 164  
142 165 @Override
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/AfterSalePageReqVO.java
... ... @@ -27,9 +27,6 @@ public class AfterSalePageReqVO extends PageParam {
27 27 @Schema(description = "售后流水号", example = "202211190847450020500077")
28 28 private String no;
29 29  
30   - @Schema(description = "用户编号", example = "1024")
31   - private Long userId;
32   -
33 30 @Schema(description = "售后状态", example = "10")
34 31 @InEnum(value = AfterSaleStatusEnum.class, message = "售后状态必须是 {value}")
35 32 private Integer status;
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/aftersale/AfterSaleMapper.java
... ... @@ -18,7 +18,6 @@ public interface AfterSaleMapper extends BaseMapperX&lt;AfterSaleDO&gt; {
18 18 return selectPage(reqVO, new LambdaQueryWrapperX<AfterSaleDO>()
19 19 .eqIfPresent(AfterSaleDO::getUserId, reqVO.getUserId())
20 20 .likeIfPresent(AfterSaleDO::getNo, reqVO.getNo())
21   - .eqIfPresent(AfterSaleDO::getUserId, reqVO.getUserId())
22 21 .eqIfPresent(AfterSaleDO::getStatus, reqVO.getStatus())
23 22 .eqIfPresent(AfterSaleDO::getType, reqVO.getType())
24 23 .eqIfPresent(AfterSaleDO::getWay, reqVO.getWay())
... ...