diff --git a/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/coupon/CouponApi.java b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/coupon/CouponApi.java index 27e5b6fb8..09fa7f9a8 100644 --- a/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/coupon/CouponApi.java +++ b/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 templateIds, List counts, Long userId); + } diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/coupon/CouponApiImpl.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/coupon/CouponApiImpl.java index b7f904583..23d088a74 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/coupon/CouponApiImpl.java +++ b/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 templateIds, List counts, Long userId) { + couponService.takeCouponsByAdmin(templateIds, counts, userId); + } + } diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponService.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponService.java index edd654275..5220a6da7 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponService.java +++ b/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 templateIds, List counts, Long userId); + /** * 【会员】领取优惠券 * diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponServiceImpl.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponServiceImpl.java index abf933d83..dcca8344f 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponServiceImpl.java +++ b/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 templateIds, List counts, Long userId) { + // 1. 获得优惠券模版 + List templateList = couponTemplateService.getCouponTemplateList(templateIds); + if (CollUtil.isEmpty(templateList)) { + return; + } + + Map templateMap = convertMap(templateList, CouponTemplateDO::getId); + // 2.1 批量构建优惠券 + List 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) { diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderDO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderDO.java index b127004aa..495287edf 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderDO.java +++ b/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 couponIds; + /** + * 赠送的优惠券数量的数组 + * + * 目的:用于后续取消或者售后订单时,需要扣减赠送 + */ + private List couponCounts; /** * 秒杀活动编号 diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderItemDO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderItemDO.java index b69997605..450bc764f 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderItemDO.java +++ b/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 couponIds; - /** - * 赠送的优惠券数量的数组 - * - * 目的:用于后续取消或者售后订单时,需要扣减赠送 - */ - private List couponCounts; - // ========== 售后基本信息 ========== /** diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java index a4f29a5b8..ee6cb90b0 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java +++ b/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); diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeCouponOrderHandler.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeCouponOrderHandler.java index eb4816719..6da931b6e 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeCouponOrderHandler.java +++ b/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 orderItems) { - + if (CollUtil.isEmpty(order.getCouponIds())) { + return; + } + // 赠送优惠券 + couponApi.takeCouponsByAdmin(order.getCouponIds(), order.getCouponCounts(), order.getUserId()); } @Override public void afterCancelOrder(TradeOrderDO order, List 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: 收回优惠券再考虑一下,是直接删除券还是改个状态 } } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/bo/TradePriceCalculateRespBO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/bo/TradePriceCalculateRespBO.java index 32043df0e..119b68ec8 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/bo/TradePriceCalculateRespBO.java +++ b/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: 订单保存时需要保存 /** * 赠送的优惠劵编号的数组 */ diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeRewardActivityPriceCalculator.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeRewardActivityPriceCalculator.java index fa5a61f3a..47420e24e 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeRewardActivityPriceCalculator.java +++ b/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 couponCounts = result.getCouponCounts(); + couponCounts.set(index, couponCounts.get(index) + couponCount); + result.setCouponCounts(couponCounts); + } else { // 情况二:还没有赠送的优惠券 + result.setCouponIds(rule.getCouponIds()).setCouponCounts(rule.getCouponCounts()); + } + } } }