magento / inventory

Magento Inventory Project (a.k.a MSI)
Open Software License 3.0
337 stars 248 forks source link

Impossible to get sellable bundles with MSI in 2.3.4? #3111

Open iphigenie opened 4 years ago

iphigenie commented 4 years ago

This is a question as much as a "bug" report - it's likely this is all a consequence of the transitional status of MSI

UPDATED FOR CLARITY and new information

  1. What tag/version of Inventory do I need to have installed on a 2.3.4 installation to have the most consistent bundle behaviour?

  2. What are the real constraints for a bundle to be sellable if MSI is on, on both the bundle and its components?

The documentation says that MSI shipment selection does not yet support bundle and implies that the solution for now is to have bundles be NOT stock managed. But that is not quite right, or not anymore.

First, a "non stock managed" bundle will still appear out of stock if any of its components are not fully "in stock" in the (not in use) default source. It works until one of the products gets out of stock, and then it cannot be put back in stock without putting every product in the default source and with back order enabled.

Every table I look it up in has a status of 1 for sellable for the bundle and all its components, for every source including the default one, but still the bundle is not sellable on the front end.

I am pretty sure stock status to 1 was all that was supposed to be needed and there might be issues on my site or my data, but I cannot be sure because there is no documention of what should be - what tables, what data, in what state is a "correctly working" bundle?

It's really unclear what the current "normal behaviour" should be, and the documentation and tickets I have found do not match the reality. Knowing what should be would go a long way to know whether I have bugs or have wrong understanding or expectations.

What settings does a simple product, bundle, grouped product etc need to have to succesfully be sellable on site with MSI. Even for simple products it is not just having sources allocated with stock of it.

What master tables should a product appear with which flags to show as sellable - I think it is both cataloginventory_stock_item and inventory_source_item which feed their respective indexes, is that even right? any other?

I thought inventory_source_item should be pushing changes to cataloginventory_stock_item but no, the link is not there or not complete

Indexes for the sites are: cataloginventory_stock_status cataloginventory_stock_status_replica (i have a cataloginventory_stock_status_idx but it is always empty?) the view inventory_stock_1 inventory_stock_2 etc. if more stocks

is that correct?

My experience so far on this one live site

My best guess is that this is linked to scope confusion or there's something missing

Clearly there is a fragility there and there is a reliance on products being in a particular status in the default stock even if other stocks are used. There should be a small bit of documentation about it? because then we can manage it rather than be baffled

m2-assistant[bot] commented 4 years ago

Hi @iphigenie. 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


luongvm commented 4 years ago

I ran to this issue with the same finding as you: I'm not using the default stock & default source, my items are in stock in different stocks and the website is assigned to that stock. Individual products is fine but the bundle product disappeared. The only way to show them is to assign default stock/source to children products.

I was thinking this is a bug but now you say this is not implemented at all in MSI, then I guess I have to turn to other ways to put bundled products up on my site. Until the feature is there.

Thanks for reporting this.

iphigenie commented 4 years ago

Hi @joturako

It's not implemented but a workaround is - it's just not documented. For example the logic around the indexes

Once you line things up just so it works, bundles can be bought and the stock of the components is handled fine on shipping

I made a clone of my site end of June and the way it was then, a bundle was in stock happily with none of the products needing to be in the default stock. Looking at the inventory_source_item table there, the bundle product has an entry in the site stock and one in the default stock, both quantity 0 but status in stock. Components are only in site stocks. It worked.

I think that is the "correct" status and is possible

Putting products in the default stock is just a way to force them to work when things get out of kilter. It's not really necessary.

But there seems to be some fragility or error conditions that put things out of kilter - I am hoping that I can get things right again then they won't be messing up again.

I think there are some things that happen via triggers or observers on "real" products that don't happen properly for composite products like a bundle or a grouped product. gaps.

I this evening found a bug that I am still getting my head around: if you change the sku of a product, the new inventory tables (the ones which use sku as a product reference) are NOT updated. Products will then vanish of the site. Of course if you clone a product in the admin interface then give it its sku, it is a sku change... though for simple products it eventually fixes itself, for bundles and grouped product it is more problematic...

I ran SELECT * FROM inventory_source_item WHERE sku not in (select sku from catalog_product_entity) and there's 200+ entries. Many are products which are gone but some are products where i changed the sku, because we're making them more logical over time.

I am wondering whether fixing this will solve a lot of my odd problems? It would be frustrating if that was the cause, so many hours wasted. But it would also be good. Something I can work through.

But the bug at the top of this thread remains - some products don^t get auto put back in stock when they get stock back. I'll report back if they are all products where skus changed

iphigenie commented 4 years ago

updated for clarity with:

my old bundles (migrated via data migration tool) show on the site, (some don't, but thats sku changes i think). All show out of stock until I make a lot of contorsions with the component products such as putting them in default stock. That didnt use to be the case. These bundles that show as "out of stock" on the website are totally fine being sold in admin. No stock warning. I thought stock_status=1 in the "old" cataloginventory tables was all that was needed, but clearly some extra conditions apply. What are they?

new bundles created do NOT show on the site at all. They are correctly in stock though and can be sold fine from admin - but not on the site. Noticed: my migrated bundles were put in the source stock tables for the default source by the migration. New bundles do not get put in. Should they be?

iphigenie commented 4 years ago

updated for clarity with

It's really unclear what the current "normal behaviour" should be

What master tables should a product appear in, with which data, to show as sellable?

I think it is both cataloginventory_stock_item and inventory_source_item which feed their respective indexes, is that even right? any other?

I thought inventory_source_item should be pushing changes to cataloginventory_stock_item but no, stock_status seems independent. Should it be linked? Am I missing a link in my database

Indexes for the sites are: cataloginventory_stock_status cataloginventory_stock_status_replica (i have a cataloginventory_stock_status_idx but it is always empty. should it not be?) the view inventory_stock_1 inventory_stock_2 etc. if more stocks

is that correct?

iphigenie commented 4 years ago

Tested on a clean 2.3.4 with sample data

  1. added 2 sources
  2. assigned new sources to a new stock for the website
  3. moved all stock from default to one of the new sources

reindex, clean caches

the one bundle product on the site doesnt show anymore

luongvm commented 4 years ago

Thats how it is with clean install of 2.3.5-p1

iphigenie commented 4 years ago

Looking further:

I can call the bundle direct, and it is "out of stock"

iphigenie commented 4 years ago

I got that demo data sprite ball to be in stock - manually that is! @joturako

neither the bundle nor component products are put in the default stock. So it is possible.

main tables:

generated cache tables:

Once data was correct in the main tables the indexes populated properly and in that state, letting cron run a few times, reindex, cache etc a few times suddenly a direct link to that product page shows it in stock

Note that almost everything there can be done in admin - except for the is_in_stock flag which doesnt show anymore, except in a few odd places, for example a bundle that is set as "stock managed" (wait a minute here...)

At that point It still doesnt show on the site

Just to test I insert a row in the inventory_stock_2 cache table for the bundle sku immediately it shows in categories etc.

So now I will go look at the code that updates that index - that code adds grouped products in there, it should add bundles too.

In short, whether it appears in stock or not depends on both sets of tables agreeing. Whether it shows or not (assuming you dont have "hide out of stock") depends only on the new tables.

I havent yet reproduced it on my live, data migration site, where i assume there's possibly other issues from data migration

iphigenie commented 4 years ago

@magento give me 2.4-develop instance

iphigenie commented 4 years ago

@magento I am working on this

m2-assistant[bot] commented 4 years ago

Hi @iphigenie! :wave: Thank you for collaboration. Only members of Community Contributors Team are allowed to be assigned to the issue. Please use @magento add to contributors team command to join Contributors team.

iphigenie commented 4 years ago

@magento add to contributors team

m2-assistant[bot] commented 4 years ago

Hi @iphigenie! :wave: Thank you for joining. Please accept team invitation :point_right: here :point_left: and add your comment one more time.

iphigenie commented 4 years ago

@magento add to contributors team

iphigenie commented 4 years ago

@magento give me 2.4-develop instance

iphigenie commented 4 years ago

@magento I am working on this

iphigenie commented 4 years ago

I never solved this, just reverted to putting a small amount of inventory for each component of a bundle IN the default stock.

2.4 changes things and this problem I think does not happen there

Berman59 commented 3 years ago

Hi, just wondering if you had more insights on this issue since then?

I am seeing the same issue, more specifically, bundles are showing fine for the default website, but any other websites won't show the product in categories due to "INNER JOIN inventory_stock_X AS stock_index ON stock_index.sku = product.sku" returning empty results, which in turn is caused by inventory_stock_x tables don't have the bundle products listed after re-indexing.

This happens even if I set bundle manage stock = no... bundle itself should still be visible in categories even if some options are not selectable when out of stock,

iphigenie commented 3 years ago

Hi

In November I moved to 2.4.x and things are cleaner there.

On 2.3.5 / 2.3.6 things only worked with:

It then took some repeat reindexing, running the inventory message queues, waiting for cron routines to kick in etc. and some bundles would appear fine. Some bundles wouldn't so I had to allow backorders on products or put some token stock for these products in the default stock for them to work.

I am not sure what the difference was, could be in my migrated data.

By all that is holy to you, make sure the bundles are set to allow shipping separately otherwise your reservations table will become unclean

ioweb-gr commented 3 years ago

I'm also facing an issue similar to this but with configurable products. I have a product that's salable in stock id = 5 and doesn't have anything in stock id = 1 (default stock) so it's out of stock there.

While I can see the product in the catalog, and add it to cart, I can't checkout with a message that "some of the products are out of stock"

Any ideas for a workaround? That's on 2.4.1 so the issue persists in 2.4 for me.

iphigenie commented 3 years ago

Hi @ioweb-gr

I have found that new clean products are working fine in 2.4.x for me BUT on my live site (and clones) there's some old data that does not seem to update as it should - i have found some both in the "old" cataloginventory tables and in the reservations table. This will cause problems on both website and admin (reservations) or only admin (for the cataloginventory tables)

Mine were certainly caused by legacy content, going through 2.1, 2.2, 2.3 etc with a live site, and probably there's an extension or two in there that aren't fully MSI happy - i.e. real use mess rather than clean new test site.

Maybe this will help you investigate

  1. tables cataloginventory_stock_item and cataloginventory_stock_status do not seem to be updated properly for status and quantity (i dont think quantity matters as much). I think it is because stock_status_changed_auto is 0 but not 100% sure. I don't know how this table should be updated when MSI is set up with sources, meaning you don't use the default source, but I suspect it should, especially for the complex products

i used queries like this one (I have a db prefix mg_ this needs changing and it needs tweaking if you have multiple stocks combining sources differently) to spot where the "old" table is different

SELECT a.item_id, product_id ,a.stock_id, a.qty, a.backorders, a.is_in_stock, a.stock_status_changed_auto, (select IFNULL((select sum(i.quantity) from mg_catalog_product_entity as c inner join mg_inventory_source_item as i on i.sku = c.sku where c.entity_id = a.product_id),'0')) as shouldbeqty, (select IFNULL((select max(i.status) from mg_catalog_product_entity as c inner join mg_inventory_source_item as i on i.sku = c.sku where c.entity_id = a.product_id),'0')) as shouldbestatus FROM mg_cataloginventory_stock_item as a

I have gone and then updated the table via query to fix some of this, and it helped in my case

These tables are bypassed in front end unless you have extensions that wrongly use them, but in admin they still seem to have an influence especially conditions, stock status in grids etc. and "in stock filter"

  1. old entries not balanced/cleared in reservations table. This has happened usually for orders "in process" when an upgrade happened that changed the inventory logic a bit.

  2. I also have a hunch that having items that have no stock entries (rather than stock entries of 0) seems to mess up whole grouped products, maybe it does it for configurable?

ioweb-gr commented 3 years ago

I've been trying to track it down also and ended up at QuantityValidator observer from Magento_CatalogInventory not finding the correct values for items \Magento\CatalogInventory\Model\Quote\Item\QuantityValidator

Basically by digging deeper into it I notice it uses the old StockRegistryInterface

    /**
     * @param int $productId
     * @param int $scopeId
     * @return \Magento\CatalogInventory\Api\Data\StockItemInterface
     */
    public function getStockItem($productId, $scopeId = null)
    {
        $scopeId = $this->stockConfiguration->getDefaultScopeId();
        return $this->stockRegistryProvider->getStockItem($productId, $scopeId);
    }

Which even though the scopeId in my case is website with id = 2

It overrides the value and checks the DefaultScopeId of id = 0

Thus ends up retrieving the wrong item when MSI is used.

Disabling the observer allows the order to finish correctly so this needs to be reworked to fetch the correct data for all quote items.

ioweb-gr commented 3 years ago

An update, the tables you mention get populated when doing normal save of a product as well, and the stock status is not resolved correctly. Basically you have to manually set the configurable status to in_stock which is actually meaningful for the default stock but not as much for MSI. Also the stock status for configurable is also an indexed value since it relies on the website assignments of the children. So I don't understand why a stock item is associated to it. It's similar to weight and qty and price the way I see it.

I think this is all a mess because not every piece of code is refactored to use the MSI logic so certain parts expect the default stock id to function, and other parts are using the MSI logic. Thus now I end up in a MSI installation, using stock items instead of source items and the stock index.

If you add to this the way old data i migrated from M1, this in turn causes this huge chain of errors in a million places and there's no data consistency in the database.

Berman59 commented 3 years ago

I don't think my issue was the same as ioweb-gr's but just wanted to mention, for my case in 2.3 above, I ended up adding a check on bundles for their status and add them to the category item collection when it is visible, regardless of children stock availability. Seems to work for me so far.

And thanks iphigenie for your earlier reply. It is indeed very important to set bundles to 'ship separately'. The ship together option will messes up shipments and stock reservations.

nmklong commented 3 years ago

I'm having the exact same issue, is this being worked on yet, how was this not reported sooner

codecodeio commented 3 years ago

I'm using Magento Commerce 2.4.2-p1 and have the same issue. I have a bundle with manage stock set to false (0) but \Magento\CatalogInventory\Model\Quote\Item\QuantityValidator::validate() sets out of stock error info because of this call: $stockStatus = $this->stockRegistry->getStockStatus($product->getId(), $product->getStore()->getWebsiteId());

I resolved the issue by creating a preference for QuantityValidator. It checks the product and parent product for manage stock false and product type bundle and sets $stockStatus / $parentStockStatus to null.

/**
 * OVERRIDE STOCK STATUS
 * turn off stock status check for bundle products with manage stock set to false
 */
$manageStock = 1;
$productType = '';
try {
    if ($product) {
        $productType = $product->getTypeId();
        $extensionAttributes = $product->getExtensionAttributes();
        if ($extensionAttributes) {
            $stockItem = $extensionAttributes->getStockItem();
            if ($stockItem) {
                $manageStock = $stockItem->getManageStock();
            }
        }
    }
} catch (Exception $e) {
    $manageStock = 1;
    $productType = '';
}
if ($manageStock == 0 && $productType == 'bundle') {
    $stockStatus = null;
}
Berman59 commented 2 years ago

Just wanted to add some notes on 2.3.x.

Upgraded to 2.3.7-p2 and the issue persists; if there is an entry for a non-default-source bundle in inventory_stock_x (where x is a non default stock id), it will show fine in category and product page; otherwise it will show as out of stock. The actual bundle can be added and checked out without issues regardless of this stock status.

I tried manually adding the entry but it gets wiped somehow during re-index. I think it might be related to 2.3 not having module-inventory-bundle-product-indexer but 2.4 does? I can see module-inventory-grouped-product-indexer and module-inventory-configurable-product-indexer but not bundle.

There is also a "IsSourceItemManagementAllowedForProductType" that returns false under module-inventory-bundle-product/Plugin/InventoryConfigurationApi. Perhaps the code that checks if bundles are in stock on category and product pages
ignores this and still try to check non-default stock sources for bundles and thus return out-of-stock when it can't find the index entry in inventory_stock_x?

Currently I run a cron right after reindex and add bundle entries back into inventory_stock_x and it sort of works.. but it would be better if we could make those entries not drop in the first place...

kevinjavitz commented 2 years ago

Lost a lot of time on this one, and low and behold it is actually in the official docs that bundles are not supported with MSI in 2.3.x: https://docs.magento.com/user-guide/v2.3/catalog/inventory-about-product-types.html

I wish I had seen this earlier, so to make a long story short bundles won't work on the non-default stock source websites.