Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Configurable product where variations are disabled on website/store view appears as salable. #3296

Open
ioweb-gr opened this issue Mar 7, 2021 · 7 comments

Comments

@ioweb-gr
Copy link

ioweb-gr commented Mar 7, 2021

Preconditions (*)

  1. Magento 2.4.1 with MSI
  2. Set Magento to hide products that are out of stock.

Steps to reproduce (*)

  1. Multiple store views
  • Store1
  • Store2
  • Store3
  1. A configurable product with 1 variation assigned to multiple sources - assigned to a stock - assigned to Store1
  • Source1 (in stock, qty 2)
  • Source2 (out of stock)
  • Source3 (out of stock)
  1. Product is enabled in "All store views"
  2. Product is disabled in store view for Store1,Store2,Store3
  3. Visit category page which shows the product. The product appears salable but is out of stock

Expected result (*)

  1. The product does not appear

Actual result (*)

  1. The product appears in the frontend as out of stock but not possible to add to cart.

e.g.
in category
image

in product
image

@m2-assistant
Copy link

m2-assistant bot commented Mar 7, 2021

Hi @ioweb-gr. Thank you for your report.
To help us process this issue please make sure that you provided sufficient information.

Please, add a comment to assign the issue: @magento I am working on this


@ioweb-gr
Copy link
Author

ioweb-gr commented Mar 7, 2021

After further investigating I notice that on the stock index for the specific store view, the configurable product's total salable quantity is incorrectly counted. It appears as instock with salable quantity = 2 because the enabled/disabled status is not taken into account correctly.

Could you point me to the code responsible for building the index of the total salable quantity of the configurable products to debug it?

@ioweb-gr
Copy link
Author

ioweb-gr commented Mar 7, 2021

I ended up tracking it all the way to this function

\Magento\InventoryIndexer\Indexer\SelectBuilder::execute

Which results in the following SQL in my case

SELECT `source_item`.`sku`,
       SUM(IF(source_item.status = 0, 0, quantity)) AS `quantity`,
       IF((legacy_stock_item.use_config_backorders = 0 AND legacy_stock_item.backorders <> 0 AND
           (legacy_stock_item.min_qty >= 0 OR legacy_stock_item.qty > legacy_stock_item.min_qty)) OR
          ((legacy_stock_item.use_config_manage_stock = 0 AND legacy_stock_item.manage_stock = 0)) OR
          ((legacy_stock_item.use_config_min_qty = 1 AND SUM(IF(source_item.status = 0, 0, quantity)) > 0) OR
           (legacy_stock_item.use_config_min_qty = 0 AND
            SUM(IF(source_item.status = 0, 0, quantity)) > legacy_stock_item.min_qty)) OR (product.sku IS NULL), 1,
          0)                                        AS `is_salable`
FROM `inventory_source_item` AS `source_item`
         LEFT JOIN `catalog_product_entity` AS `product` ON product.sku = source_item.sku
         LEFT JOIN `cataloginventory_stock_item` AS `legacy_stock_item`
                   ON product.entity_id = legacy_stock_item.product_id
WHERE (source_item.source_code IN
       ('glyfada', 'junior_running', 'kentriki_apothiki_melenikou', 'marousi', 'outlet_running', 'outlet_tennis'))
GROUP BY `sku`

Which seems to calculate the total quantity available of the product in the required sources but fails to take into account the store view and the simple product (child of configurable in this case) status in the store view.

If the focus here is just to mark the salable quantity and then filter it out somewhere else I'm not sure where this would happen. However it seems that the isSalable function will look in the inventory_stock_X tables and if the product is salable it will appear in the lists even though it shouldn't.

The end result on inventory_stock table is this one

image

But since

1041A004-011-45 and 1041A004-011-46 are not enabled in the store view, the product should actually be not salable.

@ioweb-gr
Copy link
Author

ioweb-gr commented Mar 8, 2021

Looking up at Configurable product indexer the query is

SELECT `parent_product_entity`.`sku`, SUM(stock.quantity) AS `quantity`, MAX(stock.is_salable) AS `is_salable`
FROM `inventory_stock_5` AS `stock`
         INNER JOIN `catalog_product_entity` AS `product_entity` ON product_entity.sku = stock.sku
         INNER JOIN `catalog_product_super_link` AS `parent_link` ON parent_link.product_id = product_entity.entity_id
         INNER JOIN `catalog_product_entity` AS `parent_product_entity`
                    ON parent_product_entity.entity_id = parent_link.parent_id
GROUP BY `parent_product_entity`.`sku`

Yielding the result as above

image

and again skipping the fact that the offending products have disabled status

+---------------+-----+--------+
|sku            |value|store_id|
+---------------+-----+--------+
|1041A004-011-45|1    |0       |
|1041A004-011-45|2    |1       |
|1041A004-011-45|2    |4       |
|1041A004-011-45|2    |5       |
|1041A004-011-45|2    |6       |
|1041A004-011-45|2    |7       |
|1041A004-011-45|2    |8       |
|1041A004-011-45|2    |9       |
|1041A004-011-45|1    |10      |
|1041A004-011-46|1    |0       |
|1041A004-011-46|2    |1       |
|1041A004-011-46|2    |4       |
|1041A004-011-46|2    |5       |
|1041A004-011-46|2    |6       |
|1041A004-011-46|2    |7       |
|1041A004-011-46|2    |8       |
|1041A004-011-46|2    |9       |
|1041A004-011-46|1    |10      |
+---------------+-----+--------+

@ioweb-gr
Copy link
Author

This seems related to #2413

@ioweb-gr ioweb-gr changed the title Configurable product where variations are disabled on store view appears as salable. Configurable product where variations are disabled on website/store view appears as salable. Mar 11, 2021
@willtran
Copy link

I don't think this issue will ever get worked on. This is because a Stock in MSI is shared between different sales channel - and product status is a website scoped attribute. I have had to bring the logic for filtering out configurable products with disabled (but saleable) children when building. the query for PLP

@karpa
Copy link

karpa commented Sep 24, 2023

Several years later we also see this exact bug. We managed to create a query that finds the problematic products.

SELECT
    stock.sku,
    stock.quantity,
	parent_products.quantity,
    stock.is_salable,
	parent_products.is_salable
FROM
    inventory_stock_1 AS stock
LEFT JOIN
    (
         SELECT `parent_product_entity`.`sku`, SUM(stock.quantity) AS `quantity`, MAX(stock.is_salable) AS `is_salable`
FROM `inventory_stock_1` AS `stock`
         INNER JOIN `catalog_product_entity` AS `product_entity` ON product_entity.sku = stock.sku
         INNER JOIN `catalog_product_super_link` AS `parent_link` ON parent_link.product_id = product_entity.entity_id
         INNER JOIN `catalog_product_entity` AS `parent_product_entity`
                    ON parent_product_entity.entity_id = parent_link.parent_id
GROUP BY `parent_product_entity`.`sku`
    ) AS parent_products
ON
    parent_products.sku = stock.sku
WHERE
    parent_products.is_salable = 0 AND stock.is_salable=1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants