package cn.iocoder.yudao.module.trade.service.price.calculator; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; 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.PromotionTypeEnum; 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.TradePriceCalculateRespBO; import jakarta.annotation.Resource; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import java.util.List; 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} 实现类 * * @author 芋道源码 */ @Component @Order(TradePriceCalculator.ORDER_REWARD_ACTIVITY) public class TradeRewardActivityPriceCalculator implements TradePriceCalculator { @Resource private RewardActivityApi rewardActivityApi; @Override public void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) { // 0. 只有【普通】订单,才计算该优惠 if (ObjectUtil.notEqual(result.getType(), TradeOrderTypeEnum.NORMAL.getType())) { return; } // 获得 SKU 对应的满减送活动 List rewardActivities = rewardActivityApi.getMatchRewardActivityListBySpuIds( convertSet(result.getItems(), TradePriceCalculateRespBO.OrderItem::getSpuId)); if (CollUtil.isEmpty(rewardActivities)) { return; } // 处理最新的满减送活动 if (!rewardActivities.isEmpty()) { calculate(param, result, rewardActivities.get(0)); } } private void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result, RewardActivityMatchRespDTO rewardActivity) { // 1.1 获得满减送的订单项(商品)列表 List orderItems = filterMatchActivityOrderItems(result, rewardActivity); if (CollUtil.isEmpty(orderItems)) { return; } // 1.2 获得最大匹配的满减送活动的规则 RewardActivityMatchRespDTO.Rule rule = getMaxMatchRewardActivityRule(rewardActivity, orderItems); if (rule == null) { TradePriceCalculatorHelper.addNotMatchPromotion(result, orderItems, rewardActivity.getId(), rewardActivity.getName(), PromotionTypeEnum.REWARD_ACTIVITY.getType(), "满减送:" + rewardActivity.getRules().get(0).getDescription()); return; } // 2.1 计算可以优惠的金额 Integer newDiscountPrice = rule.getDiscountPrice(); // 2.2 计算分摊的优惠金额 List divideDiscountPrices = TradePriceCalculatorHelper.dividePrice(orderItems, newDiscountPrice); // 2.3 计算是否包邮 if (Boolean.TRUE.equals(rule.getFreeDelivery())) { result.setFreeDelivery(true); } // 3.1 记录使用的优惠劵 result.setCouponId(param.getCouponId()); // 3.2 记录优惠明细 TradePriceCalculatorHelper.addPromotion(result, orderItems, rewardActivity.getId(), rewardActivity.getName(), PromotionTypeEnum.REWARD_ACTIVITY.getType(), StrUtil.format("满减送:省 {} 元", formatPrice(rule.getDiscountPrice())), divideDiscountPrices); // 3.3 更新 SKU 优惠金额 for (int i = 0; i < orderItems.size(); i++) { TradePriceCalculateRespBO.OrderItem orderItem = orderItems.get(i); orderItem.setDiscountPrice(orderItem.getDiscountPrice() + divideDiscountPrices.get(i)); TradePriceCalculatorHelper.recountPayPrice(orderItem); } TradePriceCalculatorHelper.recountAllPrice(result); // 4.1 记录赠送的积分 if (rule.getPoint() != null && rule.getPoint() > 0) { List dividePoints = TradePriceCalculatorHelper.dividePrice(orderItems, rule.getPoint()); for (int i = 0; i < orderItems.size(); i++) { // 商品可能赠送了积分,所以这里要加上 TradePriceCalculateRespBO.OrderItem orderItem = orderItems.get(i); orderItem.setGivePoint(orderItem.getGivePoint() + dividePoints.get(i)); } } // 4.2 记录订单是否包邮 if (Boolean.TRUE.equals(rule.getFreeDelivery())) { // 只要满足一个活动包邮那么这单就包邮 result.setFreeDelivery(true); } // 4.3 记录赠送的优惠券 if (CollUtil.isNotEmpty(rule.getGiveCouponTemplateCounts())) { for (Map.Entry entry : rule.getGiveCouponTemplateCounts().entrySet()) { result.getGiveCouponTemplateCounts().put(entry.getKey(), result.getGiveCouponTemplateCounts().getOrDefault(entry.getKey(), 0) + entry.getValue()); } } } /** * 获得满减送的订单项(商品)列表 * * @param result 计算结果 * @param rewardActivity 满减送活动 * @return 订单项(商品)列表 */ private List filterMatchActivityOrderItems(TradePriceCalculateRespBO result, RewardActivityMatchRespDTO rewardActivity) { return filterList(result.getItems(), orderItem -> CollUtil.contains(rewardActivity.getSpuIds(), orderItem.getSpuId())); } /** * 获得最大匹配的满减送活动的规则 * * @param rewardActivity 满减送活动 * @param orderItems 商品项 * @return 匹配的活动规则 */ private RewardActivityMatchRespDTO.Rule getMaxMatchRewardActivityRule(RewardActivityMatchRespDTO rewardActivity, List orderItems) { // 1. 计算数量和价格 Integer count = TradePriceCalculatorHelper.calculateTotalCount(orderItems); Integer price = TradePriceCalculatorHelper.calculateTotalPayPrice(orderItems); assert count != null && price != null; // 2. 倒序找一个最大优惠的规则 for (int i = rewardActivity.getRules().size() - 1; i >= 0; i--) { RewardActivityMatchRespDTO.Rule rule = rewardActivity.getRules().get(i); if (PromotionConditionTypeEnum.PRICE.getType().equals(rewardActivity.getConditionType()) && price >= rule.getLimit()) { return rule; } if (PromotionConditionTypeEnum.COUNT.getType().equals(rewardActivity.getConditionType()) && count >= rule.getLimit()) { return rule; } } return null; } }