I'm creating a product programmatically and trying to update its stock quantity (XXX) afterwards, but the products grid always shows Quantity: XXX, Default Stock: 0.
I'm using Magento 2.4.4 [which uses MultiSource Inventory by default], with only the default source and default stock.
Here's what I've tried:
/** @var \Magento\Catalog\Model\Product $product */
$product = $this->productFactory->create();
$product
->setTypeId(Type::TYPE_SIMPLE)
->setSku('test');
(...)
/** @var \Magento\Catalog\Api\ProductRepositoryInterface $this->productRepository */
$product = $this->productRepository->save($product)
Later I try to update the stock with:
1: works but it is deprecated
/** @var \Magento\CatalogInventory\Model\Stock\Item $stockItem */
$stockItem = $product->getExtensionAttributes()->getStockItem();
$stockItem
->setIsInStock(true)
->setQty(XXX)
->setStockStatusChangedAuto(true);
$product = $this->productRepository->save($product)
2: works but it is deprecated
$product->setQuantityAndStockStatus(['qty' => XXX, 'is_in_stock' => 1]);
$product = $this->productRepository->save($product)
3: updates product quantity but doesn't update its salable quantity. The table inventory_stock_1
is filled with zero quantity and is_salable
= 0
/** @var \Magento\CatalogInventory\Model\Stock\Item $stockItem */
$stockItem = $product->getExtensionAttributes()->getStockItem();
$stockItem
->setIsInStock(true)
->setQty(XXX)
->setStockStatusChangedAuto(true);
/** @var \Magento\InventoryApi\Api\GetSourceItemsBySkuInterface $this->getSourceItemsBySku */
$stockItems = $this->getSourceItemsBySku->execute($product->getSku());
reset($stockItems)->setQuantity(XXX);
reset($stockItems)->setStatus(SourceItemInterface::STATUS_IN_STOCK);
/** @var \Magento\InventoryApi\Api\SourceItemsSaveInterface $this->sourceItemsSave */
$this->sourceItemsSave->execute($stockItems);
Am I missing any additional steps so the Inventory API method works correctly?
The way I do it is with source items and you need to know which sources are assigned to the product first, then iterate over the sources to see if the source you are trying to update exists for that product.
Create your product as you are, and make sure to save it before proceeding to this step.
You will need to know your source code which you get from Magento Admin -> Stores -> Inventory -> Sources -> Code -> {Your source code: ie: 'default'}
/**
* @var \Magento\Inventory\Model\SourceItem\Command\GetSourceItemsBySku $getSourceItemsBySku
* @var \Magento\InventoryApi\Api\Data\SourceItemInterface $sourceItemInterface
* @var \Magento\InventoryApi\Api\Data\SourceItemInterfaceFactory $sourceItemFactory
*
* Create your constructor etc...
**/
$sku = 'test';
$qty = 10;
// CREATE AND SAVE YOUR PRODUCT HERE AS YOU ARE
// Optional
$inventorySaveArray = [];
$sourceItems = $this->getSourceItemsBySku->execute($product->getSku());
foreach ($sourceItems as $item){
if ($item->getSourceCode() === 'my_source_code'){
$sourceItem = $this->sourceItemFactory->create();
$sourceItem->setSourceCode('my_source_code');
$sourceItem->setSku($sku);
$sourceItem->setQuantity((int)$qty);
$sourceItem->setStatus($this->sourceItemInterface::STATUS_IN_STOCK);
$this->sourceItemsSave->execute([$sourceItem]);
break;
}
}
For multiple products, you can append $sourceItem to an array and pass the array to $this->sourceItemsSave->execute($inventorySaveArray) once iterated over all of your products. This speeds up the process by a few minutes on around 200 products.
in the above code, replace:
$this->sourceItemsSave->execute([$sourceItem]);
with:
array_push($inventorySaveArray, $sourceItem);
then after you have iterated over all of your products, save the array:
Example:
$this->sourceItemsSave->execute($inventorySaveArray);
Works for me on Magento 2.4.3, 2.4.4 and 2.4.5