Having gone the Magento 2 web store live, we’ve faced some troubles. When there’s high demand for goods, oversell happens. The record oversell number on live was -17. With the help of tests, we managed to get -81. The business logic of our web store is based on sales, that’s why the bug was rather crucial for us. Actually, it was clear that the problem was in the method responsible for products write-off:
\Magento\CatalogInventory\Model\StockManagement::registerProductsSale
When refactoring, we paid attention to the following line:
$stockItem = $this->stockRegistryProvider->getStockItem($productId, $websiteId);
The following method should also be considered:
\Magento\CatalogInventory\Model\StockRegistryStorage::getStockItem
1 2 3 4 5 6 7 8 9 |
/** * @param int $productId * @param int $scopeId * @return StockItemInterface */ public function getStockItem($productId, $scopeId) { return isset($this->stockItems[$productId][$scopeId]) ? $this->stockItems[$productId][$scopeId] : null; } |
Now it’s clear that stock can be cached in PHP while script running. Since the stock is used when placing an order, so stock in the method
\Magento\CatalogInventory\Model\StockRegistryStorage::getStockItem is taken from cache and if a lot of people are trying to make a purchase, so some “place order” can start simultaneously. Our situation has made worse because of our customers represented by bots which bought all goods within minutes.
Having found out the reason, it was easy to solve the issue. We clear cache with the method \Magento\CatalogInventory\Model\StockRegistryStorage::removeStockItem, and do it not always, but when the following method is called \Magento\CatalogInventory\Model\ResourceModel\Stock::lockProductsStock. Usually, it is called before stock check and place orders. If you’re not interested in writing your own plugin, you can use the module by following the link https://github.com/Galillei/magento2-belvg-concurrent-checkout-fix. We’ve used the module for a year and no longer faced oversell.
What type of PayPal do you use? This solution should work for all payments, because it works on low layer, where all payments must be. Another type of error, that I see with PayPal – that for some reason PayPal may fire error, but still create an order. And in this situation when the error was fired, observer revert stock. So, in this case, we have order, for example with 1 qty, and 1 qty was returned by observer in the end we have -1 in stock.
I followed your guide
That solution resolves all payments except Paypal
Pls help
Hi Simon!
Yes we created issue report for Magento https://github.com/magento/magento2/issues/6363 .
Have you reported this issue to Magento or – even better – created a pull request?