Commit 3e66a922bf37a0446aaa244620ef5e0b99644c77

Authored by puhui999
1 parent e0d9f7cf

【功能新增】商城: 满减送活动下单后,赠送优惠劵

yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/coupon/CouponApi.java
... ... @@ -3,9 +3,10 @@ package cn.iocoder.yudao.module.promotion.api.coupon;
3 3 import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponRespDTO;
4 4 import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponUseReqDTO;
5 5 import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponValidReqDTO;
6   -
7 6 import jakarta.validation.Valid;
8 7  
  8 +import java.util.List;
  9 +
9 10 /**
10 11 * 优惠劵 API 接口
11 12 *
... ... @@ -35,4 +36,13 @@ public interface CouponApi {
35 36 */
36 37 CouponRespDTO validateCoupon(@Valid CouponValidReqDTO validReqDTO);
37 38  
  39 + /**
  40 + * 【管理员】给指定用户批量发送优惠券
  41 + *
  42 + * @param templateIds 优惠劵编号的数组
  43 + * @param counts 优惠券数量的数组
  44 + * @param userId 用户编号
  45 + */
  46 + void takeCouponsByAdmin(List<Long> templateIds, List<Integer> counts, Long userId);
  47 +
38 48 }
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/coupon/CouponApiImpl.java
... ... @@ -7,10 +7,11 @@ import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponValidReqDTO;
7 7 import cn.iocoder.yudao.module.promotion.convert.coupon.CouponConvert;
8 8 import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponDO;
9 9 import cn.iocoder.yudao.module.promotion.service.coupon.CouponService;
  10 +import jakarta.annotation.Resource;
10 11 import org.springframework.stereotype.Service;
11 12 import org.springframework.validation.annotation.Validated;
12 13  
13   -import jakarta.annotation.Resource;
  14 +import java.util.List;
14 15  
15 16 /**
16 17 * 优惠劵 API 实现类
... ... @@ -41,4 +42,9 @@ public class CouponApiImpl implements CouponApi {
41 42 return CouponConvert.INSTANCE.convert(coupon);
42 43 }
43 44  
  45 + @Override
  46 + public void takeCouponsByAdmin(List<Long> templateIds, List<Integer> counts, Long userId) {
  47 + couponService.takeCouponsByAdmin(templateIds, counts, userId);
  48 + }
  49 +
44 50 }
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponService.java
... ... @@ -106,6 +106,15 @@ public interface CouponService {
106 106 }
107 107  
108 108 /**
  109 + * 【管理员】给指定用户批量发送优惠券
  110 + *
  111 + * @param templateIds 优惠劵编号的数组
  112 + * @param counts 优惠券数量的数组
  113 + * @param userId 用户编号
  114 + */
  115 + void takeCouponsByAdmin(List<Long> templateIds, List<Integer> counts, Long userId);
  116 +
  117 + /**
109 118 * 【会员】领取优惠券
110 119 *
111 120 * @param templateId 优惠券模板编号
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponServiceImpl.java
... ... @@ -19,19 +19,19 @@ import cn.iocoder.yudao.module.promotion.dal.mysql.coupon.CouponMapper;
19 19 import cn.iocoder.yudao.module.promotion.enums.coupon.CouponStatusEnum;
20 20 import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTakeTypeEnum;
21 21 import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTemplateValidityTypeEnum;
  22 +import jakarta.annotation.Resource;
22 23 import lombok.extern.slf4j.Slf4j;
23 24 import org.springframework.stereotype.Service;
24 25 import org.springframework.transaction.annotation.Transactional;
25 26 import org.springframework.validation.annotation.Validated;
26 27  
27   -import jakarta.annotation.Resource;
28   -
29 28 import java.time.LocalDateTime;
30 29 import java.util.*;
31 30 import java.util.stream.Collectors;
32 31  
33 32 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
34 33 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
  34 +import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen;
35 35 import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
36 36 import static java.util.Arrays.asList;
37 37  
... ... @@ -175,11 +175,35 @@ public class CouponServiceImpl implements CouponService {
175 175 // 3. 批量保存优惠劵
176 176 couponMapper.insertBatch(convertList(userIds, userId -> CouponConvert.INSTANCE.convert(template, userId)));
177 177  
178   - // 3. 增加优惠劵模板的领取数量
  178 + // 4. 增加优惠劵模板的领取数量
179 179 couponTemplateService.updateCouponTemplateTakeCount(templateId, userIds.size());
180 180 }
181 181  
182 182 @Override
  183 + public void takeCouponsByAdmin(List<Long> templateIds, List<Integer> counts, Long userId) {
  184 + // 1. 获得优惠券模版
  185 + List<CouponTemplateDO> templateList = couponTemplateService.getCouponTemplateList(templateIds);
  186 + if (CollUtil.isEmpty(templateList)) {
  187 + return;
  188 + }
  189 +
  190 + Map<Long, CouponTemplateDO> templateMap = convertMap(templateList, CouponTemplateDO::getId);
  191 + // 2.1 批量构建优惠券
  192 + List<CouponDO> couponList = new ArrayList<>();
  193 + for (int i = 0; i < templateIds.size(); i++) {
  194 + int finalI = i;
  195 + findAndThen(templateMap, templateIds.get(i), template -> {
  196 + for (int j = 0; j < counts.get(finalI); j++) {
  197 + couponList.add(CouponConvert.INSTANCE.convert(template, userId)
  198 + .setTakeType(CouponTakeTypeEnum.ADMIN.getValue()));
  199 + }
  200 + });
  201 + }
  202 + // 2.2 批量保存优惠券
  203 + couponMapper.insertBatch(couponList);
  204 + }
  205 +
  206 + @Override
183 207 @Transactional(rollbackFor = Exception.class)
184 208 public void takeCouponByRegister(Long userId) {
185 209 List<CouponTemplateDO> templates = couponTemplateService.getCouponTemplateListByTakeType(CouponTakeTypeEnum.REGISTER);
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderDO.java
... ... @@ -16,6 +16,7 @@ import com.baomidou.mybatisplus.annotation.TableName;
16 16 import lombok.*;
17 17  
18 18 import java.time.LocalDateTime;
  19 +import java.util.List;
19 20  
20 21 /**
21 22 * 交易订单 DO
... ... @@ -290,6 +291,18 @@ public class TradeOrderDO extends BaseDO {
290 291 * VIP 减免金额,单位:分
291 292 */
292 293 private Integer vipPrice;
  294 + /**
  295 + * 赠送的优惠劵编号的数组
  296 + *
  297 + * 目的:用于后续取消或者售后订单时,需要扣减赠送
  298 + */
  299 + private List<Long> couponIds;
  300 + /**
  301 + * 赠送的优惠券数量的数组
  302 + *
  303 + * 目的:用于后续取消或者售后订单时,需要扣减赠送
  304 + */
  305 + private List<Integer> couponCounts;
293 306  
294 307 /**
295 308 * 秒杀活动编号
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderItemDO.java
... ... @@ -160,19 +160,6 @@ public class TradeOrderItemDO extends BaseDO {
160 160 */
161 161 private Integer vipPrice;
162 162  
163   - /**
164   - * 赠送的优惠劵编号的数组
165   - *
166   - * 目的:用于后续取消或者售后订单时,需要扣减赠送
167   - */
168   - private List<Long> couponIds;
169   - /**
170   - * 赠送的优惠券数量的数组
171   - *
172   - * 目的:用于后续取消或者售后订单时,需要扣减赠送
173   - */
174   - private List<Integer> couponCounts;
175   -
176 163 // ========== 售后基本信息 ==========
177 164  
178 165 /**
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java
... ... @@ -201,6 +201,8 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
201 201 order.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus());
202 202 order.setProductCount(getSumValue(calculateRespBO.getItems(), TradePriceCalculateRespBO.OrderItem::getCount, Integer::sum));
203 203 order.setUserIp(getClientIP()).setTerminal(getTerminal());
  204 + // 优惠券
  205 + order.setCouponIds(calculateRespBO.getCouponIds()).setCouponCounts(calculateRespBO.getCouponCounts());
204 206 // 支付 + 退款信息
205 207 order.setAdjustPrice(0).setPayStatus(false);
206 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
1 1 package cn.iocoder.yudao.module.trade.service.order.handler;
2 2  
  3 +import cn.hutool.core.collection.CollUtil;
3 4 import cn.iocoder.yudao.module.promotion.api.coupon.CouponApi;
4 5 import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponUseReqDTO;
5 6 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
... ... @@ -32,16 +33,25 @@ public class TradeCouponOrderHandler implements TradeOrderHandler {
32 33  
33 34 @Override
34 35 public void afterPayOrder(TradeOrderDO order, List<TradeOrderItemDO> orderItems) {
35   -
  36 + if (CollUtil.isEmpty(order.getCouponIds())) {
  37 + return;
  38 + }
  39 + // 赠送优惠券
  40 + couponApi.takeCouponsByAdmin(order.getCouponIds(), order.getCouponCounts(), order.getUserId());
36 41 }
37 42  
38 43 @Override
39 44 public void afterCancelOrder(TradeOrderDO order, List<TradeOrderItemDO> orderItems) {
40   - if (order.getCouponId() == null || order.getCouponId() <= 0) {
  45 + // 情况一:退还订单使用的优惠券
  46 + if (order.getCouponId() != null && order.getCouponId() > 0) {
  47 + // 退回优惠劵
  48 + couponApi.returnUsedCoupon(order.getCouponId());
  49 + }
  50 + // 情况二:收回赠送的优惠券
  51 + if (CollUtil.isEmpty(order.getCouponIds())) {
41 52 return;
42 53 }
43   - // 退回优惠劵
44   - couponApi.returnUsedCoupon(order.getCouponId());
  54 + // TODO @puhui999: 收回优惠券再考虑一下,是直接删除券还是改个状态
45 55 }
46 56  
47 57 }
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/bo/TradePriceCalculateRespBO.java
... ... @@ -72,7 +72,6 @@ public class TradePriceCalculateRespBO {
72 72 */
73 73 private Boolean freeDelivery;
74 74  
75   - // TODO @puhui999: 订单保存时需要保存
76 75 /**
77 76 * 赠送的优惠劵编号的数组
78 77 */
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeRewardActivityPriceCalculator.java
... ... @@ -19,6 +19,7 @@ import org.springframework.stereotype.Component;
19 19 import java.util.ArrayList;
20 20 import java.util.Comparator;
21 21 import java.util.List;
  22 +import java.util.Objects;
22 23  
23 24 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
24 25 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList;
... ... @@ -105,8 +106,18 @@ public class TradeRewardActivityPriceCalculator implements TradePriceCalculator
105 106 }
106 107 // 4.3 记录赠送的优惠券
107 108 if (rule.getGiveCoupon()) {
108   - // TODO @puhui999: 需要考虑赠送的优惠券是否重叠,重叠则对数量进行累加
109   - result.setCouponIds(rule.getCouponIds()).setCouponCounts(rule.getCouponCounts());
  109 + for (int i = 0; i < rule.getCouponIds().size(); i++) {
  110 + Long couponId = result.getCouponIds().get(i);
  111 + Integer couponCount = result.getCouponCounts().get(i);
  112 + int index = CollUtil.indexOf(result.getCouponIds(), id -> Objects.equals(couponId, id));
  113 + if (index != -1) { // 情况一:别的满减活动送过同类优惠券,则直接增加数量
  114 + List<Integer> couponCounts = result.getCouponCounts();
  115 + couponCounts.set(index, couponCounts.get(index) + couponCount);
  116 + result.setCouponCounts(couponCounts);
  117 + } else { // 情况二:还没有赠送的优惠券
  118 + result.setCouponIds(rule.getCouponIds()).setCouponCounts(rule.getCouponCounts());
  119 + }
  120 + }
110 121 }
111 122 }
112 123  
... ...