Commit ebf5693255ca571c1d96cf02b9d6847404c50ce8

Authored by 芋道源码
Committed by Gitee
2 parents f00b3005 81e38666

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

Merge pull request !1069 from puhui999/develop
Showing 18 changed files with 256 additions and 222 deletions
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/coupon/CouponApi.java
... ... @@ -5,6 +5,7 @@ import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponUseReqDTO;
5 5 import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponValidReqDTO;
6 6 import jakarta.validation.Valid;
7 7  
  8 +import java.util.List;
8 9 import java.util.Map;
9 10  
10 11 /**
... ... @@ -36,23 +37,21 @@ public interface CouponApi {
36 37 */
37 38 CouponRespDTO validateCoupon(@Valid CouponValidReqDTO validReqDTO);
38 39  
39   - // TODO @puhui999:可能需要根据 TradeOrderDO 的建议,进行修改;需要返回优惠劵编号
40 40 /**
41 41 * 【管理员】给指定用户批量发送优惠券
42 42 *
43   - * @param giveCouponsMap key: 优惠劵编号,value:对应的优惠券数量
  43 + * @param giveCoupons key: 优惠劵模版编号,value:对应的数量
44 44 * @param userId 用户编号
  45 + * @return 优惠券编号列表
45 46 */
46   - // TODO @puhui999:giveCouponsMap 可能改成 giveCoupons 更合适?优惠劵模版编号、数量
47   - void takeCouponsByAdmin(Map<Long, Integer> giveCouponsMap, Long userId);
  47 + List<Long> takeCouponsByAdmin(Map<Long, Integer> giveCoupons, Long userId);
48 48  
49   - // TODO @puhui999:可能需要根据 TradeOrderDO 的建议,进行修改 giveCouponsMap 参数
50 49 /**
51 50 * 【管理员】作废指定用户的指定优惠劵
52 51 *
53   - * @param giveCouponsMap key: 优惠劵编号,value:对应的优惠券数量
  52 + * @param giveCouponIds 赠送的优惠券编号
54 53 * @param userId 用户编号
55 54 */
56   - void invalidateCouponsByAdmin(Map<Long, Integer> giveCouponsMap, Long userId);
  55 + void invalidateCouponsByAdmin(List<Long> giveCouponIds, Long userId);
57 56  
58 57 }
... ...
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/reward/dto/RewardActivityMatchRespDTO.java
... ... @@ -86,27 +86,17 @@ public class RewardActivityMatchRespDTO {
86 86 * 是否包邮
87 87 */
88 88 private Boolean freeDelivery;
89   - // TODO @puhui999:建议不返回 + 去掉 givePoint、giveCoupon 字段哈。
90   - /**
91   - * 是否赠送积分
92   - */
93   - private Boolean givePoint;
94 89 /**
95 90 * 赠送的积分
96 91 */
97 92 private Integer point;
98 93 /**
99   - * 是否赠送优惠券
100   - */
101   - private Boolean giveCoupon;
102   - // TODO @puhui999:giveCoupons 即可
103   - /**
104 94 * 赠送的优惠劵
105 95 *
106 96 * key: 优惠劵模版编号
107 97 * value:对应的优惠券数量
108 98 */
109   - private Map<Long, Integer> giveCouponsMap;
  99 + private Map<Long, Integer> giveCoupons;
110 100  
111 101 }
112 102  
... ...
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/coupon/CouponStatusEnum.java
... ... @@ -17,9 +17,7 @@ public enum CouponStatusEnum implements IntArrayValuable {
17 17  
18 18 UNUSED(1, "未使用"),
19 19 USED(2, "已使用"),
20   - EXPIRE(3, "已过期"),
21   - // TODO @puhui999:捉摸了下,貌似搞成逻辑删除好了?不然好多地方的 status 都要做一些变动。可能未来加个 invalidateType 来标识,是管理后台删除,还是取消回收。或者优惠劵的 change log 可能更好。
22   - INVALID(4, "已作废");
  20 + EXPIRE(3, "已过期");
23 21  
24 22 public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(CouponStatusEnum::getStatus).toArray();
25 23  
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/coupon/CouponApiImpl.java
... ... @@ -11,6 +11,7 @@ import jakarta.annotation.Resource;
11 11 import org.springframework.stereotype.Service;
12 12 import org.springframework.validation.annotation.Validated;
13 13  
  14 +import java.util.List;
14 15 import java.util.Map;
15 16  
16 17 /**
... ... @@ -43,13 +44,13 @@ public class CouponApiImpl implements CouponApi {
43 44 }
44 45  
45 46 @Override
46   - public void takeCouponsByAdmin(Map<Long, Integer> giveCouponsMap, Long userId) {
47   - couponService.takeCouponsByAdmin(giveCouponsMap, userId);
  47 + public List<Long> takeCouponsByAdmin(Map<Long, Integer> giveCoupons, Long userId) {
  48 + return couponService.takeCouponsByAdmin(giveCoupons, userId);
48 49 }
49 50  
50 51 @Override
51   - public void invalidateCouponsByAdmin(Map<Long, Integer> giveCouponsMap, Long userId) {
52   - couponService.invalidateCouponsByAdmin(giveCouponsMap, userId);
  52 + public void invalidateCouponsByAdmin(List<Long> giveCouponIds, Long userId) {
  53 + couponService.invalidateCouponsByAdmin(giveCouponIds, userId);
53 54 }
54 55  
55 56 }
... ...
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;
5 4 import cn.iocoder.yudao.framework.common.validation.InEnum;
6 5 import cn.iocoder.yudao.module.promotion.enums.common.PromotionConditionTypeEnum;
7 6 import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum;
... ... @@ -77,24 +76,16 @@ public class RewardActivityBaseVO {
77 76 @NotNull(message = "规则是否包邮不能为空")
78 77 private Boolean freeDelivery;
79 78  
80   - @Schema(description = "是否赠送积分", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
81   - @NotNull(message = "规则是否赠送积分不能为空")
82   - private Boolean givePoint;
83   -
84 79 @Schema(description = "赠送的积分", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
85 80 private Integer point;
86 81  
87   - @Schema(description = "是否赠送优惠券", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
88   - @NotNull(message = "规则是否赠送优惠券不能为空")
89   - private Boolean giveCoupon;
90   -
91 82 @Schema(description = "赠送的优惠劵编号的数组", example = "1,2,3")
92 83 private Map<Long, Integer> giveCouponsMap;
93 84  
94 85 @AssertTrue(message = "赠送的积分不能小于 1")
95 86 @JsonIgnore
96 87 public boolean isPointValid() {
97   - return BooleanUtil.isFalse(givePoint) || (point != null && point >= 1);
  88 + return point == null || point >= 1;
98 89 }
99 90  
100 91 }
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/reward/RewardActivityDO.java
... ... @@ -100,20 +100,10 @@ public class RewardActivityDO extends BaseDO {
100 100 * 是否包邮
101 101 */
102 102 private Boolean freeDelivery;
103   - // TODO @puhui999:是不是大于零,就认为赠送积分哈;简洁一点;
104   - /**
105   - * 是否赠送积分
106   - */
107   - private Boolean givePoint;
108 103 /**
109 104 * 赠送的积分
110 105 */
111 106 private Integer point;
112   - // TODO @puhui999:非空,就认为赠送优惠劵
113   - /**
114   - * 是否赠送优惠券
115   - */
116   - private Boolean giveCoupon;
117 107 /**
118 108 * 赠送的优惠劵
119 109 *
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/coupon/CouponMapper.java
... ... @@ -8,6 +8,7 @@ import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
8 8 import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.coupon.CouponPageReqVO;
9 9 import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponDO;
10 10 import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum;
  11 +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
11 12 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
12 13 import com.github.yulichang.toolkit.MPJWrappers;
13 14 import org.apache.ibatis.annotations.Mapper;
... ... @@ -72,15 +73,6 @@ public interface CouponMapper extends BaseMapperX&lt;CouponDO&gt; {
72 73 );
73 74 }
74 75  
75   - default List<CouponDO> selectListByTemplateIdAndUserIdAndTakeType(Long templateId, Collection<Long> userIds,
76   - Integer takeType) {
77   - return selectList(new LambdaQueryWrapperX<CouponDO>()
78   - .eq(CouponDO::getTemplateId, templateId)
79   - .eq(CouponDO::getTakeType, takeType)
80   - .in(CouponDO::getUserId, userIds)
81   - );
82   - }
83   -
84 76 default Map<Long, Integer> selectCountByUserIdAndTemplateIdIn(Long userId, Collection<Long> templateIds) {
85 77 String templateIdAlias = "templateId";
86 78 String countAlias = "count";
... ... @@ -116,4 +108,11 @@ public interface CouponMapper extends BaseMapperX&lt;CouponDO&gt; {
116 108 );
117 109 }
118 110  
  111 + default List<CouponDO> selectListByIdAndUserIdAndTakeType(Long couponId, Long userId, Integer takeType) {
  112 + return selectList(new LambdaQueryWrapper<CouponDO>()
  113 + .eq(CouponDO::getId, couponId)
  114 + .eq(CouponDO::getUserId, userId)
  115 + .eq(CouponDO::getTakeType, takeType));
  116 + }
  117 +
119 118 }
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponService.java
... ... @@ -39,14 +39,6 @@ public interface CouponService {
39 39 void validCoupon(CouponDO coupon);
40 40  
41 41 /**
42   - * 获得优惠劵分页
43   - *
44   - * @param pageReqVO 分页查询
45   - * @return 优惠劵分页
46   - */
47   - PageResult<CouponDO> getCouponPage(CouponPageReqVO pageReqVO);
48   -
49   - /**
50 42 * 使用优惠劵
51 43 *
52 44 * @param id 优惠劵编号
... ... @@ -70,56 +62,42 @@ public interface CouponService {
70 62 void deleteCoupon(Long id);
71 63  
72 64 /**
73   - * 获得用户的优惠劵列表
74   - *
75   - * @param userId 用户编号
76   - * @param status 优惠劵状态
77   - * @return 优惠劵列表
78   - */
79   - List<CouponDO> getCouponList(Long userId, Integer status);
80   -
81   - /**
82   - * 获得未使用的优惠劵数量
83   - *
84   - * @param userId 用户编号
85   - * @return 未使用的优惠劵数量
86   - */
87   - Long getUnusedCouponCount(Long userId);
88   -
89   - /**
90 65 * 领取优惠券
91 66 *
92 67 * @param templateId 优惠券模板编号
93 68 * @param userIds 用户编号列表
94 69 * @param takeType 领取方式
  70 + * @return key: userId, value: 优惠券编号列表
95 71 */
96   - void takeCoupon(Long templateId, Set<Long> userIds, CouponTakeTypeEnum takeType);
  72 + Map<Long, List<Long>> takeCoupon(Long templateId, Set<Long> userIds, CouponTakeTypeEnum takeType);
97 73  
98 74 /**
99 75 * 【管理员】给用户发送优惠券
100 76 *
101 77 * @param templateId 优惠券模板编号
102 78 * @param userIds 用户编号列表
  79 + * @return key: userId, value: 优惠券编号列表
103 80 */
104   - default void takeCouponByAdmin(Long templateId, Set<Long> userIds) {
105   - takeCoupon(templateId, userIds, CouponTakeTypeEnum.ADMIN);
  81 + default Map<Long, List<Long>> takeCouponByAdmin(Long templateId, Set<Long> userIds) {
  82 + return takeCoupon(templateId, userIds, CouponTakeTypeEnum.ADMIN);
106 83 }
107 84  
108 85 /**
109 86 * 【管理员】给指定用户批量发送优惠券
110 87 *
111   - * @param giveCouponsMap key: 优惠劵编号,value:对应的优惠券数量
  88 + * @param giveCoupons key: 优惠劵模版编号,value:对应的数量
112 89 * @param userId 用户编号
  90 + * @return 优惠券编号列表
113 91 */
114   - void takeCouponsByAdmin(Map<Long, Integer> giveCouponsMap, Long userId);
  92 + List<Long> takeCouponsByAdmin(Map<Long, Integer> giveCoupons, Long userId);
115 93  
116 94 /**
117   - * 【管理员】收回给指定用户批量发送优惠券
  95 + * 【管理员】作废指定用户的指定优惠劵
118 96 *
119   - * @param giveCouponsMap key: 优惠劵编号,value:对应的优惠券数量
  97 + * @param giveCouponIds 赠送的优惠券编号
120 98 * @param userId 用户编号
121 99 */
122   - void invalidateCouponsByAdmin(Map<Long, Integer> giveCouponsMap, Long userId);
  100 + void invalidateCouponsByAdmin(List<Long> giveCouponIds, Long userId);
123 101  
124 102 /**
125 103 * 【会员】领取优惠券
... ... @@ -139,16 +117,38 @@ public interface CouponService {
139 117 void takeCouponByRegister(Long userId);
140 118  
141 119 /**
142   - * 获取会员领取指定优惠券的数量
  120 + * 过期优惠券
143 121 *
144   - * @param templateId 优惠券模板编号
145   - * @param userId 用户编号
146   - * @return 领取优惠券的数量
  122 + * @return 过期数量
147 123 */
148   - default Integer getTakeCount(Long templateId, Long userId) {
149   - Map<Long, Integer> map = getTakeCountMapByTemplateIds(Collections.singleton(templateId), userId);
150   - return MapUtil.getInt(map, templateId, 0);
151   - }
  124 + int expireCoupon();
  125 +
  126 + //======================= 查询相关 =======================
  127 +
  128 + /**
  129 + * 获得未使用的优惠劵数量
  130 + *
  131 + * @param userId 用户编号
  132 + * @return 未使用的优惠劵数量
  133 + */
  134 + Long getUnusedCouponCount(Long userId);
  135 +
  136 + /**
  137 + * 获得优惠劵分页
  138 + *
  139 + * @param pageReqVO 分页查询
  140 + * @return 优惠劵分页
  141 + */
  142 + PageResult<CouponDO> getCouponPage(CouponPageReqVO pageReqVO);
  143 +
  144 + /**
  145 + * 获得用户的优惠劵列表
  146 + *
  147 + * @param userId 用户编号
  148 + * @param status 优惠劵状态
  149 + * @return 优惠劵列表
  150 + */
  151 + List<CouponDO> getCouponList(Long userId, Integer status);
152 152  
153 153 /**
154 154 * 统计会员领取优惠券的数量
... ... @@ -160,20 +160,25 @@ public interface CouponService {
160 160 Map<Long, Integer> getTakeCountMapByTemplateIds(Collection<Long> templateIds, Long userId);
161 161  
162 162 /**
163   - * 获取用户匹配的优惠券列表
  163 + * 获取会员领取指定优惠券的数量
164 164 *
  165 + * @param templateId 优惠券模板编号
165 166 * @param userId 用户编号
166   - * @param matchReqVO 匹配参数
167   - * @return 优惠券列表
  167 + * @return 领取优惠券的数量
168 168 */
169   - List<CouponDO> getMatchCouponList(Long userId, AppCouponMatchReqVO matchReqVO);
  169 + default Integer getTakeCount(Long templateId, Long userId) {
  170 + Map<Long, Integer> map = getTakeCountMapByTemplateIds(Collections.singleton(templateId), userId);
  171 + return MapUtil.getInt(map, templateId, 0);
  172 + }
170 173  
171 174 /**
172   - * 过期优惠券
  175 + * 获取用户匹配的优惠券列表
173 176 *
174   - * @return 过期数量
  177 + * @param userId 用户编号
  178 + * @param matchReqVO 匹配参数
  179 + * @return 优惠券列表
175 180 */
176   - int expireCoupon();
  181 + List<CouponDO> getMatchCouponList(Long userId, AppCouponMatchReqVO matchReqVO);
177 182  
178 183 /**
179 184 * 获取用户是否可以领取优惠券
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponServiceImpl.java
... ... @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.promotion.service.coupon;
3 3 import cn.hutool.core.collection.CollStreamUtil;
4 4 import cn.hutool.core.collection.CollUtil;
5 5 import cn.hutool.core.map.MapUtil;
  6 +import cn.hutool.core.util.ObjUtil;
6 7 import cn.hutool.core.util.ObjectUtil;
7 8 import cn.hutool.core.util.StrUtil;
8 9 import cn.hutool.extra.spring.SpringUtil;
... ... @@ -31,6 +32,7 @@ import java.util.stream.Collectors;
31 32  
32 33 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
33 34 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
  35 +import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen;
34 36 import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
35 37 import static java.util.Arrays.asList;
36 38  
... ... @@ -76,20 +78,6 @@ public class CouponServiceImpl implements CouponService {
76 78 }
77 79  
78 80 @Override
79   - public PageResult<CouponDO> getCouponPage(CouponPageReqVO pageReqVO) {
80   - // 获得用户编号
81   - if (StrUtil.isNotEmpty(pageReqVO.getNickname())) {
82   - List<MemberUserRespDTO> users = memberUserApi.getUserListByNickname(pageReqVO.getNickname());
83   - if (CollUtil.isEmpty(users)) {
84   - return PageResult.empty();
85   - }
86   - pageReqVO.setUserIds(convertSet(users, MemberUserRespDTO::getId));
87   - }
88   - // 分页查询
89   - return couponMapper.selectPage(pageReqVO);
90   - }
91   -
92   - @Override
93 81 public void useCoupon(Long id, Long userId, Long orderId) {
94 82 // 校验优惠劵
95 83 validCoupon(id, userId);
... ... @@ -146,26 +134,8 @@ public class CouponServiceImpl implements CouponService {
146 134 }
147 135  
148 136 @Override
149   - public List<CouponDO> getCouponList(Long userId, Integer status) {
150   - return couponMapper.selectListByUserIdAndStatus(userId, status);
151   - }
152   -
153   - private CouponDO validateCouponExists(Long id) {
154   - CouponDO coupon = couponMapper.selectById(id);
155   - if (coupon == null) {
156   - throw exception(COUPON_NOT_EXISTS);
157   - }
158   - return coupon;
159   - }
160   -
161   - @Override
162   - public Long getUnusedCouponCount(Long userId) {
163   - return couponMapper.selectCountByUserIdAndStatus(userId, CouponStatusEnum.UNUSED.getStatus());
164   - }
165   -
166   - @Override
167 137 @Transactional(rollbackFor = Exception.class)
168   - public void takeCoupon(Long templateId, Set<Long> userIds, CouponTakeTypeEnum takeType) {
  138 + public Map<Long, List<Long>> takeCoupon(Long templateId, Set<Long> userIds, CouponTakeTypeEnum takeType) {
169 139 CouponTemplateDO template = couponTemplateService.getCouponTemplate(templateId);
170 140 // 1. 过滤掉达到领取限制的用户
171 141 removeTakeLimitUser(userIds, template);
... ... @@ -173,40 +143,45 @@ public class CouponServiceImpl implements CouponService {
173 143 validateCouponTemplateCanTake(template, userIds, takeType);
174 144  
175 145 // 3. 批量保存优惠劵
176   - couponMapper.insertBatch(convertList(userIds, userId -> CouponConvert.INSTANCE.convert(template, userId)));
  146 + List<CouponDO> couponList = convertList(userIds, userId -> CouponConvert.INSTANCE.convert(template, userId));
  147 + couponMapper.insertBatch(couponList);
177 148  
178 149 // 4. 增加优惠劵模板的领取数量
179 150 couponTemplateService.updateCouponTemplateTakeCount(templateId, userIds.size());
  151 +
  152 + return convertMultiMap(couponList, CouponDO::getUserId, CouponDO::getId);
180 153 }
181 154  
182 155 @Override
183   - public void takeCouponsByAdmin(Map<Long, Integer> giveCouponsMap, Long userId) {
184   - if (CollUtil.isEmpty(giveCouponsMap)) {
185   - return;
  156 + public List<Long> takeCouponsByAdmin(Map<Long, Integer> giveCoupons, Long userId) {
  157 + if (CollUtil.isEmpty(giveCoupons)) {
  158 + return Collections.emptyList();
186 159 }
187 160  
  161 + List<Long> couponIds = new ArrayList<>();
188 162 // 循环发放
189   - for (Map.Entry<Long, Integer> entry : giveCouponsMap.entrySet()) {
  163 + for (Map.Entry<Long, Integer> entry : giveCoupons.entrySet()) {
190 164 try {
191 165 for (int i = 0; i < entry.getValue(); i++) {
192   - getSelf().takeCoupon(entry.getKey(), CollUtil.newHashSet(userId), CouponTakeTypeEnum.ADMIN);
  166 + Map<Long, List<Long>> userCouponIdsMap = getSelf().takeCoupon(entry.getKey(), CollUtil.newHashSet(userId),
  167 + CouponTakeTypeEnum.ADMIN);
  168 + findAndThen(userCouponIdsMap, userId, couponIds::addAll);
193 169 }
194 170 } catch (Exception e) {
195 171 log.error("[takeCouponsByAdmin][coupon({}) 优惠券发放失败]", entry, e);
196 172 }
197 173 }
  174 + return couponIds;
198 175 }
199 176  
200 177 @Override
201   - public void invalidateCouponsByAdmin(Map<Long, Integer> giveCouponsMap, Long userId) {
  178 + public void invalidateCouponsByAdmin(List<Long> giveCouponIds, Long userId) {
202 179 // 循环收回
203   - for (Map.Entry<Long, Integer> entry : giveCouponsMap.entrySet()) {
  180 + for (Long couponId : giveCouponIds) {
204 181 try {
205   - for (int i = 0; i < entry.getValue(); i++) {
206   - getSelf().takeBackCoupon(entry.getKey(), CollUtil.newHashSet(userId), CouponTakeTypeEnum.ADMIN);
207   - }
  182 + getSelf().takeBackCoupon(couponId, userId, CouponTakeTypeEnum.ADMIN);
208 183 } catch (Exception e) {
209   - log.error("[takeBackCouponsByAdmin][coupon({}) 收回优惠券失败]", entry, e);
  184 + log.error("[invalidateCouponsByAdmin][couponId({}) 收回优惠券失败]", couponId, e);
210 185 }
211 186 }
212 187 }
... ... @@ -214,32 +189,36 @@ public class CouponServiceImpl implements CouponService {
214 189 /**
215 190 * 【管理员】收回优惠券
216 191 *
217   - * @param templateId 模版编号
218   - * @param userIds 用户编号列表
  192 + * @param couponId 模版编号
  193 + * @param userId 用户编号
219 194 * @param takeType 领取方式
220 195 */
221 196 @Transactional(rollbackFor = Exception.class)
222   - public void takeBackCoupon(Long templateId, Set<Long> userIds, CouponTakeTypeEnum takeType) {
223   - CouponTemplateDO couponTemplate = couponTemplateService.getCouponTemplate(templateId);
224   - // 1.1 校验模板
  197 + public void takeBackCoupon(Long couponId, Long userId, CouponTakeTypeEnum takeType) {
  198 + // 1.1 校验优惠券
  199 + CouponDO coupon = couponMapper.selectByIdAndUserId(couponId, userId);
  200 + if (coupon == null) {
  201 + throw exception(COUPON_NOT_EXISTS);
  202 + }
  203 + // 1.2 校验模板
  204 + CouponTemplateDO couponTemplate = couponTemplateService.getCouponTemplate(coupon.getTemplateId());
225 205 if (couponTemplate == null) {
226 206 throw exception(COUPON_TEMPLATE_NOT_EXISTS);
227 207 }
228   - // 1.2 校验领取方式
  208 + // 1.3 校验领取方式
229 209 if (ObjectUtil.notEqual(couponTemplate.getTakeType(), takeType.getValue())) {
230 210 throw exception(COUPON_TEMPLATE_CANNOT_TAKE);
231 211 }
232 212  
233   - // 2.1 过滤出还未使用的赠送的优惠券
234   - List<CouponDO> couponList = couponMapper.selectListByTemplateIdAndUserIdAndTakeType(templateId, userIds,
235   - takeType.getValue());
236   - List<CouponDO> unUsedCouponList = filterList(couponList, item -> !CouponStatusEnum.USED.getStatus().equals(item.getStatus()));
  213 + // 2.1 校验优惠券是否已经使用,如若使用则先不管
  214 + if (ObjUtil.equal(coupon.getStatus(), CouponStatusEnum.USED.getStatus())) {
  215 + return;
  216 + }
237 217 // 2.2 减少优惠劵模板的领取数量
238   - couponTemplateService.updateCouponTemplateTakeCount(templateId, unUsedCouponList.size() * -1);
239   - // 2.3 批量更新优惠劵状态
240   - couponMapper.updateById(convertList(unUsedCouponList, item -> new CouponDO().setId(item.getId())
241   - .setStatus(CouponStatusEnum.INVALID.getStatus())));
242   -
  218 + couponTemplateService.updateCouponTemplateTakeCount(couponTemplate.getId(), -1);
  219 + // 2.3 批量作废优惠劵
  220 + // TODO @puhui999:捉摸了下,貌似搞成逻辑删除好了?不然好多地方的 status 都要做一些变动。可能未来加个 invalidateType 来标识,是管理后台删除,还是取消回收。或者优惠劵的 change log 可能更好。
  221 + couponMapper.deleteById(couponId);
243 222 }
244 223  
245 224 @Override
... ... @@ -252,24 +231,6 @@ public class CouponServiceImpl implements CouponService {
252 231 }
253 232  
254 233 @Override
255   - public Map<Long, Integer> getTakeCountMapByTemplateIds(Collection<Long> templateIds, Long userId) {
256   - if (CollUtil.isEmpty(templateIds)) {
257   - return Collections.emptyMap();
258   - }
259   - return couponMapper.selectCountByUserIdAndTemplateIdIn(userId, templateIds);
260   - }
261   -
262   - @Override
263   - public List<CouponDO> getMatchCouponList(Long userId, AppCouponMatchReqVO matchReqVO) {
264   - List<CouponDO> list = couponMapper.selectListByUserIdAndStatusAndUsePriceLeAndProductScope(userId,
265   - CouponStatusEnum.UNUSED.getStatus(),
266   - matchReqVO.getPrice(), matchReqVO.getSpuIds(), matchReqVO.getCategoryIds());
267   - // 兜底逻辑:如果 CouponExpireJob 未执行,status 未变成 EXPIRE ,但是 validEndTime 已经过期了,需要进行过滤
268   - list.removeIf(coupon -> !LocalDateTimeUtils.isBetween(coupon.getValidStartTime(), coupon.getValidEndTime()));
269   - return list;
270   - }
271   -
272   - @Override
273 234 public int expireCoupon() {
274 235 // 1. 查询待过期的优惠券
275 236 List<CouponDO> list = couponMapper.selectListByStatusAndValidEndTimeLe(
... ... @@ -293,27 +254,6 @@ public class CouponServiceImpl implements CouponService {
293 254 return count;
294 255 }
295 256  
296   - @Override
297   - public Map<Long, Boolean> getUserCanCanTakeMap(Long userId, List<CouponTemplateDO> templates) {
298   - // 1. 未登录时,都显示可以领取
299   - Map<Long, Boolean> userCanTakeMap = convertMap(templates, CouponTemplateDO::getId, templateId -> true);
300   - if (userId == null) {
301   - return userCanTakeMap;
302   - }
303   -
304   - // 2.1 过滤领取数量无限制的
305   - Set<Long> templateIds = convertSet(templates, CouponTemplateDO::getId, template -> template.getTakeLimitCount() != -1);
306   - // 2.2 检查用户领取的数量是否超过限制
307   - if (CollUtil.isNotEmpty(templateIds)) {
308   - Map<Long, Integer> couponTakeCountMap = this.getTakeCountMapByTemplateIds(templateIds, userId);
309   - for (CouponTemplateDO template : templates) {
310   - Integer takeCount = couponTakeCountMap.get(template.getId());
311   - userCanTakeMap.put(template.getId(), takeCount == null || takeCount < template.getTakeLimitCount());
312   - }
313   - }
314   - return userCanTakeMap;
315   - }
316   -
317 257 /**
318 258 * 过期单个优惠劵
319 259 *
... ... @@ -385,11 +325,84 @@ public class CouponServiceImpl implements CouponService {
385 325 userIds.removeIf(userId -> MapUtil.getInt(userTakeCountMap, userId, 0) >= couponTemplate.getTakeLimitCount());
386 326 }
387 327  
  328 + //======================= 查询相关 =======================
  329 +
  330 + @Override
  331 + public Long getUnusedCouponCount(Long userId) {
  332 + return couponMapper.selectCountByUserIdAndStatus(userId, CouponStatusEnum.UNUSED.getStatus());
  333 + }
  334 +
  335 + @Override
  336 + public PageResult<CouponDO> getCouponPage(CouponPageReqVO pageReqVO) {
  337 + // 获得用户编号
  338 + if (StrUtil.isNotEmpty(pageReqVO.getNickname())) {
  339 + List<MemberUserRespDTO> users = memberUserApi.getUserListByNickname(pageReqVO.getNickname());
  340 + if (CollUtil.isEmpty(users)) {
  341 + return PageResult.empty();
  342 + }
  343 + pageReqVO.setUserIds(convertSet(users, MemberUserRespDTO::getId));
  344 + }
  345 + // 分页查询
  346 + return couponMapper.selectPage(pageReqVO);
  347 + }
  348 +
  349 + @Override
  350 + public List<CouponDO> getCouponList(Long userId, Integer status) {
  351 + return couponMapper.selectListByUserIdAndStatus(userId, status);
  352 + }
  353 +
  354 + @Override
  355 + public Map<Long, Integer> getTakeCountMapByTemplateIds(Collection<Long> templateIds, Long userId) {
  356 + if (CollUtil.isEmpty(templateIds)) {
  357 + return Collections.emptyMap();
  358 + }
  359 + return couponMapper.selectCountByUserIdAndTemplateIdIn(userId, templateIds);
  360 + }
  361 +
  362 + @Override
  363 + public List<CouponDO> getMatchCouponList(Long userId, AppCouponMatchReqVO matchReqVO) {
  364 + List<CouponDO> list = couponMapper.selectListByUserIdAndStatusAndUsePriceLeAndProductScope(userId,
  365 + CouponStatusEnum.UNUSED.getStatus(),
  366 + matchReqVO.getPrice(), matchReqVO.getSpuIds(), matchReqVO.getCategoryIds());
  367 + // 兜底逻辑:如果 CouponExpireJob 未执行,status 未变成 EXPIRE ,但是 validEndTime 已经过期了,需要进行过滤
  368 + list.removeIf(coupon -> !LocalDateTimeUtils.isBetween(coupon.getValidStartTime(), coupon.getValidEndTime()));
  369 + return list;
  370 + }
  371 +
  372 + @Override
  373 + public Map<Long, Boolean> getUserCanCanTakeMap(Long userId, List<CouponTemplateDO> templates) {
  374 + // 1. 未登录时,都显示可以领取
  375 + Map<Long, Boolean> userCanTakeMap = convertMap(templates, CouponTemplateDO::getId, templateId -> true);
  376 + if (userId == null) {
  377 + return userCanTakeMap;
  378 + }
  379 +
  380 + // 2.1 过滤领取数量无限制的
  381 + Set<Long> templateIds = convertSet(templates, CouponTemplateDO::getId, template -> template.getTakeLimitCount() != -1);
  382 + // 2.2 检查用户领取的数量是否超过限制
  383 + if (CollUtil.isNotEmpty(templateIds)) {
  384 + Map<Long, Integer> couponTakeCountMap = this.getTakeCountMapByTemplateIds(templateIds, userId);
  385 + for (CouponTemplateDO template : templates) {
  386 + Integer takeCount = couponTakeCountMap.get(template.getId());
  387 + userCanTakeMap.put(template.getId(), takeCount == null || takeCount < template.getTakeLimitCount());
  388 + }
  389 + }
  390 + return userCanTakeMap;
  391 + }
  392 +
388 393 @Override
389 394 public CouponDO getCoupon(Long userId, Long id) {
390 395 return couponMapper.selectByIdAndUserId(id, userId);
391 396 }
392 397  
  398 + private CouponDO validateCouponExists(Long id) {
  399 + CouponDO coupon = couponMapper.selectById(id);
  400 + if (coupon == null) {
  401 + throw exception(COUPON_NOT_EXISTS);
  402 + }
  403 + return coupon;
  404 + }
  405 +
393 406 /**
394 407 * 获得自身的代理对象,解决 AOP 生效问题
395 408 *
... ... @@ -398,4 +411,5 @@ public class CouponServiceImpl implements CouponService {
398 411 private CouponServiceImpl getSelf() {
399 412 return SpringUtil.getBean(getClass());
400 413 }
  414 +
401 415 }
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/reward/RewardActivityServiceImpl.java
... ... @@ -159,7 +159,6 @@ public class RewardActivityServiceImpl implements RewardActivityService {
159 159  
160 160 @Override
161 161 public List<RewardActivityMatchRespDTO> getMatchRewardActivityList(Collection<Long> spuIds) {
162   - // TODO 芋艿:待实现;先指定,然后再全局的;
163 162 List<RewardActivityDO> list = rewardActivityMapper.selectListBySpuIdsAndStatus(spuIds, CommonStatusEnum.ENABLE.getStatus());
164 163 return BeanUtils.toBean(list, RewardActivityMatchRespDTO.class);
165 164 }
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderDO.java
... ... @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.trade.dal.dataobject.order;
2 2  
3 3 import cn.iocoder.yudao.framework.common.enums.TerminalEnum;
4 4 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  5 +import cn.iocoder.yudao.framework.mybatis.core.type.LongListTypeHandler;
5 6 import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
6 7 import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.BrokerageUserDO;
7 8 import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressDO;
... ... @@ -18,6 +19,7 @@ import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
18 19 import lombok.*;
19 20  
20 21 import java.time.LocalDateTime;
  22 +import java.util.List;
21 23 import java.util.Map;
22 24  
23 25 /**
... ... @@ -294,17 +296,23 @@ public class TradeOrderDO extends BaseDO {
294 296 */
295 297 private Integer vipPrice;
296 298  
297   - // TODO @puhui999:项了下,貌似这里存储 List<Long> giveCouponIds 更合适。因为优惠劵赠送到最后是对应的编号,然后从而进行取消?
298 299 /**
299 300 * 赠送的优惠劵
300 301 *
301 302 * key: 优惠劵编号
302 303 * value:对应的优惠券数量
303 304 *
304   - * 目的:用于后续取消或者售后订单时,需要扣减赠送
  305 + * 目的:用于订单支付后赠送优惠券
305 306 */
306 307 @TableField(typeHandler = JacksonTypeHandler.class)
307 308 private Map<Long, Integer> giveCouponsMap;
  309 + /**
  310 + * 赠送的优惠劵编号
  311 + *
  312 + * 目的:用于后续取消或者售后订单时,需要扣减赠送
  313 + */
  314 + @TableField(typeHandler = LongListTypeHandler.class)
  315 + private List<Long> giveCouponIds;
308 316  
309 317 /**
310 318 * 秒杀活动编号
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateService.java
... ... @@ -11,6 +11,8 @@ import cn.iocoder.yudao.module.trade.controller.app.order.vo.item.AppTradeOrderI
11 11 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
12 12 import jakarta.validation.constraints.NotNull;
13 13  
  14 +import java.util.List;
  15 +
14 16 /**
15 17 * 交易订单【写】Service 接口
16 18 *
... ... @@ -194,4 +196,13 @@ public interface TradeOrderUpdateService {
194 196 */
195 197 void cancelPaidOrder(Long userId, Long orderId, Integer cancelType);
196 198  
  199 + /**
  200 + * 更新下单赠送的优惠券编号到订单
  201 + *
  202 + * @param userId 用户编号
  203 + * @param orderId 订单编号
  204 + * @param giveCouponIds 赠送的优惠券编号列表
  205 + */
  206 + void updateOrderGiveCouponIds(Long userId, Long orderId, List<Long> giveCouponIds);
  207 +
197 208 }
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java
... ... @@ -202,7 +202,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
202 202 order.setProductCount(getSumValue(calculateRespBO.getItems(), TradePriceCalculateRespBO.OrderItem::getCount, Integer::sum));
203 203 order.setUserIp(getClientIP()).setTerminal(getTerminal());
204 204 // 使用 + 赠送优惠券
205   - order.setGiveCouponsMap(calculateRespBO.getGiveCouponsMap());
  205 + order.setGiveCouponsMap(calculateRespBO.getGiveCoupons());
206 206 // 支付 + 退款信息
207 207 order.setAdjustPrice(0).setPayStatus(false);
208 208 order.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus()).setRefundPrice(0);
... ... @@ -890,6 +890,22 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
890 890 .setReason(TradeOrderCancelTypeEnum.COMBINATION_CLOSE.getName()).setPrice(order.getPayPrice()));// 价格信息
891 891 }
892 892  
  893 + @Override
  894 + public void updateOrderGiveCouponIds(Long userId, Long orderId, List<Long> giveCouponIds) {
  895 + // 1.1 检验订单存在
  896 + TradeOrderDO order = tradeOrderMapper.selectOrderByIdAndUserId(orderId, userId);
  897 + if (order == null) {
  898 + throw exception(ORDER_NOT_FOUND);
  899 + }
  900 + // 1.2 校验订单是否支付
  901 + if (!order.getPayStatus()) {
  902 + throw exception(ORDER_CANCEL_PAID_FAIL, "已支付");
  903 + }
  904 +
  905 + // 2. 更新订单赠送的优惠券编号列表
  906 + tradeOrderMapper.updateById(new TradeOrderDO().setId(orderId).setGiveCouponIds(giveCouponIds));
  907 + }
  908 +
893 909 /**
894 910 * 创建单个订单的评论
895 911 *
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeCouponOrderHandler.java
... ... @@ -5,7 +5,10 @@ import cn.iocoder.yudao.module.promotion.api.coupon.CouponApi;
5 5 import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponUseReqDTO;
6 6 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
7 7 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
  8 +import cn.iocoder.yudao.module.trade.service.order.TradeOrderQueryService;
  9 +import cn.iocoder.yudao.module.trade.service.order.TradeOrderUpdateService;
8 10 import jakarta.annotation.Resource;
  11 +import org.springframework.context.annotation.Lazy;
9 12 import org.springframework.stereotype.Component;
10 13  
11 14 import java.util.List;
... ... @@ -19,6 +22,12 @@ import java.util.List;
19 22 public class TradeCouponOrderHandler implements TradeOrderHandler {
20 23  
21 24 @Resource
  25 + @Lazy // 延迟加载,避免循环依赖
  26 + private TradeOrderUpdateService orderUpdateService;
  27 + @Resource
  28 + private TradeOrderQueryService orderQueryService;
  29 +
  30 + @Resource
22 31 private CouponApi couponApi;
23 32  
24 33 @Override
... ... @@ -37,7 +46,11 @@ public class TradeCouponOrderHandler implements TradeOrderHandler {
37 46 return;
38 47 }
39 48 // 赠送优惠券
40   - couponApi.takeCouponsByAdmin(order.getGiveCouponsMap(), order.getUserId());
  49 + List<Long> couponIds = couponApi.takeCouponsByAdmin(order.getGiveCouponsMap(), order.getUserId());
  50 + if (CollUtil.isEmpty(couponIds)) {
  51 + return;
  52 + }
  53 + orderUpdateService.updateOrderGiveCouponIds(order.getUserId(), order.getId(), couponIds);
41 54 }
42 55  
43 56 @Override
... ... @@ -48,10 +61,10 @@ public class TradeCouponOrderHandler implements TradeOrderHandler {
48 61 couponApi.returnUsedCoupon(order.getCouponId());
49 62 }
50 63 // 情况二:收回赠送的优惠券
51   - if (CollUtil.isEmpty(order.getGiveCouponsMap())) {
  64 + if (CollUtil.isEmpty(order.getGiveCouponIds())) {
52 65 return;
53 66 }
54   - couponApi.invalidateCouponsByAdmin(order.getGiveCouponsMap(), order.getUserId());
  67 + couponApi.invalidateCouponsByAdmin(order.getGiveCouponIds(), order.getUserId());
55 68 }
56 69  
57 70 }
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/bo/TradePriceCalculateRespBO.java
... ... @@ -79,7 +79,7 @@ public class TradePriceCalculateRespBO {
79 79 * key: 优惠劵编号,value:对应的优惠券数量
80 80 * 目的:用于后续取消或者售后订单时,需要扣减赠送
81 81 */
82   - private Map<Long, Integer> giveCouponsMap;
  82 + private Map<Long, Integer> giveCoupons;
83 83  
84 84 /**
85 85 * 订单价格
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePriceCalculatorHelper.java
... ... @@ -32,7 +32,7 @@ public class TradePriceCalculatorHelper {
32 32 List<ProductSpuRespDTO> spuList, List<ProductSkuRespDTO> skuList) {
33 33 // 创建 PriceCalculateRespDTO 对象
34 34 TradePriceCalculateRespBO result = new TradePriceCalculateRespBO();
35   - result.setType(getOrderType(param)).setPromotions(new ArrayList<>()).setGiveCouponsMap(new LinkedHashMap<>());
  35 + result.setType(getOrderType(param)).setPromotions(new ArrayList<>()).setGiveCoupons(new LinkedHashMap<>());
36 36  
37 37 // 创建它的 OrderItem 属性
38 38 result.setItems(new ArrayList<>(param.getItems().size()));
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeRewardActivityPriceCalculator.java
... ... @@ -93,7 +93,7 @@ public class TradeRewardActivityPriceCalculator implements TradePriceCalculator
93 93 TradePriceCalculatorHelper.recountAllPrice(result);
94 94  
95 95 // 4.1 记录赠送的积分
96   - if (Boolean.TRUE.equals(rule.getGivePoint())) {
  96 + if (rule.getPoint() != null && rule.getPoint() > 0) {
97 97 List<Integer> dividePoints = TradePriceCalculatorHelper.dividePrice(orderItems, rule.getPoint());
98 98 for (int i = 0; i < orderItems.size(); i++) {
99 99 // 商品可能赠送了积分,所以这里要加上
... ... @@ -107,13 +107,13 @@ public class TradeRewardActivityPriceCalculator implements TradePriceCalculator
107 107 result.setFreeDelivery(true);
108 108 }
109 109 // 4.3 记录赠送的优惠券
110   - if (Boolean.TRUE.equals(rule.getGiveCoupon())) {
111   - for (Map.Entry<Long, Integer> entry : rule.getGiveCouponsMap().entrySet()) {
112   - Map<Long, Integer> giveCouponsMap = result.getGiveCouponsMap();
113   - if (giveCouponsMap.get(entry.getKey()) == null) { // 情况一:还没有赠送的优惠券
114   - result.setGiveCouponsMap(rule.getGiveCouponsMap());
  110 + if (CollUtil.isNotEmpty(rule.getGiveCoupons())) {
  111 + for (Map.Entry<Long, Integer> entry : rule.getGiveCoupons().entrySet()) {
  112 + Map<Long, Integer> giveCoupons = result.getGiveCoupons();
  113 + if (giveCoupons.get(entry.getKey()) == null) { // 情况一:还没有赠送的优惠券
  114 + result.setGiveCoupons(rule.getGiveCoupons());
115 115 } else { // 情况二:别的满减活动送过同类优惠券,则直接增加数量
116   - giveCouponsMap.put(entry.getKey(), giveCouponsMap.get(entry.getKey()) + entry.getValue());
  116 + giveCoupons.put(entry.getKey(), giveCoupons.get(entry.getKey()) + entry.getValue());
117 117 }
118 118 }
119 119 }
... ...
yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeRewardActivityPriceCalculatorTest.java
... ... @@ -49,7 +49,7 @@ public class TradeRewardActivityPriceCalculatorTest extends BaseMockitoUnitTest
49 49 TradePriceCalculateRespBO result = new TradePriceCalculateRespBO()
50 50 .setType(TradeOrderTypeEnum.NORMAL.getType())
51 51 .setPrice(new TradePriceCalculateRespBO.Price())
52   - .setPromotions(new ArrayList<>()).setGiveCouponsMap(new LinkedHashMap<>())
  52 + .setPromotions(new ArrayList<>()).setGiveCoupons(new LinkedHashMap<>())
53 53 .setItems(asList(
54 54 new TradePriceCalculateRespBO.OrderItem().setSkuId(10L).setCount(2).setSelected(true)
55 55 .setPrice(100).setSpuId(1L),
... ... @@ -68,16 +68,16 @@ public class TradeRewardActivityPriceCalculatorTest extends BaseMockitoUnitTest
68 68 .setConditionType(PromotionConditionTypeEnum.PRICE.getType())
69 69 .setProductScope(PromotionProductScopeEnum.SPU.getScope()).setProductScopeValues(asList(1L, 2L))
70 70 .setRules(singletonList(new RewardActivityMatchRespDTO.Rule().setLimit(20).setDiscountPrice(70)
71   - .setGivePoint(false).setFreeDelivery(false)))),
  71 + .setFreeDelivery(false)))),
72 72 randomPojo(RewardActivityMatchRespDTO.class, o -> o.setId(2000L).setName("活动 2000 号")
73 73 .setConditionType(PromotionConditionTypeEnum.COUNT.getType())
74 74 .setProductScope(PromotionProductScopeEnum.SPU.getScope()).setProductScopeValues(singletonList(3L))
75 75 .setRules(asList(new RewardActivityMatchRespDTO.Rule().setLimit(1).setDiscountPrice(10)
76   - .setGivePoint(true).setPoint(50).setFreeDelivery(false),
77   - new RewardActivityMatchRespDTO.Rule().setLimit(2).setDiscountPrice(60).setGivePoint(true)
  76 + .setPoint(50).setFreeDelivery(false),
  77 + new RewardActivityMatchRespDTO.Rule().setLimit(2).setDiscountPrice(60)
78 78 .setPoint(100).setFreeDelivery(false), // 最大可满足,因为是 4 个
79 79 new RewardActivityMatchRespDTO.Rule().setLimit(10).setDiscountPrice(100)
80   - .setGivePoint(false).setFreeDelivery(false))))
  80 + .setFreeDelivery(false))))
81 81 ));
82 82  
83 83 // 调用
... ...