Commit 806c828bb50fb7077803b19a5b8a96325a279053

Authored by puhui999
1 parent d60374d6

【代码优化】商城: 满减送活动优惠券相关

Showing 16 changed files with 136 additions and 89 deletions
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/coupon/CouponApi.java
@@ -5,7 +5,7 @@ import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponUseReqDTO; @@ -5,7 +5,7 @@ import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponUseReqDTO;
5 import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponValidReqDTO; 5 import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponValidReqDTO;
6 import jakarta.validation.Valid; 6 import jakarta.validation.Valid;
7 7
8 -import java.util.List; 8 +import java.util.Map;
9 9
10 /** 10 /**
11 * 优惠劵 API 接口 11 * 优惠劵 API 接口
@@ -36,14 +36,20 @@ public interface CouponApi { @@ -36,14 +36,20 @@ public interface CouponApi {
36 */ 36 */
37 CouponRespDTO validateCoupon(@Valid CouponValidReqDTO validReqDTO); 37 CouponRespDTO validateCoupon(@Valid CouponValidReqDTO validReqDTO);
38 38
39 - // TODO @puhui999:Map<Long, Integer> 优惠劵 会不会好点。  
40 /** 39 /**
41 * 【管理员】给指定用户批量发送优惠券 40 * 【管理员】给指定用户批量发送优惠券
42 * 41 *
43 - * @param templateIds 优惠劵编号的数组  
44 - * @param counts 优惠券数量的数组 42 + * @param giveCouponsMap key: 优惠劵编号,value:对应的优惠券数量
45 * @param userId 用户编号 43 * @param userId 用户编号
46 */ 44 */
47 - void takeCouponsByAdmin(List<Long> templateIds, List<Integer> counts, Long userId); 45 + void takeCouponsByAdmin(Map<Long, Integer> giveCouponsMap, Long userId);
  46 +
  47 + /**
  48 + * 【管理员】收回给指定用户批量发送优惠券
  49 + *
  50 + * @param giveCouponsMap key: 优惠劵编号,value:对应的优惠券数量
  51 + * @param userId 用户编号
  52 + */
  53 + void takeBackCouponsByAdmin(Map<Long, Integer> giveCouponsMap, Long userId);
48 54
49 } 55 }
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/reward/dto/RewardActivityMatchRespDTO.java
@@ -8,6 +8,7 @@ import lombok.Data; @@ -8,6 +8,7 @@ import lombok.Data;
8 import java.io.Serializable; 8 import java.io.Serializable;
9 import java.time.LocalDateTime; 9 import java.time.LocalDateTime;
10 import java.util.List; 10 import java.util.List;
  11 +import java.util.Map;
11 12
12 /** 13 /**
13 * 满减送活动的匹配 Response DTO 14 * 满减送活动的匹配 Response DTO
@@ -98,13 +99,11 @@ public class RewardActivityMatchRespDTO { @@ -98,13 +99,11 @@ public class RewardActivityMatchRespDTO {
98 */ 99 */
99 private Boolean giveCoupon; 100 private Boolean giveCoupon;
100 /** 101 /**
101 - * 赠送的优惠劵编号的数组  
102 - */  
103 - private List<Long> couponIds;  
104 - /**  
105 - * 赠送的优惠券数量的数组 102 + * 赠送的优惠劵
  103 + *
  104 + * key: 优惠劵编号,value:对应的优惠券数量
106 */ 105 */
107 - private List<Integer> couponCounts; 106 + private Map<Long, Integer> giveCouponsMap;
108 107
109 } 108 }
110 109
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/coupon/CouponStatusEnum.java
@@ -18,7 +18,7 @@ public enum CouponStatusEnum implements IntArrayValuable { @@ -18,7 +18,7 @@ public enum CouponStatusEnum implements IntArrayValuable {
18 UNUSED(1, "未使用"), 18 UNUSED(1, "未使用"),
19 USED(2, "已使用"), 19 USED(2, "已使用"),
20 EXPIRE(3, "已过期"), 20 EXPIRE(3, "已过期"),
21 - ; 21 + INVALID(4, "已作废");
22 22
23 public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(CouponStatusEnum::getStatus).toArray(); 23 public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(CouponStatusEnum::getStatus).toArray();
24 24
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/coupon/CouponApiImpl.java
@@ -11,7 +11,7 @@ import jakarta.annotation.Resource; @@ -11,7 +11,7 @@ import jakarta.annotation.Resource;
11 import org.springframework.stereotype.Service; 11 import org.springframework.stereotype.Service;
12 import org.springframework.validation.annotation.Validated; 12 import org.springframework.validation.annotation.Validated;
13 13
14 -import java.util.List; 14 +import java.util.Map;
15 15
16 /** 16 /**
17 * 优惠劵 API 实现类 17 * 优惠劵 API 实现类
@@ -43,8 +43,13 @@ public class CouponApiImpl implements CouponApi { @@ -43,8 +43,13 @@ public class CouponApiImpl implements CouponApi {
43 } 43 }
44 44
45 @Override 45 @Override
46 - public void takeCouponsByAdmin(List<Long> templateIds, List<Integer> counts, Long userId) {  
47 - couponService.takeCouponsByAdmin(templateIds, counts, userId); 46 + public void takeCouponsByAdmin(Map<Long, Integer> giveCouponsMap, Long userId) {
  47 + couponService.takeCouponsByAdmin(giveCouponsMap, userId);
  48 + }
  49 +
  50 + @Override
  51 + public void takeBackCouponsByAdmin(Map<Long, Integer> giveCouponsMap, Long userId) {
  52 + couponService.takeBackCouponsByAdmin(giveCouponsMap, userId);
48 } 53 }
49 54
50 } 55 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/reward/vo/RewardActivityBaseVO.java
@@ -16,6 +16,7 @@ import lombok.Data; @@ -16,6 +16,7 @@ import lombok.Data;
16 16
17 import java.time.LocalDateTime; 17 import java.time.LocalDateTime;
18 import java.util.List; 18 import java.util.List;
  19 +import java.util.Map;
19 import java.util.Objects; 20 import java.util.Objects;
20 21
21 /** 22 /**
@@ -88,16 +89,7 @@ public class RewardActivityBaseVO { @@ -88,16 +89,7 @@ public class RewardActivityBaseVO {
88 private Boolean giveCoupon; 89 private Boolean giveCoupon;
89 90
90 @Schema(description = "赠送的优惠劵编号的数组", example = "1,2,3") 91 @Schema(description = "赠送的优惠劵编号的数组", example = "1,2,3")
91 - private List<Long> couponIds;  
92 -  
93 - @Schema(description = "赠送的优惠券数量的数组", example = "1,2,3")  
94 - private List<Integer> couponCounts;  
95 -  
96 - @AssertTrue(message = "优惠劵和数量必须一一对应")  
97 - @JsonIgnore  
98 - public boolean isCouponCountsValid() {  
99 - return BooleanUtil.isFalse(giveCoupon) || CollUtil.size(couponIds) == CollUtil.size(couponCounts);  
100 - } 92 + private Map<Long, Integer> giveCouponsMap;
101 93
102 @AssertTrue(message = "赠送的积分不能小于 1") 94 @AssertTrue(message = "赠送的积分不能小于 1")
103 @JsonIgnore 95 @JsonIgnore
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/coupon/CouponDO.java
@@ -50,7 +50,6 @@ public class CouponDO extends BaseDO { @@ -50,7 +50,6 @@ public class CouponDO extends BaseDO {
50 * 50 *
51 * 枚举 {@link CouponStatusEnum} 51 * 枚举 {@link CouponStatusEnum}
52 */ 52 */
53 - // TODO 芋艿:已作废?  
54 private Integer status; 53 private Integer status;
55 54
56 // TODO 芋艿:发放 adminid? 55 // TODO 芋艿:发放 adminid?
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/reward/RewardActivityDO.java
@@ -16,6 +16,7 @@ import lombok.EqualsAndHashCode; @@ -16,6 +16,7 @@ import lombok.EqualsAndHashCode;
16 import java.io.Serializable; 16 import java.io.Serializable;
17 import java.time.LocalDateTime; 17 import java.time.LocalDateTime;
18 import java.util.List; 18 import java.util.List;
  19 +import java.util.Map;
19 20
20 /** 21 /**
21 * 满减送活动 DO 22 * 满减送活动 DO
@@ -114,13 +115,11 @@ public class RewardActivityDO extends BaseDO { @@ -114,13 +115,11 @@ public class RewardActivityDO extends BaseDO {
114 */ 115 */
115 private Boolean giveCoupon; 116 private Boolean giveCoupon;
116 /** 117 /**
117 - * 赠送的优惠劵编号的数组  
118 - */  
119 - private List<Long> couponIds;  
120 - /**  
121 - * 赠送的优惠券数量的数组 118 + * 赠送的优惠劵
  119 + *
  120 + * key: 优惠劵编号,value:对应的优惠券数量
122 */ 121 */
123 - private List<Integer> couponCounts; 122 + private Map<Long, Integer> giveCouponsMap;
124 123
125 } 124 }
126 125
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/coupon/CouponMapper.java
@@ -72,6 +72,15 @@ public interface CouponMapper extends BaseMapperX&lt;CouponDO&gt; { @@ -72,6 +72,15 @@ public interface CouponMapper extends BaseMapperX&lt;CouponDO&gt; {
72 ); 72 );
73 } 73 }
74 74
  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 +
75 default Map<Long, Integer> selectCountByUserIdAndTemplateIdIn(Long userId, Collection<Long> templateIds) { 84 default Map<Long, Integer> selectCountByUserIdAndTemplateIdIn(Long userId, Collection<Long> templateIds) {
76 String templateIdAlias = "templateId"; 85 String templateIdAlias = "templateId";
77 String countAlias = "count"; 86 String countAlias = "count";
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponService.java
@@ -108,11 +108,18 @@ public interface CouponService { @@ -108,11 +108,18 @@ public interface CouponService {
108 /** 108 /**
109 * 【管理员】给指定用户批量发送优惠券 109 * 【管理员】给指定用户批量发送优惠券
110 * 110 *
111 - * @param templateIds 优惠劵编号的数组  
112 - * @param counts 优惠券数量的数组 111 + * @param giveCouponsMap key: 优惠劵编号,value:对应的优惠券数量
113 * @param userId 用户编号 112 * @param userId 用户编号
114 */ 113 */
115 - void takeCouponsByAdmin(List<Long> templateIds, List<Integer> counts, Long userId); 114 + void takeCouponsByAdmin(Map<Long, Integer> giveCouponsMap, Long userId);
  115 +
  116 + /**
  117 + * 【管理员】收回给指定用户批量发送优惠券
  118 + *
  119 + * @param giveCouponsMap key: 优惠劵编号,value:对应的优惠券数量
  120 + * @param userId 用户编号
  121 + */
  122 + void takeBackCouponsByAdmin(Map<Long, Integer> giveCouponsMap, Long userId);
116 123
117 /** 124 /**
118 * 【会员】领取优惠券 125 * 【会员】领取优惠券
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponServiceImpl.java
@@ -31,7 +31,6 @@ import java.util.stream.Collectors; @@ -31,7 +31,6 @@ import java.util.stream.Collectors;
31 31
32 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 32 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
33 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; 33 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
34 -import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen;  
35 import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*; 34 import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
36 import static java.util.Arrays.asList; 35 import static java.util.Arrays.asList;
37 36
@@ -165,6 +164,7 @@ public class CouponServiceImpl implements CouponService { @@ -165,6 +164,7 @@ public class CouponServiceImpl implements CouponService {
165 } 164 }
166 165
167 @Override 166 @Override
  167 + @Transactional(rollbackFor = Exception.class)
168 public void takeCoupon(Long templateId, Set<Long> userIds, CouponTakeTypeEnum takeType) { 168 public void takeCoupon(Long templateId, Set<Long> userIds, CouponTakeTypeEnum takeType) {
169 CouponTemplateDO template = couponTemplateService.getCouponTemplate(templateId); 169 CouponTemplateDO template = couponTemplateService.getCouponTemplate(templateId);
170 // 1. 过滤掉达到领取限制的用户 170 // 1. 过滤掉达到领取限制的用户
@@ -180,28 +180,66 @@ public class CouponServiceImpl implements CouponService { @@ -180,28 +180,66 @@ public class CouponServiceImpl implements CouponService {
180 } 180 }
181 181
182 @Override 182 @Override
183 - public void takeCouponsByAdmin(List<Long> templateIds, List<Integer> counts, Long userId) {  
184 - // TODO @puhui999:要不要循环调用上面的 takeCoupon 方法?按道理说,赠送也不会很多张。如果某次发卷失败,可以打个 error log;  
185 - // 1. 获得优惠券模版  
186 - List<CouponTemplateDO> templateList = couponTemplateService.getCouponTemplateList(templateIds);  
187 - if (CollUtil.isEmpty(templateList)) { 183 + public void takeCouponsByAdmin(Map<Long, Integer> giveCouponsMap, Long userId) {
  184 + if (CollUtil.isEmpty(giveCouponsMap)) {
188 return; 185 return;
189 } 186 }
190 187
191 - Map<Long, CouponTemplateDO> templateMap = convertMap(templateList, CouponTemplateDO::getId);  
192 - // 2.1 批量构建优惠券  
193 - List<CouponDO> couponList = new ArrayList<>();  
194 - for (int i = 0; i < templateIds.size(); i++) {  
195 - int finalI = i;  
196 - findAndThen(templateMap, templateIds.get(i), template -> {  
197 - for (int j = 0; j < counts.get(finalI); j++) {  
198 - couponList.add(CouponConvert.INSTANCE.convert(template, userId)  
199 - .setTakeType(CouponTakeTypeEnum.ADMIN.getValue())); 188 + // 循环发放
  189 + for (Map.Entry<Long, Integer> entry : giveCouponsMap.entrySet()) {
  190 + try {
  191 + for (int i = 0; i < entry.getValue(); i++) {
  192 + getSelf().takeCoupon(entry.getKey(), CollUtil.newHashSet(userId), CouponTakeTypeEnum.ADMIN);
200 } 193 }
201 - }); 194 + } catch (Exception e) {
  195 + log.error("[takeCouponsByAdmin][coupon({}) 优惠券发放失败]", entry, e);
  196 + }
  197 + }
  198 + }
  199 +
  200 + @Override
  201 + public void takeBackCouponsByAdmin(Map<Long, Integer> giveCouponsMap, Long userId) {
  202 + // 循环收回
  203 + for (Map.Entry<Long, Integer> entry : giveCouponsMap.entrySet()) {
  204 + try {
  205 + for (int i = 0; i < entry.getValue(); i++) {
  206 + getSelf().takeBackCoupon(entry.getKey(), CollUtil.newHashSet(userId), CouponTakeTypeEnum.ADMIN);
  207 + }
  208 + } catch (Exception e) {
  209 + log.error("[takeBackCouponsByAdmin][coupon({}) 收回优惠券失败]", entry, e);
  210 + }
  211 + }
  212 + }
  213 +
  214 + /**
  215 + * 【管理员】收回优惠券
  216 + *
  217 + * @param templateId 模版编号
  218 + * @param userIds 用户编号列表
  219 + * @param takeType 领取方式
  220 + */
  221 + @Transactional(rollbackFor = Exception.class)
  222 + public void takeBackCoupon(Long templateId, Set<Long> userIds, CouponTakeTypeEnum takeType) {
  223 + CouponTemplateDO couponTemplate = couponTemplateService.getCouponTemplate(templateId);
  224 + // 1.1 校验模板
  225 + if (couponTemplate == null) {
  226 + throw exception(COUPON_TEMPLATE_NOT_EXISTS);
  227 + }
  228 + // 1.2 校验领取方式
  229 + if (ObjectUtil.notEqual(couponTemplate.getTakeType(), takeType.getValue())) {
  230 + throw exception(COUPON_TEMPLATE_CANNOT_TAKE);
202 } 231 }
203 - // 2.2 批量保存优惠券  
204 - couponMapper.insertBatch(couponList); 232 +
  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()));
  237 + // 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 +
205 } 243 }
206 244
207 @Override 245 @Override
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderDO.java
@@ -12,11 +12,13 @@ import cn.iocoder.yudao.module.trade.enums.order.TradeOrderRefundStatusEnum; @@ -12,11 +12,13 @@ import cn.iocoder.yudao.module.trade.enums.order.TradeOrderRefundStatusEnum;
12 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum; 12 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum;
13 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum; 13 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
14 import com.baomidou.mybatisplus.annotation.KeySequence; 14 import com.baomidou.mybatisplus.annotation.KeySequence;
  15 +import com.baomidou.mybatisplus.annotation.TableField;
15 import com.baomidou.mybatisplus.annotation.TableName; 16 import com.baomidou.mybatisplus.annotation.TableName;
  17 +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
16 import lombok.*; 18 import lombok.*;
17 19
18 import java.time.LocalDateTime; 20 import java.time.LocalDateTime;
19 -import java.util.List; 21 +import java.util.Map;
20 22
21 /** 23 /**
22 * 交易订单 DO 24 * 交易订单 DO
@@ -292,19 +294,14 @@ public class TradeOrderDO extends BaseDO { @@ -292,19 +294,14 @@ public class TradeOrderDO extends BaseDO {
292 */ 294 */
293 private Integer vipPrice; 295 private Integer vipPrice;
294 296
295 - // TODO @puhui999::1)建议命名要 giveXXX;不然不好理解哈;2)是不是搞成 Map 好点哈。  
296 /** 297 /**
297 - * 赠送的优惠劵编号的数组 298 + * 赠送的优惠劵
298 * 299 *
  300 + * key: 优惠劵编号,value:对应的优惠券数量
299 * 目的:用于后续取消或者售后订单时,需要扣减赠送 301 * 目的:用于后续取消或者售后订单时,需要扣减赠送
300 */ 302 */
301 - private List<Long> couponIds;  
302 - /**  
303 - * 赠送的优惠券数量的数组  
304 - *  
305 - * 目的:用于后续取消或者售后订单时,需要扣减赠送  
306 - */  
307 - private List<Integer> couponCounts; 303 + @TableField(typeHandler = JacksonTypeHandler.class)
  304 + private Map<Long, Integer> giveCouponsMap;
308 305
309 /** 306 /**
310 * 秒杀活动编号 307 * 秒杀活动编号
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,7 +202,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
202 order.setProductCount(getSumValue(calculateRespBO.getItems(), TradePriceCalculateRespBO.OrderItem::getCount, Integer::sum)); 202 order.setProductCount(getSumValue(calculateRespBO.getItems(), TradePriceCalculateRespBO.OrderItem::getCount, Integer::sum));
203 order.setUserIp(getClientIP()).setTerminal(getTerminal()); 203 order.setUserIp(getClientIP()).setTerminal(getTerminal());
204 // 使用 + 赠送优惠券 204 // 使用 + 赠送优惠券
205 - order.setCouponIds(calculateRespBO.getCouponIds()).setCouponCounts(calculateRespBO.getCouponCounts()); 205 + order.setGiveCouponsMap(calculateRespBO.getGiveCouponsMap());
206 // 支付 + 退款信息 206 // 支付 + 退款信息
207 order.setAdjustPrice(0).setPayStatus(false); 207 order.setAdjustPrice(0).setPayStatus(false);
208 order.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus()).setRefundPrice(0); 208 order.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus()).setRefundPrice(0);
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeCouponOrderHandler.java
@@ -33,11 +33,11 @@ public class TradeCouponOrderHandler implements TradeOrderHandler { @@ -33,11 +33,11 @@ public class TradeCouponOrderHandler implements TradeOrderHandler {
33 33
34 @Override 34 @Override
35 public void afterPayOrder(TradeOrderDO order, List<TradeOrderItemDO> orderItems) { 35 public void afterPayOrder(TradeOrderDO order, List<TradeOrderItemDO> orderItems) {
36 - if (CollUtil.isEmpty(order.getCouponIds())) { 36 + if (CollUtil.isEmpty(order.getGiveCouponsMap())) {
37 return; 37 return;
38 } 38 }
39 // 赠送优惠券 39 // 赠送优惠券
40 - couponApi.takeCouponsByAdmin(order.getCouponIds(), order.getCouponCounts(), order.getUserId()); 40 + couponApi.takeCouponsByAdmin(order.getGiveCouponsMap(), order.getUserId());
41 } 41 }
42 42
43 @Override 43 @Override
@@ -48,10 +48,10 @@ public class TradeCouponOrderHandler implements TradeOrderHandler { @@ -48,10 +48,10 @@ public class TradeCouponOrderHandler implements TradeOrderHandler {
48 couponApi.returnUsedCoupon(order.getCouponId()); 48 couponApi.returnUsedCoupon(order.getCouponId());
49 } 49 }
50 // 情况二:收回赠送的优惠券 50 // 情况二:收回赠送的优惠券
51 - if (CollUtil.isEmpty(order.getCouponIds())) { 51 + if (CollUtil.isEmpty(order.getGiveCouponsMap())) {
52 return; 52 return;
53 } 53 }
54 - // TODO @puhui999: 收回优惠券再考虑一下,是直接删除券还是改个状态;建议是【已作废】 54 + couponApi.takeBackCouponsByAdmin(order.getGiveCouponsMap(), order.getUserId());
55 } 55 }
56 56
57 } 57 }
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/bo/TradePriceCalculateRespBO.java
@@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum; @@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
6 import lombok.Data; 6 import lombok.Data;
7 7
8 import java.util.List; 8 import java.util.List;
  9 +import java.util.Map;
9 10
10 /** 11 /**
11 * 价格计算 Response BO 12 * 价格计算 Response BO
@@ -72,15 +73,13 @@ public class TradePriceCalculateRespBO { @@ -72,15 +73,13 @@ public class TradePriceCalculateRespBO {
72 */ 73 */
73 private Boolean freeDelivery; 74 private Boolean freeDelivery;
74 75
75 - // TODO @puhui999:感觉要不要试着改成 Map<Long, Integer> giveCoupons?貌似整体会更好理解一点。  
76 /** 76 /**
77 - * 赠送的优惠劵编号的数组  
78 - */  
79 - private List<Long> couponIds;  
80 - /**  
81 - * 赠送的优惠券数量的数组 77 + * 赠送的优惠劵
  78 + *
  79 + * key: 优惠劵编号,value:对应的优惠券数量
  80 + * 目的:用于后续取消或者售后订单时,需要扣减赠送
82 */ 81 */
83 - private List<Integer> couponCounts; 82 + private Map<Long, Integer> giveCouponsMap;
84 83
85 /** 84 /**
86 * 订单价格 85 * 订单价格
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePriceCalculatorHelper.java
@@ -11,6 +11,7 @@ import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; @@ -11,6 +11,7 @@ import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO;
11 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; 11 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO;
12 12
13 import java.util.ArrayList; 13 import java.util.ArrayList;
  14 +import java.util.LinkedHashMap;
14 import java.util.List; 15 import java.util.List;
15 import java.util.Map; 16 import java.util.Map;
16 17
@@ -31,8 +32,7 @@ public class TradePriceCalculatorHelper { @@ -31,8 +32,7 @@ public class TradePriceCalculatorHelper {
31 List<ProductSpuRespDTO> spuList, List<ProductSkuRespDTO> skuList) { 32 List<ProductSpuRespDTO> spuList, List<ProductSkuRespDTO> skuList) {
32 // 创建 PriceCalculateRespDTO 对象 33 // 创建 PriceCalculateRespDTO 对象
33 TradePriceCalculateRespBO result = new TradePriceCalculateRespBO(); 34 TradePriceCalculateRespBO result = new TradePriceCalculateRespBO();
34 - result.setType(getOrderType(param)).setPromotions(new ArrayList<>())  
35 - .setCouponIds(new ArrayList<>()).setCouponCounts(new ArrayList<>()); 35 + result.setType(getOrderType(param)).setPromotions(new ArrayList<>()).setGiveCouponsMap(new LinkedHashMap<>());
36 36
37 // 创建它的 OrderItem 属性 37 // 创建它的 OrderItem 属性
38 result.setItems(new ArrayList<>(param.getItems().size())); 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
@@ -19,13 +19,14 @@ import org.springframework.stereotype.Component; @@ -19,13 +19,14 @@ import org.springframework.stereotype.Component;
19 import java.util.ArrayList; 19 import java.util.ArrayList;
20 import java.util.Comparator; 20 import java.util.Comparator;
21 import java.util.List; 21 import java.util.List;
22 -import java.util.Objects; 22 +import java.util.Map;
23 23
24 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; 24 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
25 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList; 25 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList;
26 import static cn.iocoder.yudao.module.trade.service.price.calculator.TradePriceCalculatorHelper.formatPrice; 26 import static cn.iocoder.yudao.module.trade.service.price.calculator.TradePriceCalculatorHelper.formatPrice;
27 27
28 // TODO @puhui999:相关的单测,建议改一改 28 // TODO @puhui999:相关的单测,建议改一改
  29 +
29 /** 30 /**
30 * 满减送活动的 {@link TradePriceCalculator} 实现类 31 * 满减送活动的 {@link TradePriceCalculator} 实现类
31 * 32 *
@@ -107,16 +108,12 @@ public class TradeRewardActivityPriceCalculator implements TradePriceCalculator @@ -107,16 +108,12 @@ public class TradeRewardActivityPriceCalculator implements TradePriceCalculator
107 } 108 }
108 // 4.3 记录赠送的优惠券 109 // 4.3 记录赠送的优惠券
109 if (rule.getGiveCoupon()) { 110 if (rule.getGiveCoupon()) {
110 - for (int i = 0; i < rule.getCouponIds().size(); i++) {  
111 - Long couponId = result.getCouponIds().get(i);  
112 - Integer couponCount = result.getCouponCounts().get(i);  
113 - int index = CollUtil.indexOf(result.getCouponIds(), id -> Objects.equals(couponId, id));  
114 - if (index != -1) { // 情况一:别的满减活动送过同类优惠券,则直接增加数量  
115 - List<Integer> couponCounts = result.getCouponCounts();  
116 - couponCounts.set(index, couponCounts.get(index) + couponCount);  
117 - result.setCouponCounts(couponCounts);  
118 - } else { // 情况二:还没有赠送的优惠券  
119 - result.setCouponIds(rule.getCouponIds()).setCouponCounts(rule.getCouponCounts()); 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());
  115 + } else { // 情况二:别的满减活动送过同类优惠券,则直接增加数量
  116 + giveCouponsMap.put(entry.getKey(), giveCouponsMap.get(entry.getKey()) + entry.getValue());
120 } 117 }
121 } 118 }
122 } 119 }
@@ -193,7 +190,7 @@ public class TradeRewardActivityPriceCalculator implements TradePriceCalculator @@ -193,7 +190,7 @@ public class TradeRewardActivityPriceCalculator implements TradePriceCalculator
193 // 2. 构建不满足时的提示信息:按最低档规则算 190 // 2. 构建不满足时的提示信息:按最低档规则算
194 String meetTip = "满减送:购满 {} {},可以减 {} 元"; 191 String meetTip = "满减送:购满 {} {},可以减 {} 元";
195 List<RewardActivityMatchRespDTO.Rule> rules = new ArrayList<>(rewardActivity.getRules()); 192 List<RewardActivityMatchRespDTO.Rule> rules = new ArrayList<>(rewardActivity.getRules());
196 - rules.sort(Comparator.comparing(RewardActivityMatchRespDTO.Rule::getLimit)); // 按优惠门槛降序 193 + rules.sort(Comparator.comparing(RewardActivityMatchRespDTO.Rule::getLimit)); // 按优惠门槛升序
197 RewardActivityMatchRespDTO.Rule rule = rules.get(0); 194 RewardActivityMatchRespDTO.Rule rule = rules.get(0);
198 if (PromotionConditionTypeEnum.PRICE.getType().equals(rewardActivity.getConditionType())) { 195 if (PromotionConditionTypeEnum.PRICE.getType().equals(rewardActivity.getConditionType())) {
199 return StrUtil.format(meetTip, rule.getLimit(), "元", MoneyUtils.fenToYuanStr(rule.getDiscountPrice())); 196 return StrUtil.format(meetTip, rule.getLimit(), "元", MoneyUtils.fenToYuanStr(rule.getDiscountPrice()));