页面提示“优惠券代码已应用”,Coupon 输入框也保留了代码,但订单摘要没有折扣。这条成功消息只可能说明代码被写进 Quote,不一定说明规则最终对任何商品产生折扣。

先看 Quote 是否真的有折扣

SELECT entity_id, coupon_code, subtotal, subtotal_with_discount,
       grand_total, applied_rule_ids
FROM quote
WHERE entity_id = 123;

SELECT item_id, sku, qty, row_total, discount_amount, applied_rule_ids
FROM quote_item
WHERE quote_id = 123;

Quote 有 coupon_code、applied_rule_ids 为空,规则没有匹配;有规则 ID 但 discount_amount 为零,可能是 action、上限、免费商品或自定义 collector 影响。数据库只用于诊断,不要手工写 discount_amount,它会在下一次 collectTotals 时被覆盖。

Conditions 和 Actions 不是一回事

Conditions 决定购物车是否有资格,Actions 下的条件决定哪些行项目享受折扣。常见配置是购物车条件匹配某分类,但 Actions 又排除了同一商品;或者“后续规则停止处理”让目标规则没有机会执行。

范围与时间

确认规则分配到当前 Website 和客户组,From/To 日期按 Magento 时区是否有效,Coupon 使用次数与每客户次数是否耗尽。访客没有 customer_id,基于客户属性或历史订单的条件可能永远不匹配。

数量和折扣步长

Buy X get Y、固定金额、每 N 件等 action 对数量和 step 有要求。购物车只有一件时,应用代码成功但折扣为零可能完全符合配置。把规则预期写成具体算式,用三组边界数量测试,而不是只用一个购物车。

Totals 被扩展覆盖

自定义费用、第三方结账或多币种扩展可能在 salesrule 之后重新设置 grand_total,或者前端没有刷新 totals。比较数据库 quote、REST/GraphQL totals 响应与页面显示:数据库已有 discount 但页面没变,是前端状态问题;数据库也为零,回到规则计算。

修复后测试访客与登录客户、含税与不含税显示、多个商品、部分商品不满足、移除 Coupon 和下单后的 sales_order_item 折扣。页面提示、Quote 和订单三处金额必须一致。

缓存规则对象也可能过期

修改 Sales Rule 后,如果长驻 Consumer、PHP 进程或自定义规则缓存仍持有旧对象,不同请求会得到不同结果。对照规则 updated_at 与计算节点,按 Magento 支持方式清理相关缓存并重启需要重载代码的长进程。不要在 totals 每次计算时无条件清缓存,那会把配置问题变成性能事故。

若 Coupon 来自自动生成池,还要核对它关联的 rule_id 与状态。导入脚本可能创建了能被查询到的 coupon 记录,却关联到已禁用或另一个网站的规则,于是代码校验通过、金额计算失败。抽查数据库关联比反复新建优惠码更快。