这个问题最容易被“后台数量还有几十个”带偏。Magento 2.3 以后用了 MSI,页面上的 Source Item 数量并不等于前台可售数量。真正参与加购判断的是库存、来源分配、缺货阈值和 reservation 共同计算出来的 salable quantity。

先让Magento自己报出可售数量

不要只查 inventory_source_item.quantity。先运行:

php bin/magento inventory:reservation:list-inconsistencies -r

再用 SKU 查可售数量。不同版本可用的 CLI 命令并不完全一致,我一般直接在一个临时 PHP 脚本里调用 GetProductSalableQtyInterface,并明确传入当前 website 对应的 stock ID。这样能避免查错库存范围。

数量有货但salable为0,就逐项对账

我会按这个顺序看:

  1. 当前 Website 是否真的分配到了这个 Stock。
  2. Stock 下是否包含保存该 SKU 的 Source。
  3. Source Item 的状态是不是 In Stock,不是只看 quantity。
  4. Out-of-Stock Threshold 是否大于或等于现有数量。
  5. inventory_reservation 里是否残留了没有补偿回来的负数。

查 reservation:

SELECT stock_id, sku, SUM(quantity) AS reserved
FROM inventory_reservation
WHERE sku = 'TEST-SKU'
GROUP BY stock_id, sku;

不要直接删表里的 reservation。先用 list-inconsistencies 找异常订单,再生成补偿:

php bin/magento inventory:reservation:list-inconsistencies -r |
php bin/magento inventory:reservation:create-compensations

处理完重新索引 inventory,再用同一 website、同一 SKU 查询 salable quantity。只有接口返回值恢复并且前台实际能加入购物车,才说明不是表面上“改了库存”,而是可售库存链路真的恢复了。