package cn.iocoder.yudao.module.trade.service.price.calculator; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.module.member.api.level.MemberLevelApi; import cn.iocoder.yudao.module.member.api.level.dto.MemberLevelRespDTO; import cn.iocoder.yudao.module.member.api.user.MemberUserApi; import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; import cn.iocoder.yudao.module.promotion.api.discount.DiscountActivityApi; import cn.iocoder.yudao.module.promotion.api.discount.dto.DiscountProductRespDTO; import cn.iocoder.yudao.module.promotion.enums.common.PromotionDiscountTypeEnum; 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.convertMap; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; import static cn.iocoder.yudao.framework.common.util.number.MoneyUtils.calculateRatePrice; import static cn.iocoder.yudao.module.trade.service.price.calculator.TradePriceCalculatorHelper.formatPrice; /** * 限时折扣的 {@link TradePriceCalculator} 实现类 * * 由于“会员折扣”和“限时折扣”是冲突,需要选择优惠金额多的,所以也放在这里计算 * * @author 芋道源码 */ @Component @Order(TradePriceCalculator.ORDER_DISCOUNT_ACTIVITY) public class TradeDiscountActivityPriceCalculator implements TradePriceCalculator { @Resource private DiscountActivityApi discountActivityApi; @Resource private MemberLevelApi memberLevelApi; @Resource private MemberUserApi memberUserApi; @Override public void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) { // 0. 只有【普通】订单,才计算该优惠 if (ObjectUtil.notEqual(result.getType(), TradeOrderTypeEnum.NORMAL.getType())) { return; } // 1.1 获得 SKU 对应的限时折扣活动 List discountProducts = discountActivityApi.getMatchDiscountProductListBySkuIds( convertSet(result.getItems(), TradePriceCalculateRespBO.OrderItem::getSkuId)); Map discountProductMap = convertMap(discountProducts, DiscountProductRespDTO::getSkuId); // 1.2 获得会员等级 MemberLevelRespDTO level = getMemberLevel(param.getUserId()); // 2. 计算每个 SKU 的优惠金额 result.getItems().forEach(orderItem -> { if (!orderItem.getSelected()) { return; } // 2.1 计算限时折扣的优惠金额 DiscountProductRespDTO discountProduct = discountProductMap.get(orderItem.getSkuId()); Integer discountPrice = calculateActivityPrice(discountProduct, orderItem); // 2.2 计算 VIP 优惠金额 Integer vipPrice = calculateVipPrice(level, orderItem); if (discountPrice <= 0 && vipPrice <= 0) { return; } // 3. 选择优惠金额多的 if (discountPrice > vipPrice) { TradePriceCalculatorHelper.addPromotion(result, orderItem, discountProduct.getActivityId(), discountProduct.getActivityName(), PromotionTypeEnum.DISCOUNT_ACTIVITY.getType(), StrUtil.format("限时折扣:省 {} 元", formatPrice(discountPrice)), discountPrice); // 更新 SKU 优惠金额 orderItem.setDiscountPrice(orderItem.getDiscountPrice() + discountPrice); } else { assert level != null; TradePriceCalculatorHelper.addPromotion(result, orderItem, level.getId(), level.getName(), PromotionTypeEnum.MEMBER_LEVEL.getType(), String.format("会员等级折扣:省 %s 元", formatPrice(vipPrice)), vipPrice); // 更新 SKU 的优惠金额 orderItem.setVipPrice(vipPrice); } // 4. 分摊优惠 TradePriceCalculatorHelper.recountPayPrice(orderItem); TradePriceCalculatorHelper.recountAllPrice(result); }); } /** * 获得用户的等级 * * @param userId 用户编号 * @return 用户等级 */ public MemberLevelRespDTO getMemberLevel(Long userId) { MemberUserRespDTO user = memberUserApi.getUser(userId); if (user == null || user.getLevelId() == null || user.getLevelId() <= 0) { return null; } return memberLevelApi.getMemberLevel(user.getLevelId()); } /** * 计算优惠活动的价格 * * @param discount 优惠活动 * @param orderItem 交易项 * @return 优惠价格 */ public Integer calculateActivityPrice(DiscountProductRespDTO discount, TradePriceCalculateRespBO.OrderItem orderItem) { if (discount == null) { return 0; } Integer newPrice = orderItem.getPayPrice(); if (PromotionDiscountTypeEnum.PRICE.getType().equals(discount.getDiscountType())) { // 减价 newPrice -= discount.getDiscountPrice() * orderItem.getCount(); } else if (PromotionDiscountTypeEnum.PERCENT.getType().equals(discount.getDiscountType())) { // 打折 newPrice = calculateRatePrice(orderItem.getPayPrice(), discount.getDiscountPercent() / 100.0); } else { throw new IllegalArgumentException(String.format("优惠活动的商品(%s) 的优惠类型不正确", discount)); } return orderItem.getPayPrice() - newPrice; } /** * 计算会员 VIP 的优惠价格 * * @param level 会员等级 * @param orderItem 交易项 * @return 优惠价格 */ public Integer calculateVipPrice(MemberLevelRespDTO level, TradePriceCalculateRespBO.OrderItem orderItem) { if (level == null || CommonStatusEnum.isDisable(level.getStatus()) || level.getDiscountPercent() == null) { return 0; } Integer newPrice = calculateRatePrice(orderItem.getPayPrice(), level.getDiscountPercent().doubleValue()); return orderItem.getPayPrice() - newPrice; } }