Magento2: Imported bundle products are not assigned stock status

Created on 17 Nov 2017  路  24Comments  路  Source: magento/magento2



When importing a new bundle product (can be entirely new, or generated through replacement), no entry is generated for it in cataloginventory_stock_status. This means that when the frontend tries to display it, it encounters a NULL entry when trying to discover whether the product is salable.

vendor/magento/module-catalog/Model/Product/Type/AbstractType.php line 355
When running getData('is_salable'), this returns NULL because the cataloginventory_stock_status row doesn't exist. Because it returns NULL, the isSalable function returns false, and that means that the bundle product does not appear in category lists and shows as out of stock on the frontend.

Reindexing does not resolve issue, and neither does saving the product in the backend.

Preconditions


  1. Magento Commerce 2.2.0
  2. PHP 7.0.23 / 7.1.11 (tested on two servers)
  3. MySQL 5.6.37 / MariaDB 10.2.7

Steps to reproduce

  1. Create bundle product that shows on frontend as in stock
  2. Export bundle product
  3. Either:
    3.a) change the SKU of the bundle product and import it
    3.b) re-import it in Replace mode

Expected result

  1. New/replaced product shows as in stock

Actual result

  1. New/replaced product shows as out of stock

ImportExport Fixed in 2.3.x Clear Description Confirmed Format is valid Ready for Work Reproduced on 2.2.x Reproduced on 2.3.x

Most helpful comment

From reading magento-engcom/import-export-improvements#80 I gather the problem is that the import does not populate table catalog_product_relation.
If you need a quick workaround without updating code:

  • Insert the missing bundle relations: INSERT IGNORE INTO catalog_product_relation SELECT parent_product_id,product_id FROM catalog_product_bundle_selection
  • Reindex stock and price indexes

All 24 comments

Addendum: this also happens when you add customisable options or change whether they are required.

We are experiencing the same with the same configuration/stack and steps to reproduce.

@indefinitedevil, thank you for your report.
We've created internal ticket(s) MAGETWO-84124 to track progress on the issue.

@magento-engcom-team Any ETA on this please guys? Our client's website has around 80% of it's products as Bundles. They are on M2.1.5 which is extremely broken and we're trying to get them upgraded to 2.2 but this is a massive show stopper. Please provide an update or temporary fix. Thank you, Tony.

@magento-engcom-team - This is also an issue for me. After upgrading from M2.1.5 bundles no longer display. Same process listed by @indefinitedevil
Is this likley to be fixed soon? Thanks Ben

@magento-engcom-team Is anybody going to get back to us re. this please? We cannot launch our clients website without this working so this is causing us a huge amount of problems! Any workaround at this point would be massively appreciated just to get the bundle products appearing. Thanks, Tony

Can you assign this to me? I鈥檒l fix it. Please add import/export label. Thanks!

Glad to see this on the way to resolution. For anyone waiting on a fix, what worked for us was: 1) import the simples on which your bundles are based; 2) import the bundles via csv; 3) note the stock status on the bundles is out of stock (the bug); 4) create a dummy simple called "AAA" with inventory zero; 5) For each bundle product, add the AAA simple to the bundle values and save it out; 6) Note the stock status is in-stock and since there is zero inventory of AAA, that option does not display; ("AAA" we used for easy sorting by name when adding the simple to the bundle). Not a very elegant solution, but it kept our project going.

This issue was moved to magento-engcom/import-export-improvements#80

The issue is not that the entry doesn't exist. Even if the entry exists, and you change the status to a 1 in the db, after reindex stock it sets it back to zero.

did you find a solution for this? I'm having the same problem.

@mariamghalleb

TonyBrown_ForceInventory.zip
Here's a hacky solution I came up with to overcome this. This always sets the isSaleable() method against the product object as true for both simple and bundle product types. It comes in two versions.

Version 1.0.0 forces this flag for all simple and bundle products as default during the indexing process.
Version 1.0.1 Adds the boolean product attribute force_visibility. This is a true/false value you can set to then force visibility conditionally during the indexing process. Only applies to simple and bundle product types. I haven't tested version 1.0.1 as I've only just created it but version 1.0.0 works fine without issue.

@tonybrown85
I installed your solution, running 2.2.3 and got this error:
Fatal error: Uncaught Error: Call to undefined method Magento\Bundle\Model\Product\Type\Interceptor::getCustomAttribute() in /app/code/TonyBrown/ForceInventory/Plugin/Bundle.php:11 Stack trace: #0 /vendor/magento/framework/Interception/Interceptor.php(135): TonyBrown\ForceInventory\Plugin\Bundle->aroundIsSalable(Object(Magento\Bundle\Model\Product\Type\Interceptor), Object(Closure), Object(Magento\Catalog\Model\Product\Interceptor)) #1 /vendor/magento/framework/Interception/Interceptor.php(153): Magento\Bundle\Model\Product\Type\Interceptor->Magento\Framework\Interception{closure}(Object(Magento\Catalog\Model\Product\Interceptor)) #2 /generated/code/Magento/Bundle/Model/Product/Type/Interceptor.php(26): Magento\Bundle\Model\Product\Type\Interceptor->___callPlugins('isSalable', Array, NULL) #3 /vendor/magento/module-catalog/Model/Product.php(1658): Magent in /app/code/TonyBrown/ForceInventory/Plugin/Bundle.php on line 11
Any help is appreciated.

@hfgoulding

I'd recommend using version 1.0.0 instead as that should work fine and just force as default, as opposed to using a product attribute to conditionally force it.

I've just installed it on my local copy of M.2.2.1 but I cannot replicate the error. Perhaps change it to if($subject->getData('force_visibility')) instead within both bundle.php and simple.php. That may fix it but I'm hazarding a guess.

Sorry I'm unable to help further but unfortunately I don't have the time to replicate, debug and fix.

I'm not sure if this is the same issue, but after upgrading from 2.1.9 to 2.2.3, I discovered all of my bundle products were showing as out of stock and with a price of $0.

I found the offending code and reverted it back to the 2.1.12 version until a proper fix has been released.

To fix the price issue, open /vendor/magento/module-bundle/Pricing/Adjustment/Calculator.php and at line 197, add:

        //**********************************************************
        //* Added from 2.1.12 due to a bug in 2.2.0
        //**********************************************************
        // Flag shows - is it necessary to find minimal option amount in case if all options are not required
        $shouldFindMinOption = false;
        if ($searchMin
            && $bundleProduct->getPriceType() == Price::PRICE_TYPE_DYNAMIC
            && !$this->hasRequiredOption($bundleProduct)
        ) {
            $shouldFindMinOption = true;
        }
        $canSkipRequiredOptions = $searchMin && !$shouldFindMinOption;

        $currentPrice = false;
        $priceList = [];
        foreach ($this->getBundleOptions($bundleProduct) as $option) {
            if ($this->canSkipOption($option, $canSkipRequiredOptions)) {
                continue;
            }
            $selectionPriceList = $this->createSelectionPriceList($option, $bundleProduct, $useRegularPrice);
            $selectionPriceList = $this->processOptions($option, $selectionPriceList, $searchMin);

            $lastSelectionPrice = end($selectionPriceList);
            $lastValue = $lastSelectionPrice->getAmount()->getValue() * $lastSelectionPrice->getQuantity();
            if ($shouldFindMinOption
                && (!$currentPrice ||
                    $lastValue < ($currentPrice->getAmount()->getValue() * $currentPrice->getQuantity()))
            ) {
                $currentPrice = end($selectionPriceList);
            } elseif (!$shouldFindMinOption) {
                $priceList = array_merge($priceList, $selectionPriceList);
            }
        }
        return $shouldFindMinOption ? [$currentPrice] : $priceList;
        //*********************************************************
        //* End 2.1.12 code
        //*********************************************************

To fix the stock issue, open /vendor/magento/module-bundle/Model/Product/Type.php and at line 581, add:

        //**********************************************************
        //* Added from 2.1.12 due to a bug in 2.2.0
        //**********************************************************
        $optionCollection = $this->getOptionsCollection($product);

        if (!count($optionCollection->getItems())) {
            return false;
        }

        $requiredOptionIds = [];

        foreach ($optionCollection->getItems() as $option) {
            if ($option->getRequired()) {
                $requiredOptionIds[$option->getId()] = 0;
            }
        }

        $selectionCollection = $this->getSelectionsCollection($optionCollection->getAllIds(), $product);

        if (!count($selectionCollection->getItems())) {
            return false;
        }
        $salableSelectionCount = 0;

        foreach ($selectionCollection as $selection) {
            /* @var $selection \Magento\Catalog\Model\Product */
            if ($selection->isSalable()) {
                $selectionEnoughQty = $this->_stockRegistry->getStockItem($selection->getId())
                    ->getManageStock()
                    ? $selection->getSelectionQty() <= $this->_stockState->getStockQty($selection->getId())
                    : $selection->isInStock();

                if (!$selection->hasSelectionQty() || $selection->getSelectionCanChangeQty() || $selectionEnoughQty) {
                    $requiredOptionIds[$selection->getOptionId()] = 1;
                    $salableSelectionCount++;
                }
            }
        }
        $isSalable = array_sum($requiredOptionIds) == count($requiredOptionIds) && $salableSelectionCount;
        $product->setData('all_items_salable', $isSalable);

        return $isSalable;
        //*********************************************************
        //* End 2.1.12 code
        //*********************************************************

From reading magento-engcom/import-export-improvements#80 I gather the problem is that the import does not populate table catalog_product_relation.
If you need a quick workaround without updating code:

  • Insert the missing bundle relations: INSERT IGNORE INTO catalog_product_relation SELECT parent_product_id,product_id FROM catalog_product_bundle_selection
  • Reindex stock and price indexes

@domeglic my problem has the same symptoms, but catalog_product_relation had the proper entries, running that query didn't affect anything.

@domeglic I confirm that this query solved my issue, Thank you!

After several days of research and headaches, thank you @domeglic. It solved my issue. This "bug" is still not fixed in Magento 2.2.4. It would be very nice, if this bug will be fixed in the next version?

Hi @indefinitedevil. Thank you for your report.
The issue has been fixed in magento-engcom/import-export-improvements#104 by @adam-paterson in 2.3-develop branch
Related commit(s):

The fix will be available with the upcoming 2.3.0 release.

I believe the same issue still applies to Magento 2.3, if you edit and "save and duplicate" a bundle it doesn't update the catalog_product_relation table

A workaround for the bug is to add a bundle option and selection entry manually and save the bundle product, then delete the option manually or via $option->delete(); and finally import via file the desired options and selections for the bundle.

  • INSERT IGNORE INTO catalog_product_relation SELECT parent_product_id,product_id FROM catalog_product_bundle_selection

Solved!!! Thanks

Hi @indefinitedevil. Thank you for your report.
The issue has been fixed in magento-engcom/import-export-improvements#104 by @adam-paterson in 2.3-develop branch
Related commit(s):

The fix will be available with the upcoming 2.3.0 release.

Hi,

I don't think this has been merged right?

Can you confirm?

Was this page helpful?
0 / 5 - 0 ratings