在超市、商场、电商网站,我们每天都在接触各种优惠:
满100减20、第二件半价、会员专享价、满3件打8折……
店铺券、平台券、品牌专属券……
有的可以叠加,有的互相排斥,有的限定时间,有的限定商品
这些看似简单的优惠背后,系统要做的事可一点都不简单。
今天我们带大家拆解一个“能应对所有优惠规则”的收银系统是怎么设计的。无论你是程序员、产品经理,还是对技术不太熟的朋友,都能看懂。
我们可以先看几个例子:
某用户买了三件衣服,享受了“满三件打8折”和“第二件半价”,价格怎么算?
某平台发了平台券、店铺券、类目券,这三种能不能一起用?优先用哪张?
某商品设置了会员价,但又参与了活动价,两个价哪个生效?
有用户在POS机、有人在App下单,是否享受一样的优惠?
复杂源于:
规则类型越来越多
每种优惠背后都有“条件 + 优惠方式 + 冲突规则”
营销团队还希望:支持灰度、支持回滚、支持多种组合策略
所以系统必须要“能表达得了、算得清楚、改得方便、控得住风险”。
我们用下面这个模型来管理各种优惠:
每一种优惠,系统都会记录三件事:
部分 | 作用 | 举例 |
---|---|---|
条件(Condition) | 什么时候生效 | 商品是服装类,购买时间在7月内,用户是会员 |
动作(Effect) | 做什么优惠 | 第二件半价、打8折、减50元 |
策略(Policy) | 与其他优惠怎么共存 | 是否叠加?优先级高低?同类券只能用一张? |
这样每条规则都非常清晰可控。
面对多个优惠,系统不是按“先算这个再算那个”,而是:
把所有可能命中的优惠列出来,然后找出最省钱的组合方案。
这就像在做一道“找最优方案”的题,比如这样:
商品原价:300 元
可用:满300减30、第二件半价、会员价、店铺券
系统会根据这些规则去“组合尝试”,最终找出一套最合适的组合。
这个过程叫做“优化器”(Optimizer),是一段高效的智能算法。
我们不会在每个阶段都去跑一次全量复杂计算,因为那样太浪费性能。
系统会在以下四个阶段,做不同级别的“优惠计算”:
阶段 | 举例 | 计算强度 | 用途 |
---|---|---|---|
加入购物车 | 点“加入购物车”按钮 | 轻量判断 | 展示“已享受会员价”等提示 |
打开结算页 | 进入订单页 | 中等强度 | 预估优惠总额,推荐券 |
提交订单 | 点“提交订单” | 全量计算 | 锁定价格,记录优惠详情 |
支付后 | 支付成功 | 异步处理 | 发返券、返积分等 |
这样可以让系统既快又准,提升用户体验。
设计一个优惠系统,不只是“能计算”,更重要的是:
运维人员可以清晰知道:哪些规则正在生效
营销人员可以安全修改规则、灰度上线
客服可以还原每笔订单“为何是这个价格”
程序员可以不出 bug 地支持新增的优惠方式
我们是这么做到的:
规则都是“带版本的”,一旦上线就不能修改,而是“新增版本”,这样可以随时回滚、比对。
类似快递单号,系统给每个订单生成“Price Proof”:这笔钱为什么是这个价、用了哪些规则、为什么没用其他优惠、用了哪个版本的规则集。
无论是后期查错,还是分析用户行为,系统都可以“回放”当时的优惠决策过程。
对于程序员来说,最大挑战是:业务总会加新规则,而代码不能天天改。
我们的做法是把系统分成模块,每种变化“只改一块”:
变化类型 | 对应模块 | 扩展方式 |
---|---|---|
新的生效条件 | Condition 模块 | 配置或写规则表达式 |
新的优惠方式 | Effect 模块 | 写新的计算逻辑 |
新的叠加/互斥策略 | Policy 模块 | 注册新策略 |
更复杂的优化方式 | Optimizer | 插件式注册算法 |
换句话说:
程序员只要“按接口写一个新插件”,就可以支持业务的新玩法,而不用动其他代码。
用“优惠模板”快速创建满减、打折、券类规则
给不同门店/渠道/用户分配不同的规则版本,实现分组投放
通过“仿真平台”在上线前测试效果,避免出错
通过“命中率分析”判断哪些规则在发挥作用、哪些可以清理
一个优秀的收银优惠系统,应该:
能表达各种复杂规则(灵活)
能组合计算出最优结果(准确)
能记录每次计算的过程(可审计)
能方便测试和回滚(安全)
能持续接纳新的规则类型(可扩展)
这不仅仅是“写几个优惠 if 语句”的问题,而是需要一套规则化 + 策略化 + 插件化 + 自动化的体系。