9

In the following code, I am able to store all the information with the exclusion of the stock data. Has something changed in Magento 2?

public function __construct(
    ScopeConfigInterface $scopeConfig, CollectionFactory $product,
    Magento\Catalog\Api\ProductRepositoryInterface $productRepository
) {
    $this->scopeConfig = $scopeConfig;
    $this->product = $product;
    $this->productRepository = $productRepository;
}

public function update(\XXXXXX\XXXXXX\Api\Data\InventoryCollectionInterface $data) {
    foreach ($data['list'] as $d) {
        $product = $this->productRepository->getById($d['entity_id']);
        $product->setStatus(($d['quantity'] > 0 ? 1 : 0));
        $product->setUpc($d['upc']);
        $product->setStockData(array(
            'qty' => $d['quantity'],
            'is_in_stock' => ($d['quantity'] > 0 ? 1 : 0)
        ));

        $this->productRepository->save($product);
    }

    return "Done";
}

10 Answers 10

29

This works for me:

$item = ['qty' => 11]; // For example
$product->setStockData(['qty' => $item['qty'], 'is_in_stock' => $item['qty'] > 0]);
$product->save();

Edit:

This is no longer the correct way to handle this, because $product->save() is deprecated since Magento 2.1. The correct way to do this is by using the StockRegistryInterface:

/**
 * @var StockRegistryInterface
 */
protected $stockRegistry;

/**
 * Inventory constructor.
 * @param StockRegistryInterface $stockRegistry
 */
public function __construct(
    StockRegistryInterface $stockRegistry
)
{
    $this->stockRegistry = $stockRegistry;
    parent::__construct();
}

With the above code, you can use the following:

$sku = 'ABC123';
$qty = 10;
$stockItem = $this->stockRegistry->getStockItemBySku($sku);
$stockItem->setQty($qty);
$this->stockRegistry->updateStockItemBySku($sku, $stockItem);

Use Managers as much as possible. Keep your modules decoupled from each other.

It's The Magento Way™

  • setStockData is what is required. There is no need to call ->setQuantityAndStockStatuses, though it seems to do no harm. – Robert Egginton Nov 15 '16 at 16:50
  • 6
    It works great for one product. However, when you reading a CSV file with 5k SKUs the performance is pretty bad. Anyone having the same issue? – medina Feb 23 '17 at 5:45
  • +1 for updating your post to magento 2.1 Version. – ZFNerd Jun 13 '18 at 7:06
  • +1 for best practices (and updating answer) – Akif Jan 9 at 22:22
  • Really appreciate the Updated Method! Magento is getting better for all of us because of community members like you doing posts like this! Way to go – JustinP Jan 10 at 17:30
14

If you are using the @giel-berkers solution, you may need to set isInStock also, because it will not be automatically sets. So, the following code was useful for me:

public function __construct(
    \Magento\CatalogInventory\Api\StockRegistryInterface $stockRegistry
)
{
    $this->stockRegistry = $stockRegistry;
    parent::__construct();
}

public function yourMethod() {
    $sku = 'ABC123';
    $qty = 10;
    $stockItem = $this->stockRegistry->getStockItemBySku($sku);
    $stockItem->setQty($qty);
    $stockItem->setIsInStock((bool)$qty); // this line
    $this->stockRegistry->updateStockItemBySku($sku, $stockItem);
}
  • how can i use this answer to update the qty store wise in magento 2? – Mujahidh Mar 22 at 11:01
  • @Mujahidh you can try to pass scopeId as a second parameter to the getStockItemBySku() method – spiil Mar 23 at 19:14
  • thanks, qty is updating but not store wise, for both store updating the same qty. – Mujahidh Mar 25 at 6:38
7

I struggled with this same issue. While debugging I found that the product data has a quantity_and_stock_status array, so I tried setting it with:

$product->setQuantityAndStockStatus(['qty' => $quantity, 'is_in_stock' => 1]);

and it started working for me. I still am setting the $product->setStockData too if you edit a product and inspect element on the fields you'll see it has both, one is on the general tab, the other on the advanced inventory fields. I have not fully investigated why there are 2 of them.

  • sort and simple , very good solution !!! works for me +1 – Manthan Dave Sep 14 '17 at 6:49
  • Preferred solution, as this works and takes way less editing than the others +1 – leedch Jan 4 '18 at 10:48
  • When product is Disable then quantity not update; else in enable status working properly. Can you help me for it. My site is in 2.1.9 – Anil Jun 27 at 9:38
7

One thing the other answers missed is that if you setQty($qty), it will apply the exact value you provide. But if a sale was made for that product a moment before your save, the original qty could have changed. So what you really want to do is tell Magento the difference you want to apply to the qty.

Fortunately, Magento 2 provides a nice mechanism for this. Take a look at Magento\CatalogInventory\Model\ResourceModel\Stock\Item:

protected function _prepareDataForTable(\Magento\Framework\DataObject $object, $table)
{
    $data = parent::_prepareDataForTable($object, $table);
    $ifNullSql = $this->getConnection()->getIfNullSql('qty');
    if (!$object->isObjectNew() && $object->getQtyCorrection()) {
        if ($object->getQty() === null) {
            $data['qty'] = null;
        } elseif ($object->getQtyCorrection() < 0) {
            $data['qty'] = new \Zend_Db_Expr($ifNullSql . '-' . abs($object->getQtyCorrection()));
        } else {
            $data['qty'] = new \Zend_Db_Expr($ifNullSql . '+' . $object->getQtyCorrection());
        }
    }
    return $data;
}

Here we see that if you set the qty_correction value, it will apply the difference incrementally instead of applying an exact amount.

So my suggestion for a safer qty save is this:

/**
 * @var \Magento\CatalogInventory\Api\StockRegistryInterface
 */
protected $stockRegistry;

public function __construct(StockRegistryInterface $stockRegistry)
{
    $this->stockRegistry = $stockRegistry;
}

/**
* Set the quantity in stock for a product
*
*/
public function applyNewQty($sku, $newQty)
{
    $stockItem = $this->stockRegistry->getStockItemBySku($sku);
    $origQty = $stockItem->getQty();
    $difference = $newQty - $origQty;
    $stockItem->setQtyCorrection($difference);
    $this->stockRegistry->updateStockItemBySku($sku, $stockItem);

    // note that at this point, $stockItem->getQty() is incorrect, so you'll need to reload if you need that value
}
1

Below code is working fine for me to update product qty,

public function __construct(
    \Magento\Catalog\Model\ProductFactory $productFactory
) {
    $this->productFactory = $productFactory;
}

public function updateQty(){
    $sku = '24-mb01';
    $product = $this->productFactory->create();
    $productId = $product->getIdBySku($sku);
    if($productId){
        $product->load($productId);
    }

    $product->setStockData(
        array(
            'use_config_manage_stock' => 0,
            'manage_stock' => 1,
            'is_in_stock' => 1,
            'qty' => 10
        )
    );

    try {
        $product->save(); 
        echo $sku.' updated. '; 
    } catch (Exception $e) {
        echo $e->getException();
    }
}
  • When product status is disable then quantity not update in my case. Can you help me for solve it. – Anil Jun 27 at 9:42
0

Try to set StoreId to $product before all, and maybe replace:

$product->setStockData(...) for $product->setData('stock_data', '...') // A Paranoid Recommendation

BTW If you look the Save ActionController at the backend M2 uses a filter for prepare stock_data you could find that filter in:

Magento\Catalog\Controller\Adminhtml\Product\Initialization\StockDataFilter

  • I appreciate the response, but that option did not work. Thanks for the help. – Stephen Malenshek Jan 9 '16 at 0:51
0

Try this, while saving the product in admin, they saved inventory data by using event catalog_product_save_after in Magento_CatalogInventory module observer

Magento\CatalogInventory\Observer\SaveInventoryDataObserver

0

I had same issue for magento 2.0.9 and following code is working in my case

$productStock = $this->_productRepository->getById($item->getMageproductId());
$productStock->setQuantityAndStockStatus(['qty' => 12, 'is_in_stock' => 1]);
$res = $productStock->save();
0
$objectManager = $bootstrap->getObjectManager();
$stockRegistry = $objectManager->create('Magento\CatalogInventory\Api\StockRegistryInterface');

$stockItem = $stockRegistry->getStockItemBySku($sku);
$stockItem->setQty($qty);
$stockItem->setIsInStock((bool)$qty);
$stockRegistry->updateStockItemBySku($sku, $stockItem);
0

Magento2 also come up with Multi stock feature so to update on particular stock source you can follow this solution

https://magento.stackexchange.com/questions/272296/how-to-set-qty-to-product-on-msi-magento-2-3

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.