How to decrease Magento 2 stock inventory on Invoice instead of Order
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:
- Set ‘No’ to Admin -> Store -> Catalog -> Catalog > Inventory > Decrease Stock When Order is placed
- Create observer sales_order_invoice_save_after in Vendor\Extension\etc\adminhtml\events.xml
1234567<?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> - Create observer file
12345678910111213141516171819202122232425262728293031323334353637383940<?phpnamespace 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.
Do not hesitate to post any doubts on the topic in the Comments section below. I’d be happy to solve them 🙂
Rate the post with 5 stars if you got the necessary solution.
Thank you.
Get help in managing the products’ stock with automated inventory reporting in grid format.
Sanjay Jethva
Sanjay is the co-founder and CTO of Meetanshi with hands-on expertise with Magento since 2011. He specializes in complex development, integrations, extensions, and customizations. Sanjay is one the top 50 contributor to the Magento community and is recognized by Adobe.
His passion for Magento 2 and Shopify solutions has made him a trusted source for businesses seeking to optimize their online stores. He loves sharing technical solutions related to Magento 2 & Shopify.
33 Comments
Hello,
I want a when i placed an order its decrease in Qauanity.
Make a same Salable quantity and Main Quantity.
Please Provide me a Solution.
Thanks,
Hello,
In default Magento 2, the salable quantity decreases when an order is placed and the main quantity decreases when the shipment is generated.
Do not forget to set “Yes” in Admin -> Store -> Catalog -> Catalog > Inventory > Decrease Stock When Order is placed
Thank you.
Is there any way to increment the product quantity on order failure?
I’m using a customized payment gateway.
Hello,
For the orders that are failed, cancel it if the invoice is not generated. Or else generate credit memo to automatically increase the quantity.
Thank you.
Thanks, buddy. This is very helpful.
Happy to help 🙂
Can u plz guide me for 2.3.4 i want to create invoice pdf at the time of invoice creation
Hello,
As mentioned earlier, the above solution is not possible for Magento 2.3.4
Thank you.
for magento 2.3 that not working. sales_order_invoice_pay even with that invoice object not retried plz guide me
Hello,
The code in the above post is only for Magento 2.2.x
Thanks.
Hii sanjay, very informative solution… i am facing issues with inventory modules… we have only one store to manage and for using pos we have just recently enabled magneto 2 inventory modules before that all of them were disabled. now we have enabled option for decrease qty after having order placed to “Yes” as we want the same… but after inventory modules enabled the behaviour has changed, the default quantty remains unchanged and saleble qty decreases and magneto manages it on basis of “inventory_reservation” table, so the issue we facing is many products that are sold previously are out of stock and they were for pre orders. so when we try to generate shipment for them we get error saying “not all of the products are available in stock” so we want change quantity decrease from “after shipment” to “after checkout”, any help will be really appreciated…
Hello Vishal,
The above code is not compatible with MSI.
Thanks.
I need Decrease Stock When Order is placed set “YES”
1> decrease salable => on place order.
2> decrease stock qty => on invoice generate.
3> dsiplay actual quantity of stock and salable after invoice.
Hello again,
You don’t need to follow the above solution for Magento 2.3.x versions.
I need Decrease Stock When Order is placed set “YES”
1> decrease salable => on place order.
2> decrease stock qty => on invoice generate.
3> but issue is on invoice salable decreases twice . while use you module.
Hey,
You have enabled decreasing the stock when the order is placed. If so, the above code won’t work.
Thanks.
@Sanjay Jethva , i used you module in M2.3.2 , unfortunately salable quantity and stock quantity decrease twice after generate invoice and ship .
Hello,
Please make sure you have followed Step 1 correctly.
If so, you won’t have this issue.
Thanks.
Hello Sanjay,
I need the full code for this modification, because this is too complicated for me. Can you help me with this? I’m prepared to pay something for the full code if it’s working well in Magento 2.3.2. Maybe, it’s easier to set “Decrease Stock When Order is placed” to “Yes”. In that case, you only have to remove the saleable quantity reduction after placing an order and add this after creating the invoice.
I have tested this module in Magento 2.3.2 and noticed that not everything works as expected. There are 2 problems that have to be solved:
1. If I set “Decrease Stock When Order is placed” to “No”, then the stock and saleable quantity don’t increase when I make a credit note.
2. The stock and saleable quantity decrease an extra time after creating a shipment. This doesn’t happen if I set “Decrease Stock When Order is placed” to “Yes”. In that case, only stock decreases.
3. After creating the invoice, only the saleable quantity should decrease. The stock should decrease after creating the shipment.
In summary, it should be:
after placing order: no change
after creating invoice: decrease saleable quantity
after creating shipment: decrease stock
after credit: increase stock and saleable quantity
Hello Jeroen,
Using the below code, you will be able to fulfill your requirements:
use Magento\CatalogInventory\Api\StockStateInterface;
$stockStatus = $this->stockItem->getStockQty($product->getId(), $product->getStore()->getWebsiteId());
Though, please note that the code given in the post is compatible with Magento 2.3.1
Thank you very much for your support by email. I didn’t know that I had to remove the spaces from the observer file. The extension is working now, so I have rated your blog post with 5 stars.
Thank you Jeroen 🙂
With which Magento versions do you have tested this module? I’m using Magento CE 2.3.2 and I also get a blank page (500 error) when I try to create an invoice in the admin. When I disable the module, I can create an invoice again.
Hello,
I have tested in Magento 2.3.1 and it works fine
Can you please check php error.log file
It will give a better idea.
Thank you
Does this work on per item bases? So when only a part of the order gets invoiced only those items will be deducted? And does this work with Magento’s MSI enabled?
Yes, it will work with invoice item as well as MSI enabled.
Thank you very much Sanjay,
its working fine now!
Thanks a lot 🙂 🙂
It’s our pleasure 😊
Dear Sanjay,
I haved disabled the module and setup magento again. The error has gone and back to normal.
Not sure if I have installed the module in a wrong way?
The module file structure is
Vendor > Extension > registration.php
Vendor > Extension > observer.php
Vendor > Extension > etc > module.xml
Vendor > Extensiob > etc > adminhtml > events.xml
Thanks again
Much appreciated
Create UpdateInventory.php in Vendor\Extension\Observer
If you still have issue feel free to contact.
Hello Sanjay,
Thank you for your tutorial.
I have installed the new module and setup in magento, everything going smoothly.
However when I try to issue an invoice from order in admin panel,
it shows a blank page, when i try to refresh it show:
“Magento Admin
404 Error”
I m using magento C E 2.3.0.
in var/log there’s no information regarding with the issue.
Hope you can help me with this, really thanks a lot!
Please try to disable this newly installed module and try again. If you don’t face the error, the issue is with the module.
If not, there is a problem in current Magento.
The above solution is currently working on a live site without any problem.