结账页显示 899 元,支付页却扣了 909 元,后台订单也是 909 元。只刷新 Checkout 有时又正常。这类金额问题必须马上处理,而且不能只盯页面 JavaScript,最终扣款来自服务端订单或支付请求。

给同一次结账建立金额时间线

  1. 购物车 collectTotals 后的 quote totals;
  2. 前端 totals API 返回值;
  3. 提交订单前发送给支付模块的金额;
  4. sales_order 的金额字段。

用 quote_id 与请求 ID 串起来,比较 subtotal、discount、shipping、tax、grand_total 和 base_* 字段,找出第一次不同。只比较 grand_total 会隐藏汇率或税额舍入问题。

重复 collectTotals 本身不是修复

自定义 total collector 应该幂等。每执行一次就追加费用,通常是没有先重置自身字段,或 sort_order 与税、折扣顺序冲突。记录 collector 类名与执行前后金额,检查同一请求是否多次运行。

前端旧 totals 也可能来自 customer-data 或并发请求覆盖。Network 中看返回顺序:较慢旧请求最后回来,会把新地址对应的金额覆盖到页面,但提交时服务端又按最新 quote 计算。

支付模块使用订单金额作为最终事实

不要从页面接收可修改金额。支付请求应基于服务端订单,并正确处理 base currency 与 order currency。回调金额不一致时明确拒绝或进入人工处理,不能默默标记已支付。

修复后测试优惠券、税、配送方式、多币种和地址切换,对比前端、订单、支付平台三方金额。第一次分叉消除后才算解决。