学习日报 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 外部配置,无需修改代码即可灵活控制优惠券的叠加和场景逻辑,扩展性极强。
相关推荐
三品吉他手会点灯1 天前
STM32F103 学习笔记-21-串口通信(第4节)—串口发送和接收代码讲解(中)
笔记·stm32·单片机·嵌入式硬件·学习
EnglishJun1 天前
ARM嵌入式学习(二十三)--- I2C总线和SPI总线
arm开发·学习
饭后一颗花生米1 天前
2026 AI加持下前端学习路线:从入门到进阶,高效突破核心竞争力
前端·人工智能·学习
北山有鸟1 天前
【学习笔记】MIPI CSI-2 协议全解析:从底层封包到像素解析
linux·驱动开发·笔记·学习·相机
YCY^v^1 天前
PSW、PFW、SPSW、SPFW 是信捷TouchWin
学习
Engineer邓祥浩1 天前
JVM学习笔记(13) 第五部分 高效并发 第12章 Java内存模型与线程
jvm·笔记·学习
我命由我123451 天前
程序员的心理学学习笔记 - 反刍思维
经验分享·笔记·学习·职场和发展·求职招聘·职场发展·学习方法
GISer_Jing1 天前
AI知识学习
人工智能·redis·学习
星辰_mya1 天前
PV之系统与并发的核心wu器
java·开发语言·后端·学习·面试·架构师
暗夜猎手-大魔王1 天前
learn-claude-code项目学习总结
学习