瀏覽代碼

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

puhui999 6 月之前
父節點
當前提交
3e66a922bf

+ 11 - 1
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;
 import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponRespDTO;
 import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponUseReqDTO;
 import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponValidReqDTO;
-
 import jakarta.validation.Valid;
 
+import java.util.List;
+
 /**
  * 优惠劵 API 接口
  *
@@ -35,4 +36,13 @@ public interface CouponApi {
      */
     CouponRespDTO validateCoupon(@Valid CouponValidReqDTO validReqDTO);
 
+    /**
+     * 【管理员】给指定用户批量发送优惠券
+     *
+     * @param templateIds 优惠劵编号的数组
+     * @param counts      优惠券数量的数组
+     * @param userId      用户编号
+     */
+    void takeCouponsByAdmin(List<Long> templateIds, List<Integer> counts, Long userId);
+
 }

+ 7 - 1
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;
 import cn.iocoder.yudao.module.promotion.convert.coupon.CouponConvert;
 import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponDO;
 import cn.iocoder.yudao.module.promotion.service.coupon.CouponService;
+import jakarta.annotation.Resource;
 import org.springframework.stereotype.Service;
 import org.springframework.validation.annotation.Validated;
 
-import jakarta.annotation.Resource;
+import java.util.List;
 
 /**
  * 优惠劵 API 实现类
@@ -41,4 +42,9 @@ public class CouponApiImpl implements CouponApi {
         return CouponConvert.INSTANCE.convert(coupon);
     }
 
+    @Override
+    public void takeCouponsByAdmin(List<Long> templateIds, List<Integer> counts, Long userId) {
+        couponService.takeCouponsByAdmin(templateIds, counts, userId);
+    }
+
 }

+ 9 - 0
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponService.java

@@ -105,6 +105,15 @@ public interface CouponService {
         takeCoupon(templateId, userIds, CouponTakeTypeEnum.ADMIN);
     }
 
+    /**
+     * 【管理员】给指定用户批量发送优惠券
+     *
+     * @param templateIds 优惠劵编号的数组
+     * @param counts      优惠券数量的数组
+     * @param userId      用户编号
+     */
+    void takeCouponsByAdmin(List<Long> templateIds, List<Integer> counts, Long userId);
+
     /**
      * 【会员】领取优惠券
      *

+ 27 - 3
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;
 import cn.iocoder.yudao.module.promotion.enums.coupon.CouponStatusEnum;
 import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTakeTypeEnum;
 import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTemplateValidityTypeEnum;
+import jakarta.annotation.Resource;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.validation.annotation.Validated;
 
-import jakarta.annotation.Resource;
-
 import java.time.LocalDateTime;
 import java.util.*;
 import java.util.stream.Collectors;
 
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
+import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen;
 import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
 import static java.util.Arrays.asList;
 
@@ -175,10 +175,34 @@ public class CouponServiceImpl implements CouponService {
         // 3. 批量保存优惠劵
         couponMapper.insertBatch(convertList(userIds, userId -> CouponConvert.INSTANCE.convert(template, userId)));
 
-        // 3. 增加优惠劵模板的领取数量
+        // 4. 增加优惠劵模板的领取数量
         couponTemplateService.updateCouponTemplateTakeCount(templateId, userIds.size());
     }
 
+    @Override
+    public void takeCouponsByAdmin(List<Long> templateIds, List<Integer> counts, Long userId) {
+        // 1. 获得优惠券模版
+        List<CouponTemplateDO> templateList = couponTemplateService.getCouponTemplateList(templateIds);
+        if (CollUtil.isEmpty(templateList)) {
+            return;
+        }
+
+        Map<Long, CouponTemplateDO> templateMap = convertMap(templateList, CouponTemplateDO::getId);
+        // 2.1 批量构建优惠券
+        List<CouponDO> couponList = new ArrayList<>();
+        for (int i = 0; i < templateIds.size(); i++) {
+            int finalI = i;
+            findAndThen(templateMap, templateIds.get(i), template -> {
+                for (int j = 0; j < counts.get(finalI); j++) {
+                    couponList.add(CouponConvert.INSTANCE.convert(template, userId)
+                            .setTakeType(CouponTakeTypeEnum.ADMIN.getValue()));
+                }
+            });
+        }
+        // 2.2 批量保存优惠券
+        couponMapper.insertBatch(couponList);
+    }
+
     @Override
     @Transactional(rollbackFor = Exception.class)
     public void takeCouponByRegister(Long userId) {

+ 13 - 0
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;
 import lombok.*;
 
 import java.time.LocalDateTime;
+import java.util.List;
 
 /**
  * 交易订单 DO
@@ -290,6 +291,18 @@ public class TradeOrderDO extends BaseDO {
      * VIP 减免金额,单位:分
      */
     private Integer vipPrice;
+    /**
+     * 赠送的优惠劵编号的数组
+     *
+     * 目的:用于后续取消或者售后订单时,需要扣减赠送
+     */
+    private List<Long> couponIds;
+    /**
+     * 赠送的优惠券数量的数组
+     *
+     * 目的:用于后续取消或者售后订单时,需要扣减赠送
+     */
+    private List<Integer> couponCounts;
 
     /**
      * 秒杀活动编号

+ 0 - 13
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 {
      */
     private Integer vipPrice;
 
-    /**
-     * 赠送的优惠劵编号的数组
-     *
-     * 目的:用于后续取消或者售后订单时,需要扣减赠送
-     */
-    private List<Long> couponIds;
-    /**
-     * 赠送的优惠券数量的数组
-     *
-     * 目的:用于后续取消或者售后订单时,需要扣减赠送
-     */
-    private List<Integer> couponCounts;
-
     // ========== 售后基本信息 ==========
 
     /**

+ 2 - 0
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 {
         order.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus());
         order.setProductCount(getSumValue(calculateRespBO.getItems(), TradePriceCalculateRespBO.OrderItem::getCount, Integer::sum));
         order.setUserIp(getClientIP()).setTerminal(getTerminal());
+        // 优惠券
+        order.setCouponIds(calculateRespBO.getCouponIds()).setCouponCounts(calculateRespBO.getCouponCounts());
         // 支付 + 退款信息
         order.setAdjustPrice(0).setPayStatus(false);
         order.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus()).setRefundPrice(0);

+ 14 - 4
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeCouponOrderHandler.java

@@ -1,5 +1,6 @@
 package cn.iocoder.yudao.module.trade.service.order.handler;
 
+import cn.hutool.core.collection.CollUtil;
 import cn.iocoder.yudao.module.promotion.api.coupon.CouponApi;
 import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponUseReqDTO;
 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
@@ -32,16 +33,25 @@ public class TradeCouponOrderHandler implements TradeOrderHandler {
 
     @Override
     public void afterPayOrder(TradeOrderDO order, List<TradeOrderItemDO> orderItems) {
-
+        if (CollUtil.isEmpty(order.getCouponIds())) {
+            return;
+        }
+        // 赠送优惠券
+        couponApi.takeCouponsByAdmin(order.getCouponIds(), order.getCouponCounts(), order.getUserId());
     }
 
     @Override
     public void afterCancelOrder(TradeOrderDO order, List<TradeOrderItemDO> orderItems) {
-        if (order.getCouponId() == null || order.getCouponId() <= 0) {
+        // 情况一:退还订单使用的优惠券
+        if (order.getCouponId() != null && order.getCouponId() > 0) {
+            // 退回优惠劵
+            couponApi.returnUsedCoupon(order.getCouponId());
+        }
+        // 情况二:收回赠送的优惠券
+        if (CollUtil.isEmpty(order.getCouponIds())) {
             return;
         }
-        // 退回优惠劵
-        couponApi.returnUsedCoupon(order.getCouponId());
+        // TODO @puhui999: 收回优惠券再考虑一下,是直接删除券还是改个状态
     }
 
 }

+ 0 - 1
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 {
      */
     private Boolean freeDelivery;
 
-    // TODO @puhui999: 订单保存时需要保存
     /**
      * 赠送的优惠劵编号的数组
      */

+ 13 - 2
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;
 import java.util.ArrayList;
 import java.util.Comparator;
 import java.util.List;
+import java.util.Objects;
 
 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList;
@@ -105,8 +106,18 @@ public class TradeRewardActivityPriceCalculator implements TradePriceCalculator
         }
         // 4.3 记录赠送的优惠券
         if (rule.getGiveCoupon()) {
-            // TODO @puhui999: 需要考虑赠送的优惠券是否重叠,重叠则对数量进行累加
-            result.setCouponIds(rule.getCouponIds()).setCouponCounts(rule.getCouponCounts());
+            for (int i = 0; i < rule.getCouponIds().size(); i++) {
+                Long couponId = result.getCouponIds().get(i);
+                Integer couponCount = result.getCouponCounts().get(i);
+                int index = CollUtil.indexOf(result.getCouponIds(), id -> Objects.equals(couponId, id));
+                if (index != -1) { // 情况一:别的满减活动送过同类优惠券,则直接增加数量
+                    List<Integer> couponCounts = result.getCouponCounts();
+                    couponCounts.set(index, couponCounts.get(index) + couponCount);
+                    result.setCouponCounts(couponCounts);
+                } else { // 情况二:还没有赠送的优惠券
+                    result.setCouponIds(rule.getCouponIds()).setCouponCounts(rule.getCouponCounts());
+                }
+            }
         }
     }