From 806c828bb50fb7077803b19a5b8a96325a279053 Mon Sep 17 00:00:00 2001 From: puhui999 Date: Fri, 30 Aug 2024 14:58:22 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E3=80=91=E5=95=86=E5=9F=8E:=20=E6=BB=A1=E5=87=8F?= =?UTF-8?q?=E9=80=81=E6=B4=BB=E5=8A=A8=E4=BC=98=E6=83=A0=E5=88=B8=E7=9B=B8?= =?UTF-8?q?=E5=85=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../promotion/api/coupon/CouponApi.java | 16 ++-- .../dto/RewardActivityMatchRespDTO.java | 11 ++- .../enums/coupon/CouponStatusEnum.java | 2 +- .../promotion/api/coupon/CouponApiImpl.java | 11 ++- .../admin/reward/vo/RewardActivityBaseVO.java | 12 +-- .../dal/dataobject/coupon/CouponDO.java | 1 - .../dataobject/reward/RewardActivityDO.java | 11 ++- .../dal/mysql/coupon/CouponMapper.java | 9 +++ .../service/coupon/CouponService.java | 13 +++- .../service/coupon/CouponServiceImpl.java | 74 ++++++++++++++----- .../dal/dataobject/order/TradeOrderDO.java | 17 ++--- .../order/TradeOrderUpdateServiceImpl.java | 2 +- .../handler/TradeCouponOrderHandler.java | 8 +- .../price/bo/TradePriceCalculateRespBO.java | 13 ++-- .../TradePriceCalculatorHelper.java | 4 +- .../TradeRewardActivityPriceCalculator.java | 21 +++--- 16 files changed, 136 insertions(+), 89 deletions(-) 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 f7b741ddb..bda835678 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 @@ -5,7 +5,7 @@ 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; +import java.util.Map; /** * 优惠劵 API 接口 @@ -36,14 +36,20 @@ public interface CouponApi { */ CouponRespDTO validateCoupon(@Valid CouponValidReqDTO validReqDTO); - // TODO @puhui999:Map 优惠劵 会不会好点。 /** * 【管理员】给指定用户批量发送优惠券 * - * @param templateIds 优惠劵编号的数组 - * @param counts 优惠券数量的数组 + * @param giveCouponsMap key: 优惠劵编号,value:对应的优惠券数量 * @param userId 用户编号 */ - void takeCouponsByAdmin(List templateIds, List counts, Long userId); + void takeCouponsByAdmin(Map giveCouponsMap, Long userId); + + /** + * 【管理员】收回给指定用户批量发送优惠券 + * + * @param giveCouponsMap key: 优惠劵编号,value:对应的优惠券数量 + * @param userId 用户编号 + */ + void takeBackCouponsByAdmin(Map giveCouponsMap, Long userId); } diff --git a/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/reward/dto/RewardActivityMatchRespDTO.java b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/reward/dto/RewardActivityMatchRespDTO.java index a174637af..9cdb922f1 100644 --- a/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/reward/dto/RewardActivityMatchRespDTO.java +++ b/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; import java.io.Serializable; import java.time.LocalDateTime; import java.util.List; +import java.util.Map; /** * 满减送活动的匹配 Response DTO @@ -98,13 +99,11 @@ public class RewardActivityMatchRespDTO { */ private Boolean giveCoupon; /** - * 赠送的优惠劵编号的数组 + * 赠送的优惠劵 + * + * key: 优惠劵编号,value:对应的优惠券数量 */ - private List couponIds; - /** - * 赠送的优惠券数量的数组 - */ - private List couponCounts; + private Map giveCouponsMap; } diff --git a/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/coupon/CouponStatusEnum.java b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/coupon/CouponStatusEnum.java index 320345d85..3edb3897f 100644 --- a/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/coupon/CouponStatusEnum.java +++ b/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 { UNUSED(1, "未使用"), USED(2, "已使用"), EXPIRE(3, "已过期"), - ; + INVALID(4, "已作废"); public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(CouponStatusEnum::getStatus).toArray(); 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 23d088a74..b4778d0fe 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 @@ -11,7 +11,7 @@ import jakarta.annotation.Resource; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; -import java.util.List; +import java.util.Map; /** * 优惠劵 API 实现类 @@ -43,8 +43,13 @@ public class CouponApiImpl implements CouponApi { } @Override - public void takeCouponsByAdmin(List templateIds, List counts, Long userId) { - couponService.takeCouponsByAdmin(templateIds, counts, userId); + public void takeCouponsByAdmin(Map giveCouponsMap, Long userId) { + couponService.takeCouponsByAdmin(giveCouponsMap, userId); + } + + @Override + public void takeBackCouponsByAdmin(Map giveCouponsMap, Long userId) { + couponService.takeBackCouponsByAdmin(giveCouponsMap, userId); } } diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/reward/vo/RewardActivityBaseVO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/reward/vo/RewardActivityBaseVO.java index f932a58d6..0ed4b7d52 100755 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/reward/vo/RewardActivityBaseVO.java +++ b/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; import java.time.LocalDateTime; import java.util.List; +import java.util.Map; import java.util.Objects; /** @@ -88,16 +89,7 @@ public class RewardActivityBaseVO { private Boolean giveCoupon; @Schema(description = "赠送的优惠劵编号的数组", example = "1,2,3") - private List couponIds; - - @Schema(description = "赠送的优惠券数量的数组", example = "1,2,3") - private List couponCounts; - - @AssertTrue(message = "优惠劵和数量必须一一对应") - @JsonIgnore - public boolean isCouponCountsValid() { - return BooleanUtil.isFalse(giveCoupon) || CollUtil.size(couponIds) == CollUtil.size(couponCounts); - } + private Map giveCouponsMap; @AssertTrue(message = "赠送的积分不能小于 1") @JsonIgnore diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/coupon/CouponDO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/coupon/CouponDO.java index 296d2a2fd..7182f0ea0 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/coupon/CouponDO.java +++ b/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 { * * 枚举 {@link CouponStatusEnum} */ - // TODO 芋艿:已作废? private Integer status; // TODO 芋艿:发放 adminid? diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/reward/RewardActivityDO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/reward/RewardActivityDO.java index 9a7135063..b1332cb3f 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/reward/RewardActivityDO.java +++ b/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; import java.io.Serializable; import java.time.LocalDateTime; import java.util.List; +import java.util.Map; /** * 满减送活动 DO @@ -114,13 +115,11 @@ public class RewardActivityDO extends BaseDO { */ private Boolean giveCoupon; /** - * 赠送的优惠劵编号的数组 + * 赠送的优惠劵 + * + * key: 优惠劵编号,value:对应的优惠券数量 */ - private List couponIds; - /** - * 赠送的优惠券数量的数组 - */ - private List couponCounts; + private Map giveCouponsMap; } diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/coupon/CouponMapper.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/coupon/CouponMapper.java index e5f1daf6c..913b84510 100755 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/coupon/CouponMapper.java +++ b/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 { ); } + default List selectListByTemplateIdAndUserIdAndTakeType(Long templateId, Collection userIds, + Integer takeType) { + return selectList(new LambdaQueryWrapperX() + .eq(CouponDO::getTemplateId, templateId) + .eq(CouponDO::getTakeType, takeType) + .in(CouponDO::getUserId, userIds) + ); + } + default Map selectCountByUserIdAndTemplateIdIn(Long userId, Collection templateIds) { String templateIdAlias = "templateId"; String countAlias = "count"; 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 5220a6da7..628a42e7f 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 @@ -108,11 +108,18 @@ public interface CouponService { /** * 【管理员】给指定用户批量发送优惠券 * - * @param templateIds 优惠劵编号的数组 - * @param counts 优惠券数量的数组 + * @param giveCouponsMap key: 优惠劵编号,value:对应的优惠券数量 * @param userId 用户编号 */ - void takeCouponsByAdmin(List templateIds, List counts, Long userId); + void takeCouponsByAdmin(Map giveCouponsMap, Long userId); + + /** + * 【管理员】收回给指定用户批量发送优惠券 + * + * @param giveCouponsMap key: 优惠劵编号,value:对应的优惠券数量 + * @param userId 用户编号 + */ + void takeBackCouponsByAdmin(Map giveCouponsMap, 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 222843c31..aff7579de 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 @@ -31,7 +31,6 @@ 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; @@ -165,6 +164,7 @@ public class CouponServiceImpl implements CouponService { } @Override + @Transactional(rollbackFor = Exception.class) public void takeCoupon(Long templateId, Set userIds, CouponTakeTypeEnum takeType) { CouponTemplateDO template = couponTemplateService.getCouponTemplate(templateId); // 1. 过滤掉达到领取限制的用户 @@ -180,28 +180,66 @@ public class CouponServiceImpl implements CouponService { } @Override - public void takeCouponsByAdmin(List templateIds, List counts, Long userId) { - // TODO @puhui999:要不要循环调用上面的 takeCoupon 方法?按道理说,赠送也不会很多张。如果某次发卷失败,可以打个 error log; - // 1. 获得优惠券模版 - List templateList = couponTemplateService.getCouponTemplateList(templateIds); - if (CollUtil.isEmpty(templateList)) { + public void takeCouponsByAdmin(Map giveCouponsMap, Long userId) { + if (CollUtil.isEmpty(giveCouponsMap)) { 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())); + // 循环发放 + for (Map.Entry entry : giveCouponsMap.entrySet()) { + try { + for (int i = 0; i < entry.getValue(); i++) { + getSelf().takeCoupon(entry.getKey(), CollUtil.newHashSet(userId), CouponTakeTypeEnum.ADMIN); } - }); + } catch (Exception e) { + log.error("[takeCouponsByAdmin][coupon({}) 优惠券发放失败]", entry, e); + } } - // 2.2 批量保存优惠券 - couponMapper.insertBatch(couponList); + } + + @Override + public void takeBackCouponsByAdmin(Map giveCouponsMap, Long userId) { + // 循环收回 + for (Map.Entry entry : giveCouponsMap.entrySet()) { + try { + for (int i = 0; i < entry.getValue(); i++) { + getSelf().takeBackCoupon(entry.getKey(), CollUtil.newHashSet(userId), CouponTakeTypeEnum.ADMIN); + } + } catch (Exception e) { + log.error("[takeBackCouponsByAdmin][coupon({}) 收回优惠券失败]", entry, e); + } + } + } + + /** + * 【管理员】收回优惠券 + * + * @param templateId 模版编号 + * @param userIds 用户编号列表 + * @param takeType 领取方式 + */ + @Transactional(rollbackFor = Exception.class) + public void takeBackCoupon(Long templateId, Set userIds, CouponTakeTypeEnum takeType) { + CouponTemplateDO couponTemplate = couponTemplateService.getCouponTemplate(templateId); + // 1.1 校验模板 + if (couponTemplate == null) { + throw exception(COUPON_TEMPLATE_NOT_EXISTS); + } + // 1.2 校验领取方式 + if (ObjectUtil.notEqual(couponTemplate.getTakeType(), takeType.getValue())) { + throw exception(COUPON_TEMPLATE_CANNOT_TAKE); + } + + // 2.1 过滤出还未使用的赠送的优惠券 + List couponList = couponMapper.selectListByTemplateIdAndUserIdAndTakeType(templateId, userIds, + takeType.getValue()); + List unUsedCouponList = filterList(couponList, item -> !CouponStatusEnum.USED.getStatus().equals(item.getStatus())); + // 2.2 减少优惠劵模板的领取数量 + couponTemplateService.updateCouponTemplateTakeCount(templateId, unUsedCouponList.size() * -1); + // 2.3 批量更新优惠劵状态 + couponMapper.updateById(convertList(unUsedCouponList, item -> new CouponDO().setId(item.getId()) + .setStatus(CouponStatusEnum.INVALID.getStatus()))); + } @Override 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 4ce025408..710d8dc3f 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 @@ -12,11 +12,13 @@ import cn.iocoder.yudao.module.trade.enums.order.TradeOrderRefundStatusEnum; import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum; import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum; import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; import lombok.*; import java.time.LocalDateTime; -import java.util.List; +import java.util.Map; /** * 交易订单 DO @@ -292,19 +294,14 @@ public class TradeOrderDO extends BaseDO { */ private Integer vipPrice; - // TODO @puhui999::1)建议命名要 giveXXX;不然不好理解哈;2)是不是搞成 Map 好点哈。 /** - * 赠送的优惠劵编号的数组 + * 赠送的优惠劵 * + * key: 优惠劵编号,value:对应的优惠券数量 * 目的:用于后续取消或者售后订单时,需要扣减赠送 */ - private List couponIds; - /** - * 赠送的优惠券数量的数组 - * - * 目的:用于后续取消或者售后订单时,需要扣减赠送 - */ - private List couponCounts; + @TableField(typeHandler = JacksonTypeHandler.class) + private Map giveCouponsMap; /** * 秒杀活动编号 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 5cb932e4e..c9c1e685b 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 @@ -202,7 +202,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { order.setProductCount(getSumValue(calculateRespBO.getItems(), TradePriceCalculateRespBO.OrderItem::getCount, Integer::sum)); order.setUserIp(getClientIP()).setTerminal(getTerminal()); // 使用 + 赠送优惠券 - order.setCouponIds(calculateRespBO.getCouponIds()).setCouponCounts(calculateRespBO.getCouponCounts()); + order.setGiveCouponsMap(calculateRespBO.getGiveCouponsMap()); // 支付 + 退款信息 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 9428c6412..e364bc007 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 @@ -33,11 +33,11 @@ public class TradeCouponOrderHandler implements TradeOrderHandler { @Override public void afterPayOrder(TradeOrderDO order, List orderItems) { - if (CollUtil.isEmpty(order.getCouponIds())) { + if (CollUtil.isEmpty(order.getGiveCouponsMap())) { return; } // 赠送优惠券 - couponApi.takeCouponsByAdmin(order.getCouponIds(), order.getCouponCounts(), order.getUserId()); + couponApi.takeCouponsByAdmin(order.getGiveCouponsMap(), order.getUserId()); } @Override @@ -48,10 +48,10 @@ public class TradeCouponOrderHandler implements TradeOrderHandler { couponApi.returnUsedCoupon(order.getCouponId()); } // 情况二:收回赠送的优惠券 - if (CollUtil.isEmpty(order.getCouponIds())) { + if (CollUtil.isEmpty(order.getGiveCouponsMap())) { return; } - // TODO @puhui999: 收回优惠券再考虑一下,是直接删除券还是改个状态;建议是【已作废】 + couponApi.takeBackCouponsByAdmin(order.getGiveCouponsMap(), order.getUserId()); } } 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 95f85aea8..e53613d26 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 @@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum; import lombok.Data; import java.util.List; +import java.util.Map; /** * 价格计算 Response BO @@ -72,15 +73,13 @@ public class TradePriceCalculateRespBO { */ private Boolean freeDelivery; - // TODO @puhui999:感觉要不要试着改成 Map giveCoupons?貌似整体会更好理解一点。 /** - * 赠送的优惠劵编号的数组 + * 赠送的优惠劵 + * + * key: 优惠劵编号,value:对应的优惠券数量 + * 目的:用于后续取消或者售后订单时,需要扣减赠送 */ - private List couponIds; - /** - * 赠送的优惠券数量的数组 - */ - private List couponCounts; + private Map giveCouponsMap; /** * 订单价格 diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePriceCalculatorHelper.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePriceCalculatorHelper.java index cb8f97c11..6fa639c5a 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePriceCalculatorHelper.java +++ b/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; import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; import java.util.ArrayList; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -31,8 +32,7 @@ public class TradePriceCalculatorHelper { List spuList, List skuList) { // 创建 PriceCalculateRespDTO 对象 TradePriceCalculateRespBO result = new TradePriceCalculateRespBO(); - result.setType(getOrderType(param)).setPromotions(new ArrayList<>()) - .setCouponIds(new ArrayList<>()).setCouponCounts(new ArrayList<>()); + result.setType(getOrderType(param)).setPromotions(new ArrayList<>()).setGiveCouponsMap(new LinkedHashMap<>()); // 创建它的 OrderItem 属性 result.setItems(new ArrayList<>(param.getItems().size())); 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 d543dc1f4..05679d836 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,13 +19,14 @@ import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.Comparator; import java.util.List; -import java.util.Objects; +import java.util.Map; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList; import static cn.iocoder.yudao.module.trade.service.price.calculator.TradePriceCalculatorHelper.formatPrice; // TODO @puhui999:相关的单测,建议改一改 + /** * 满减送活动的 {@link TradePriceCalculator} 实现类 * @@ -107,16 +108,12 @@ public class TradeRewardActivityPriceCalculator implements TradePriceCalculator } // 4.3 记录赠送的优惠券 if (rule.getGiveCoupon()) { - 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()); + for (Map.Entry entry : rule.getGiveCouponsMap().entrySet()) { + Map giveCouponsMap = result.getGiveCouponsMap(); + if (giveCouponsMap.get(entry.getKey()) == null) { // 情况一:还没有赠送的优惠券 + result.setGiveCouponsMap(rule.getGiveCouponsMap()); + } else { // 情况二:别的满减活动送过同类优惠券,则直接增加数量 + giveCouponsMap.put(entry.getKey(), giveCouponsMap.get(entry.getKey()) + entry.getValue()); } } } @@ -193,7 +190,7 @@ public class TradeRewardActivityPriceCalculator implements TradePriceCalculator // 2. 构建不满足时的提示信息:按最低档规则算 String meetTip = "满减送:购满 {} {},可以减 {} 元"; List rules = new ArrayList<>(rewardActivity.getRules()); - rules.sort(Comparator.comparing(RewardActivityMatchRespDTO.Rule::getLimit)); // 按优惠门槛降序 + rules.sort(Comparator.comparing(RewardActivityMatchRespDTO.Rule::getLimit)); // 按优惠门槛升序 RewardActivityMatchRespDTO.Rule rule = rules.get(0); if (PromotionConditionTypeEnum.PRICE.getType().equals(rewardActivity.getConditionType())) { return StrUtil.format(meetTip, rule.getLimit(), "元", MoneyUtils.fenToYuanStr(rule.getDiscountPrice())); From d26ef6b89e2c3748360a92255ffbee61822c6429 Mon Sep 17 00:00:00 2001 From: puhui999 Date: Fri, 30 Aug 2024 16:17:19 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E3=80=91=E5=95=86=E5=9F=8E:=20TradeRewardActivityPric?= =?UTF-8?q?eCalculatorTest?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../TradeRewardActivityPriceCalculator.java | 6 ++--- ...radeRewardActivityPriceCalculatorTest.java | 27 +++++++++++++------ .../src/test/resources/sql/create_tables.sql | 1 + 3 files changed, 23 insertions(+), 11 deletions(-) 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 05679d836..6b333df47 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 @@ -93,7 +93,7 @@ public class TradeRewardActivityPriceCalculator implements TradePriceCalculator TradePriceCalculatorHelper.recountAllPrice(result); // 4.1 记录赠送的积分 - if (rule.getGivePoint()) { + if (Boolean.TRUE.equals(rule.getGivePoint())) { List dividePoints = TradePriceCalculatorHelper.dividePrice(orderItems, rule.getPoint()); for (int i = 0; i < orderItems.size(); i++) { // 商品可能赠送了积分,所以这里要加上 @@ -102,12 +102,12 @@ public class TradeRewardActivityPriceCalculator implements TradePriceCalculator } } // 4.2 记录订单是否包邮 - if (rule.getFreeDelivery()) { + if (Boolean.TRUE.equals(rule.getFreeDelivery())) { // 只要满足一个活动包邮那么这单就包邮 result.setFreeDelivery(true); } // 4.3 记录赠送的优惠券 - if (rule.getGiveCoupon()) { + if (Boolean.TRUE.equals(rule.getGiveCoupon())) { for (Map.Entry entry : rule.getGiveCouponsMap().entrySet()) { Map giveCouponsMap = result.getGiveCouponsMap(); if (giveCouponsMap.get(entry.getKey()) == null) { // 情况一:还没有赠送的优惠券 diff --git a/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeRewardActivityPriceCalculatorTest.java b/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeRewardActivityPriceCalculatorTest.java index 219ae727e..3ae34514d 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeRewardActivityPriceCalculatorTest.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeRewardActivityPriceCalculatorTest.java @@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; import cn.iocoder.yudao.module.promotion.api.reward.RewardActivityApi; import cn.iocoder.yudao.module.promotion.api.reward.dto.RewardActivityMatchRespDTO; import cn.iocoder.yudao.module.promotion.enums.common.PromotionConditionTypeEnum; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum; import cn.iocoder.yudao.module.promotion.enums.common.PromotionTypeEnum; import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum; import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; @@ -13,6 +14,7 @@ import org.mockito.InjectMocks; import org.mockito.Mock; import java.util.ArrayList; +import java.util.LinkedHashMap; import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet; import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; @@ -47,7 +49,7 @@ public class TradeRewardActivityPriceCalculatorTest extends BaseMockitoUnitTest TradePriceCalculateRespBO result = new TradePriceCalculateRespBO() .setType(TradeOrderTypeEnum.NORMAL.getType()) .setPrice(new TradePriceCalculateRespBO.Price()) - .setPromotions(new ArrayList<>()) + .setPromotions(new ArrayList<>()).setGiveCouponsMap(new LinkedHashMap<>()) .setItems(asList( new TradePriceCalculateRespBO.OrderItem().setSkuId(10L).setCount(2).setSelected(true) .setPrice(100).setSpuId(1L), @@ -60,16 +62,22 @@ public class TradeRewardActivityPriceCalculatorTest extends BaseMockitoUnitTest TradePriceCalculatorHelper.recountPayPrice(result.getItems()); TradePriceCalculatorHelper.recountAllPrice(result); - // mock 方法(限时折扣 DiscountActivity 信息) + // mock 方法(满减送 RewardActivity 信息) when(rewardActivityApi.getMatchRewardActivityList(eq(asSet(1L, 2L, 3L)))).thenReturn(asList( randomPojo(RewardActivityMatchRespDTO.class, o -> o.setId(1000L).setName("活动 1000 号") - .setProductScopeValues(asList(1L, 2L)).setConditionType(PromotionConditionTypeEnum.PRICE.getType()) - .setRules(singletonList(new RewardActivityMatchRespDTO.Rule().setLimit(200).setDiscountPrice(70)))), + .setConditionType(PromotionConditionTypeEnum.PRICE.getType()) + .setProductScope(PromotionProductScopeEnum.SPU.getScope()).setProductScopeValues(asList(1L, 2L)) + .setRules(singletonList(new RewardActivityMatchRespDTO.Rule().setLimit(20).setDiscountPrice(70) + .setGivePoint(false).setFreeDelivery(false)))), randomPojo(RewardActivityMatchRespDTO.class, o -> o.setId(2000L).setName("活动 2000 号") - .setProductScopeValues(singletonList(3L)).setConditionType(PromotionConditionTypeEnum.COUNT.getType()) - .setRules(asList(new RewardActivityMatchRespDTO.Rule().setLimit(1).setDiscountPrice(10), - new RewardActivityMatchRespDTO.Rule().setLimit(2).setDiscountPrice(60), // 最大可满足,因为是 4 个 - new RewardActivityMatchRespDTO.Rule().setLimit(10).setDiscountPrice(100)))) + .setConditionType(PromotionConditionTypeEnum.COUNT.getType()) + .setProductScope(PromotionProductScopeEnum.SPU.getScope()).setProductScopeValues(singletonList(3L)) + .setRules(asList(new RewardActivityMatchRespDTO.Rule().setLimit(1).setDiscountPrice(10) + .setGivePoint(true).setPoint(50).setFreeDelivery(false), + new RewardActivityMatchRespDTO.Rule().setLimit(2).setDiscountPrice(60).setGivePoint(true) + .setPoint(100).setFreeDelivery(false), // 最大可满足,因为是 4 个 + new RewardActivityMatchRespDTO.Rule().setLimit(10).setDiscountPrice(100) + .setGivePoint(false).setFreeDelivery(false)))) )); // 调用 @@ -94,6 +102,7 @@ public class TradeRewardActivityPriceCalculatorTest extends BaseMockitoUnitTest assertEquals(orderItem01.getCouponPrice(), 0); assertEquals(orderItem01.getPointPrice(), 0); assertEquals(orderItem01.getPayPrice(), 160); + assertEquals(orderItem01.getGivePoint(), 0); // 断言:SKU 2 TradePriceCalculateRespBO.OrderItem orderItem02 = result.getItems().get(1); assertEquals(orderItem02.getSkuId(), 20L); @@ -104,6 +113,7 @@ public class TradeRewardActivityPriceCalculatorTest extends BaseMockitoUnitTest assertEquals(orderItem02.getCouponPrice(), 0); assertEquals(orderItem02.getPointPrice(), 0); assertEquals(orderItem02.getPayPrice(), 120); + assertEquals(orderItem02.getGivePoint(), 0); // 断言:SKU 3 TradePriceCalculateRespBO.OrderItem orderItem03 = result.getItems().get(2); assertEquals(orderItem03.getSkuId(), 30L); @@ -114,6 +124,7 @@ public class TradeRewardActivityPriceCalculatorTest extends BaseMockitoUnitTest assertEquals(orderItem03.getCouponPrice(), 0); assertEquals(orderItem03.getPointPrice(), 0); assertEquals(orderItem03.getPayPrice(), 60); + assertEquals(orderItem03.getGivePoint(), 100); // 断言:Promotion 部分(第一个) assertEquals(result.getPromotions().size(), 2); TradePriceCalculateRespBO.Promotion promotion01 = result.getPromotions().get(0); diff --git a/yudao-module-mall/yudao-module-trade-biz/src/test/resources/sql/create_tables.sql b/yudao-module-mall/yudao-module-trade-biz/src/test/resources/sql/create_tables.sql index f619c01de..1d7ed24ee 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/test/resources/sql/create_tables.sql +++ b/yudao-module-mall/yudao-module-trade-biz/src/test/resources/sql/create_tables.sql @@ -48,6 +48,7 @@ CREATE TABLE IF NOT EXISTS "trade_order" "give_point" int NULL, "refund_point" int NULL, "vip_price" int NULL, + "give_coupons_map" varchar NULL, "seckill_activity_id" long NULL, "bargain_activity_id" long NULL, "bargain_record_id" long NULL,