满 100 减 30 的券和新人 20 元无门槛券一起用,订单小计 58,结算接口返回 payable=-12。前端格式化成 ¥-12.00,支付按钮点下去渠道报参数错误。第一次遇到会往复杂处想,其实漏掉的多是个小前提。

$discount = min($couponTotal, $subtotal);
$payable = max(0, $subtotal - $discount);
if ($couponTotal > $subtotal) {
    // 记录溢出部分,按规则转余额或作废
}

两张券各自独立判断门槛,减完没有对结果做下限保护,应付金额直接由小计减两张券得出。券的互斥关系也没有配置,同一订单允许叠加任意张。这一点先确认清楚,后面就不用反复试。

碰到「优惠券叠加负数」这类问题,我习惯先把当前配置原样备份一份,改坏了立刻换回来,不用现场推。新版本先放一台机器上跑一天再全量,问题一般在这段时间暴露。

具体做法是,结算时应付取 max(0, 小计减优惠合计),并在返回体里标出实际抵扣了多少;优惠合计超过小计时把余额留下次用或者直接截断,按业务定一种,别让负数流出去;券的配置里设互斥组,同一组只允许用一张,前端选择时同步提示。

改完照着核一遍,同样两张券下单,应付显示 0.00,接口返回的 discount 等于小计,不出现负号。

作者 9823189