magento2: Incorrect Item Count on Catalog Search Pages

Preconditions and environment

Magento 2.4.5-p1 Set Stores->Config->Catalog->Inventory->Stock Options->Show Out Of Stock Products = Yes

Steps to reproduce

On a clean install on Magento 2.4.5-p1 with sample data, enter “Marco” as the search string

Expected result

A single product Marco Lightweight Active Hoodie is displayed and an Item count of 1

Actual result

A single product Marco Lightweight Active Hoodie is displayed and an Item count of 181 !

Additional information

I debugged the code and it appears there may be a bug in the plugin vendor/magento/module-inventory-catalog/Plugin/Catalog/Block/ProductList/UpdateToolbarCount.php in the following method

    public function afterGetTotalNum(Toolbar $subject, int $result): int
    {
        if ($this->stockConfiguration->isShowOutOfStock()) {
            try {
                $currentCategory = $this->layerResolver->get()->getCurrentCategory();
                $category = $this->categoryFactory->create()->load($currentCategory->getEntityId());
                $defaultScopeId = $this->storeManager->getWebsite()->getCode();
                $stock_id = (int) $this->stockRegistry->getStock($defaultScopeId)->getStockId();
                $skus = [];
                $items = $category->getProductCollection()->getItems();
                array_walk(
                    $items,
                    function ($item) use (&$skus) {
                        array_push($skus, $item->getSku());
                    }
                );
                $salableProducts = $this->areProductsSalable->execute($skus, $stock_id);
                if ($salableProducts) {
                    $result = count($salableProducts);
                }
            } catch (\Exception $e) {
                $this->logger->critical($e->getMessage());
            }
        }
        return $result;
    }

This method gets called when a frontend search is performed. You can see that this code only gets called if Show Out Of Stock Products is set to true. It then executes logic based on the current category which does not seem to be logical for a catalog search page.

Release note

No response

Triage and priority

  • Severity: S0 - Affects critical data or functionality and leaves users without workaround.
  • Severity: S1 - Affects critical data or functionality and forces users to employ a workaround.
  • Severity: S2 - Affects non-critical data or functionality and forces users to employ a workaround.
  • Severity: S3 - Affects non-critical data or functionality and does not force users to employ a workaround.
  • Severity: S4 - Affects aesthetics, professional look and feel, “quality” or “usability”.

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Reactions: 6
  • Comments: 57 (14 by maintainers)

Most upvoted comments

@engcom-November I checked with develop inventory repository(magento/inventory: Magento Inventory Project (a.k.a MSI) (github.com)) .This repository doesn’t have this plugin file.How we can add PR with this file?

This issue will resolve , if we change code in the plugin vendor/magento/module-inventory-catalog/Plugin/Catalog/Block/ProductList/UpdateToolbarCount.php in the following method

$items = $category->getProductCollection()->getItems();

to

$items = $subject->getCollection()->getItems();

public function afterGetTotalNum(Toolbar $subject, int $result): int
    {
        if ($this->stockConfiguration->isShowOutOfStock()) {
            try {
                $defaultScopeId = $this->storeManager->getWebsite()->getCode();
                $stock_id = (int) $this->stockRegistry->getStock($defaultScopeId)->getStockId();
                $skus = [];
                $items = $subject->getCollection()->getItems();
                array_walk(
                    $items,
                    function ($item) use (&$skus) {
                        array_push($skus, $item->getSku());
                    }
                );
                $salableProducts = $this->areProductsSalable->execute($skus, $stock_id);
                if ($salableProducts) {
                    $result = count($salableProducts);
                }
            } catch (\Exception $e) {
                $this->logger->critical($e->getMessage());
            }
        }
        return $result;
    }

In my test environment, this solution does not result in the correct number of search results. The number returned with the above-suggested change is the number on the current page, which is incorrect.

From what I can see, the number of salable products is already accounted for, and you can use just one line of code inside the if-statement:

        if ($this->stockConfiguration->isShowOutOfStock()) {
            try {
                $result = $subject->getCollection()->getSize();

            } catch (\Exception $e) {
                $this->logger->critical($e->getMessage());
            }
        }
        return $result;

In addition the try-catch could also be removed, as the result is always an integer number (so 0 when there are no results).