In default Magento 2, the inventory is managed based on the orders placed. For example, the inventory decreases from 1 to 0 when a user places the order. However, what if that order was a test order. Or, if the user chose Cash On Delivery method and the payment was not captured due to some reasons!
In such scenarios, the storefront shows out of stock which is not the case in reality. Due to failure in payment processing, the order was cancelled. Hence, the product was not out of stock. If any other visitor is interested in that product, your store might lose a sale due to this conflict!
The solution is to manage the stock inventory when an invoice is generated instead of the order placed. That’s because the invoice is only generated once the payment is confirmed in any case.
The programmatic solution to decrease Magento 2 stock inventory on invoice instead of order is given here.
Note: The solution works with Magento 2.2.x
Steps to Decrease Magento 2 Stock Inventory on Invoice Instead of Order:
Step 1: Set ‘No’ to Admin > Store > Catalog > Catalog > Inventory > Decrease Stock When Order is placed
Step 2: Create observer sales_order_invoice_save_after in Vendor\Extension\etc\adminhtml\events.xml
<?xml version="1.0"?> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd"> <event name="sales_order_invoice_save_after"> <observer name="meetanshi_sales_order_invoice_save_after" instance="Vendor\Extension\Observer\UpdateInventory"/> </event> </config>
Step 3: Create observer file
<?php namespace Vendor\Extension\Observer; use Magento\Framework\Event\ObserverInterface; use Magento\Framework\Event\Observer; use Magento\CatalogInventory\Api\StockRegistryInterface; use Magento\Catalog\Model\ProductRepository; class UpdateInventory implements ObserverInterface { protected $productRepository; protected $stockRegistry; public function __construct(ProductRepository $productRepository, StockRegistryInterface $stockRegistry) { $this->productRepository = $productRepository; $this->stockRegistry = $stockRegistry; } public function execute(Observer $observer) { try { $invoice = $observer->getEvent()->getInvoice(); $invoiceItems = $invoice->getAllItems(); foreach ($invoiceItems as $item) { $productId = $item->getProductId(); $product = $this->productRepository->getById($productId); $sku = $product->getSku(); $stockItem = $this->stockRegistry->getStockItemBySku($sku); $qty = $stockItem->getQty() - $item->getQty(); $stockItem->setQty($qty); $stockItem->setIsInStock((bool)$qty); $this->stockRegistry->updateStockItemBySku($sku, $stockItem); } } catch (\Exception $e) { return $e->getMessage(); } } }
Implement the above solution and your Magento 2 store stock inventory management will be flawless! No visitors will ever face a false out-of-stock status for their interested products. Get Product salable quantity in Magento 2 to have the sum of available resources, grouped in stocks.
Thank you.