Magento 2.3 saw the introduction of the Multi-Source Inventory system. The solution is in principle a great improvement over the original stock management system, allowing you to manage stock levels across a range of stock sources, and to aggregate these into a single computed stock figure that takes into account inventory reservations from unshipped/unprocessed orders.
We recently discovered a bug with the inventory system and credit memos. This bug is present in versions 2.4.3 and 2.4.4 (that we’ve tested, although a bug report in Magento suggests this has been present since 2.2.x).
What’s the saleable quantity problem?
If a product’s stock becomes 0 after an order has been shipped, it will automatically mark the product as out of stock – Great.
If you then need to refund an order for the same product, you follow the usual steps, click credit memo, and tick “return to stock”. Finally clicking the orange button to create the credit memo and issue the refund via your payment gateway.
What we’d expect at this point is that the products stock level moves from 0, to the qty credited. Magento works fine here. What we find however, is that the “stock status” (in stock, out of stock) is not updated, and therefore the saleable quantity still shows as 0.
What’s the solution to the credit memo bug?
After identifying the bug when issuing credit memos we tried a number of things to resolve the problem. Typical steps such as re-indexing, runing crons, clearing caches or running inventory inconsistency CLI commands failed to resolve the issue which ruled out an automated or deferred task. We decided therefore to develop a small extension to overcome the issue.
Our extension implements a basic observer on the sales_order_creditmemo_save_after event. We check each line of the credit memo for items that are being refunded, we also check that the product in question has a 0 stock level, and is currently not set as “in stock”. If these requirements are met, we create a SourceItemInterfaceFactory to correctly set the stock status and execute it against the SourceItemsSaveInterface.
We’ve decided to release this extension for free in the hope it helps others who have experienced this issue.