I just completed a migration from M1 to M2 version 2.3.5-p1.
All of the product and stock data was correctly migrated (I can see it in the database) but no matter what I do, products are all showing as "Out of Stock" on the frontend product pages.
This seems to be because the $_product->isAvailable()
check always returns false in the file vendor/magento/module-catalog/view/frontend/templates/product/view/type/default.phtml
.
However I triple checked all the product and inventory data in the database and everything (stock, associated products, etc.) are definitely correct for my products.
I have done all the usual: re-indexing, clearing cache, deleting folders, etc. etc.
I even made a quick external script to check the products were salable programatically, and they are:
<?php
// ---------------------
// Config
// ---------------------
$sku = "SOMESKU123";
$storeId = 1;
// ---------------------
// Get Object Manager
require __DIR__ . "/../app/bootstrap.php";
\Magento\Framework\App\Bootstrap::create(BP, $_SERVER);
$objectManager = \Magento\Framework\App\ObjectManager::getInstance();
// Set Magento area to frontend
$objectManager->get("Magento\Framework\App\State")->setAreaCode("frontend");
// Ensure correct store view is set
$storeManager = $objectManager->get("Magento\Store\Model\StoreManagerInterface");
$storeManager->setCurrentStore($storeId);
// Get product data
$myHelper = $objectManager->get("MyModule\MyFunctions\Helper\Data");
$product = $objectManager->get("\Magento\Catalog\Model\ProductFactory")->create()->loadByAttribute("sku", $sku);
echo "\n Magento area code: " . $objectManager->get("\Magento\Framework\App\State")->getAreaCode();
echo "\n Product Name: " . $product->getName();
echo "\n isSalable: " . $product->isSalable();
echo "\n isAvailable: " . $product->isAvailable();
echo "\n isInStock: " . $product->isInStock();
The output of the above script when I run it on the same Magento 2 instance:
Area code: frontend
Name: Whatever Product
isSalable: 1
isAvailable: 1
isInStock: 1
But when I load the same product on the "real" Magento 2 frontend, it shows as Out of Stock and isAvailable()
returns false.
Why would this happen?
Update
I've done more debugging. It turns out there are many files involved in displaying the stock status on the product page:
vendor\magento\module-catalog\view\frontend\templates\product\view\type\default.phtml
vendor\magento\module-catalog\Model\Product.php
vendor\magento\module-configurable-product\Model\Product\Type\Configurable.php
vendor\magento\module-catalog\Model\Product\Type\AbstractType.php
vendor\magento\module-catalog\Model\ProductRender.php
vendor\magento\module-catalog-inventory\Observer\AddInventoryDataObserver.php
vendor\magento\module-catalog-inventory\Helper\Stock.php
vendor\magento\module-catalog-inventory\Model\StockRegistryStorage.php
vendor\magento\module-inventory-catalog\Plugin\CatalogInventory\Helper\Stock\AdaptAssignStatusToProductPlugin.php
vendor\magento\module-inventory-catalog\etc\di.xml
vendor\magento\framework\Interception\Interceptor.php
vendor\magento\module-inventory-catalog\Plugin\InventorySalesApi\StockResolver\AdaptStockResolverToAdminWebsitePlugin.php
vendor\magento\module-inventory-configurable-product\etc\frontend\di.xml
However, I believe the problem is related to the assignStatusToProduct
function, which is expanded upon by the aroundAssignStatusToProduct
function inside vendor/magento/module-inventory-catalog/Plugin/CatalogInventory/Helper/Stock/AdaptAssignStatusToProductPlugin.php
.
If I modify framework/Interception/Interceptor.php
and add a hack to effectively skip the above plugin, the stock status starts to appear normally:
public function ___callParent($method, array $arguments)
{
// Begin hack
if ($method == "assignStatusToProduct") {
return;
}
// End hack
return parent::$method(...array_values($arguments));
}
Obviously this is not a real solution. I don't fully understand why this plugin or function would result in an incorrect stock status, but from what I've read it might be related to 2.3's new Multi Source Inventory functionality so I will try disabling those inventory modules next and see what happens.
Also, this is a wild guess, but the reason this issue only happens on the Magento frontend (and not via my PHP script above) might be because this function is inserted via dependency injection (module-inventory-catalog\etc\di.xml
) which might not be injected when I call ObjectManager directly in my script.
Any suggestions are appreciated.