后台已经启用 Flat Rate,商品也有库存,但结账页配送方式区域一直转圈,最后只剩一句“没有可用的配送方式”。遇到这种问题,我不会先卸载主题或清空全部缓存,因为配送方式不是一个静态配置,它是根据当前 quote、地址、网站、商品属性和承运商返回值动态算出来的。

先保存一次真正失败的请求

在浏览器 Network 中找到 shipping-information 或 estimate-shipping-methods 请求,保存请求体、响应体、quote_id 和时间。地址里的 country_id、region_id、postcode 只要缺一个,某些承运商就会直接返回空集合。前端表单看起来填了省份,不代表传给后端的是有效 region_id。

我会用同一个购物车分别测试:完整地址、另一个邮编、默认配送方式和访客/登录用户。只有某个地址失败,优先看区域规则;所有地址都失败,才继续查全局配置或代码。

后台显示启用,不代表当前 Website 启用

配送配置通常有 Website 或 Store View 作用域。切换作用域后核对 Enabled、Allowed Countries、Specific Error Message、价格和最小订单条件。配置值可能在 Default 是 Yes,但当前 Website 明确覆盖成 No。

用 CLI 读取实际作用域比凭后台截图更可靠:

php bin/magento config:show carriers/flatrate/active
php bin/magento config:show carriers/flatrate/sallowspecific
php bin/magento config:show carriers/flatrate/specificcountry

第三方承运商还要检查 API 凭据、沙箱/生产地址、超时和币种。外部接口失败时,模块如果吞掉异常,只会让前端看到空数组,所以需要在 carrier 的 collectRates() 入口和返回处加临时日志,记录条件但不要记录客户完整地址或密钥。

免费配送、购物车规则和重量条件经常互相影响

查看 quote item 的重量、是否虚拟商品、free_shipping 标记和折扣规则。一个商品重量为 0,可能被承运商判定不可报价;一个购物车规则把部分商品标成免费配送,也可能让自定义模块算出负数或直接跳过。

多源库存环境还要确认当前 Stock 能否为地址提供货源。商品“有货”只代表可销售,未必所有来源都支持该区域或配送组合。若自定义 Source Selection 在报价前介入,检查它是否错误过滤了来源。

前端有旧缓存时,后端其实已经返回了方法

响应 JSON 已包含 rates,但页面仍空,问题就在 JS 状态。比较 Knockout shipping-service、checkout-data 和 customer-data 中的地址标识,确认旧请求没有在较晚时返回并覆盖新结果。切换地址后应触发重新估价,而不是继续使用上一个 postcode 的结果。

我最后会用四组用例验收:访客与登录用户、国内与国外地址、普通商品与含虚拟商品购物车、优惠券前后。每组都要确认后端返回的方法、页面显示价格和订单最终 shipping_amount 一致。只有这样,才不是“某个测试地址碰巧好了”。