这个问题表面看是父商品库存,实际几乎都要落到子SKU。可配置父商品没有独立的真实数量,它能不能卖取决于至少一个子商品在当前Stock下可售。后台“数量”正确,只能证明source_item有值,不能证明销售渠道使用的Stock能算出正的salable quantity。

先选一个确实应该可售的子SKU

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

上面两条不要盲目直接连着执行。先运行第一条保存输出,确认不一致记录对应的订单确实已经完成、取消或退款,再把确认过的结果交给补偿命令。生产环境建议先在数据库备份或从库中核对。

三个位置要同时看

1. Source Item

SELECT source_code,sku,quantity,status
FROM inventory_source_item
WHERE sku IN ('CHILD-SKU-1','CHILD-SKU-2');

quantity大于0但status=0时,商品仍不可售。CSV导入尤其容易只更新数量而漏掉状态。需要重新导入status=1,或通过SourceItemsSaveInterface更新,别直接长期用SQL改业务数据。

2. Stock与销售渠道映射

SELECT s.stock_id,s.name,sc.type,sc.code
FROM inventory_stock s
LEFT JOIN inventory_stock_sales_channel sc ON sc.stock_id=s.stock_id;

确认当前网站代码映射到预期Stock。如果网站还指向Default Stock,而数量被录入到只属于另一个Stock的Source,后台看起来有库存,前台仍会是0。

3. 预留数量

SELECT sku,SUM(quantity) AS reservation_total
FROM inventory_reservation
WHERE sku='CHILD-SKU-1'
GROUP BY sku;

reservation是追加式流水,不应该删除某一行来“修库存”。如果订单状态流转曾被自定义插件中断,应创建相反数量的补偿记录,并修正那个状态流转插件,避免每天继续产生负数。

重新索引并验证当前Stock

bin/magento indexer:reindex inventory
bin/magento cache:clean

不同版本的索引器名称可能显示为inventory或inventory_stock,先用 bin/magento indexer:info 确认。然后查询对应的 inventory_stock_<stock_id> 视图或表。

SELECT sku,quantity,is_salable
FROM inventory_stock_2
WHERE sku IN ('CHILD-SKU-1','CHILD-SKU-2');
  • source_item数量和状态正确
  • 网站映射到包含该Source的Stock
  • reservation汇总符合订单实际
  • inventory_stock_N中至少一个子SKU的is_salable=1
  • 前台切换到该子商品组合后能加入购物车

如果这些都正确而父商品仍不可售,再检查自定义 salability condition、backorder配置和最小销售数量。排查顺序很重要:先把MSI基础数据链路走通,再看插件,不然很容易在父商品上反复改数量却没有任何效果。