学习日报 20250930|多优惠券叠加核销及场景互斥逻辑

要实现多优惠券叠加核销及场景互斥逻辑,需从规则定义、校验流程、核销执行 三方面入手,结合优惠券模板(CouponTemplate)的配置来控制业务逻辑。以下是具体实现方案:

一、核心思路

通过优惠券模板(CouponTemplate配置每张优惠券的叠加规则适用场景,在核销前先校验多券的兼容性,再按规则执行核销。

二、具体实现步骤

1. 扩展优惠券模板(CouponTemplate
java 复制代码
import lombok.Data;
import java.util.List;

/**
 * 优惠券模板:定义优惠券的基础规则(可叠加、适用场景等)
 */
@Data
public class CouponTemplate {
    private Long id;
    private String name;
    private CouponTypeEnum type; // 优惠券类型(满减、折扣等)
    
    /** 可叠加的优惠券类型(为空表示可与所有类型叠加;非空则仅能与指定类型叠加) */
    private List<CouponTypeEnum> allowStackWith;
    
    /** 适用场景标签(如 "生鲜"、"数码"、"全品类" 等) */
    private List<String> sceneTags;
}
2. 多优惠券叠加核销实现

步骤 1:校验多券叠加规则在核销前,先检查所有优惠券是否满足 "可叠加" 规则:

java 复制代码
/**
 * 校验多优惠券是否可叠加
 * @param coupons 待核销的优惠券列表(需包含关联的 CouponTemplate)
 * @return 是否可叠加
 */
private boolean checkStackable(List<UserCoupon> coupons) {
    // 若只有1张券,默认可核销
    if (coupons.size() <= 1) return true;
    
    // 遍历每两张券,检查是否满足互相叠加规则
    for (int i = 0; i < coupons.size(); i++) {
        for (int j = i + 1; j < coupons.size(); j++) {
            UserCoupon couponA = coupons.get(i);
            UserCoupon couponB = coupons.get(j);
            
            CouponTemplate templateA = couponA.getTemplate();
            CouponTemplate templateB = couponB.getTemplate();
            
            // 检查 A 是否允许与 B 类型叠加
            if (!templateA.getAllowStackWith().contains(templateB.getType())) {
                log.warn("优惠券{}(类型:{})不允许与优惠券{}(类型:{})叠加",
                        couponA.getId(), templateA.getType(),
                        couponB.getId(), templateB.getType());
                return false;
            }
        }
    }
    return true;
}

步骤 2:执行多券核销若校验通过,循环调用各券的核销逻辑:

java 复制代码
public void writeOffMultipleCoupons(List<UserCoupon> coupons) {
    // 1. 校验叠加规则
    if (!checkStackable(coupons)) {
        throw new CouponStackException("优惠券不可叠加");
    }
    
    // 2. 循环核销每张券
    for (UserCoupon coupon : coupons) {
        CouponTypeEnum type = coupon.getTemplate().getType();
        ICouponWriteOffService service = factory.getWriteOffService(type);
        service.writeOff(coupon);
    }
}
3. 多优惠券场景互斥实现

步骤 1:定义订单与商品的场景标签 订单或商品需携带 "场景标签",与优惠券模板的 sceneTags 匹配:

java 复制代码
@Data
public class Order {
    private Long id;
    private List<OrderItem> items; // 订单商品
    private List<String> sceneTags; // 订单整体场景(如 "全品类")
}

@Data
public class OrderItem {
    private Long id;
    private String sceneTag; // 商品所属场景(如 "生鲜")
    private BigDecimal price;
}

步骤 2:校验优惠券场景兼容性

java 复制代码
/**
 * 校验优惠券与订单场景是否匹配
 * @param coupons 待核销优惠券
 * @param order 目标订单
 * @return 是否匹配
 */
private boolean checkSceneMatch(List<UserCoupon> coupons, Order order) {
    for (UserCoupon coupon : coupons) {
        CouponTemplate template = coupon.getTemplate();
        List<String> couponScenes = template.getSceneTags();
        
        // 检查订单整体场景是否匹配
        boolean orderSceneMatch = order.getSceneTags().stream()
                .anyMatch(couponScenes::contains);
        
        // 检查订单商品场景是否匹配
        boolean itemSceneMatch = order.getItems().stream()
                .anyMatch(item -> couponScenes.contains(item.getSceneTag()));
        
        if (!orderSceneMatch && !itemSceneMatch) {
            log.warn("优惠券{}(场景:{})与订单场景不匹配",
                    coupon.getId(), couponScenes);
            return false;
        }
    }
    return true;
}

步骤 3:整合场景校验到核销流程

java 复制代码
public void writeOffCouponsWithSceneCheck(List<UserCoupon> coupons, Order order) {
    // 1. 校验场景匹配
    if (!checkSceneMatch(coupons, order)) {
        throw new CouponSceneException("优惠券场景不匹配");
    }
    
    // 2. 校验叠加规则(复用之前的 checkStackable 方法)
    if (!checkStackable(coupons)) {
        throw new CouponStackException("优惠券不可叠加");
    }
    
    // 3. 执行核销
    writeOffMultipleCoupons(coupons);
}

三、总结

  • 多券叠加 :通过 CouponTemplateallowStackWith 配置可叠加的优惠券类型,核销前校验每两张券是否满足互相叠加规则。
  • 场景互斥 :通过 CouponTemplatesceneTags 配置适用场景,核销前校验优惠券场景与订单 / 商品场景是否匹配。
  • 优势 :所有规则通过 CouponTemplate 外部配置,无需修改代码即可灵活控制优惠券的叠加和场景逻辑,扩展性极强。
相关推荐
西岸行者4 天前
学习笔记:SKILLS 能帮助更好的vibe coding
笔记·学习
悠哉悠哉愿意4 天前
【单片机学习笔记】串口、超声波、NE555的同时使用
笔记·单片机·学习
别催小唐敲代码4 天前
嵌入式学习路线
学习
毛小茛4 天前
计算机系统概论——校验码
学习
babe小鑫4 天前
大专经济信息管理专业学习数据分析的必要性
学习·数据挖掘·数据分析
winfreedoms4 天前
ROS2知识大白话
笔记·学习·ros2
在这habit之下4 天前
Linux Virtual Server(LVS)学习总结
linux·学习·lvs
我想我不够好。4 天前
2026.2.25监控学习
学习
im_AMBER4 天前
Leetcode 127 删除有序数组中的重复项 | 删除有序数组中的重复项 II
数据结构·学习·算法·leetcode
CodeJourney_J4 天前
从“Hello World“ 开始 C++
c语言·c++·学习