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

Merge pull request !1064 from puhui999/develop
This commit is contained in:
芋道源码 2024-08-30 13:25:32 +00:00 committed by Gitee
commit 69d1a70900
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
18 changed files with 159 additions and 100 deletions

View File

@ -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 cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponValidReqDTO;
import jakarta.validation.Valid; import jakarta.validation.Valid;
import java.util.List; import java.util.Map;
/** /**
* 优惠劵 API 接口 * 优惠劵 API 接口
@ -36,14 +36,20 @@ public interface CouponApi {
*/ */
CouponRespDTO validateCoupon(@Valid CouponValidReqDTO validReqDTO); CouponRespDTO validateCoupon(@Valid CouponValidReqDTO validReqDTO);
// TODO @puhui999Map<Long, Integer> 优惠劵 会不会好点
/** /**
* 管理员给指定用户批量发送优惠券 * 管理员给指定用户批量发送优惠券
* *
* @param templateIds 优惠劵编号的数组 * @param giveCouponsMap key: 优惠劵编号value对应的优惠券数量
* @param counts 优惠券数量的数组
* @param userId 用户编号 * @param userId 用户编号
*/ */
void takeCouponsByAdmin(List<Long> templateIds, List<Integer> counts, Long userId); void takeCouponsByAdmin(Map<Long, Integer> giveCouponsMap, Long userId);
/**
* 管理员收回给指定用户批量发送优惠券
*
* @param giveCouponsMap key: 优惠劵编号value对应的优惠券数量
* @param userId 用户编号
*/
void takeBackCouponsByAdmin(Map<Long, Integer> giveCouponsMap, Long userId);
} }

View File

@ -8,6 +8,7 @@ import lombok.Data;
import java.io.Serializable; import java.io.Serializable;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.List; import java.util.List;
import java.util.Map;
/** /**
* 满减送活动的匹配 Response DTO * 满减送活动的匹配 Response DTO
@ -98,13 +99,11 @@ public class RewardActivityMatchRespDTO {
*/ */
private Boolean giveCoupon; private Boolean giveCoupon;
/** /**
* 赠送的优惠劵编号的数组 * 赠送的优惠劵
*
* key: 优惠劵编号value对应的优惠券数量
*/ */
private List<Long> couponIds; private Map<Long, Integer> giveCouponsMap;
/**
* 赠送的优惠券数量的数组
*/
private List<Integer> couponCounts;
} }

View File

@ -18,7 +18,7 @@ public enum CouponStatusEnum implements IntArrayValuable {
UNUSED(1, "未使用"), UNUSED(1, "未使用"),
USED(2, "已使用"), USED(2, "已使用"),
EXPIRE(3, "已过期"), EXPIRE(3, "已过期"),
; INVALID(4, "已作废");
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(CouponStatusEnum::getStatus).toArray(); public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(CouponStatusEnum::getStatus).toArray();

View File

@ -11,7 +11,7 @@ import jakarta.annotation.Resource;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import java.util.List; import java.util.Map;
/** /**
* 优惠劵 API 实现类 * 优惠劵 API 实现类
@ -43,8 +43,13 @@ public class CouponApiImpl implements CouponApi {
} }
@Override @Override
public void takeCouponsByAdmin(List<Long> templateIds, List<Integer> counts, Long userId) { public void takeCouponsByAdmin(Map<Long, Integer> giveCouponsMap, Long userId) {
couponService.takeCouponsByAdmin(templateIds, counts, userId); couponService.takeCouponsByAdmin(giveCouponsMap, userId);
}
@Override
public void takeBackCouponsByAdmin(Map<Long, Integer> giveCouponsMap, Long userId) {
couponService.takeBackCouponsByAdmin(giveCouponsMap, userId);
} }
} }

View File

@ -16,6 +16,7 @@ import lombok.Data;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Objects; import java.util.Objects;
/** /**
@ -88,16 +89,7 @@ public class RewardActivityBaseVO {
private Boolean giveCoupon; private Boolean giveCoupon;
@Schema(description = "赠送的优惠劵编号的数组", example = "1,2,3") @Schema(description = "赠送的优惠劵编号的数组", example = "1,2,3")
private List<Long> couponIds; private Map<Long, Integer> giveCouponsMap;
@Schema(description = "赠送的优惠券数量的数组", example = "1,2,3")
private List<Integer> couponCounts;
@AssertTrue(message = "优惠劵和数量必须一一对应")
@JsonIgnore
public boolean isCouponCountsValid() {
return BooleanUtil.isFalse(giveCoupon) || CollUtil.size(couponIds) == CollUtil.size(couponCounts);
}
@AssertTrue(message = "赠送的积分不能小于 1") @AssertTrue(message = "赠送的积分不能小于 1")
@JsonIgnore @JsonIgnore

View File

@ -50,7 +50,6 @@ public class CouponDO extends BaseDO {
* *
* 枚举 {@link CouponStatusEnum} * 枚举 {@link CouponStatusEnum}
*/ */
// TODO 芋艿已作废
private Integer status; private Integer status;
// TODO 芋艿发放 adminid // TODO 芋艿发放 adminid

View File

@ -16,6 +16,7 @@ import lombok.EqualsAndHashCode;
import java.io.Serializable; import java.io.Serializable;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.List; import java.util.List;
import java.util.Map;
/** /**
* 满减送活动 DO * 满减送活动 DO
@ -114,13 +115,11 @@ public class RewardActivityDO extends BaseDO {
*/ */
private Boolean giveCoupon; private Boolean giveCoupon;
/** /**
* 赠送的优惠劵编号的数组 * 赠送的优惠劵
*
* key: 优惠劵编号value对应的优惠券数量
*/ */
private List<Long> couponIds; private Map<Long, Integer> giveCouponsMap;
/**
* 赠送的优惠券数量的数组
*/
private List<Integer> couponCounts;
} }

View File

@ -72,6 +72,15 @@ public interface CouponMapper extends BaseMapperX<CouponDO> {
); );
} }
default List<CouponDO> selectListByTemplateIdAndUserIdAndTakeType(Long templateId, Collection<Long> userIds,
Integer takeType) {
return selectList(new LambdaQueryWrapperX<CouponDO>()
.eq(CouponDO::getTemplateId, templateId)
.eq(CouponDO::getTakeType, takeType)
.in(CouponDO::getUserId, userIds)
);
}
default Map<Long, Integer> selectCountByUserIdAndTemplateIdIn(Long userId, Collection<Long> templateIds) { default Map<Long, Integer> selectCountByUserIdAndTemplateIdIn(Long userId, Collection<Long> templateIds) {
String templateIdAlias = "templateId"; String templateIdAlias = "templateId";
String countAlias = "count"; String countAlias = "count";

View File

@ -108,11 +108,18 @@ public interface CouponService {
/** /**
* 管理员给指定用户批量发送优惠券 * 管理员给指定用户批量发送优惠券
* *
* @param templateIds 优惠劵编号的数组 * @param giveCouponsMap key: 优惠劵编号value对应的优惠券数量
* @param counts 优惠券数量的数组
* @param userId 用户编号 * @param userId 用户编号
*/ */
void takeCouponsByAdmin(List<Long> templateIds, List<Integer> counts, Long userId); void takeCouponsByAdmin(Map<Long, Integer> giveCouponsMap, Long userId);
/**
* 管理员收回给指定用户批量发送优惠券
*
* @param giveCouponsMap key: 优惠劵编号value对应的优惠券数量
* @param userId 用户编号
*/
void takeBackCouponsByAdmin(Map<Long, Integer> giveCouponsMap, Long userId);
/** /**
* 会员领取优惠券 * 会员领取优惠券

View File

@ -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.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; 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 cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
import static java.util.Arrays.asList; import static java.util.Arrays.asList;
@ -165,6 +164,7 @@ public class CouponServiceImpl implements CouponService {
} }
@Override @Override
@Transactional(rollbackFor = Exception.class)
public void takeCoupon(Long templateId, Set<Long> userIds, CouponTakeTypeEnum takeType) { public void takeCoupon(Long templateId, Set<Long> userIds, CouponTakeTypeEnum takeType) {
CouponTemplateDO template = couponTemplateService.getCouponTemplate(templateId); CouponTemplateDO template = couponTemplateService.getCouponTemplate(templateId);
// 1. 过滤掉达到领取限制的用户 // 1. 过滤掉达到领取限制的用户
@ -180,28 +180,66 @@ public class CouponServiceImpl implements CouponService {
} }
@Override @Override
public void takeCouponsByAdmin(List<Long> templateIds, List<Integer> counts, Long userId) { public void takeCouponsByAdmin(Map<Long, Integer> giveCouponsMap, Long userId) {
// TODO @puhui999要不要循环调用上面的 takeCoupon 方法按道理说赠送也不会很多张如果某次发卷失败可以打个 error log if (CollUtil.isEmpty(giveCouponsMap)) {
// 1. 获得优惠券模版
List<CouponTemplateDO> templateList = couponTemplateService.getCouponTemplateList(templateIds);
if (CollUtil.isEmpty(templateList)) {
return; return;
} }
Map<Long, CouponTemplateDO> templateMap = convertMap(templateList, CouponTemplateDO::getId); // 循环发放
// 2.1 批量构建优惠券 for (Map.Entry<Long, Integer> entry : giveCouponsMap.entrySet()) {
List<CouponDO> couponList = new ArrayList<>(); try {
for (int i = 0; i < templateIds.size(); i++) { for (int i = 0; i < entry.getValue(); i++) {
int finalI = i; getSelf().takeCoupon(entry.getKey(), CollUtil.newHashSet(userId), CouponTakeTypeEnum.ADMIN);
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()));
} }
}); } catch (Exception e) {
log.error("[takeCouponsByAdmin][coupon({}) 优惠券发放失败]", entry, e);
}
} }
// 2.2 批量保存优惠券 }
couponMapper.insertBatch(couponList);
@Override
public void takeBackCouponsByAdmin(Map<Long, Integer> giveCouponsMap, Long userId) {
// 循环收回
for (Map.Entry<Long, Integer> 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<Long> 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<CouponDO> couponList = couponMapper.selectListByTemplateIdAndUserIdAndTakeType(templateId, userIds,
takeType.getValue());
List<CouponDO> 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 @Override

View File

@ -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.TradeOrderStatusEnum;
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum; import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
import lombok.*; import lombok.*;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.List; import java.util.Map;
/** /**
* 交易订单 DO * 交易订单 DO
@ -292,19 +294,14 @@ public class TradeOrderDO extends BaseDO {
*/ */
private Integer vipPrice; private Integer vipPrice;
// TODO @puhui999:1建议命名要 giveXXX不然不好理解哈2是不是搞成 Map 好点哈
/** /**
* 赠送的优惠劵编号的数组 * 赠送的优惠劵
* *
* key: 优惠劵编号value对应的优惠券数量
* 目的用于后续取消或者售后订单时需要扣减赠送 * 目的用于后续取消或者售后订单时需要扣减赠送
*/ */
private List<Long> couponIds; @TableField(typeHandler = JacksonTypeHandler.class)
/** private Map<Long, Integer> giveCouponsMap;
* 赠送的优惠券数量的数组
*
* 目的用于后续取消或者售后订单时需要扣减赠送
*/
private List<Integer> couponCounts;
/** /**
* 秒杀活动编号 * 秒杀活动编号

View File

@ -202,7 +202,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
order.setProductCount(getSumValue(calculateRespBO.getItems(), TradePriceCalculateRespBO.OrderItem::getCount, Integer::sum)); order.setProductCount(getSumValue(calculateRespBO.getItems(), TradePriceCalculateRespBO.OrderItem::getCount, Integer::sum));
order.setUserIp(getClientIP()).setTerminal(getTerminal()); order.setUserIp(getClientIP()).setTerminal(getTerminal());
// 使用 + 赠送优惠券 // 使用 + 赠送优惠券
order.setCouponIds(calculateRespBO.getCouponIds()).setCouponCounts(calculateRespBO.getCouponCounts()); order.setGiveCouponsMap(calculateRespBO.getGiveCouponsMap());
// 支付 + 退款信息 // 支付 + 退款信息
order.setAdjustPrice(0).setPayStatus(false); order.setAdjustPrice(0).setPayStatus(false);
order.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus()).setRefundPrice(0); order.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus()).setRefundPrice(0);

View File

@ -33,11 +33,11 @@ public class TradeCouponOrderHandler implements TradeOrderHandler {
@Override @Override
public void afterPayOrder(TradeOrderDO order, List<TradeOrderItemDO> orderItems) { public void afterPayOrder(TradeOrderDO order, List<TradeOrderItemDO> orderItems) {
if (CollUtil.isEmpty(order.getCouponIds())) { if (CollUtil.isEmpty(order.getGiveCouponsMap())) {
return; return;
} }
// 赠送优惠券 // 赠送优惠券
couponApi.takeCouponsByAdmin(order.getCouponIds(), order.getCouponCounts(), order.getUserId()); couponApi.takeCouponsByAdmin(order.getGiveCouponsMap(), order.getUserId());
} }
@Override @Override
@ -48,10 +48,10 @@ public class TradeCouponOrderHandler implements TradeOrderHandler {
couponApi.returnUsedCoupon(order.getCouponId()); couponApi.returnUsedCoupon(order.getCouponId());
} }
// 情况二收回赠送的优惠券 // 情况二收回赠送的优惠券
if (CollUtil.isEmpty(order.getCouponIds())) { if (CollUtil.isEmpty(order.getGiveCouponsMap())) {
return; return;
} }
// TODO @puhui999: 收回优惠券再考虑一下是直接删除券还是改个状态建议是已作废 couponApi.takeBackCouponsByAdmin(order.getGiveCouponsMap(), order.getUserId());
} }
} }

View File

@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
import lombok.Data; import lombok.Data;
import java.util.List; import java.util.List;
import java.util.Map;
/** /**
* 价格计算 Response BO * 价格计算 Response BO
@ -72,15 +73,13 @@ public class TradePriceCalculateRespBO {
*/ */
private Boolean freeDelivery; private Boolean freeDelivery;
// TODO @puhui999感觉要不要试着改成 Map<Long, Integer> giveCoupons貌似整体会更好理解一点
/** /**
* 赠送的优惠劵编号的数组 * 赠送的优惠劵
*
* key: 优惠劵编号value对应的优惠券数量
* 目的用于后续取消或者售后订单时需要扣减赠送
*/ */
private List<Long> couponIds; private Map<Long, Integer> giveCouponsMap;
/**
* 赠送的优惠券数量的数组
*/
private List<Integer> couponCounts;
/** /**
* 订单价格 * 订单价格

View File

@ -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 cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -31,8 +32,7 @@ public class TradePriceCalculatorHelper {
List<ProductSpuRespDTO> spuList, List<ProductSkuRespDTO> skuList) { List<ProductSpuRespDTO> spuList, List<ProductSkuRespDTO> skuList) {
// 创建 PriceCalculateRespDTO 对象 // 创建 PriceCalculateRespDTO 对象
TradePriceCalculateRespBO result = new TradePriceCalculateRespBO(); TradePriceCalculateRespBO result = new TradePriceCalculateRespBO();
result.setType(getOrderType(param)).setPromotions(new ArrayList<>()) result.setType(getOrderType(param)).setPromotions(new ArrayList<>()).setGiveCouponsMap(new LinkedHashMap<>());
.setCouponIds(new ArrayList<>()).setCouponCounts(new ArrayList<>());
// 创建它的 OrderItem 属性 // 创建它的 OrderItem 属性
result.setItems(new ArrayList<>(param.getItems().size())); result.setItems(new ArrayList<>(param.getItems().size()));

View File

@ -19,13 +19,14 @@ import org.springframework.stereotype.Component;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Comparator; import java.util.Comparator;
import java.util.List; 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.convertSet;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList;
import static cn.iocoder.yudao.module.trade.service.price.calculator.TradePriceCalculatorHelper.formatPrice; import static cn.iocoder.yudao.module.trade.service.price.calculator.TradePriceCalculatorHelper.formatPrice;
// TODO @puhui999相关的单测建议改一改 // TODO @puhui999相关的单测建议改一改
/** /**
* 满减送活动的 {@link TradePriceCalculator} 实现类 * 满减送活动的 {@link TradePriceCalculator} 实现类
* *
@ -92,7 +93,7 @@ public class TradeRewardActivityPriceCalculator implements TradePriceCalculator
TradePriceCalculatorHelper.recountAllPrice(result); TradePriceCalculatorHelper.recountAllPrice(result);
// 4.1 记录赠送的积分 // 4.1 记录赠送的积分
if (rule.getGivePoint()) { if (Boolean.TRUE.equals(rule.getGivePoint())) {
List<Integer> dividePoints = TradePriceCalculatorHelper.dividePrice(orderItems, rule.getPoint()); List<Integer> dividePoints = TradePriceCalculatorHelper.dividePrice(orderItems, rule.getPoint());
for (int i = 0; i < orderItems.size(); i++) { for (int i = 0; i < orderItems.size(); i++) {
// 商品可能赠送了积分所以这里要加上 // 商品可能赠送了积分所以这里要加上
@ -101,22 +102,18 @@ public class TradeRewardActivityPriceCalculator implements TradePriceCalculator
} }
} }
// 4.2 记录订单是否包邮 // 4.2 记录订单是否包邮
if (rule.getFreeDelivery()) { if (Boolean.TRUE.equals(rule.getFreeDelivery())) {
// 只要满足一个活动包邮那么这单就包邮 // 只要满足一个活动包邮那么这单就包邮
result.setFreeDelivery(true); result.setFreeDelivery(true);
} }
// 4.3 记录赠送的优惠券 // 4.3 记录赠送的优惠券
if (rule.getGiveCoupon()) { if (Boolean.TRUE.equals(rule.getGiveCoupon())) {
for (int i = 0; i < rule.getCouponIds().size(); i++) { for (Map.Entry<Long, Integer> entry : rule.getGiveCouponsMap().entrySet()) {
Long couponId = result.getCouponIds().get(i); Map<Long, Integer> giveCouponsMap = result.getGiveCouponsMap();
Integer couponCount = result.getCouponCounts().get(i); if (giveCouponsMap.get(entry.getKey()) == null) { // 情况一还没有赠送的优惠券
int index = CollUtil.indexOf(result.getCouponIds(), id -> Objects.equals(couponId, id)); result.setGiveCouponsMap(rule.getGiveCouponsMap());
if (index != -1) { // 情况一别的满减活动送过同类优惠券则直接增加数量 } else { // 情况二别的满减活动送过同类优惠券则直接增加数量
List<Integer> couponCounts = result.getCouponCounts(); giveCouponsMap.put(entry.getKey(), giveCouponsMap.get(entry.getKey()) + entry.getValue());
couponCounts.set(index, couponCounts.get(index) + couponCount);
result.setCouponCounts(couponCounts);
} else { // 情况二还没有赠送的优惠券
result.setCouponIds(rule.getCouponIds()).setCouponCounts(rule.getCouponCounts());
} }
} }
} }
@ -193,7 +190,7 @@ public class TradeRewardActivityPriceCalculator implements TradePriceCalculator
// 2. 构建不满足时的提示信息按最低档规则算 // 2. 构建不满足时的提示信息按最低档规则算
String meetTip = "满减送:购满 {} {},可以减 {} 元"; String meetTip = "满减送:购满 {} {},可以减 {} 元";
List<RewardActivityMatchRespDTO.Rule> rules = new ArrayList<>(rewardActivity.getRules()); List<RewardActivityMatchRespDTO.Rule> 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); RewardActivityMatchRespDTO.Rule rule = rules.get(0);
if (PromotionConditionTypeEnum.PRICE.getType().equals(rewardActivity.getConditionType())) { if (PromotionConditionTypeEnum.PRICE.getType().equals(rewardActivity.getConditionType())) {
return StrUtil.format(meetTip, rule.getLimit(), "", MoneyUtils.fenToYuanStr(rule.getDiscountPrice())); return StrUtil.format(meetTip, rule.getLimit(), "", MoneyUtils.fenToYuanStr(rule.getDiscountPrice()));

View File

@ -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.RewardActivityApi;
import cn.iocoder.yudao.module.promotion.api.reward.dto.RewardActivityMatchRespDTO; 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.PromotionConditionTypeEnum;
import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum;
import cn.iocoder.yudao.module.promotion.enums.common.PromotionTypeEnum; import cn.iocoder.yudao.module.promotion.enums.common.PromotionTypeEnum;
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum; import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO;
@ -13,6 +14,7 @@ import org.mockito.InjectMocks;
import org.mockito.Mock; import org.mockito.Mock;
import java.util.ArrayList; 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.common.util.collection.SetUtils.asSet;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
@ -47,7 +49,7 @@ public class TradeRewardActivityPriceCalculatorTest extends BaseMockitoUnitTest
TradePriceCalculateRespBO result = new TradePriceCalculateRespBO() TradePriceCalculateRespBO result = new TradePriceCalculateRespBO()
.setType(TradeOrderTypeEnum.NORMAL.getType()) .setType(TradeOrderTypeEnum.NORMAL.getType())
.setPrice(new TradePriceCalculateRespBO.Price()) .setPrice(new TradePriceCalculateRespBO.Price())
.setPromotions(new ArrayList<>()) .setPromotions(new ArrayList<>()).setGiveCouponsMap(new LinkedHashMap<>())
.setItems(asList( .setItems(asList(
new TradePriceCalculateRespBO.OrderItem().setSkuId(10L).setCount(2).setSelected(true) new TradePriceCalculateRespBO.OrderItem().setSkuId(10L).setCount(2).setSelected(true)
.setPrice(100).setSpuId(1L), .setPrice(100).setSpuId(1L),
@ -60,16 +62,22 @@ public class TradeRewardActivityPriceCalculatorTest extends BaseMockitoUnitTest
TradePriceCalculatorHelper.recountPayPrice(result.getItems()); TradePriceCalculatorHelper.recountPayPrice(result.getItems());
TradePriceCalculatorHelper.recountAllPrice(result); TradePriceCalculatorHelper.recountAllPrice(result);
// mock 方法限时折扣 DiscountActivity 信息 // mock 方法满减送 RewardActivity 信息
when(rewardActivityApi.getMatchRewardActivityList(eq(asSet(1L, 2L, 3L)))).thenReturn(asList( when(rewardActivityApi.getMatchRewardActivityList(eq(asSet(1L, 2L, 3L)))).thenReturn(asList(
randomPojo(RewardActivityMatchRespDTO.class, o -> o.setId(1000L).setName("活动 1000 号") randomPojo(RewardActivityMatchRespDTO.class, o -> o.setId(1000L).setName("活动 1000 号")
.setProductScopeValues(asList(1L, 2L)).setConditionType(PromotionConditionTypeEnum.PRICE.getType()) .setConditionType(PromotionConditionTypeEnum.PRICE.getType())
.setRules(singletonList(new RewardActivityMatchRespDTO.Rule().setLimit(200).setDiscountPrice(70)))), .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 号") randomPojo(RewardActivityMatchRespDTO.class, o -> o.setId(2000L).setName("活动 2000 号")
.setProductScopeValues(singletonList(3L)).setConditionType(PromotionConditionTypeEnum.COUNT.getType()) .setConditionType(PromotionConditionTypeEnum.COUNT.getType())
.setRules(asList(new RewardActivityMatchRespDTO.Rule().setLimit(1).setDiscountPrice(10), .setProductScope(PromotionProductScopeEnum.SPU.getScope()).setProductScopeValues(singletonList(3L))
new RewardActivityMatchRespDTO.Rule().setLimit(2).setDiscountPrice(60), // 最大可满足因为是 4 .setRules(asList(new RewardActivityMatchRespDTO.Rule().setLimit(1).setDiscountPrice(10)
new RewardActivityMatchRespDTO.Rule().setLimit(10).setDiscountPrice(100)))) .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.getCouponPrice(), 0);
assertEquals(orderItem01.getPointPrice(), 0); assertEquals(orderItem01.getPointPrice(), 0);
assertEquals(orderItem01.getPayPrice(), 160); assertEquals(orderItem01.getPayPrice(), 160);
assertEquals(orderItem01.getGivePoint(), 0);
// 断言SKU 2 // 断言SKU 2
TradePriceCalculateRespBO.OrderItem orderItem02 = result.getItems().get(1); TradePriceCalculateRespBO.OrderItem orderItem02 = result.getItems().get(1);
assertEquals(orderItem02.getSkuId(), 20L); assertEquals(orderItem02.getSkuId(), 20L);
@ -104,6 +113,7 @@ public class TradeRewardActivityPriceCalculatorTest extends BaseMockitoUnitTest
assertEquals(orderItem02.getCouponPrice(), 0); assertEquals(orderItem02.getCouponPrice(), 0);
assertEquals(orderItem02.getPointPrice(), 0); assertEquals(orderItem02.getPointPrice(), 0);
assertEquals(orderItem02.getPayPrice(), 120); assertEquals(orderItem02.getPayPrice(), 120);
assertEquals(orderItem02.getGivePoint(), 0);
// 断言SKU 3 // 断言SKU 3
TradePriceCalculateRespBO.OrderItem orderItem03 = result.getItems().get(2); TradePriceCalculateRespBO.OrderItem orderItem03 = result.getItems().get(2);
assertEquals(orderItem03.getSkuId(), 30L); assertEquals(orderItem03.getSkuId(), 30L);
@ -114,6 +124,7 @@ public class TradeRewardActivityPriceCalculatorTest extends BaseMockitoUnitTest
assertEquals(orderItem03.getCouponPrice(), 0); assertEquals(orderItem03.getCouponPrice(), 0);
assertEquals(orderItem03.getPointPrice(), 0); assertEquals(orderItem03.getPointPrice(), 0);
assertEquals(orderItem03.getPayPrice(), 60); assertEquals(orderItem03.getPayPrice(), 60);
assertEquals(orderItem03.getGivePoint(), 100);
// 断言Promotion 部分第一个 // 断言Promotion 部分第一个
assertEquals(result.getPromotions().size(), 2); assertEquals(result.getPromotions().size(), 2);
TradePriceCalculateRespBO.Promotion promotion01 = result.getPromotions().get(0); TradePriceCalculateRespBO.Promotion promotion01 = result.getPromotions().get(0);

View File

@ -48,6 +48,7 @@ CREATE TABLE IF NOT EXISTS "trade_order"
"give_point" int NULL, "give_point" int NULL,
"refund_point" int NULL, "refund_point" int NULL,
"vip_price" int NULL, "vip_price" int NULL,
"give_coupons_map" varchar NULL,
"seckill_activity_id" long NULL, "seckill_activity_id" long NULL,
"bargain_activity_id" long NULL, "bargain_activity_id" long NULL,
"bargain_record_id" long NULL, "bargain_record_id" long NULL,