diff --git a/vendor/magento/module-inventory-export-stock/Model/Api/SearchCriteria/FilterProcessor/InventoryStockFilter.php b/vendor/magento/module-inventory-export-stock/Model/Api/SearchCriteria/FilterProcessor/InventoryStockFilter.php new file mode 100644 index 000000000000..3f57af5ebde6 --- /dev/null +++ b/vendor/magento/module-inventory-export-stock/Model/Api/SearchCriteria/FilterProcessor/InventoryStockFilter.php @@ -0,0 +1,68 @@ +getValue(); + $select = $collection->getSelect(); + + $notAllowedProductTypes = array_keys( + array_filter( + $this->stockConfiguration->getIsQtyTypeIds(), + fn($allowed) => $allowed === false + ) + ); + + $select->joinLeft( + ['inventory_source_item' => $this->resourceConnection->getTableName('inventory_source_item')], + 'inventory_source_item.sku = e.sku', + [] + )->joinLeft( + ['stock_source_link' => $this->resourceConnection->getTableName('inventory_source_stock_link')], + 'stock_source_link.source_code = inventory_source_item.source_code', + [] + )->where( + 'stock_source_link.stock_id = ?', + $stockId + )->orWhere( + 'e.type_id IN (?)', + $notAllowedProductTypes + ); + + // Prevent duplicates when a product has multiple source items in the same stock + $select->group('e.entity_id'); + + return true; + } +} diff --git a/vendor/magento/module-inventory-export-stock/Model/ExportStockSalableQtyBySalesChannel.php b/vendor/magento/module-inventory-export-stock/Model/ExportStockSalableQtyBySalesChannel.php index 8fd7f5d93133..3a143fdb2384 100644 --- a/vendor/magento/module-inventory-export-stock/Model/ExportStockSalableQtyBySalesChannel.php +++ b/vendor/magento/module-inventory-export-stock/Model/ExportStockSalableQtyBySalesChannel.php @@ -8,14 +8,12 @@ namespace Magento\InventoryExportStock\Model; use Magento\Catalog\Api\ProductRepositoryInterface; +use Magento\Framework\Api\SearchCriteriaBuilder; use Magento\Framework\Api\SearchCriteriaInterface; use Magento\Framework\Api\SearchResultsInterface; -use Magento\Framework\Exception\LocalizedException; use Magento\InventoryExportStockApi\Api\Data\ExportStockSalableQtySearchResultInterface; use Magento\InventoryExportStockApi\Api\Data\ExportStockSalableQtySearchResultInterfaceFactory; use Magento\InventoryExportStockApi\Api\ExportStockSalableQtyBySalesChannelInterface; -use Magento\InventorySalesApi\Api\Data\SalesChannelInterface; -use Magento\InventorySalesApi\Api\Data\SalesChannelInterfaceFactory; use Magento\InventorySalesApi\Api\GetStockBySalesChannelInterface; /** @@ -44,29 +42,29 @@ class ExportStockSalableQtyBySalesChannel implements ExportStockSalableQtyBySale private $getStockBySalesChannel; /** - * @var SalesChannelInterfaceFactory + * @var SearchCriteriaBuilder */ - private $salesChannelInterfaceFactory; + private $searchCriteriaBuilder; /** * @param ProductRepositoryInterface $productRepository * @param ExportStockSalableQtySearchResultInterfaceFactory $exportStockSalableQtySearchResultFactory * @param PreciseExportStockProcessor $preciseExportStockProcessor * @param GetStockBySalesChannelInterface $getStockBySalesChannel - * @param SalesChannelInterfaceFactory $salesChannelInterfaceFactory + * @param SearchCriteriaBuilder $searchCriteriaBuilder */ public function __construct( ProductRepositoryInterface $productRepository, ExportStockSalableQtySearchResultInterfaceFactory $exportStockSalableQtySearchResultFactory, PreciseExportStockProcessor $preciseExportStockProcessor, GetStockBySalesChannelInterface $getStockBySalesChannel, - SalesChannelInterfaceFactory $salesChannelInterfaceFactory + SearchCriteriaBuilder $searchCriteriaBuilder ) { $this->productRepository = $productRepository; $this->exportStockSalableQtySearchResultFactory = $exportStockSalableQtySearchResultFactory; $this->preciseExportStockProcessor = $preciseExportStockProcessor; $this->getStockBySalesChannel = $getStockBySalesChannel; - $this->salesChannelInterfaceFactory = $salesChannelInterfaceFactory; + $this->searchCriteriaBuilder = $searchCriteriaBuilder; } /** @@ -79,13 +77,29 @@ public function execute( \Magento\Framework\Api\SearchCriteriaInterface $searchCriteria ): ExportStockSalableQtySearchResultInterface { $stock = $this->getStockBySalesChannel->execute($salesChannel); - $productSearchResult = $this->getProducts($searchCriteria); + // Build a fresh SearchCriteria with original filters + our inventory filter + $builder = $this->searchCriteriaBuilder; + $builder->setCurrentPage($searchCriteria->getCurrentPage()); + $builder->setPageSize($searchCriteria->getPageSize()); + foreach ($searchCriteria->getFilterGroups() as $filterGroup) { + $builder->addFilters($filterGroup->getFilters()); + } + foreach ($searchCriteria->getSortOrders() ?: [] as $sortOrder) { + $builder->addSortOrder($sortOrder); + } + // Add stock filter that our custom processor intercepts + $builder->addFilter('inventory_stock_id', $stock->getStockId(), 'eq'); + $searchCriteriaWithInventory = $builder->create(); + + $productSearchResult = $this->getProducts($searchCriteriaWithInventory); $items = $this->preciseExportStockProcessor->execute($productSearchResult->getItems(), $stock->getStockId()); + /** @var ExportStockSalableQtySearchResultInterface $searchResult */ $searchResult = $this->exportStockSalableQtySearchResultFactory->create(); - $searchResult->setSearchCriteria($productSearchResult->getSearchCriteria()); + $searchResult->setSearchCriteria($searchCriteria); $searchResult->setItems($items); - $searchResult->setTotalCount(count($items)); + // Single-pass: total count comes from filtered collection getSize() + $searchResult->setTotalCount($productSearchResult->getTotalCount()); return $searchResult; } diff --git a/vendor/magento/module-inventory-export-stock/etc/di.xml b/vendor/magento/module-inventory-export-stock/etc/di.xml index b51672dc9ca2..f688f06f572c 100644 --- a/vendor/magento/module-inventory-export-stock/etc/di.xml +++ b/vendor/magento/module-inventory-export-stock/etc/di.xml @@ -17,4 +17,13 @@ + + + + + + Magento\InventoryExportStock\Model\Api\SearchCriteria\FilterProcessor\InventoryStockFilter + + +