Produkt pokazywał „In Stock” na stronie produktu mimo że rzeczywiście nie było go na stanie. Klienci składali zamówienia na produkt który nie mógł zostać zrealizowany. Dopiero przy tworzeniu shipmentu pojawiał się błąd. Problem dotyczył produktów konfigurowalnych z MSI. Czas naprawy: 4 godziny.
Objawy
- Produkt konfigurowalny pokazuje „In Stock” przy qty = 0 w panelu admin
- Klienci mogą dodać do koszyka i złożyć zamówienie
- Błąd przy tworzeniu shipmentu: „Not enough qty available”
- W
cataloginventory_stock_item: qty = 0, is_in_stock = 1 - W
inventory_source_item: quantity = 0, status = 1
Diagnoza
-- Sprawdź rozbieżność między starym a nowym systemem stock
SELECT
csi.product_id,
csi.qty as legacy_qty,
csi.is_in_stock as legacy_status,
isi.quantity as msi_qty,
isi.status as msi_status,
isi.source_code
FROM cataloginventory_stock_item csi
JOIN catalog_product_entity cpe ON cpe.entity_id = csi.product_id
JOIN inventory_source_item isi ON isi.sku = cpe.sku
WHERE csi.qty != isi.quantity
OR csi.is_in_stock != isi.status
LIMIT 20;
-- Sprawdź salable quantity
SELECT sku, quantity
FROM inventory_stock_1 -- stock_id = 1 (default)
WHERE sku IN ('SKU-001', 'SKU-002');
Przyczyna
Import produktów aktualizował starą tabelę cataloginventory_stock_item ale nie tabele MSI (inventory_source_item). Po migracji na MSI stare API stocku jest tylko aliasem – prawdziwe dane są w tabelach inventory_*. Indekser cataloginventory_stock synchronizował dane w złym kierunku.
Rozwiązanie
<?php
// Poprawny sposób aktualizacji stocku w Magento 2 z MSI
use Magento\InventoryApi\Api\SourceItemsSaveInterface;
use Magento\InventoryApi\Api\Data\SourceItemInterfaceFactory;
class StockUpdater
{
public function __construct(
private SourceItemsSaveInterface $sourceItemsSave,
private SourceItemInterfaceFactory $sourceItemFactory,
) {}
public function update(array $items): void
{
// $items = [['sku' => 'SKU-001', 'qty' => 50, 'source' => 'default'], ...]
$sourceItems = [];
foreach ($items as $item) {
$sourceItem = $this->sourceItemFactory->create();
$sourceItem->setSku($item['sku']);
$sourceItem->setSourceCode($item['source'] ?? 'default');
$sourceItem->setQuantity($item['qty']);
$sourceItem->setStatus($item['qty'] > 0 ? 1 : 0);
$sourceItems[] = $sourceItem;
}
$this->sourceItemsSave->execute($sourceItems);
// MSI automatycznie zaktualizuje salable quantity i indeksy
}
}
# Zsynchronizuj stary stock z MSI bin/magento indexer:reindex cataloginventory_stock bin/magento indexer:reindex inventory # Uruchom kompensację rezerwacji jeśli są niespójności bin/magento inventory:reservation:list-inconsistencies bin/magento inventory:reservation:create-compensations
Wnioski
Po włączeniu MSI wszystkie operacje na stocku muszą używać API InventoryApi – nie starego cataloginventory. Stary interfejs działa jako wrapper ale tylko dla domyślnego źródła. Własne importery i integracje ERP wymagają aktualizacji do nowego API MSI.
