结账页切换配送方式、使用优惠码或修改地址后,总价仍显示旧金额,刷新页面才正确。问题可能在后端 Quote 没有重算,也可能接口已经返回新 totals,但 Knockout 组件没有更新。先区分数据与显示,才能避免在错误层修补。

以接口响应判断后端是否正确

在 Network 中查看 estimate-shipping-methods、shipping-information、payment-information 或 totals-information 请求。响应中的 subtotal、shipping、tax、discount 和 grand_total 已更新,说明后端计算正确;响应仍旧则查 Quote、地址和 total collector。

不要只看页面文本。一步结账扩展可能显示自己的汇总,却仍发送核心接口。

Knockout totals 是 observable 数据

核心 checkout 使用 quote totals observable。自定义组件如果在 initialize 时读取一次普通值,后续不会响应变化。正确方式是订阅 totals 或使用计算属性,并处理 segment 暂时不存在的状态。

define(['Magento_Checkout/js/model/quote'], function (quote) {
    'use strict';
    return function () {
        var totals = quote.getTotals()();
        return totals ? totals.grand_total : 0;
    };
});

示例只说明数据来源,真实组件应避免在模板每次渲染中创建重复订阅。

自定义 Total 必须前后端名称一致

PHP Total Collector 的 code、REST totals segment、jsLayout 组件与模板取值必须对应。后端返回 custom_fee,前端却查 custom-fee,组件就会一直显示空。排序值还会决定它在税、折扣和 grand total 周围的位置。

Promise 链未完成会阻止下一次更新

配送或支付模块覆盖 action 后,如果没有 return 原 Promise,调用方无法等待完成;失败分支没有 reject/always,也可能让 loader 和 totals 更新卡住。检查 mixin 是否保留函数返回值,并从 Console 第一条异常开始修复。

竞争请求会让旧响应覆盖新响应

客户快速切换地址或配送方式时,多个 totals 请求并发。较早请求较晚返回,就可能覆盖新选择。自定义组件应取消过期请求或根据当前状态忽略旧响应,不能简单在每次键盘输入都发完整 totals。

缓存不能缓存客户专属 totals

结账数据属于 Quote 私有状态。CDN、Service Worker 或错误的 Ajax 缓存规则如果缓存 totals API,会让不同请求得到旧数据。确认接口响应使用合适的私有/不缓存策略。

修复后按顺序测试地址、运费、优惠码、支付方式、数量和货币切换,观察每一步接口与页面金额一致。还要验证下单后的 Order、Invoice 与页面最终金额相同,不能只让 UI 看起来更新。