From 17215514a152314de358a2ec5c4d3fb63acf9c03 Mon Sep 17 00:00:00 2001 From: oleksandrkravchuk Date: Fri, 8 May 2020 17:07:05 +0200 Subject: [PATCH 01/50] magento/inventory#3013: [Async Salable Status] Storefront implementation for IsProductSalable service. Add Lightweight implementation. --- InventoryIndexer/Model/IsProductSalable.php | 48 +++++++++++++++++++++ InventoryIndexer/etc/frontend/di.xml | 10 +++++ InventoryIndexer/etc/graphql/di.xml | 10 +++++ 3 files changed, 68 insertions(+) create mode 100644 InventoryIndexer/Model/IsProductSalable.php create mode 100644 InventoryIndexer/etc/frontend/di.xml create mode 100644 InventoryIndexer/etc/graphql/di.xml diff --git a/InventoryIndexer/Model/IsProductSalable.php b/InventoryIndexer/Model/IsProductSalable.php new file mode 100644 index 000000000000..ca83bf6d28ee --- /dev/null +++ b/InventoryIndexer/Model/IsProductSalable.php @@ -0,0 +1,48 @@ +stockItemData = $stockItemData; + } + + /** + * @inheritdoc + */ + public function execute(string $sku, int $stockId): bool + { + try { + $stockItem = $this->stockItemData->execute($sku, $stockId); + $isSalable = (bool)($stockItem[GetStockItemDataInterface::IS_SALABLE] ?? false); + } catch (LocalizedException $exception) { + $isSalable = false; + } + + return $isSalable; + } +} diff --git a/InventoryIndexer/etc/frontend/di.xml b/InventoryIndexer/etc/frontend/di.xml new file mode 100644 index 000000000000..cc63fe51d98b --- /dev/null +++ b/InventoryIndexer/etc/frontend/di.xml @@ -0,0 +1,10 @@ + + + + + diff --git a/InventoryIndexer/etc/graphql/di.xml b/InventoryIndexer/etc/graphql/di.xml new file mode 100644 index 000000000000..cc63fe51d98b --- /dev/null +++ b/InventoryIndexer/etc/graphql/di.xml @@ -0,0 +1,10 @@ + + + + + From 4bc0e480add70b9874073a09b346c3ec1b89f857 Mon Sep 17 00:00:00 2001 From: Lyzun Oleksandr Date: Wed, 6 May 2020 16:46:37 +0200 Subject: [PATCH 02/50] Add queues for reservation placed --- InventoryIndexer/Model/ReservationDummy.php | 23 +++++++++ ...uleAfterPlaceReservationsForSalesEvent.php | 48 +++++++++++++++++++ InventoryIndexer/etc/communication.xml | 12 +++++ InventoryIndexer/etc/di.xml | 3 ++ InventoryIndexer/etc/queue_consumer.xml | 10 ++++ InventoryIndexer/etc/queue_publisher.xml | 12 +++++ InventoryIndexer/etc/queue_topology.xml | 12 +++++ 7 files changed, 120 insertions(+) create mode 100644 InventoryIndexer/Model/ReservationDummy.php create mode 100644 InventoryIndexer/Plugin/InventorySales/ScheduleAfterPlaceReservationsForSalesEvent.php create mode 100644 InventoryIndexer/etc/communication.xml create mode 100644 InventoryIndexer/etc/queue_consumer.xml create mode 100644 InventoryIndexer/etc/queue_publisher.xml create mode 100644 InventoryIndexer/etc/queue_topology.xml diff --git a/InventoryIndexer/Model/ReservationDummy.php b/InventoryIndexer/Model/ReservationDummy.php new file mode 100644 index 000000000000..736558a38394 --- /dev/null +++ b/InventoryIndexer/Model/ReservationDummy.php @@ -0,0 +1,23 @@ +publisher = $publisher; + } + + /** + * Schedule stock status update after resevation placed + * + * @param PlaceReservationsForSalesEvent $subject + * @param void $result + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function afterExecute( + PlaceReservationsForSalesEvent $subject, + $result + ) { + $this->publisher->publish(self::TOPIC_RESERVATION_PLACED, []); + } +} diff --git a/InventoryIndexer/etc/communication.xml b/InventoryIndexer/etc/communication.xml new file mode 100644 index 000000000000..dfc7c64451db --- /dev/null +++ b/InventoryIndexer/etc/communication.xml @@ -0,0 +1,12 @@ + + + + + + + diff --git a/InventoryIndexer/etc/di.xml b/InventoryIndexer/etc/di.xml index dd7946176835..496f39e034f4 100644 --- a/InventoryIndexer/etc/di.xml +++ b/InventoryIndexer/etc/di.xml @@ -61,4 +61,7 @@ stock_ + + + diff --git a/InventoryIndexer/etc/queue_consumer.xml b/InventoryIndexer/etc/queue_consumer.xml new file mode 100644 index 000000000000..e73199976fbf --- /dev/null +++ b/InventoryIndexer/etc/queue_consumer.xml @@ -0,0 +1,10 @@ + + + + + diff --git a/InventoryIndexer/etc/queue_publisher.xml b/InventoryIndexer/etc/queue_publisher.xml new file mode 100644 index 000000000000..f41f63fa286b --- /dev/null +++ b/InventoryIndexer/etc/queue_publisher.xml @@ -0,0 +1,12 @@ + + + + + + + diff --git a/InventoryIndexer/etc/queue_topology.xml b/InventoryIndexer/etc/queue_topology.xml new file mode 100644 index 000000000000..ea1251849b0e --- /dev/null +++ b/InventoryIndexer/etc/queue_topology.xml @@ -0,0 +1,12 @@ + + + + + + + From 53a64b20e2d59fbcfc61d2767dc303e005d43ccb Mon Sep 17 00:00:00 2001 From: Maksym Novik Date: Sat, 9 May 2020 16:28:39 +0300 Subject: [PATCH 03/50] [Async Salable Status] Create infrastructure for async status update #3012. Updated queue message format. --- .../RecalculateIndexSalabilityStatus.php | 24 ++++++ .../Model/Queue/ReservationData.php | 54 +++++++++++++ InventoryIndexer/Model/ReservationDummy.php | 23 ------ ...uleAfterPlaceReservationsForSalesEvent.php | 75 ++++++++++++++++--- InventoryIndexer/etc/communication.xml | 4 +- 5 files changed, 144 insertions(+), 36 deletions(-) create mode 100644 InventoryIndexer/Model/Queue/RecalculateIndexSalabilityStatus.php create mode 100644 InventoryIndexer/Model/Queue/ReservationData.php delete mode 100644 InventoryIndexer/Model/ReservationDummy.php diff --git a/InventoryIndexer/Model/Queue/RecalculateIndexSalabilityStatus.php b/InventoryIndexer/Model/Queue/RecalculateIndexSalabilityStatus.php new file mode 100644 index 000000000000..eb032f00936b --- /dev/null +++ b/InventoryIndexer/Model/Queue/RecalculateIndexSalabilityStatus.php @@ -0,0 +1,24 @@ +skus = $skus; + $this->stockId = $stockId; + } + + /** + * Retrieve products SKUs to process. + * + * @return string[] + */ + public function getSkus(): array + { + return $this->skus; + } + + /** + * Retrieve stock id. + * + * @return int + */ + public function getStockId(): int + { + return $this->stockId; + } +} diff --git a/InventoryIndexer/Model/ReservationDummy.php b/InventoryIndexer/Model/ReservationDummy.php deleted file mode 100644 index 736558a38394..000000000000 --- a/InventoryIndexer/Model/ReservationDummy.php +++ /dev/null @@ -1,23 +0,0 @@ -publisher = $publisher; + $this->getAssignedStockIdForWebsite = $getAssignedStockIdForWebsite; + $this->reservationDataFactory = $reservationDataFactory; } /** - * Schedule stock status update after resevation placed - * * @param PlaceReservationsForSalesEvent $subject - * @param void $result - * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * @param null $result + * @param ItemToSellInterface[] $items + * @param SalesChannelInterface $salesChannel + * + * @return void */ public function afterExecute( PlaceReservationsForSalesEvent $subject, - $result + $result, + array $items, + SalesChannelInterface $salesChannel ) { - $this->publisher->publish(self::TOPIC_RESERVATION_PLACED, []); + $this->publisher->publish( + self::TOPIC_RESERVATION_PLACED, + $this->getReservationsDataObject($salesChannel, $items) + ); + } + + /** + * @param SalesChannelInterface $salesChannel + * @param ItemToSellInterface[] $items + * + * @return ReservationData + */ + private function getReservationsDataObject(SalesChannelInterface $salesChannel, array $items): ReservationData + { + $stockId = $this->getAssignedStockIdForWebsite->execute($salesChannel->getCode()); + $skus = array_map( + function (ItemToSellInterface $itemToSell): string { + return $itemToSell->getSku(); + }, + $items + ); + + return $this->reservationDataFactory->create( + [ + 'stockId' => $stockId, + 'skus' => $skus + ] + ); } } diff --git a/InventoryIndexer/etc/communication.xml b/InventoryIndexer/etc/communication.xml index dfc7c64451db..2f7b5b928ebd 100644 --- a/InventoryIndexer/etc/communication.xml +++ b/InventoryIndexer/etc/communication.xml @@ -6,7 +6,7 @@ */ --> - - + + From 169e2b335962bc792d5aeeca3811f6a5516cf56c Mon Sep 17 00:00:00 2001 From: Maksym Novik Date: Sat, 9 May 2020 17:16:50 +0300 Subject: [PATCH 04/50] [Async Salable Status] Create infrastructure for async status update #3012. Fixed queue consumer param name. --- .../Model/Queue/RecalculateIndexSalabilityStatus.php | 1 + InventoryIndexer/Model/Queue/ReservationData.php | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/InventoryIndexer/Model/Queue/RecalculateIndexSalabilityStatus.php b/InventoryIndexer/Model/Queue/RecalculateIndexSalabilityStatus.php index eb032f00936b..96a6bcbea3f7 100644 --- a/InventoryIndexer/Model/Queue/RecalculateIndexSalabilityStatus.php +++ b/InventoryIndexer/Model/Queue/RecalculateIndexSalabilityStatus.php @@ -20,5 +20,6 @@ class RecalculateIndexSalabilityStatus public function execute(ReservationData $reservationData): void { //TODO + list($skus, $stock) = [$reservationData->getSkus(), $reservationData->getStock()]; } } diff --git a/InventoryIndexer/Model/Queue/ReservationData.php b/InventoryIndexer/Model/Queue/ReservationData.php index 6b607183880d..780f2dbd4411 100644 --- a/InventoryIndexer/Model/Queue/ReservationData.php +++ b/InventoryIndexer/Model/Queue/ReservationData.php @@ -24,12 +24,12 @@ class ReservationData /** * @param string[] $skus - * @param int $stockId + * @param int $stock */ - public function __construct(array $skus, int $stockId) + public function __construct(array $skus, int $stock) { $this->skus = $skus; - $this->stockId = $stockId; + $this->stockId = $stock; } /** @@ -47,7 +47,7 @@ public function getSkus(): array * * @return int */ - public function getStockId(): int + public function getStock(): int { return $this->stockId; } From a24043e298eedeb3cd87129231a530f7226e22e7 Mon Sep 17 00:00:00 2001 From: Maksym Novik Date: Mon, 11 May 2020 15:46:51 +0300 Subject: [PATCH 05/50] [Async Salable Status] Create infrastructure for async status update #3012. Implemented salability status recalculation. --- .../RecalculateIndexSalabilityStatus.php | 128 +++++++++++++++++- .../IsSalableWithReservationsCondition.php | 4 +- 2 files changed, 128 insertions(+), 4 deletions(-) diff --git a/InventoryIndexer/Model/Queue/RecalculateIndexSalabilityStatus.php b/InventoryIndexer/Model/Queue/RecalculateIndexSalabilityStatus.php index 96a6bcbea3f7..1e4fa7d7f233 100644 --- a/InventoryIndexer/Model/Queue/RecalculateIndexSalabilityStatus.php +++ b/InventoryIndexer/Model/Queue/RecalculateIndexSalabilityStatus.php @@ -7,19 +7,143 @@ namespace Magento\InventoryIndexer\Model\Queue; +use Magento\Framework\App\ResourceConnection; +use Magento\Framework\Exception\LocalizedException; +use Magento\Framework\Exception\StateException; +use Magento\InventoryCatalogApi\Api\DefaultStockProviderInterface; +use Magento\InventoryIndexer\Indexer\IndexStructure; +use Magento\InventoryIndexer\Indexer\InventoryIndexer; +use Magento\InventoryMultiDimensionalIndexerApi\Model\Alias; +use Magento\InventoryMultiDimensionalIndexerApi\Model\IndexHandlerInterface; +use Magento\InventoryMultiDimensionalIndexerApi\Model\IndexNameBuilder; +use Magento\InventoryMultiDimensionalIndexerApi\Model\IndexStructureInterface; +use Magento\InventorySalesApi\Api\AreProductsSalableInterface; +use Magento\InventorySalesApi\Api\Data\IsProductSalableResultInterface; +use Magento\InventorySalesApi\Model\GetStockItemDataInterface; + /** * Recalculates index items salability status. */ class RecalculateIndexSalabilityStatus { + /** + * @var IndexNameBuilder + */ + private $indexNameBuilder; + + /** + * @var DefaultStockProviderInterface + */ + private $defaultStockProvider; + + /** + * @var IndexStructureInterface + */ + private $indexStructure; + + /** + * @var IndexHandlerInterface + */ + private $indexHandler; + + /** + * @var AreProductsSalableInterface + */ + private $areProductsSalable; + + /** + * @var GetStockItemDataInterface + */ + private $getStockItemData; + + /** + * @param IndexNameBuilder $indexNameBuilder + * @param DefaultStockProviderInterface $defaultStockProvider + * @param IndexStructureInterface $indexStructure + * @param IndexHandlerInterface $indexHandler + * @param AreProductsSalableInterface $areProductsSalable + * @param GetStockItemDataInterface $getStockItemData + */ + public function __construct( + IndexNameBuilder $indexNameBuilder, + DefaultStockProviderInterface $defaultStockProvider, + IndexStructureInterface $indexStructure, + IndexHandlerInterface $indexHandler, + AreProductsSalableInterface $areProductsSalable, + GetStockItemDataInterface $getStockItemData + ) { + $this->indexNameBuilder = $indexNameBuilder; + $this->defaultStockProvider = $defaultStockProvider; + $this->indexStructure = $indexStructure; + $this->indexHandler = $indexHandler; + $this->areProductsSalable = $areProductsSalable; + $this->getStockItemData = $getStockItemData; + } + /** * @param ReservationData $reservationData * * @return void + * @throws StateException */ public function execute(ReservationData $reservationData): void { - //TODO - list($skus, $stock) = [$reservationData->getSkus(), $reservationData->getStock()]; + $stockId = $reservationData->getStock(); + if ($this->defaultStockProvider->getId() === $stockId || !$reservationData->getSkus()) { + return; + } + + $mainIndexName = $this->indexNameBuilder + ->setIndexId(InventoryIndexer::INDEXER_ID) + ->addDimension('stock_', (string)$reservationData->getStock()) + ->setAlias(Alias::ALIAS_MAIN) + ->build(); + if (!$this->indexStructure->isExist($mainIndexName, ResourceConnection::DEFAULT_CONNECTION)) { + $this->indexStructure->create($mainIndexName, ResourceConnection::DEFAULT_CONNECTION); + } + $this->indexHandler->saveIndex( + $mainIndexName, + $this->getSalabilityData($reservationData->getSkus(), $stockId), + ResourceConnection::DEFAULT_CONNECTION + ); + } + + /** + * @param string[] $skuList + * + * @param int $stockId + * + * @return \Traversable + */ + private function getSalabilityData(array $skuList, int $stockId): \Traversable + { + $data = array_map( + function (IsProductSalableResultInterface $isProductSalableResult) use ($stockId): array { + return [ + IndexStructure::SKU => $isProductSalableResult->getSku(), + IndexStructure::IS_SALABLE => $isProductSalableResult->isSalable(), + IndexStructure::QUANTITY => $this->getIndexQty($isProductSalableResult->getSku(), $stockId) + ]; + }, + $this->areProductsSalable->execute($skuList, $stockId) + ); + + return new \ArrayIterator($data); + } + + /** + * Get current index QTY value. + * + * @param string $sku + * @param int $stockId + * + * @return float|null + * @throws LocalizedException + */ + private function getIndexQty(string $sku, int $stockId): ?float + { + $data = $this->getStockItemData->execute($sku, $stockId); + + return $data ? (float)$data[GetStockItemDataInterface::QUANTITY] : null; } } diff --git a/InventorySales/Model/IsProductSalableCondition/IsSalableWithReservationsCondition.php b/InventorySales/Model/IsProductSalableCondition/IsSalableWithReservationsCondition.php index 66c30718eac1..cc8dee8b5ba2 100644 --- a/InventorySales/Model/IsProductSalableCondition/IsSalableWithReservationsCondition.php +++ b/InventorySales/Model/IsProductSalableCondition/IsSalableWithReservationsCondition.php @@ -86,7 +86,7 @@ public function execute(string $sku, int $stockId): bool $stockItemConfiguration = $this->getStockItemConfiguration->execute($sku, $stockId); $qtyWithReservation = $stockItemData[GetStockItemDataInterface::QUANTITY] + $this->getReservationsQuantity->execute($sku, $stockId); - return (bool)$stockItemData[GetStockItemDataInterface::IS_SALABLE] && - $qtyWithReservation > $stockItemConfiguration->getMinQty(); + + return $qtyWithReservation > $stockItemConfiguration->getMinQty(); } } From 8e5c2c175c8f54f0260585b029aab66f50cee01b Mon Sep 17 00:00:00 2001 From: Maksym Novik Date: Mon, 11 May 2020 16:15:28 +0300 Subject: [PATCH 06/50] [Async Salable Status] Create infrastructure for async status update #3012. Renamed queue. --- .../ScheduleAfterPlaceReservationsForSalesEvent.php | 4 ++-- InventoryIndexer/etc/communication.xml | 4 ++-- InventoryIndexer/etc/queue_consumer.xml | 2 +- InventoryIndexer/etc/queue_publisher.xml | 2 +- InventoryIndexer/etc/queue_topology.xml | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/InventoryIndexer/Plugin/InventorySales/ScheduleAfterPlaceReservationsForSalesEvent.php b/InventoryIndexer/Plugin/InventorySales/ScheduleAfterPlaceReservationsForSalesEvent.php index 8ee4a5137ea5..e9166dbc1cbf 100644 --- a/InventoryIndexer/Plugin/InventorySales/ScheduleAfterPlaceReservationsForSalesEvent.php +++ b/InventoryIndexer/Plugin/InventorySales/ScheduleAfterPlaceReservationsForSalesEvent.php @@ -23,7 +23,7 @@ class ScheduleAfterPlaceReservationsForSalesEvent /** * Queue topic name. */ - private const TOPIC_RESERVATION_PLACED = "inventory.reservation.place"; + private const TOPIC_RESERVATIONS_UPDATE_SALABILITY_STATUS = "inventory.reservations.updateSalabilityStatus"; /** * @var PublisherInterface @@ -70,7 +70,7 @@ public function afterExecute( SalesChannelInterface $salesChannel ) { $this->publisher->publish( - self::TOPIC_RESERVATION_PLACED, + self::TOPIC_RESERVATIONS_UPDATE_SALABILITY_STATUS, $this->getReservationsDataObject($salesChannel, $items) ); } diff --git a/InventoryIndexer/etc/communication.xml b/InventoryIndexer/etc/communication.xml index 2f7b5b928ebd..19b1c7778811 100644 --- a/InventoryIndexer/etc/communication.xml +++ b/InventoryIndexer/etc/communication.xml @@ -6,7 +6,7 @@ */ --> - - + + diff --git a/InventoryIndexer/etc/queue_consumer.xml b/InventoryIndexer/etc/queue_consumer.xml index e73199976fbf..90eaf26b6ff2 100644 --- a/InventoryIndexer/etc/queue_consumer.xml +++ b/InventoryIndexer/etc/queue_consumer.xml @@ -6,5 +6,5 @@ */ --> - + diff --git a/InventoryIndexer/etc/queue_publisher.xml b/InventoryIndexer/etc/queue_publisher.xml index f41f63fa286b..782ca27f88d8 100644 --- a/InventoryIndexer/etc/queue_publisher.xml +++ b/InventoryIndexer/etc/queue_publisher.xml @@ -6,7 +6,7 @@ */ --> - + diff --git a/InventoryIndexer/etc/queue_topology.xml b/InventoryIndexer/etc/queue_topology.xml index ea1251849b0e..e3b7dd80926a 100644 --- a/InventoryIndexer/etc/queue_topology.xml +++ b/InventoryIndexer/etc/queue_topology.xml @@ -7,6 +7,6 @@ --> - + From 813617b140f59daf49bdb7c7b23f9e9865bf3f9b Mon Sep 17 00:00:00 2001 From: Maksym Novik Date: Wed, 13 May 2020 12:33:34 +0300 Subject: [PATCH 07/50] [Async Salable Status] Create infrastructure for async status update #3012. Fixed constructor param name. --- InventoryIndexer/Model/Queue/ReservationData.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/InventoryIndexer/Model/Queue/ReservationData.php b/InventoryIndexer/Model/Queue/ReservationData.php index 780f2dbd4411..8c8aae0ab9bc 100644 --- a/InventoryIndexer/Model/Queue/ReservationData.php +++ b/InventoryIndexer/Model/Queue/ReservationData.php @@ -24,12 +24,12 @@ class ReservationData /** * @param string[] $skus - * @param int $stock + * @param int $stockId */ - public function __construct(array $skus, int $stock) + public function __construct(array $skus, int $stockId) { $this->skus = $skus; - $this->stockId = $stock; + $this->stockId = $stockId; } /** From fb4392178a6dd731addee09956ff05d55d691283 Mon Sep 17 00:00:00 2001 From: Maksym Novik Date: Thu, 14 May 2020 11:53:09 +0300 Subject: [PATCH 08/50] Revert "[Async Salable Status] Create infrastructure for async status update #3012." This reverts commit 813617b140f59daf49bdb7c7b23f9e9865bf3f9b. --- InventoryIndexer/Model/Queue/ReservationData.php | 6 +++--- .../ScheduleAfterPlaceReservationsForSalesEvent.php | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/InventoryIndexer/Model/Queue/ReservationData.php b/InventoryIndexer/Model/Queue/ReservationData.php index 8c8aae0ab9bc..780f2dbd4411 100644 --- a/InventoryIndexer/Model/Queue/ReservationData.php +++ b/InventoryIndexer/Model/Queue/ReservationData.php @@ -24,12 +24,12 @@ class ReservationData /** * @param string[] $skus - * @param int $stockId + * @param int $stock */ - public function __construct(array $skus, int $stockId) + public function __construct(array $skus, int $stock) { $this->skus = $skus; - $this->stockId = $stockId; + $this->stockId = $stock; } /** diff --git a/InventoryIndexer/Plugin/InventorySales/ScheduleAfterPlaceReservationsForSalesEvent.php b/InventoryIndexer/Plugin/InventorySales/ScheduleAfterPlaceReservationsForSalesEvent.php index e9166dbc1cbf..ec181d280937 100644 --- a/InventoryIndexer/Plugin/InventorySales/ScheduleAfterPlaceReservationsForSalesEvent.php +++ b/InventoryIndexer/Plugin/InventorySales/ScheduleAfterPlaceReservationsForSalesEvent.php @@ -93,7 +93,7 @@ function (ItemToSellInterface $itemToSell): string { return $this->reservationDataFactory->create( [ - 'stockId' => $stockId, + 'stock' => $stockId, 'skus' => $skus ] ); From 7663d0300529e65e2ed148c98917bbac13c5f0f4 Mon Sep 17 00:00:00 2001 From: oleksandrkravchuk Date: Thu, 14 May 2020 20:56:34 +0300 Subject: [PATCH 09/50] magento/inventory#3013: [Async Salable Status] Storefront implementation for IsProductSalable service. Remove cache. --- .../ResourceModel/GetStockItemDataCache.php | 47 ------------------- InventoryIndexer/etc/di.xml | 2 +- 2 files changed, 1 insertion(+), 48 deletions(-) delete mode 100644 InventoryIndexer/Model/ResourceModel/GetStockItemDataCache.php diff --git a/InventoryIndexer/Model/ResourceModel/GetStockItemDataCache.php b/InventoryIndexer/Model/ResourceModel/GetStockItemDataCache.php deleted file mode 100644 index 676f7af926d5..000000000000 --- a/InventoryIndexer/Model/ResourceModel/GetStockItemDataCache.php +++ /dev/null @@ -1,47 +0,0 @@ -getStockItemData = $getStockItemData; - } - - /** - * @inheritdoc - */ - public function execute(string $sku, int $stockId): ?array - { - if (!isset($this->stockItemData[$stockId][$sku])) { - $this->stockItemData[$stockId][$sku] = $this->getStockItemData->execute($sku, $stockId); - } - - return $this->stockItemData[$stockId][$sku]; - } -} diff --git a/InventoryIndexer/etc/di.xml b/InventoryIndexer/etc/di.xml index dd7946176835..32d17b85c42a 100644 --- a/InventoryIndexer/etc/di.xml +++ b/InventoryIndexer/etc/di.xml @@ -54,7 +54,7 @@ - + From a9ca49fd84efda85ab61e57485a40e5c449e1c61 Mon Sep 17 00:00:00 2001 From: oleksandrkravchuk Date: Thu, 14 May 2020 21:50:43 +0300 Subject: [PATCH 10/50] magento/inventory#3013: [Async Salable Status] Storefront implementation for IsProductSalable service. Recover cache for storefront areas. --- .../ResourceModel/GetStockItemDataCache.php | 47 +++++++++++++++++++ InventoryIndexer/etc/frontend/di.xml | 1 + InventoryIndexer/etc/graphql/di.xml | 1 + 3 files changed, 49 insertions(+) create mode 100644 InventoryIndexer/Model/ResourceModel/GetStockItemDataCache.php diff --git a/InventoryIndexer/Model/ResourceModel/GetStockItemDataCache.php b/InventoryIndexer/Model/ResourceModel/GetStockItemDataCache.php new file mode 100644 index 000000000000..676f7af926d5 --- /dev/null +++ b/InventoryIndexer/Model/ResourceModel/GetStockItemDataCache.php @@ -0,0 +1,47 @@ +getStockItemData = $getStockItemData; + } + + /** + * @inheritdoc + */ + public function execute(string $sku, int $stockId): ?array + { + if (!isset($this->stockItemData[$stockId][$sku])) { + $this->stockItemData[$stockId][$sku] = $this->getStockItemData->execute($sku, $stockId); + } + + return $this->stockItemData[$stockId][$sku]; + } +} diff --git a/InventoryIndexer/etc/frontend/di.xml b/InventoryIndexer/etc/frontend/di.xml index cc63fe51d98b..2e3ac3d91f21 100644 --- a/InventoryIndexer/etc/frontend/di.xml +++ b/InventoryIndexer/etc/frontend/di.xml @@ -7,4 +7,5 @@ --> + diff --git a/InventoryIndexer/etc/graphql/di.xml b/InventoryIndexer/etc/graphql/di.xml index cc63fe51d98b..2e3ac3d91f21 100644 --- a/InventoryIndexer/etc/graphql/di.xml +++ b/InventoryIndexer/etc/graphql/di.xml @@ -7,4 +7,5 @@ --> + From 5a1611780aeeca80c673d915a390780adf5d6dea Mon Sep 17 00:00:00 2001 From: oleksandrkravchuk Date: Fri, 15 May 2020 18:09:00 +0300 Subject: [PATCH 11/50] magento/inventory#3013: [Async Salable Status] Storefront implementation for IsProductSalable service. Remove reservations cache for general scope. Keep cache only for storefront application. --- InventoryReservations/etc/di.xml | 2 +- InventoryReservations/etc/frontend/di.xml | 10 ++++++++++ InventoryReservations/etc/graphql/di.xml | 10 ++++++++++ 3 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 InventoryReservations/etc/frontend/di.xml create mode 100644 InventoryReservations/etc/graphql/di.xml diff --git a/InventoryReservations/etc/di.xml b/InventoryReservations/etc/di.xml index bb3c3acd4ce1..901e2f45700d 100644 --- a/InventoryReservations/etc/di.xml +++ b/InventoryReservations/etc/di.xml @@ -10,7 +10,7 @@ - + 32768 diff --git a/InventoryReservations/etc/frontend/di.xml b/InventoryReservations/etc/frontend/di.xml new file mode 100644 index 000000000000..8b50dcd399ef --- /dev/null +++ b/InventoryReservations/etc/frontend/di.xml @@ -0,0 +1,10 @@ + + + + + diff --git a/InventoryReservations/etc/graphql/di.xml b/InventoryReservations/etc/graphql/di.xml new file mode 100644 index 000000000000..8b50dcd399ef --- /dev/null +++ b/InventoryReservations/etc/graphql/di.xml @@ -0,0 +1,10 @@ + + + + + From 11a7e297cf0c7e9ead71a1ff883c1765990b2502 Mon Sep 17 00:00:00 2001 From: oleksandrkravchuk Date: Fri, 15 May 2020 18:10:45 +0300 Subject: [PATCH 12/50] magento/inventory#3013: [Async Salable Status] Storefront implementation for IsProductSalable service. Revert cache movement to storefront for Stock data. --- InventoryIndexer/etc/di.xml | 2 +- InventoryIndexer/etc/frontend/di.xml | 1 - InventoryIndexer/etc/graphql/di.xml | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/InventoryIndexer/etc/di.xml b/InventoryIndexer/etc/di.xml index 32d17b85c42a..dd7946176835 100644 --- a/InventoryIndexer/etc/di.xml +++ b/InventoryIndexer/etc/di.xml @@ -54,7 +54,7 @@ - + diff --git a/InventoryIndexer/etc/frontend/di.xml b/InventoryIndexer/etc/frontend/di.xml index 2e3ac3d91f21..cc63fe51d98b 100644 --- a/InventoryIndexer/etc/frontend/di.xml +++ b/InventoryIndexer/etc/frontend/di.xml @@ -7,5 +7,4 @@ --> - diff --git a/InventoryIndexer/etc/graphql/di.xml b/InventoryIndexer/etc/graphql/di.xml index 2e3ac3d91f21..cc63fe51d98b 100644 --- a/InventoryIndexer/etc/graphql/di.xml +++ b/InventoryIndexer/etc/graphql/di.xml @@ -7,5 +7,4 @@ --> - From f176c1a346c37429dabe486f009b01ace4c3ecac Mon Sep 17 00:00:00 2001 From: oleksandrkravchuk Date: Fri, 15 May 2020 18:13:13 +0300 Subject: [PATCH 13/50] magento/inventory#3013: [Async Salable Status] Storefront implementation for IsProductSalable service. Apply code review changes. --- InventoryIndexer/Model/IsProductSalable.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/InventoryIndexer/Model/IsProductSalable.php b/InventoryIndexer/Model/IsProductSalable.php index ca83bf6d28ee..713245d23b1c 100644 --- a/InventoryIndexer/Model/IsProductSalable.php +++ b/InventoryIndexer/Model/IsProductSalable.php @@ -21,14 +21,14 @@ class IsProductSalable implements IsProductSalableInterface /** * @var GetStockItemDataInterface */ - private $stockItemData; + private $getStockItemData; /** * @param GetStockItemDataInterface $stockItemData */ - public function __construct(GetStockItemDataInterface $stockItemData) + public function __construct(GetStockItemDataInterface $getStockItemData) { - $this->stockItemData = $stockItemData; + $this->getStockItemData = $getStockItemData; } /** @@ -37,7 +37,7 @@ public function __construct(GetStockItemDataInterface $stockItemData) public function execute(string $sku, int $stockId): bool { try { - $stockItem = $this->stockItemData->execute($sku, $stockId); + $stockItem = $this->getStockItemData->execute($sku, $stockId); $isSalable = (bool)($stockItem[GetStockItemDataInterface::IS_SALABLE] ?? false); } catch (LocalizedException $exception) { $isSalable = false; From 66498310711eb74ab99a61c103be4564d14b7c62 Mon Sep 17 00:00:00 2001 From: Maksym Novik Date: Sun, 17 May 2020 16:29:46 +0300 Subject: [PATCH 14/50] [Async Salable Status] Create infrastructure for async status update #3012. CR changes. --- .../Model/Queue/RecalculateIndexSalabilityStatus.php | 10 +++++++--- ... => EnqueueAfterPlaceReservationsForSalesEvent.php} | 6 +++--- InventoryIndexer/etc/di.xml | 2 +- 3 files changed, 11 insertions(+), 7 deletions(-) rename InventoryIndexer/Plugin/InventorySales/{ScheduleAfterPlaceReservationsForSalesEvent.php => EnqueueAfterPlaceReservationsForSalesEvent.php} (96%) diff --git a/InventoryIndexer/Model/Queue/RecalculateIndexSalabilityStatus.php b/InventoryIndexer/Model/Queue/RecalculateIndexSalabilityStatus.php index 1e4fa7d7f233..42668aed1ed3 100644 --- a/InventoryIndexer/Model/Queue/RecalculateIndexSalabilityStatus.php +++ b/InventoryIndexer/Model/Queue/RecalculateIndexSalabilityStatus.php @@ -138,12 +138,16 @@ function (IsProductSalableResultInterface $isProductSalableResult) use ($stockId * @param int $stockId * * @return float|null - * @throws LocalizedException */ private function getIndexQty(string $sku, int $stockId): ?float { - $data = $this->getStockItemData->execute($sku, $stockId); + try { + $data = $this->getStockItemData->execute($sku, $stockId); + $qty = $data ? (float)$data[GetStockItemDataInterface::QUANTITY] : null; + } catch (LocalizedException $e) { + $qty = null; + } - return $data ? (float)$data[GetStockItemDataInterface::QUANTITY] : null; + return $qty; } } diff --git a/InventoryIndexer/Plugin/InventorySales/ScheduleAfterPlaceReservationsForSalesEvent.php b/InventoryIndexer/Plugin/InventorySales/EnqueueAfterPlaceReservationsForSalesEvent.php similarity index 96% rename from InventoryIndexer/Plugin/InventorySales/ScheduleAfterPlaceReservationsForSalesEvent.php rename to InventoryIndexer/Plugin/InventorySales/EnqueueAfterPlaceReservationsForSalesEvent.php index ec181d280937..9fc61dae823b 100644 --- a/InventoryIndexer/Plugin/InventorySales/ScheduleAfterPlaceReservationsForSalesEvent.php +++ b/InventoryIndexer/Plugin/InventorySales/EnqueueAfterPlaceReservationsForSalesEvent.php @@ -18,12 +18,12 @@ /** * Enqueue reservations processing after appending in order to recalculate index salability status. */ -class ScheduleAfterPlaceReservationsForSalesEvent +class EnqueueAfterPlaceReservationsForSalesEvent { /** * Queue topic name. */ - private const TOPIC_RESERVATIONS_UPDATE_SALABILITY_STATUS = "inventory.reservations.updateSalabilityStatus"; + private const TOPIC_RESERVATIONS_UPDATE_SALABILITY_STATUS = 'inventory.reservations.updateSalabilityStatus'; /** * @var PublisherInterface @@ -68,7 +68,7 @@ public function afterExecute( $result, array $items, SalesChannelInterface $salesChannel - ) { + ): void { $this->publisher->publish( self::TOPIC_RESERVATIONS_UPDATE_SALABILITY_STATUS, $this->getReservationsDataObject($salesChannel, $items) diff --git a/InventoryIndexer/etc/di.xml b/InventoryIndexer/etc/di.xml index 496f39e034f4..47081f86e412 100644 --- a/InventoryIndexer/etc/di.xml +++ b/InventoryIndexer/etc/di.xml @@ -62,6 +62,6 @@ - + From 067a706e342d0f8146c150b03d54dbe04f58f95c Mon Sep 17 00:00:00 2001 From: Maksym Novik Date: Sun, 17 May 2020 17:50:57 +0300 Subject: [PATCH 15/50] [Async Salable Status] Create infrastructure for async status update #3012. Moved stock item caching to storefront only. --- InventoryIndexer/etc/di.xml | 2 +- InventoryIndexer/etc/frontend/di.xml | 1 + InventoryIndexer/etc/graphql/di.xml | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/InventoryIndexer/etc/di.xml b/InventoryIndexer/etc/di.xml index 47081f86e412..0d5383376011 100644 --- a/InventoryIndexer/etc/di.xml +++ b/InventoryIndexer/etc/di.xml @@ -54,7 +54,7 @@ - + diff --git a/InventoryIndexer/etc/frontend/di.xml b/InventoryIndexer/etc/frontend/di.xml index cc63fe51d98b..2e3ac3d91f21 100644 --- a/InventoryIndexer/etc/frontend/di.xml +++ b/InventoryIndexer/etc/frontend/di.xml @@ -7,4 +7,5 @@ --> + diff --git a/InventoryIndexer/etc/graphql/di.xml b/InventoryIndexer/etc/graphql/di.xml index cc63fe51d98b..2e3ac3d91f21 100644 --- a/InventoryIndexer/etc/graphql/di.xml +++ b/InventoryIndexer/etc/graphql/di.xml @@ -7,4 +7,5 @@ --> + From 3ae30ea3de6c6cfce7d060b35f6e2790a037559f Mon Sep 17 00:00:00 2001 From: Maksym Novik Date: Sun, 17 May 2020 20:33:44 +0300 Subject: [PATCH 16/50] [Async Salable Status] Create infrastructure for async status update #3012. Refactored consumer. Updating salability status directly instead of inserting on duplicate. --- ...us.php => UpdateIndexSalabilityStatus.php} | 104 +++++++++--------- .../Model/ResourceModel/UpdateIsSalable.php | 57 ++++++++++ InventoryIndexer/etc/communication.xml | 2 +- 3 files changed, 111 insertions(+), 52 deletions(-) rename InventoryIndexer/Model/Queue/{RecalculateIndexSalabilityStatus.php => UpdateIndexSalabilityStatus.php} (52%) create mode 100644 InventoryIndexer/Model/ResourceModel/UpdateIsSalable.php diff --git a/InventoryIndexer/Model/Queue/RecalculateIndexSalabilityStatus.php b/InventoryIndexer/Model/Queue/UpdateIndexSalabilityStatus.php similarity index 52% rename from InventoryIndexer/Model/Queue/RecalculateIndexSalabilityStatus.php rename to InventoryIndexer/Model/Queue/UpdateIndexSalabilityStatus.php index 42668aed1ed3..1c4c891d024e 100644 --- a/InventoryIndexer/Model/Queue/RecalculateIndexSalabilityStatus.php +++ b/InventoryIndexer/Model/Queue/UpdateIndexSalabilityStatus.php @@ -11,10 +11,9 @@ use Magento\Framework\Exception\LocalizedException; use Magento\Framework\Exception\StateException; use Magento\InventoryCatalogApi\Api\DefaultStockProviderInterface; -use Magento\InventoryIndexer\Indexer\IndexStructure; use Magento\InventoryIndexer\Indexer\InventoryIndexer; +use Magento\InventoryIndexer\Model\ResourceModel\UpdateIsSalable; use Magento\InventoryMultiDimensionalIndexerApi\Model\Alias; -use Magento\InventoryMultiDimensionalIndexerApi\Model\IndexHandlerInterface; use Magento\InventoryMultiDimensionalIndexerApi\Model\IndexNameBuilder; use Magento\InventoryMultiDimensionalIndexerApi\Model\IndexStructureInterface; use Magento\InventorySalesApi\Api\AreProductsSalableInterface; @@ -24,7 +23,7 @@ /** * Recalculates index items salability status. */ -class RecalculateIndexSalabilityStatus +class UpdateIndexSalabilityStatus { /** * @var IndexNameBuilder @@ -41,11 +40,6 @@ class RecalculateIndexSalabilityStatus */ private $indexStructure; - /** - * @var IndexHandlerInterface - */ - private $indexHandler; - /** * @var AreProductsSalableInterface */ @@ -56,98 +50,106 @@ class RecalculateIndexSalabilityStatus */ private $getStockItemData; + /** + * @var UpdateIsSalable + */ + private $updateIsSalable; + /** * @param IndexNameBuilder $indexNameBuilder * @param DefaultStockProviderInterface $defaultStockProvider * @param IndexStructureInterface $indexStructure - * @param IndexHandlerInterface $indexHandler * @param AreProductsSalableInterface $areProductsSalable * @param GetStockItemDataInterface $getStockItemData + * @param UpdateIsSalable $updateIsSalable */ public function __construct( IndexNameBuilder $indexNameBuilder, DefaultStockProviderInterface $defaultStockProvider, IndexStructureInterface $indexStructure, - IndexHandlerInterface $indexHandler, AreProductsSalableInterface $areProductsSalable, - GetStockItemDataInterface $getStockItemData + GetStockItemDataInterface $getStockItemData, + UpdateIsSalable $updateIsSalable ) { $this->indexNameBuilder = $indexNameBuilder; $this->defaultStockProvider = $defaultStockProvider; $this->indexStructure = $indexStructure; - $this->indexHandler = $indexHandler; $this->areProductsSalable = $areProductsSalable; $this->getStockItemData = $getStockItemData; + $this->updateIsSalable = $updateIsSalable; } /** * @param ReservationData $reservationData * - * @return void + * @return bool[] - ['sku' => bool] * @throws StateException */ - public function execute(ReservationData $reservationData): void + public function execute(ReservationData $reservationData): array { $stockId = $reservationData->getStock(); - if ($this->defaultStockProvider->getId() === $stockId || !$reservationData->getSkus()) { - return; - } + $dataForUpdate = []; + if ($stockId !== $this->defaultStockProvider->getId() && $reservationData->getSkus()) { + $mainIndexName = $this->indexNameBuilder + ->setIndexId(InventoryIndexer::INDEXER_ID) + ->addDimension('stock_', (string)$reservationData->getStock()) + ->setAlias(Alias::ALIAS_MAIN) + ->build(); + if (!$this->indexStructure->isExist($mainIndexName, ResourceConnection::DEFAULT_CONNECTION)) { + $this->indexStructure->create($mainIndexName, ResourceConnection::DEFAULT_CONNECTION); + } + $salabilityData = $this->areProductsSalable->execute( + $reservationData->getSkus(), + $reservationData->getStock() + ); - $mainIndexName = $this->indexNameBuilder - ->setIndexId(InventoryIndexer::INDEXER_ID) - ->addDimension('stock_', (string)$reservationData->getStock()) - ->setAlias(Alias::ALIAS_MAIN) - ->build(); - if (!$this->indexStructure->isExist($mainIndexName, ResourceConnection::DEFAULT_CONNECTION)) { - $this->indexStructure->create($mainIndexName, ResourceConnection::DEFAULT_CONNECTION); + $dataForUpdate = $this->getDataForUpdate($salabilityData, $stockId); + $this->updateIsSalable->execute( + $mainIndexName, + $dataForUpdate, + ResourceConnection::DEFAULT_CONNECTION + ); } - $this->indexHandler->saveIndex( - $mainIndexName, - $this->getSalabilityData($reservationData->getSkus(), $stockId), - ResourceConnection::DEFAULT_CONNECTION - ); + + return $dataForUpdate; } /** - * @param string[] $skuList - * + * @param IsProductSalableResultInterface[] $salabilityData * @param int $stockId * - * @return \Traversable + * @return bool[] - ['sku' => bool] */ - private function getSalabilityData(array $skuList, int $stockId): \Traversable + private function getDataForUpdate(array $salabilityData, int $stockId): array { - $data = array_map( - function (IsProductSalableResultInterface $isProductSalableResult) use ($stockId): array { - return [ - IndexStructure::SKU => $isProductSalableResult->getSku(), - IndexStructure::IS_SALABLE => $isProductSalableResult->isSalable(), - IndexStructure::QUANTITY => $this->getIndexQty($isProductSalableResult->getSku(), $stockId) - ]; - }, - $this->areProductsSalable->execute($skuList, $stockId) - ); - - return new \ArrayIterator($data); + $data = []; + foreach ($salabilityData as $isProductSalableResult) { + $currentStatus = $this->getIndexSalabilityStatus($isProductSalableResult->getSku(), $stockId); + if ($isProductSalableResult->isSalable() != $currentStatus && $currentStatus !== null) { + $data[$isProductSalableResult->getSku()] = $isProductSalableResult->isSalable(); + } + } + + return $data; } /** - * Get current index QTY value. + * Get current index is_salable value. * * @param string $sku * @param int $stockId * - * @return float|null + * @return bool|null */ - private function getIndexQty(string $sku, int $stockId): ?float + private function getIndexSalabilityStatus(string $sku, int $stockId): ?bool { try { $data = $this->getStockItemData->execute($sku, $stockId); - $qty = $data ? (float)$data[GetStockItemDataInterface::QUANTITY] : null; + $isSalable = $data ? (bool)$data[GetStockItemDataInterface::IS_SALABLE] : false; } catch (LocalizedException $e) { - $qty = null; + $isSalable = null; } - return $qty; + return $isSalable; } } diff --git a/InventoryIndexer/Model/ResourceModel/UpdateIsSalable.php b/InventoryIndexer/Model/ResourceModel/UpdateIsSalable.php new file mode 100644 index 000000000000..35c8ab6a9932 --- /dev/null +++ b/InventoryIndexer/Model/ResourceModel/UpdateIsSalable.php @@ -0,0 +1,57 @@ +indexNameResolver = $indexNameResolver; + $this->resourceConnection = $resourceConnection; + } + + /** + * Update index salability data. + * + * @param IndexName $indexName + * @param array $dataForUpdate = ['sku' => bool] + * @param string $connectionName + * + * @return void + */ + public function execute(IndexName $indexName, array $dataForUpdate, string $connectionName): void + { + $connection = $this->resourceConnection->getConnection($connectionName); + $tableName = $this->indexNameResolver->resolveName($indexName); + foreach ($dataForUpdate as $sku => $isSalable) { + $connection->update($tableName, [IndexStructure::IS_SALABLE => $isSalable], ['sku = ?' => $sku]); + } + } +} diff --git a/InventoryIndexer/etc/communication.xml b/InventoryIndexer/etc/communication.xml index 19b1c7778811..9d439b12e2a2 100644 --- a/InventoryIndexer/etc/communication.xml +++ b/InventoryIndexer/etc/communication.xml @@ -7,6 +7,6 @@ --> - + From abe49deeea73ec704a394b3033b68575bc461f50 Mon Sep 17 00:00:00 2001 From: Maksym Novik Date: Sun, 17 May 2020 21:30:11 +0300 Subject: [PATCH 17/50] [Async Salable Status] Create infrastructure for async status update #3012. Flushing cache on status change. --- .../UpdateSalabilityStatus/CacheFlush.php | 61 +++++++++++++++++++ InventoryCache/etc/di.xml | 3 + .../Queue/UpdateIndexSalabilityStatus.php | 2 +- 3 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 InventoryCache/Plugin/InventoryIndexer/Queue/Reservation/UpdateSalabilityStatus/CacheFlush.php diff --git a/InventoryCache/Plugin/InventoryIndexer/Queue/Reservation/UpdateSalabilityStatus/CacheFlush.php b/InventoryCache/Plugin/InventoryIndexer/Queue/Reservation/UpdateSalabilityStatus/CacheFlush.php new file mode 100644 index 000000000000..d4939d475620 --- /dev/null +++ b/InventoryCache/Plugin/InventoryIndexer/Queue/Reservation/UpdateSalabilityStatus/CacheFlush.php @@ -0,0 +1,61 @@ +flushCacheByIds = $flushCacheByIds; + $this->getProductIdsBySkus = $getProductIdsBySkus; + } + + /** + * @param UpdateIndexSalabilityStatus $subject + * @param array $skusAffected + * + * @return array + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function afterExecute(UpdateIndexSalabilityStatus $subject, array $skusAffected) + { + if ($skus = array_keys($skusAffected)) { + try { + $this->flushCacheByIds->execute($this->getProductIdsBySkus->execute($skus)); + } catch (NoSuchEntityException $e) { // phpcs:ignore Magento2.CodeAnalysis.EmptyBlock.DetectedCatch + // Do nothing. + } + } + + return $skusAffected; + } +} diff --git a/InventoryCache/etc/di.xml b/InventoryCache/etc/di.xml index 0b6c1024f4d9..9f3a921eea2a 100644 --- a/InventoryCache/etc/di.xml +++ b/InventoryCache/etc/di.xml @@ -12,6 +12,9 @@ + + + catalog_product_entity diff --git a/InventoryIndexer/Model/Queue/UpdateIndexSalabilityStatus.php b/InventoryIndexer/Model/Queue/UpdateIndexSalabilityStatus.php index 1c4c891d024e..e6c3e3e36dc2 100644 --- a/InventoryIndexer/Model/Queue/UpdateIndexSalabilityStatus.php +++ b/InventoryIndexer/Model/Queue/UpdateIndexSalabilityStatus.php @@ -82,7 +82,7 @@ public function __construct( /** * @param ReservationData $reservationData * - * @return bool[] - ['sku' => bool] + * @return bool[] - ['sku' => bool]: list of SKUs with salability status changed. * @throws StateException */ public function execute(ReservationData $reservationData): array From 0abdaabf5fad11db59361ad9d219950beea721a4 Mon Sep 17 00:00:00 2001 From: nmalevanec Date: Tue, 19 May 2020 14:06:19 +0300 Subject: [PATCH 18/50] Fix tests. --- ...tityConfigurableProductCustomStockTest.xml | 2 +- ...tityConfigurableProductCustomStockTest.xml | 5 +- .../UpdateSalabilityStatus/CacheFlush.php | 2 + InventoryIndexer/Model/IsProductSalable.php | 4 +- .../Queue/UpdateIndexSalabilityStatus.php | 114 ++------------ .../IndexProcessor.php | 147 ++++++++++++++++++ ...eueAfterPlaceReservationsForSalesEvent.php | 5 + InventoryIndexer/composer.json | 1 + .../etc/frontend/di.xml | 10 ++ 9 files changed, 178 insertions(+), 112 deletions(-) create mode 100644 InventoryIndexer/Model/Queue/UpdateIndexSalabilityStatus/IndexProcessor.php create mode 100644 dev/tests/integration/_files/Magento/TestModuleInventoryStateCache/etc/frontend/di.xml diff --git a/InventoryAdminUi/Test/Mftf/Test/StorefrontCreateOrderAllQuantityConfigurableProductCustomStockTest.xml b/InventoryAdminUi/Test/Mftf/Test/StorefrontCreateOrderAllQuantityConfigurableProductCustomStockTest.xml index c9fe01799ddd..a424370c5ae0 100644 --- a/InventoryAdminUi/Test/Mftf/Test/StorefrontCreateOrderAllQuantityConfigurableProductCustomStockTest.xml +++ b/InventoryAdminUi/Test/Mftf/Test/StorefrontCreateOrderAllQuantityConfigurableProductCustomStockTest.xml @@ -93,7 +93,7 @@ - + diff --git a/InventoryAdminUi/Test/Mftf/Test/StorefrontLoggedInCustomerCreateOrderAllOptionQuantityConfigurableProductCustomStockTest.xml b/InventoryAdminUi/Test/Mftf/Test/StorefrontLoggedInCustomerCreateOrderAllOptionQuantityConfigurableProductCustomStockTest.xml index 1fa03183f366..5c214c18a050 100644 --- a/InventoryAdminUi/Test/Mftf/Test/StorefrontLoggedInCustomerCreateOrderAllOptionQuantityConfigurableProductCustomStockTest.xml +++ b/InventoryAdminUi/Test/Mftf/Test/StorefrontLoggedInCustomerCreateOrderAllOptionQuantityConfigurableProductCustomStockTest.xml @@ -119,9 +119,8 @@ - - - + + diff --git a/InventoryCache/Plugin/InventoryIndexer/Queue/Reservation/UpdateSalabilityStatus/CacheFlush.php b/InventoryCache/Plugin/InventoryIndexer/Queue/Reservation/UpdateSalabilityStatus/CacheFlush.php index d4939d475620..39b052e4aa99 100644 --- a/InventoryCache/Plugin/InventoryIndexer/Queue/Reservation/UpdateSalabilityStatus/CacheFlush.php +++ b/InventoryCache/Plugin/InventoryIndexer/Queue/Reservation/UpdateSalabilityStatus/CacheFlush.php @@ -40,6 +40,8 @@ public function __construct( } /** + * Flush cache after reindex. + * * @param UpdateIndexSalabilityStatus $subject * @param array $skusAffected * diff --git a/InventoryIndexer/Model/IsProductSalable.php b/InventoryIndexer/Model/IsProductSalable.php index 713245d23b1c..a1ba2eef7dc3 100644 --- a/InventoryIndexer/Model/IsProductSalable.php +++ b/InventoryIndexer/Model/IsProductSalable.php @@ -12,8 +12,6 @@ use Magento\InventorySalesApi\Model\GetStockItemDataInterface; /** - * @inheritDoc - * * Lightweight implementation for Storefront application. */ class IsProductSalable implements IsProductSalableInterface @@ -24,7 +22,7 @@ class IsProductSalable implements IsProductSalableInterface private $getStockItemData; /** - * @param GetStockItemDataInterface $stockItemData + * @param GetStockItemDataInterface $getStockItemData */ public function __construct(GetStockItemDataInterface $getStockItemData) { diff --git a/InventoryIndexer/Model/Queue/UpdateIndexSalabilityStatus.php b/InventoryIndexer/Model/Queue/UpdateIndexSalabilityStatus.php index e6c3e3e36dc2..87ac385753ba 100644 --- a/InventoryIndexer/Model/Queue/UpdateIndexSalabilityStatus.php +++ b/InventoryIndexer/Model/Queue/UpdateIndexSalabilityStatus.php @@ -7,79 +7,40 @@ namespace Magento\InventoryIndexer\Model\Queue; -use Magento\Framework\App\ResourceConnection; -use Magento\Framework\Exception\LocalizedException; use Magento\Framework\Exception\StateException; use Magento\InventoryCatalogApi\Api\DefaultStockProviderInterface; -use Magento\InventoryIndexer\Indexer\InventoryIndexer; -use Magento\InventoryIndexer\Model\ResourceModel\UpdateIsSalable; -use Magento\InventoryMultiDimensionalIndexerApi\Model\Alias; -use Magento\InventoryMultiDimensionalIndexerApi\Model\IndexNameBuilder; -use Magento\InventoryMultiDimensionalIndexerApi\Model\IndexStructureInterface; -use Magento\InventorySalesApi\Api\AreProductsSalableInterface; -use Magento\InventorySalesApi\Api\Data\IsProductSalableResultInterface; -use Magento\InventorySalesApi\Model\GetStockItemDataInterface; +use Magento\InventoryIndexer\Model\Queue\UpdateIndexSalabilityStatus\IndexProcessor; /** * Recalculates index items salability status. */ class UpdateIndexSalabilityStatus { - /** - * @var IndexNameBuilder - */ - private $indexNameBuilder; - /** * @var DefaultStockProviderInterface */ private $defaultStockProvider; /** - * @var IndexStructureInterface - */ - private $indexStructure; - - /** - * @var AreProductsSalableInterface - */ - private $areProductsSalable; - - /** - * @var GetStockItemDataInterface - */ - private $getStockItemData; - - /** - * @var UpdateIsSalable + * @var IndexProcessor */ - private $updateIsSalable; + private $indexProcessor; /** - * @param IndexNameBuilder $indexNameBuilder * @param DefaultStockProviderInterface $defaultStockProvider - * @param IndexStructureInterface $indexStructure - * @param AreProductsSalableInterface $areProductsSalable - * @param GetStockItemDataInterface $getStockItemData - * @param UpdateIsSalable $updateIsSalable + * @param IndexProcessor $indexProcessor */ public function __construct( - IndexNameBuilder $indexNameBuilder, DefaultStockProviderInterface $defaultStockProvider, - IndexStructureInterface $indexStructure, - AreProductsSalableInterface $areProductsSalable, - GetStockItemDataInterface $getStockItemData, - UpdateIsSalable $updateIsSalable + IndexProcessor $indexProcessor ) { - $this->indexNameBuilder = $indexNameBuilder; $this->defaultStockProvider = $defaultStockProvider; - $this->indexStructure = $indexStructure; - $this->areProductsSalable = $areProductsSalable; - $this->getStockItemData = $getStockItemData; - $this->updateIsSalable = $updateIsSalable; + $this->indexProcessor = $indexProcessor; } /** + * Reindex items salability statuses. + * * @param ReservationData $reservationData * * @return bool[] - ['sku' => bool]: list of SKUs with salability status changed. @@ -90,66 +51,9 @@ public function execute(ReservationData $reservationData): array $stockId = $reservationData->getStock(); $dataForUpdate = []; if ($stockId !== $this->defaultStockProvider->getId() && $reservationData->getSkus()) { - $mainIndexName = $this->indexNameBuilder - ->setIndexId(InventoryIndexer::INDEXER_ID) - ->addDimension('stock_', (string)$reservationData->getStock()) - ->setAlias(Alias::ALIAS_MAIN) - ->build(); - if (!$this->indexStructure->isExist($mainIndexName, ResourceConnection::DEFAULT_CONNECTION)) { - $this->indexStructure->create($mainIndexName, ResourceConnection::DEFAULT_CONNECTION); - } - $salabilityData = $this->areProductsSalable->execute( - $reservationData->getSkus(), - $reservationData->getStock() - ); - - $dataForUpdate = $this->getDataForUpdate($salabilityData, $stockId); - $this->updateIsSalable->execute( - $mainIndexName, - $dataForUpdate, - ResourceConnection::DEFAULT_CONNECTION - ); + $dataForUpdate = $this->indexProcessor->execute($reservationData, $stockId); } return $dataForUpdate; } - - /** - * @param IsProductSalableResultInterface[] $salabilityData - * @param int $stockId - * - * @return bool[] - ['sku' => bool] - */ - private function getDataForUpdate(array $salabilityData, int $stockId): array - { - $data = []; - foreach ($salabilityData as $isProductSalableResult) { - $currentStatus = $this->getIndexSalabilityStatus($isProductSalableResult->getSku(), $stockId); - if ($isProductSalableResult->isSalable() != $currentStatus && $currentStatus !== null) { - $data[$isProductSalableResult->getSku()] = $isProductSalableResult->isSalable(); - } - } - - return $data; - } - - /** - * Get current index is_salable value. - * - * @param string $sku - * @param int $stockId - * - * @return bool|null - */ - private function getIndexSalabilityStatus(string $sku, int $stockId): ?bool - { - try { - $data = $this->getStockItemData->execute($sku, $stockId); - $isSalable = $data ? (bool)$data[GetStockItemDataInterface::IS_SALABLE] : false; - } catch (LocalizedException $e) { - $isSalable = null; - } - - return $isSalable; - } } diff --git a/InventoryIndexer/Model/Queue/UpdateIndexSalabilityStatus/IndexProcessor.php b/InventoryIndexer/Model/Queue/UpdateIndexSalabilityStatus/IndexProcessor.php new file mode 100644 index 000000000000..e2bd7623d8f1 --- /dev/null +++ b/InventoryIndexer/Model/Queue/UpdateIndexSalabilityStatus/IndexProcessor.php @@ -0,0 +1,147 @@ +indexNameBuilder = $indexNameBuilder; + $this->indexStructure = $indexStructure; + $this->areProductsSalable = $areProductsSalable; + $this->getStockItemData = $getStockItemData; + $this->updateIsSalable = $updateIsSalable; + } + + /** + * Process index for given reservation data and stock. + * + * @param ReservationData $reservationData + * @param int $stockId + * @return bool[] + * @throws StateException + */ + public function execute(ReservationData $reservationData, int $stockId): array + { + $mainIndexName = $this->indexNameBuilder + ->setIndexId(InventoryIndexer::INDEXER_ID) + ->addDimension('stock_', (string)$reservationData->getStock()) + ->setAlias(Alias::ALIAS_MAIN) + ->build(); + if (!$this->indexStructure->isExist($mainIndexName, ResourceConnection::DEFAULT_CONNECTION)) { + $this->indexStructure->create($mainIndexName, ResourceConnection::DEFAULT_CONNECTION); + } + $salabilityData = $this->areProductsSalable->execute( + $reservationData->getSkus(), + $reservationData->getStock() + ); + + $dataForUpdate = $this->getDataForUpdate($salabilityData, $stockId); + $this->updateIsSalable->execute( + $mainIndexName, + $dataForUpdate, + ResourceConnection::DEFAULT_CONNECTION + ); + + return $dataForUpdate; + } + + /** + * Build data for index update. + * + * @param IsProductSalableResultInterface[] $salabilityData + * @param int $stockId + * + * @return bool[] - ['sku' => bool] + */ + private function getDataForUpdate(array $salabilityData, int $stockId): array + { + $data = []; + foreach ($salabilityData as $isProductSalableResult) { + $currentStatus = $this->getIndexSalabilityStatus($isProductSalableResult->getSku(), $stockId); + if ($isProductSalableResult->isSalable() != $currentStatus && $currentStatus !== null) { + $data[$isProductSalableResult->getSku()] = $isProductSalableResult->isSalable(); + } + } + + return $data; + } + + /** + * Get current index is_salable value. + * + * @param string $sku + * @param int $stockId + * + * @return bool|null + */ + private function getIndexSalabilityStatus(string $sku, int $stockId): ?bool + { + try { + $data = $this->getStockItemData->execute($sku, $stockId); + $isSalable = $data ? (bool)$data[GetStockItemDataInterface::IS_SALABLE] : false; + } catch (LocalizedException $e) { + $isSalable = null; + } + + return $isSalable; + } +} diff --git a/InventoryIndexer/Plugin/InventorySales/EnqueueAfterPlaceReservationsForSalesEvent.php b/InventoryIndexer/Plugin/InventorySales/EnqueueAfterPlaceReservationsForSalesEvent.php index 9fc61dae823b..00a427144c50 100644 --- a/InventoryIndexer/Plugin/InventorySales/EnqueueAfterPlaceReservationsForSalesEvent.php +++ b/InventoryIndexer/Plugin/InventorySales/EnqueueAfterPlaceReservationsForSalesEvent.php @@ -56,12 +56,15 @@ public function __construct( } /** + * Publish reservation data for reindex. + * * @param PlaceReservationsForSalesEvent $subject * @param null $result * @param ItemToSellInterface[] $items * @param SalesChannelInterface $salesChannel * * @return void + * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function afterExecute( PlaceReservationsForSalesEvent $subject, @@ -76,6 +79,8 @@ public function afterExecute( } /** + * Build reservation data transfer objects. + * * @param SalesChannelInterface $salesChannel * @param ItemToSellInterface[] $items * diff --git a/InventoryIndexer/composer.json b/InventoryIndexer/composer.json index 093a4bc38c42..741e2493f783 100644 --- a/InventoryIndexer/composer.json +++ b/InventoryIndexer/composer.json @@ -4,6 +4,7 @@ "require": { "php": "~7.3.0||~7.4.0", "magento/framework": "*", + "magento/framework-message-queue": "*", "magento/module-inventory-multi-dimensional-indexer-api": "*", "magento/module-inventory": "*", "magento/module-inventory-api": "*", diff --git a/dev/tests/integration/_files/Magento/TestModuleInventoryStateCache/etc/frontend/di.xml b/dev/tests/integration/_files/Magento/TestModuleInventoryStateCache/etc/frontend/di.xml new file mode 100644 index 000000000000..1dba1542b79d --- /dev/null +++ b/dev/tests/integration/_files/Magento/TestModuleInventoryStateCache/etc/frontend/di.xml @@ -0,0 +1,10 @@ + + + + + From b627df28d001047be2f5fe66a7bd23a2c257b7f7 Mon Sep 17 00:00:00 2001 From: oleksandrkravchuk Date: Tue, 19 May 2020 17:54:37 +0200 Subject: [PATCH 19/50] Fix static tests. --- .../EnqueueAfterPlaceReservationsForSalesEvent.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/InventoryIndexer/Plugin/InventorySales/EnqueueAfterPlaceReservationsForSalesEvent.php b/InventoryIndexer/Plugin/InventorySales/EnqueueAfterPlaceReservationsForSalesEvent.php index 00a427144c50..5deb3f81c079 100644 --- a/InventoryIndexer/Plugin/InventorySales/EnqueueAfterPlaceReservationsForSalesEvent.php +++ b/InventoryIndexer/Plugin/InventorySales/EnqueueAfterPlaceReservationsForSalesEvent.php @@ -59,7 +59,7 @@ public function __construct( * Publish reservation data for reindex. * * @param PlaceReservationsForSalesEvent $subject - * @param null $result + * @param void $result * @param ItemToSellInterface[] $items * @param SalesChannelInterface $salesChannel * From c2517538086ef1ba1f091c7e6b4ad8ffbcc36bb9 Mon Sep 17 00:00:00 2001 From: oleksandrkravchuk Date: Tue, 19 May 2020 19:27:36 +0200 Subject: [PATCH 20/50] Remove qty check during setQty method. Move Qty check before persist. --- .../Quote/Api/ValidateQtyBeforeSave.php | 65 +++++++++++++++++ .../ValidateQtyBeforePersist.php | 72 +++++++++++++++++++ InventorySales/composer.json | 3 +- InventorySales/etc/di.xml | 6 ++ InventorySales/etc/events.xml | 4 ++ 5 files changed, 149 insertions(+), 1 deletion(-) create mode 100644 InventorySales/Plugin/Quote/Api/ValidateQtyBeforeSave.php create mode 100644 InventorySales/Plugin/Quote/Model/Quote/Item/CartItemPersister/ValidateQtyBeforePersist.php diff --git a/InventorySales/Plugin/Quote/Api/ValidateQtyBeforeSave.php b/InventorySales/Plugin/Quote/Api/ValidateQtyBeforeSave.php new file mode 100644 index 000000000000..ec4101481367 --- /dev/null +++ b/InventorySales/Plugin/Quote/Api/ValidateQtyBeforeSave.php @@ -0,0 +1,65 @@ +validator = $validator; + $this->observerFactory = $observerFactory; + } + + /** + * @param CartItemRepositoryInterface $subject + * @param CartItemInterface $item + * + * @return array + * @throws LocalizedException + */ + public function beforeSave(CartItemRepositoryInterface $subject, CartItemInterface $item): array + { + /** @var Event $event */ + $event = $this->observerFactory->create(Event::class, ['data' => ['item' => $item]]); + /** @var Observer $observer */ + $observer = $this->observerFactory->create(Observer::class, ['data' => ['event' => $event]]); + + $this->validator->validate($observer); + + if (!empty($item->getMessage()) && $item->getHasError()) { + throw new LocalizedException(__($item->getMessage())); + } + + return [$item]; + } +} diff --git a/InventorySales/Plugin/Quote/Model/Quote/Item/CartItemPersister/ValidateQtyBeforePersist.php b/InventorySales/Plugin/Quote/Model/Quote/Item/CartItemPersister/ValidateQtyBeforePersist.php new file mode 100644 index 000000000000..e4527a56aaad --- /dev/null +++ b/InventorySales/Plugin/Quote/Model/Quote/Item/CartItemPersister/ValidateQtyBeforePersist.php @@ -0,0 +1,72 @@ +qtyValidator = $validator; + $this->observerFactory = $observerFactory; + } + + /** + * Validate item qty before save. + * + * @param CartItemPersister $subject + * @param CartInterface $quote + * @param CartItemInterface $item + * + * @return array + * @throws LocalizedException + * + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function beforeSave(CartItemPersister $subject, CartInterface $quote, CartItemInterface $item): array + { + /** @var Event $event */ + $event = $this->observerFactory->create(Event::class, ['data' => ['item' => $item]]); + /** @var Observer $observer */ + $observer = $this->observerFactory->create(Observer::class, ['data' => ['event' => $event]]); + + $this->qtyValidator->validate($observer); + if (!empty($item->getMessage()) && $item->getHasError()) { + throw new LocalizedException(__($item->getMessage())); + } + + return [ + $quote, + $item + ]; + } +} diff --git a/InventorySales/composer.json b/InventorySales/composer.json index e6a579643343..f401f79a71e7 100644 --- a/InventorySales/composer.json +++ b/InventorySales/composer.json @@ -19,7 +19,8 @@ "magento/module-sales": "*" }, "suggest": { - "magento/module-inventory-catalog": "*" + "magento/module-inventory-catalog": "*", + "magento/module-quote": "*" }, "require-dev": { "magento/module-inventory-indexer": "*" diff --git a/InventorySales/etc/di.xml b/InventorySales/etc/di.xml index e98fa584ef90..b664f83a2817 100644 --- a/InventorySales/etc/di.xml +++ b/InventorySales/etc/di.xml @@ -189,4 +189,10 @@ + + + + + + diff --git a/InventorySales/etc/events.xml b/InventorySales/etc/events.xml index 63cfbdac4429..5d7a1bcbb668 100644 --- a/InventorySales/etc/events.xml +++ b/InventorySales/etc/events.xml @@ -23,4 +23,8 @@ + + + + From e5aaae50d347f369352312bfdebca5afa6532341 Mon Sep 17 00:00:00 2001 From: Maksym Novik Date: Tue, 19 May 2020 21:59:31 +0300 Subject: [PATCH 21/50] [Async Salable Status] Moved product salability calculation from observer to plugin method to be executed on demand. --- .../AdaptAssignStatusToProductPlugin.php | 96 --------------- InventoryBundleProduct/etc/di.xml | 3 - InventoryCatalog/Model/IsProductSalable.php | 67 +++++++++++ .../Model/Product/AfterGetIsSaleable.php | 49 ++++++++ .../Model/Product/Type/AfterGetIsSaleable.php | 43 +++++++ .../AdaptAssignStatusToProductPlugin.php | 110 ------------------ InventoryCatalog/etc/di.xml | 7 +- InventoryCatalog/etc/events.xml | 12 ++ .../AdaptAssignStatusToProductPlugin.php | 97 --------------- .../etc/frontend/di.xml | 3 - 10 files changed, 177 insertions(+), 310 deletions(-) delete mode 100644 InventoryBundleProduct/Plugin/CatalogInventory/Helper/Stock/AdaptAssignStatusToProductPlugin.php create mode 100644 InventoryCatalog/Model/IsProductSalable.php create mode 100644 InventoryCatalog/Plugin/Catalog/Model/Product/AfterGetIsSaleable.php create mode 100644 InventoryCatalog/Plugin/Catalog/Model/Product/Type/AfterGetIsSaleable.php delete mode 100644 InventoryCatalog/Plugin/CatalogInventory/Helper/Stock/AdaptAssignStatusToProductPlugin.php create mode 100644 InventoryCatalog/etc/events.xml delete mode 100644 InventoryConfigurableProduct/Plugin/CatalogInventory/Helper/Stock/AdaptAssignStatusToProductPlugin.php diff --git a/InventoryBundleProduct/Plugin/CatalogInventory/Helper/Stock/AdaptAssignStatusToProductPlugin.php b/InventoryBundleProduct/Plugin/CatalogInventory/Helper/Stock/AdaptAssignStatusToProductPlugin.php deleted file mode 100644 index 5e95a438df8a..000000000000 --- a/InventoryBundleProduct/Plugin/CatalogInventory/Helper/Stock/AdaptAssignStatusToProductPlugin.php +++ /dev/null @@ -1,96 +0,0 @@ -bundleProductType = $bundleProductType; - $this->getBundleProductStockStatus = $getBundleProductStockStatus; - $this->storeManager = $storeManager; - $this->stockResolver = $stockResolver; - } - - /** - * Process bundle product stock status, considering bundle selections. - * - * @param Stock $subject - * @param Product $product - * @param int|null $status - * @return array - * @throws LocalizedException - * @throws NoSuchEntityException - * @SuppressWarnings(PHPMD.UnusedFormalParameter) - */ - public function beforeAssignStatusToProduct( - Stock $subject, - Product $product, - $status = null - ): array { - if ($product->getTypeId() === Type::TYPE_CODE) { - $website = $this->storeManager->getWebsite(); - $stock = $this->stockResolver->execute(SalesChannelInterface::TYPE_WEBSITE, $website->getCode()); - $options = $this->bundleProductType->getOptionsCollection($product); - try { - $status = (int)$this->getBundleProductStockStatus->execute( - $product, - $options->getItems(), - $stock->getStockId() - ); - } catch (LocalizedException $e) { - $status = 0; - } - } - - return [$product, $status]; - } -} diff --git a/InventoryBundleProduct/etc/di.xml b/InventoryBundleProduct/etc/di.xml index 622c345aecdb..e4ace09948a9 100644 --- a/InventoryBundleProduct/etc/di.xml +++ b/InventoryBundleProduct/etc/di.xml @@ -26,7 +26,4 @@ - - - diff --git a/InventoryCatalog/Model/IsProductSalable.php b/InventoryCatalog/Model/IsProductSalable.php new file mode 100644 index 000000000000..fdebd5a3790d --- /dev/null +++ b/InventoryCatalog/Model/IsProductSalable.php @@ -0,0 +1,67 @@ +getStockIdForCurrentWebsite = $getStockIdForCurrentWebsite; + $this->areProductsSalable = $areProductsSalable; + } + + /** + * @param Product $product + * + * @return bool + */ + public function execute(Product $product): bool + { + $salabilityStatus = false; + if ($product->getSku() !== null) { + $stockId = $this->getStockIdForCurrentWebsite->execute(); + if (isset($this->productStatusCache[$stockId][$product->getSku()])) { + return $this->productStatusCache[$stockId][$product->getSku()]; + } + + $stockId = $this->getStockIdForCurrentWebsite->execute(); + $result = current($this->areProductsSalable->execute([$product->getSku()], $stockId)); + $salabilityStatus = $result->isSalable(); + $this->productStatusCache[$stockId][$product->getSku()] = $salabilityStatus; + } + + return $salabilityStatus; + } +} diff --git a/InventoryCatalog/Plugin/Catalog/Model/Product/AfterGetIsSaleable.php b/InventoryCatalog/Plugin/Catalog/Model/Product/AfterGetIsSaleable.php new file mode 100644 index 000000000000..e2348e68916f --- /dev/null +++ b/InventoryCatalog/Plugin/Catalog/Model/Product/AfterGetIsSaleable.php @@ -0,0 +1,49 @@ +isProductSalable = $isProductSalable; + } + + /** + * @param Product $product + * + * @return bool + */ + public function aroundGetIsSalable(Product $product): bool + { + return $this->isProductSalable->execute($product); + } + + /** + * @param Product $product + * + * @return bool + */ + public function aroundIsSalable(Product $product): bool + { + return $this->isProductSalable->execute($product); + } +} diff --git a/InventoryCatalog/Plugin/Catalog/Model/Product/Type/AfterGetIsSaleable.php b/InventoryCatalog/Plugin/Catalog/Model/Product/Type/AfterGetIsSaleable.php new file mode 100644 index 000000000000..535a29656881 --- /dev/null +++ b/InventoryCatalog/Plugin/Catalog/Model/Product/Type/AfterGetIsSaleable.php @@ -0,0 +1,43 @@ +isProductSalable = $isProductSalable; + } + + /** + * @param AbstractType $subject + * @param callable $proceed + * @param Product $product + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * + * @return bool + */ + public function aroundIsSalable(AbstractType $subject, callable $proceed, $product): bool + { + return $this->isProductSalable->execute($product); + } +} diff --git a/InventoryCatalog/Plugin/CatalogInventory/Helper/Stock/AdaptAssignStatusToProductPlugin.php b/InventoryCatalog/Plugin/CatalogInventory/Helper/Stock/AdaptAssignStatusToProductPlugin.php deleted file mode 100644 index 9c6a40de4ff0..000000000000 --- a/InventoryCatalog/Plugin/CatalogInventory/Helper/Stock/AdaptAssignStatusToProductPlugin.php +++ /dev/null @@ -1,110 +0,0 @@ -getStockIdForCurrentWebsite = $getStockIdForCurrentWebsite; - $this->areProductsSalable = $areProductsSalable; - $this->defaultStockProvider = $defaultStockProvider; - $this->getProductIdsBySkus = $getProductIdsBySkus; - } - - /** - * Assign stock status to product considering multi stock environment. - * - * @param Stock $subject - * @param callable $proceed - * @param Product $product - * @param int|null $status - * @return void - * - * @SuppressWarnings(PHPMD.UnusedFormalParameter) - */ - public function aroundAssignStatusToProduct( - Stock $subject, - callable $proceed, - Product $product, - $status = null - ) { - if (null === $product->getSku()) { - return; - } - - $stockId = $this->getStockIdForCurrentWebsite->execute(); - if (isset($this->productStatus[$stockId][$product->getSku()])) { - $proceed($product, $this->productStatus[$stockId][$product->getSku()]); - return; - } - - try { - $productIds = $this->getProductIdsBySkus->execute([$product->getSku()]); - $productId = current($productIds); - - if (null === $status) { - $stockId = $this->getStockIdForCurrentWebsite->execute(); - $result = $this->areProductsSalable->execute([$product->getSku()], $stockId); - $result = current($result); - $status = (int)$result->isSalable(); - $this->productStatus[$stockId][$productId] = $status; - } - - $proceed($product, $status); - } catch (NoSuchEntityException $e) { - return; - } - } -} diff --git a/InventoryCatalog/etc/di.xml b/InventoryCatalog/etc/di.xml index 1c6eb311d1a8..9543320c9416 100644 --- a/InventoryCatalog/etc/di.xml +++ b/InventoryCatalog/etc/di.xml @@ -50,7 +50,6 @@ - @@ -162,4 +161,10 @@ + + + + + + diff --git a/InventoryCatalog/etc/events.xml b/InventoryCatalog/etc/events.xml new file mode 100644 index 000000000000..3ff4e7df341a --- /dev/null +++ b/InventoryCatalog/etc/events.xml @@ -0,0 +1,12 @@ + + + + + + + diff --git a/InventoryConfigurableProduct/Plugin/CatalogInventory/Helper/Stock/AdaptAssignStatusToProductPlugin.php b/InventoryConfigurableProduct/Plugin/CatalogInventory/Helper/Stock/AdaptAssignStatusToProductPlugin.php deleted file mode 100644 index 68449ceca0ef..000000000000 --- a/InventoryConfigurableProduct/Plugin/CatalogInventory/Helper/Stock/AdaptAssignStatusToProductPlugin.php +++ /dev/null @@ -1,97 +0,0 @@ -configurable = $configurable; - $this->areProductsSalable = $areProductsSalable; - $this->storeManager = $storeManager; - $this->stockResolver = $stockResolver; - } - - /** - * Process configurable product stock status, considering configurable options. - * - * @param Stock $subject - * @param Product $product - * @param int|null $status - * @return array - * - * @SuppressWarnings(PHPMD.UnusedFormalParameter) - */ - public function beforeAssignStatusToProduct( - Stock $subject, - Product $product, - $status = null - ): array { - if ($product->getTypeId() === Configurable::TYPE_CODE) { - $website = $this->storeManager->getWebsite(); - $stock = $this->stockResolver->execute(SalesChannelInterface::TYPE_WEBSITE, $website->getCode()); - $options = $this->configurable->getConfigurableOptions($product); - $status = 0; - $skus = [[]]; - foreach ($options as $attribute) { - $skus[] = array_column($attribute, 'sku'); - } - $skus = array_merge(...$skus); - $results = $this->areProductsSalable->execute($skus, $stock->getStockId()); - foreach ($results as $result) { - if ($result->isSalable()) { - $status = 1; - break; - } - } - } - - return [$product, $status]; - } -} diff --git a/InventoryConfigurableProduct/etc/frontend/di.xml b/InventoryConfigurableProduct/etc/frontend/di.xml index e2e71d3e3cdf..68515ce01275 100644 --- a/InventoryConfigurableProduct/etc/frontend/di.xml +++ b/InventoryConfigurableProduct/etc/frontend/di.xml @@ -12,7 +12,4 @@ - - - From 90c3f0afc6f27677129c29c98e387f89fcd95814 Mon Sep 17 00:00:00 2001 From: Maksym Novik Date: Wed, 20 May 2020 18:16:26 +0300 Subject: [PATCH 22/50] [Async Salable Status] Moved plugins to isAvailable only. --- ...AfterGetIsSaleable.php => IsAvailable.php} | 14 +----- .../Model/Product/Type/AfterGetIsSaleable.php | 43 ------------------- InventoryCatalog/etc/di.xml | 5 +-- 3 files changed, 3 insertions(+), 59 deletions(-) rename InventoryCatalog/Plugin/Catalog/Model/Product/{AfterGetIsSaleable.php => IsAvailable.php} (71%) delete mode 100644 InventoryCatalog/Plugin/Catalog/Model/Product/Type/AfterGetIsSaleable.php diff --git a/InventoryCatalog/Plugin/Catalog/Model/Product/AfterGetIsSaleable.php b/InventoryCatalog/Plugin/Catalog/Model/Product/IsAvailable.php similarity index 71% rename from InventoryCatalog/Plugin/Catalog/Model/Product/AfterGetIsSaleable.php rename to InventoryCatalog/Plugin/Catalog/Model/Product/IsAvailable.php index e2348e68916f..59f208f500a1 100644 --- a/InventoryCatalog/Plugin/Catalog/Model/Product/AfterGetIsSaleable.php +++ b/InventoryCatalog/Plugin/Catalog/Model/Product/IsAvailable.php @@ -11,7 +11,7 @@ use Magento\Catalog\Model\Product; use Magento\InventoryCatalog\Model\IsProductSalable; -class AfterGetIsSaleable +class IsAvailable { /** * @var IsProductSalable @@ -32,17 +32,7 @@ public function __construct( * * @return bool */ - public function aroundGetIsSalable(Product $product): bool - { - return $this->isProductSalable->execute($product); - } - - /** - * @param Product $product - * - * @return bool - */ - public function aroundIsSalable(Product $product): bool + public function aroundIsAvailable(Product $product): bool { return $this->isProductSalable->execute($product); } diff --git a/InventoryCatalog/Plugin/Catalog/Model/Product/Type/AfterGetIsSaleable.php b/InventoryCatalog/Plugin/Catalog/Model/Product/Type/AfterGetIsSaleable.php deleted file mode 100644 index 535a29656881..000000000000 --- a/InventoryCatalog/Plugin/Catalog/Model/Product/Type/AfterGetIsSaleable.php +++ /dev/null @@ -1,43 +0,0 @@ -isProductSalable = $isProductSalable; - } - - /** - * @param AbstractType $subject - * @param callable $proceed - * @param Product $product - * @SuppressWarnings(PHPMD.UnusedFormalParameter) - * - * @return bool - */ - public function aroundIsSalable(AbstractType $subject, callable $proceed, $product): bool - { - return $this->isProductSalable->execute($product); - } -} diff --git a/InventoryCatalog/etc/di.xml b/InventoryCatalog/etc/di.xml index 9543320c9416..168ac227336d 100644 --- a/InventoryCatalog/etc/di.xml +++ b/InventoryCatalog/etc/di.xml @@ -162,9 +162,6 @@ - - - - + From 15d5049e31f7a1177aeb9c4c32423c8183845ab8 Mon Sep 17 00:00:00 2001 From: Stanislav Idolov Date: Thu, 21 May 2020 13:37:53 -0500 Subject: [PATCH 23/50] Fixed plugin configuration --- InventorySales/etc/di.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/InventorySales/etc/di.xml b/InventorySales/etc/di.xml index 44e03fda3feb..830ee0f8644d 100644 --- a/InventorySales/etc/di.xml +++ b/InventorySales/etc/di.xml @@ -198,6 +198,6 @@ - + From 25859d0d49235990b8208b94afced6944cde951f Mon Sep 17 00:00:00 2001 From: nmalevanec Date: Fri, 22 May 2020 14:01:20 +0300 Subject: [PATCH 24/50] Fix tests. --- InventoryCatalog/Model/IsProductSalable.php | 33 +++++++++++-------- .../Simple/IsSalablePlugin.php} | 17 +++++++--- InventoryCatalog/etc/di.xml | 4 +-- .../Quote/Api/ValidateQtyBeforeSave.php | 3 ++ .../ValidateQtyBeforePersist.php | 3 +- 5 files changed, 37 insertions(+), 23 deletions(-) rename InventoryCatalog/Plugin/Catalog/Model/{Product/IsAvailable.php => Type/Simple/IsSalablePlugin.php} (56%) diff --git a/InventoryCatalog/Model/IsProductSalable.php b/InventoryCatalog/Model/IsProductSalable.php index fdebd5a3790d..79072897c318 100644 --- a/InventoryCatalog/Model/IsProductSalable.php +++ b/InventoryCatalog/Model/IsProductSalable.php @@ -9,9 +9,11 @@ namespace Magento\InventoryCatalog\Model; use Magento\Catalog\Model\Product; -use Magento\InventoryCatalogApi\Model\GetProductIdsBySkusInterface; use Magento\InventorySalesApi\Api\AreProductsSalableInterface; +/** + * Get salable product status service. + */ class IsProductSalable { /** @@ -32,7 +34,6 @@ class IsProductSalable /** * @param GetStockIdForCurrentWebsite $getStockIdForCurrentWebsite * @param AreProductsSalableInterface $areProductsSalable - * @param GetProductIdsBySkusInterface $getProductIdsBySkus */ public function __construct( GetStockIdForCurrentWebsite $getStockIdForCurrentWebsite, @@ -43,24 +44,28 @@ public function __construct( } /** - * @param Product $product + * Verify product salable status. * + * @param Product $product * @return bool */ public function execute(Product $product): bool { - $salabilityStatus = false; - if ($product->getSku() !== null) { - $stockId = $this->getStockIdForCurrentWebsite->execute(); - if (isset($this->productStatusCache[$stockId][$product->getSku()])) { - return $this->productStatusCache[$stockId][$product->getSku()]; - } - - $stockId = $this->getStockIdForCurrentWebsite->execute(); - $result = current($this->areProductsSalable->execute([$product->getSku()], $stockId)); - $salabilityStatus = $result->isSalable(); - $this->productStatusCache[$stockId][$product->getSku()] = $salabilityStatus; + if (null === $product->getSku()) { + return false; + } + if ($product->getData('is_salable') !== null) { + return (bool)$product->getData('is_salable'); } + $stockId = $this->getStockIdForCurrentWebsite->execute(); + if (isset($this->productStatusCache[$stockId][$product->getSku()])) { + return $this->productStatusCache[$stockId][$product->getSku()]; + } + + $stockId = $this->getStockIdForCurrentWebsite->execute(); + $result = current($this->areProductsSalable->execute([$product->getSku()], $stockId)); + $salabilityStatus = $result->isSalable(); + $this->productStatusCache[$stockId][$product->getSku()] = $salabilityStatus; return $salabilityStatus; } diff --git a/InventoryCatalog/Plugin/Catalog/Model/Product/IsAvailable.php b/InventoryCatalog/Plugin/Catalog/Model/Type/Simple/IsSalablePlugin.php similarity index 56% rename from InventoryCatalog/Plugin/Catalog/Model/Product/IsAvailable.php rename to InventoryCatalog/Plugin/Catalog/Model/Type/Simple/IsSalablePlugin.php index 59f208f500a1..3a6ea88803ef 100644 --- a/InventoryCatalog/Plugin/Catalog/Model/Product/IsAvailable.php +++ b/InventoryCatalog/Plugin/Catalog/Model/Type/Simple/IsSalablePlugin.php @@ -3,15 +3,18 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ - declare(strict_types=1); -namespace Magento\InventoryCatalog\Plugin\Catalog\Model\Product; +namespace Magento\InventoryCatalog\Plugin\Catalog\Model\Type\Simple; use Magento\Catalog\Model\Product; +use Magento\Catalog\Model\Product\Type\Simple; use Magento\InventoryCatalog\Model\IsProductSalable; -class IsAvailable +/** + * Apply the inventory is-salable result to the according method of the product type model. + */ +class IsSalablePlugin { /** * @var IsProductSalable @@ -28,11 +31,15 @@ public function __construct( } /** - * @param Product $product + * Fetches is salable status from multi-stock. * + * @param Simple $subject + * @param \Closure $proceed + * @param Product $product * @return bool + * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ - public function aroundIsAvailable(Product $product): bool + public function aroundIsSalable(Simple $subject, \Closure $proceed, Product $product): bool { return $this->isProductSalable->execute($product); } diff --git a/InventoryCatalog/etc/di.xml b/InventoryCatalog/etc/di.xml index 168ac227336d..9a941f68e143 100644 --- a/InventoryCatalog/etc/di.xml +++ b/InventoryCatalog/etc/di.xml @@ -161,7 +161,7 @@ - - + + diff --git a/InventorySales/Plugin/Quote/Api/ValidateQtyBeforeSave.php b/InventorySales/Plugin/Quote/Api/ValidateQtyBeforeSave.php index ec4101481367..968c9e964b68 100644 --- a/InventorySales/Plugin/Quote/Api/ValidateQtyBeforeSave.php +++ b/InventorySales/Plugin/Quote/Api/ValidateQtyBeforeSave.php @@ -41,11 +41,14 @@ public function __construct(QuantityValidator $validator, ObserverFactory $obser } /** + * Validate qty before save cart item. + * * @param CartItemRepositoryInterface $subject * @param CartItemInterface $item * * @return array * @throws LocalizedException + * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function beforeSave(CartItemRepositoryInterface $subject, CartItemInterface $item): array { diff --git a/InventorySales/Plugin/Quote/Model/Quote/Item/CartItemPersister/ValidateQtyBeforePersist.php b/InventorySales/Plugin/Quote/Model/Quote/Item/CartItemPersister/ValidateQtyBeforePersist.php index e4527a56aaad..9e77ede07553 100644 --- a/InventorySales/Plugin/Quote/Model/Quote/Item/CartItemPersister/ValidateQtyBeforePersist.php +++ b/InventorySales/Plugin/Quote/Model/Quote/Item/CartItemPersister/ValidateQtyBeforePersist.php @@ -17,7 +17,7 @@ use Magento\Quote\Model\Quote\Item\CartItemPersister; /** - * Validate qty before persist. + * Validate cart item qty before persist. */ class ValidateQtyBeforePersist { @@ -49,7 +49,6 @@ public function __construct(QuantityValidator $validator, ObserverFactory $obser * * @return array * @throws LocalizedException - * * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function beforeSave(CartItemPersister $subject, CartInterface $quote, CartItemInterface $item): array From e27d74e9780ab5fcf40e278d578b487c2a6b034e Mon Sep 17 00:00:00 2001 From: nmalevanec Date: Fri, 22 May 2020 19:48:50 +0300 Subject: [PATCH 25/50] Fix tests. --- .../ValidateQtyBeforePersist.php | 20 ++++++++----------- 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/InventorySales/Plugin/Quote/Model/Quote/Item/CartItemPersister/ValidateQtyBeforePersist.php b/InventorySales/Plugin/Quote/Model/Quote/Item/CartItemPersister/ValidateQtyBeforePersist.php index 9e77ede07553..127886c6d960 100644 --- a/InventorySales/Plugin/Quote/Model/Quote/Item/CartItemPersister/ValidateQtyBeforePersist.php +++ b/InventorySales/Plugin/Quote/Model/Quote/Item/CartItemPersister/ValidateQtyBeforePersist.php @@ -53,19 +53,15 @@ public function __construct(QuantityValidator $validator, ObserverFactory $obser */ public function beforeSave(CartItemPersister $subject, CartInterface $quote, CartItemInterface $item): array { - /** @var Event $event */ - $event = $this->observerFactory->create(Event::class, ['data' => ['item' => $item]]); - /** @var Observer $observer */ - $observer = $this->observerFactory->create(Observer::class, ['data' => ['event' => $event]]); - - $this->qtyValidator->validate($observer); - if (!empty($item->getMessage()) && $item->getHasError()) { - throw new LocalizedException(__($item->getMessage())); + if ($quote->getIsActive()) { + $event = $this->observerFactory->create(Event::class, ['data' => ['item' => $item]]); + $observer = $this->observerFactory->create(Observer::class, ['data' => ['event' => $event]]); + $this->qtyValidator->validate($observer); + if (!empty($item->getMessage()) && $item->getHasError()) { + throw new LocalizedException(__($item->getMessage())); + } } - return [ - $quote, - $item - ]; + return [$quote, $item]; } } From 372ac737c3e8dfc6644d2c9492b153a2eedc718f Mon Sep 17 00:00:00 2001 From: Stanislav Idolov Date: Sat, 23 May 2020 09:53:28 -0500 Subject: [PATCH 26/50] Fix salable logic --- .../ProductOptionsCondition.php | 67 +++++++++++++++++ InventoryBundleProduct/etc/di.xml | 10 +++ .../IsAvailablePlugin.php} | 10 ++- .../Catalog/Model/Product/IsSalablePlugin.php | 41 +++++++++++ InventoryCatalog/etc/di.xml | 5 +- .../ProductOptionsCondition.php | 71 +++++++++++++++++++ InventoryConfigurableProduct/etc/di.xml | 10 +++ .../StatusCondition.php | 36 ++++++++++ InventorySales/etc/di.xml | 4 ++ 9 files changed, 246 insertions(+), 8 deletions(-) create mode 100644 InventoryBundleProduct/Model/IsProductSalableCondition/ProductOptionsCondition.php rename InventoryCatalog/Plugin/Catalog/Model/{Type/Simple/IsSalablePlugin.php => Product/IsAvailablePlugin.php} (75%) create mode 100644 InventoryCatalog/Plugin/Catalog/Model/Product/IsSalablePlugin.php create mode 100644 InventoryConfigurableProduct/Model/IsProductSalableCondition/ProductOptionsCondition.php create mode 100644 InventorySales/Model/IsProductSalableCondition/StatusCondition.php diff --git a/InventoryBundleProduct/Model/IsProductSalableCondition/ProductOptionsCondition.php b/InventoryBundleProduct/Model/IsProductSalableCondition/ProductOptionsCondition.php new file mode 100644 index 000000000000..bf0599b72c48 --- /dev/null +++ b/InventoryBundleProduct/Model/IsProductSalableCondition/ProductOptionsCondition.php @@ -0,0 +1,67 @@ +type = $type; + $this->productRepository = $productRepository; + $this->getBundleProductStockStatus = $getBundleProductStockStatus; + } + + /** + * @inheritdoc + */ + public function execute(string $sku, int $stockId): bool + { + $status = true; + $product = $this->productRepository->get($sku); + + if ($product->getTypeId() === Type::TYPE_CODE) { + $options = $this->type->getOptionsCollection($product); + try { + $status = $this->getBundleProductStockStatus->execute($product, $options->getItems(), $stockId); + } catch (LocalizedException $e) { + $status = false; + } + } + return $status; + } +} diff --git a/InventoryBundleProduct/etc/di.xml b/InventoryBundleProduct/etc/di.xml index e4ace09948a9..b1f8b5cf43d8 100644 --- a/InventoryBundleProduct/etc/di.xml +++ b/InventoryBundleProduct/etc/di.xml @@ -26,4 +26,14 @@ + + + + + true + Magento\InventoryBundleProduct\Model\IsProductSalableCondition\ProductOptionsCondition + + + + diff --git a/InventoryCatalog/Plugin/Catalog/Model/Type/Simple/IsSalablePlugin.php b/InventoryCatalog/Plugin/Catalog/Model/Product/IsAvailablePlugin.php similarity index 75% rename from InventoryCatalog/Plugin/Catalog/Model/Type/Simple/IsSalablePlugin.php rename to InventoryCatalog/Plugin/Catalog/Model/Product/IsAvailablePlugin.php index 3a6ea88803ef..7e024826844f 100644 --- a/InventoryCatalog/Plugin/Catalog/Model/Type/Simple/IsSalablePlugin.php +++ b/InventoryCatalog/Plugin/Catalog/Model/Product/IsAvailablePlugin.php @@ -5,16 +5,14 @@ */ declare(strict_types=1); -namespace Magento\InventoryCatalog\Plugin\Catalog\Model\Type\Simple; +namespace Magento\InventoryCatalog\Plugin\Catalog\Model\Product; use Magento\Catalog\Model\Product; use Magento\Catalog\Model\Product\Type\Simple; use Magento\InventoryCatalog\Model\IsProductSalable; -/** - * Apply the inventory is-salable result to the according method of the product type model. - */ -class IsSalablePlugin + +class IsAvailablePlugin { /** * @var IsProductSalable @@ -39,7 +37,7 @@ public function __construct( * @return bool * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ - public function aroundIsSalable(Simple $subject, \Closure $proceed, Product $product): bool + public function aroundIsAvailable(Product $product): bool { return $this->isProductSalable->execute($product); } diff --git a/InventoryCatalog/Plugin/Catalog/Model/Product/IsSalablePlugin.php b/InventoryCatalog/Plugin/Catalog/Model/Product/IsSalablePlugin.php new file mode 100644 index 000000000000..25913986e5cf --- /dev/null +++ b/InventoryCatalog/Plugin/Catalog/Model/Product/IsSalablePlugin.php @@ -0,0 +1,41 @@ +isProductSalable = $isProductSalable; + } + + /** + * Fetches is salable status from multi-stock. + * + * @param Product $product + * @return bool + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function aroundIsSalable(Product $product): bool + { + return $this->isProductSalable->execute($product); + } +} diff --git a/InventoryCatalog/etc/di.xml b/InventoryCatalog/etc/di.xml index 9a941f68e143..6a559b19e0e1 100644 --- a/InventoryCatalog/etc/di.xml +++ b/InventoryCatalog/etc/di.xml @@ -161,7 +161,8 @@ - - + + + diff --git a/InventoryConfigurableProduct/Model/IsProductSalableCondition/ProductOptionsCondition.php b/InventoryConfigurableProduct/Model/IsProductSalableCondition/ProductOptionsCondition.php new file mode 100644 index 000000000000..b056460baa67 --- /dev/null +++ b/InventoryConfigurableProduct/Model/IsProductSalableCondition/ProductOptionsCondition.php @@ -0,0 +1,71 @@ +type = $type; + $this->productRepository = $productRepository; + $this->areProductsSalable = $areProductsSalable; + } + /** + * @inheritdoc + */ + public function execute(string $sku, int $stockId): bool + { + $status = true; + $product = $this->productRepository->get($sku); + + if ($product->getTypeId() === Configurable::TYPE_CODE) { + $status = false; + $options = $this->type->getConfigurableOptions($product); + $skus = [[]]; + foreach ($options as $attribute) { + $skus[] = array_column($attribute, 'sku'); + } + $skus = array_merge(...$skus); + $results = $this->areProductsSalable->execute($skus, $stockId); + foreach ($results as $result) { + if ($result->isSalable()) { + $status = true; + break; + } + } + } + return $status; + } +} diff --git a/InventoryConfigurableProduct/etc/di.xml b/InventoryConfigurableProduct/etc/di.xml index 77358c2d991e..fa7543ecc50f 100644 --- a/InventoryConfigurableProduct/etc/di.xml +++ b/InventoryConfigurableProduct/etc/di.xml @@ -26,4 +26,14 @@ + + + + + true + Magento\InventoryConfigurableProduct\Model\IsProductSalableCondition\ProductOptionsCondition + + + + diff --git a/InventorySales/Model/IsProductSalableCondition/StatusCondition.php b/InventorySales/Model/IsProductSalableCondition/StatusCondition.php new file mode 100644 index 000000000000..7057b2541339 --- /dev/null +++ b/InventorySales/Model/IsProductSalableCondition/StatusCondition.php @@ -0,0 +1,36 @@ +productRepository = $productRepository; + } + + /** + * @inheritdoc + */ + public function execute(string $sku, int $stockId): bool + { + $product = $this->productRepository->get($sku); + return $product->getStatus() === \Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED; + } +} diff --git a/InventorySales/etc/di.xml b/InventorySales/etc/di.xml index 830ee0f8644d..2e8c536396a8 100644 --- a/InventorySales/etc/di.xml +++ b/InventorySales/etc/di.xml @@ -57,6 +57,10 @@ + + true + Magento\InventorySales\Model\IsProductSalableCondition\StatusCondition + true Magento\InventorySales\Model\IsProductSalableCondition\IsSetInStockStatusForCompositeProductCondition From f761396ce07507903a148600e67c6bfa5af3d25e Mon Sep 17 00:00:00 2001 From: Stanislav Idolov Date: Sun, 24 May 2020 08:32:21 -0500 Subject: [PATCH 27/50] Disable configurable condition --- InventoryConfigurableProduct/etc/di.xml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/InventoryConfigurableProduct/etc/di.xml b/InventoryConfigurableProduct/etc/di.xml index fa7543ecc50f..a88bf8f8f193 100644 --- a/InventoryConfigurableProduct/etc/di.xml +++ b/InventoryConfigurableProduct/etc/di.xml @@ -26,14 +26,14 @@ - - - - - true - Magento\InventoryConfigurableProduct\Model\IsProductSalableCondition\ProductOptionsCondition - - - - + + + + + + + + + + From a06648d5d44750ff9caf42528f2511c3f43b94ff Mon Sep 17 00:00:00 2001 From: nmalevanec Date: Mon, 25 May 2020 10:46:57 +0300 Subject: [PATCH 28/50] Fix tests. --- InventoryBundleProduct/composer.json | 3 +- .../Model/Product/IsAvailablePlugin.php | 12 ++-- .../Catalog/Model/Product/IsSalablePlugin.php | 4 +- .../StatusCondition.php | 8 ++- .../ValidateQtyBeforePersist.php | 67 ------------------- .../Quote/Item/ValidateQtyBeforePersist.php} | 42 +++++------- InventorySales/etc/di.xml | 7 +- 7 files changed, 35 insertions(+), 108 deletions(-) delete mode 100644 InventorySales/Plugin/Quote/Model/Quote/Item/CartItemPersister/ValidateQtyBeforePersist.php rename InventorySales/Plugin/Quote/{Api/ValidateQtyBeforeSave.php => Model/Quote/Item/ValidateQtyBeforePersist.php} (52%) diff --git a/InventoryBundleProduct/composer.json b/InventoryBundleProduct/composer.json index 3c27572ebecc..d101f485dbf2 100644 --- a/InventoryBundleProduct/composer.json +++ b/InventoryBundleProduct/composer.json @@ -13,7 +13,8 @@ "magento/module-store": "*" }, "suggest": { - "magento/module-catalog-inventory": "*" + "magento/module-catalog-inventory": "*", + "magento/module-inventory-sales": "*" }, "type": "magento2-module", "license": [ diff --git a/InventoryCatalog/Plugin/Catalog/Model/Product/IsAvailablePlugin.php b/InventoryCatalog/Plugin/Catalog/Model/Product/IsAvailablePlugin.php index 7e024826844f..e4dda555376b 100644 --- a/InventoryCatalog/Plugin/Catalog/Model/Product/IsAvailablePlugin.php +++ b/InventoryCatalog/Plugin/Catalog/Model/Product/IsAvailablePlugin.php @@ -8,10 +8,11 @@ namespace Magento\InventoryCatalog\Plugin\Catalog\Model\Product; use Magento\Catalog\Model\Product; -use Magento\Catalog\Model\Product\Type\Simple; use Magento\InventoryCatalog\Model\IsProductSalable; - +/** + * Is product available in multi stock environment plugin. + */ class IsAvailablePlugin { /** @@ -31,14 +32,13 @@ public function __construct( /** * Fetches is salable status from multi-stock. * - * @param Simple $subject + * @param Product $subject * @param \Closure $proceed - * @param Product $product * @return bool * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ - public function aroundIsAvailable(Product $product): bool + public function aroundIsAvailable(Product $subject, \Closure $proceed): bool { - return $this->isProductSalable->execute($product); + return $this->isProductSalable->execute($subject); } } diff --git a/InventoryCatalog/Plugin/Catalog/Model/Product/IsSalablePlugin.php b/InventoryCatalog/Plugin/Catalog/Model/Product/IsSalablePlugin.php index 25913986e5cf..1c8b7a96a473 100644 --- a/InventoryCatalog/Plugin/Catalog/Model/Product/IsSalablePlugin.php +++ b/InventoryCatalog/Plugin/Catalog/Model/Product/IsSalablePlugin.php @@ -8,7 +8,6 @@ namespace Magento\InventoryCatalog\Plugin\Catalog\Model\Product; use Magento\Catalog\Model\Product; -use Magento\Catalog\Model\Product\Type\Simple; use Magento\InventoryCatalog\Model\IsProductSalable; class IsSalablePlugin @@ -31,10 +30,11 @@ public function __construct( * Fetches is salable status from multi-stock. * * @param Product $product + * @param \Closure $proceed * @return bool * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ - public function aroundIsSalable(Product $product): bool + public function aroundIsSalable(Product $product, \Closure $proceed): bool { return $this->isProductSalable->execute($product); } diff --git a/InventorySales/Model/IsProductSalableCondition/StatusCondition.php b/InventorySales/Model/IsProductSalableCondition/StatusCondition.php index 7057b2541339..6f0696057dbe 100644 --- a/InventorySales/Model/IsProductSalableCondition/StatusCondition.php +++ b/InventorySales/Model/IsProductSalableCondition/StatusCondition.php @@ -6,9 +6,13 @@ namespace Magento\InventorySales\Model\IsProductSalableCondition; +use Magento\Catalog\Model\Product\Attribute\Source\Status; use Magento\Catalog\Model\ProductRepository; use Magento\InventorySalesApi\Api\IsProductSalableInterface; +/** + * Is product enabled condition. + */ class StatusCondition implements IsProductSalableInterface { /** @@ -17,7 +21,6 @@ class StatusCondition implements IsProductSalableInterface private $productRepository; /** - * StatusCondition constructor. * @param ProductRepository $productRepository */ public function __construct(ProductRepository $productRepository) @@ -30,7 +33,6 @@ public function __construct(ProductRepository $productRepository) */ public function execute(string $sku, int $stockId): bool { - $product = $this->productRepository->get($sku); - return $product->getStatus() === \Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED; + return (int)$this->productRepository->get($sku)->getStatus() === Status::STATUS_ENABLED; } } diff --git a/InventorySales/Plugin/Quote/Model/Quote/Item/CartItemPersister/ValidateQtyBeforePersist.php b/InventorySales/Plugin/Quote/Model/Quote/Item/CartItemPersister/ValidateQtyBeforePersist.php deleted file mode 100644 index 127886c6d960..000000000000 --- a/InventorySales/Plugin/Quote/Model/Quote/Item/CartItemPersister/ValidateQtyBeforePersist.php +++ /dev/null @@ -1,67 +0,0 @@ -qtyValidator = $validator; - $this->observerFactory = $observerFactory; - } - - /** - * Validate item qty before save. - * - * @param CartItemPersister $subject - * @param CartInterface $quote - * @param CartItemInterface $item - * - * @return array - * @throws LocalizedException - * @SuppressWarnings(PHPMD.UnusedFormalParameter) - */ - public function beforeSave(CartItemPersister $subject, CartInterface $quote, CartItemInterface $item): array - { - if ($quote->getIsActive()) { - $event = $this->observerFactory->create(Event::class, ['data' => ['item' => $item]]); - $observer = $this->observerFactory->create(Observer::class, ['data' => ['event' => $event]]); - $this->qtyValidator->validate($observer); - if (!empty($item->getMessage()) && $item->getHasError()) { - throw new LocalizedException(__($item->getMessage())); - } - } - - return [$quote, $item]; - } -} diff --git a/InventorySales/Plugin/Quote/Api/ValidateQtyBeforeSave.php b/InventorySales/Plugin/Quote/Model/Quote/Item/ValidateQtyBeforePersist.php similarity index 52% rename from InventorySales/Plugin/Quote/Api/ValidateQtyBeforeSave.php rename to InventorySales/Plugin/Quote/Model/Quote/Item/ValidateQtyBeforePersist.php index 968c9e964b68..a3aad885926d 100644 --- a/InventorySales/Plugin/Quote/Api/ValidateQtyBeforeSave.php +++ b/InventorySales/Plugin/Quote/Model/Quote/Item/ValidateQtyBeforePersist.php @@ -5,25 +5,24 @@ */ declare(strict_types=1); -namespace Magento\InventorySales\Plugin\Quote\Api; +namespace Magento\InventorySales\Plugin\Quote\Model\Quote\Item; use Magento\CatalogInventory\Model\Quote\Item\QuantityValidator; use Magento\Framework\Event; use Magento\Framework\Event\Observer; use Magento\Framework\Event\ObserverFactory; use Magento\Framework\Exception\LocalizedException; -use Magento\Quote\Api\CartItemRepositoryInterface; -use Magento\Quote\Api\Data\CartItemInterface; +use Magento\Quote\Model\Quote\Item; /** - * Validate item qty before save. + * Validate cart item qty before persist. */ -class ValidateQtyBeforeSave +class ValidateQtyBeforePersist { /** * @var QuantityValidator */ - private $validator; + private $qtyValidator; /** * @var ObserverFactory @@ -36,33 +35,28 @@ class ValidateQtyBeforeSave */ public function __construct(QuantityValidator $validator, ObserverFactory $observerFactory) { - $this->validator = $validator; + $this->qtyValidator = $validator; $this->observerFactory = $observerFactory; } /** - * Validate qty before save cart item. + * Validate item qty before save. * - * @param CartItemRepositoryInterface $subject - * @param CartItemInterface $item - * - * @return array + * @param Item $subject + * @return void * @throws LocalizedException - * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ - public function beforeSave(CartItemRepositoryInterface $subject, CartItemInterface $item): array + public function beforeBeforeSave(Item $subject): void { - /** @var Event $event */ - $event = $this->observerFactory->create(Event::class, ['data' => ['item' => $item]]); - /** @var Observer $observer */ + $quote = $subject->getQuote(); + if ($quote->getIsActive() === false) { + return; + } + $event = $this->observerFactory->create(Event::class, ['data' => ['item' => $subject]]); $observer = $this->observerFactory->create(Observer::class, ['data' => ['event' => $event]]); - - $this->validator->validate($observer); - - if (!empty($item->getMessage()) && $item->getHasError()) { - throw new LocalizedException(__($item->getMessage())); + $this->qtyValidator->validate($observer); + if (!empty($subject->getMessage()) && $subject->getHasError()) { + throw new LocalizedException(__($subject->getMessage())); } - - return [$item]; } } diff --git a/InventorySales/etc/di.xml b/InventorySales/etc/di.xml index 2e8c536396a8..9c212d61b9d0 100644 --- a/InventorySales/etc/di.xml +++ b/InventorySales/etc/di.xml @@ -198,10 +198,7 @@ - - - - - + + From 9aea1b437c31ccc6275f9000daa48d536f05de55 Mon Sep 17 00:00:00 2001 From: nmalevanec Date: Mon, 25 May 2020 19:08:11 +0300 Subject: [PATCH 29/50] Fix tests. --- .../Model/IsAnyConfigurableOptionSalable.php | 69 +++++++++++++++++++ .../ProductOptionsCondition.php | 41 ++++------- InventoryConfigurableProduct/etc/di.xml | 20 +++--- 3 files changed, 91 insertions(+), 39 deletions(-) create mode 100644 InventoryConfigurableProduct/Model/IsAnyConfigurableOptionSalable.php diff --git a/InventoryConfigurableProduct/Model/IsAnyConfigurableOptionSalable.php b/InventoryConfigurableProduct/Model/IsAnyConfigurableOptionSalable.php new file mode 100644 index 000000000000..fddda1042445 --- /dev/null +++ b/InventoryConfigurableProduct/Model/IsAnyConfigurableOptionSalable.php @@ -0,0 +1,69 @@ +type = $type; + $this->areProductsSalable = $areProductsSalable; + } + + /** + * Verify if any configurable product options is salable for given stock. + * + * @param ProductInterface $product + * @param int $stockId + * @return bool + */ + public function execute(ProductInterface $product, int $stockId): bool + { + $status = false; + $options = $this->type->getConfigurableOptions($product); + $skus = [[]]; + foreach ($options as $attribute) { + $skus[] = array_column($attribute, 'sku'); + } + $skus = array_merge(...$skus); + $results = $this->areProductsSalable->execute($skus, $stockId); + foreach ($results as $result) { + if ($result->isSalable()) { + $status = true; + break; + } + } + + return $status; + } +} diff --git a/InventoryConfigurableProduct/Model/IsProductSalableCondition/ProductOptionsCondition.php b/InventoryConfigurableProduct/Model/IsProductSalableCondition/ProductOptionsCondition.php index b056460baa67..09b955f71b5e 100644 --- a/InventoryConfigurableProduct/Model/IsProductSalableCondition/ProductOptionsCondition.php +++ b/InventoryConfigurableProduct/Model/IsProductSalableCondition/ProductOptionsCondition.php @@ -7,10 +7,13 @@ namespace Magento\InventoryConfigurableProduct\Model\IsProductSalableCondition; use Magento\Catalog\Model\ProductRepository; -use Magento\InventorySalesApi\Api\IsProductSalableInterface; use Magento\ConfigurableProduct\Model\Product\Type\Configurable; -use Magento\InventorySalesApi\Api\AreProductsSalableInterface; +use Magento\InventoryConfigurableProduct\Model\IsAnyConfigurableOptionSalable; +use Magento\InventorySalesApi\Api\IsProductSalableInterface; +/** + * Are configurable product option in stock condition. + */ class ProductOptionsCondition implements IsProductSalableInterface { /** @@ -19,29 +22,22 @@ class ProductOptionsCondition implements IsProductSalableInterface private $productRepository; /** - * @var Configurable + * @var IsAnyConfigurableOptionSalable */ - private $type; + private $isAnyConfigurableOptionSalable; /** - * @var AreProductsSalableInterface - */ - private $areProductsSalable; - - /** - * @param Configurable $type * @param ProductRepository $productRepository - * @param AreProductsSalableInterface $areProductsSalable + * @param IsAnyConfigurableOptionSalable $isAnyConfigurableOptionSalable */ public function __construct( - Configurable $type, ProductRepository $productRepository, - AreProductsSalableInterface $areProductsSalable + IsAnyConfigurableOptionSalable $isAnyConfigurableOptionSalable ) { - $this->type = $type; $this->productRepository = $productRepository; - $this->areProductsSalable = $areProductsSalable; + $this->isAnyConfigurableOptionSalable = $isAnyConfigurableOptionSalable; } + /** * @inheritdoc */ @@ -51,20 +47,7 @@ public function execute(string $sku, int $stockId): bool $product = $this->productRepository->get($sku); if ($product->getTypeId() === Configurable::TYPE_CODE) { - $status = false; - $options = $this->type->getConfigurableOptions($product); - $skus = [[]]; - foreach ($options as $attribute) { - $skus[] = array_column($attribute, 'sku'); - } - $skus = array_merge(...$skus); - $results = $this->areProductsSalable->execute($skus, $stockId); - foreach ($results as $result) { - if ($result->isSalable()) { - $status = true; - break; - } - } + $status = $this->isAnyConfigurableOptionSalable->execute($product, $stockId); } return $status; } diff --git a/InventoryConfigurableProduct/etc/di.xml b/InventoryConfigurableProduct/etc/di.xml index a88bf8f8f193..fa7543ecc50f 100644 --- a/InventoryConfigurableProduct/etc/di.xml +++ b/InventoryConfigurableProduct/etc/di.xml @@ -26,14 +26,14 @@ - - - - - - - - - - + + + + + true + Magento\InventoryConfigurableProduct\Model\IsProductSalableCondition\ProductOptionsCondition + + + + From b71d88407f74342b50a4a1f52547c405b8e6c35f Mon Sep 17 00:00:00 2001 From: nmalevanec Date: Tue, 26 May 2020 11:34:34 +0300 Subject: [PATCH 30/50] Fix tests. --- InventoryBundleProduct/composer.json | 3 +- InventoryBundleProduct/etc/di.xml | 10 ----- .../Model/Product/IsAvailablePlugin.php | 44 ------------------- .../Simple}/IsSalablePlugin.php | 11 +++-- InventoryCatalog/etc/di.xml | 5 +-- InventoryConfigurableProduct/etc/di.xml | 10 ----- 6 files changed, 11 insertions(+), 72 deletions(-) delete mode 100644 InventoryCatalog/Plugin/Catalog/Model/Product/IsAvailablePlugin.php rename InventoryCatalog/Plugin/Catalog/Model/{Product => Type/Simple}/IsSalablePlugin.php (70%) diff --git a/InventoryBundleProduct/composer.json b/InventoryBundleProduct/composer.json index d101f485dbf2..3c27572ebecc 100644 --- a/InventoryBundleProduct/composer.json +++ b/InventoryBundleProduct/composer.json @@ -13,8 +13,7 @@ "magento/module-store": "*" }, "suggest": { - "magento/module-catalog-inventory": "*", - "magento/module-inventory-sales": "*" + "magento/module-catalog-inventory": "*" }, "type": "magento2-module", "license": [ diff --git a/InventoryBundleProduct/etc/di.xml b/InventoryBundleProduct/etc/di.xml index b1f8b5cf43d8..e4ace09948a9 100644 --- a/InventoryBundleProduct/etc/di.xml +++ b/InventoryBundleProduct/etc/di.xml @@ -26,14 +26,4 @@ - - - - - true - Magento\InventoryBundleProduct\Model\IsProductSalableCondition\ProductOptionsCondition - - - - diff --git a/InventoryCatalog/Plugin/Catalog/Model/Product/IsAvailablePlugin.php b/InventoryCatalog/Plugin/Catalog/Model/Product/IsAvailablePlugin.php deleted file mode 100644 index e4dda555376b..000000000000 --- a/InventoryCatalog/Plugin/Catalog/Model/Product/IsAvailablePlugin.php +++ /dev/null @@ -1,44 +0,0 @@ -isProductSalable = $isProductSalable; - } - - /** - * Fetches is salable status from multi-stock. - * - * @param Product $subject - * @param \Closure $proceed - * @return bool - * @SuppressWarnings(PHPMD.UnusedFormalParameter) - */ - public function aroundIsAvailable(Product $subject, \Closure $proceed): bool - { - return $this->isProductSalable->execute($subject); - } -} diff --git a/InventoryCatalog/Plugin/Catalog/Model/Product/IsSalablePlugin.php b/InventoryCatalog/Plugin/Catalog/Model/Type/Simple/IsSalablePlugin.php similarity index 70% rename from InventoryCatalog/Plugin/Catalog/Model/Product/IsSalablePlugin.php rename to InventoryCatalog/Plugin/Catalog/Model/Type/Simple/IsSalablePlugin.php index 1c8b7a96a473..3a6ea88803ef 100644 --- a/InventoryCatalog/Plugin/Catalog/Model/Product/IsSalablePlugin.php +++ b/InventoryCatalog/Plugin/Catalog/Model/Type/Simple/IsSalablePlugin.php @@ -5,11 +5,15 @@ */ declare(strict_types=1); -namespace Magento\InventoryCatalog\Plugin\Catalog\Model\Product; +namespace Magento\InventoryCatalog\Plugin\Catalog\Model\Type\Simple; use Magento\Catalog\Model\Product; +use Magento\Catalog\Model\Product\Type\Simple; use Magento\InventoryCatalog\Model\IsProductSalable; +/** + * Apply the inventory is-salable result to the according method of the product type model. + */ class IsSalablePlugin { /** @@ -29,12 +33,13 @@ public function __construct( /** * Fetches is salable status from multi-stock. * - * @param Product $product + * @param Simple $subject * @param \Closure $proceed + * @param Product $product * @return bool * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ - public function aroundIsSalable(Product $product, \Closure $proceed): bool + public function aroundIsSalable(Simple $subject, \Closure $proceed, Product $product): bool { return $this->isProductSalable->execute($product); } diff --git a/InventoryCatalog/etc/di.xml b/InventoryCatalog/etc/di.xml index 6a559b19e0e1..9a941f68e143 100644 --- a/InventoryCatalog/etc/di.xml +++ b/InventoryCatalog/etc/di.xml @@ -161,8 +161,7 @@ - - - + + diff --git a/InventoryConfigurableProduct/etc/di.xml b/InventoryConfigurableProduct/etc/di.xml index fa7543ecc50f..77358c2d991e 100644 --- a/InventoryConfigurableProduct/etc/di.xml +++ b/InventoryConfigurableProduct/etc/di.xml @@ -26,14 +26,4 @@ - - - - - true - Magento\InventoryConfigurableProduct\Model\IsProductSalableCondition\ProductOptionsCondition - - - - From 3c29f98ca9afa5a09d5c6860ecc6a2f539152c2c Mon Sep 17 00:00:00 2001 From: nmalevanec Date: Wed, 27 May 2020 15:34:06 +0300 Subject: [PATCH 31/50] Fix tests. --- .../ProductOptionsCondition.php | 67 ------------------ InventoryCatalog/Model/IsProductSalable.php | 3 +- .../Model/Type/Virtual/IsSalablePlugin.php | 45 ++++++++++++ .../AdaptGetStockStatusPlugin.php | 14 +++- .../Model/Product/Type/IsSalablePlugin.php | 46 +++++++++++++ InventoryCatalog/composer.json | 1 + InventoryCatalog/etc/di.xml | 6 ++ .../Model/IsAnyConfigurableOptionSalable.php | 69 ------------------- .../ProductOptionsCondition.php | 54 --------------- .../StatusCondition.php | 38 ---------- .../Quote/Item/ValidateQtyBeforePersist.php | 62 ----------------- InventorySales/composer.json | 3 +- InventorySales/etc/di.xml | 7 -- InventorySales/etc/events.xml | 4 -- 14 files changed, 114 insertions(+), 305 deletions(-) delete mode 100644 InventoryBundleProduct/Model/IsProductSalableCondition/ProductOptionsCondition.php create mode 100644 InventoryCatalog/Plugin/Catalog/Model/Type/Virtual/IsSalablePlugin.php create mode 100644 InventoryCatalog/Plugin/Downloadable/Model/Product/Type/IsSalablePlugin.php delete mode 100644 InventoryConfigurableProduct/Model/IsAnyConfigurableOptionSalable.php delete mode 100644 InventoryConfigurableProduct/Model/IsProductSalableCondition/ProductOptionsCondition.php delete mode 100644 InventorySales/Model/IsProductSalableCondition/StatusCondition.php delete mode 100644 InventorySales/Plugin/Quote/Model/Quote/Item/ValidateQtyBeforePersist.php diff --git a/InventoryBundleProduct/Model/IsProductSalableCondition/ProductOptionsCondition.php b/InventoryBundleProduct/Model/IsProductSalableCondition/ProductOptionsCondition.php deleted file mode 100644 index bf0599b72c48..000000000000 --- a/InventoryBundleProduct/Model/IsProductSalableCondition/ProductOptionsCondition.php +++ /dev/null @@ -1,67 +0,0 @@ -type = $type; - $this->productRepository = $productRepository; - $this->getBundleProductStockStatus = $getBundleProductStockStatus; - } - - /** - * @inheritdoc - */ - public function execute(string $sku, int $stockId): bool - { - $status = true; - $product = $this->productRepository->get($sku); - - if ($product->getTypeId() === Type::TYPE_CODE) { - $options = $this->type->getOptionsCollection($product); - try { - $status = $this->getBundleProductStockStatus->execute($product, $options->getItems(), $stockId); - } catch (LocalizedException $e) { - $status = false; - } - } - return $status; - } -} diff --git a/InventoryCatalog/Model/IsProductSalable.php b/InventoryCatalog/Model/IsProductSalable.php index 79072897c318..148006a0ef96 100644 --- a/InventoryCatalog/Model/IsProductSalable.php +++ b/InventoryCatalog/Model/IsProductSalable.php @@ -9,6 +9,7 @@ namespace Magento\InventoryCatalog\Model; use Magento\Catalog\Model\Product; +use Magento\Catalog\Model\Product\Attribute\Source\Status; use Magento\InventorySalesApi\Api\AreProductsSalableInterface; /** @@ -51,7 +52,7 @@ public function __construct( */ public function execute(Product $product): bool { - if (null === $product->getSku()) { + if (null === $product->getSku() || (int)$product->getStatus() === Status::STATUS_DISABLED) { return false; } if ($product->getData('is_salable') !== null) { diff --git a/InventoryCatalog/Plugin/Catalog/Model/Type/Virtual/IsSalablePlugin.php b/InventoryCatalog/Plugin/Catalog/Model/Type/Virtual/IsSalablePlugin.php new file mode 100644 index 000000000000..2554d070a554 --- /dev/null +++ b/InventoryCatalog/Plugin/Catalog/Model/Type/Virtual/IsSalablePlugin.php @@ -0,0 +1,45 @@ +isProductSalable = $isProductSalable; + } + + /** + * Fetches is salable status from multi-stock. + * + * @param Product\Type\Virtual $subject + * @param \Closure $proceed + * @param Product $product + * @return bool + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function aroundIsSalable(Product\Type\Virtual $subject, \Closure $proceed, Product $product): bool + { + return $this->isProductSalable->execute($product); + } +} diff --git a/InventoryCatalog/Plugin/CatalogInventory/Api/StockRegistry/AdaptGetStockStatusPlugin.php b/InventoryCatalog/Plugin/CatalogInventory/Api/StockRegistry/AdaptGetStockStatusPlugin.php index 6593389973a0..721fc72de5e1 100644 --- a/InventoryCatalog/Plugin/CatalogInventory/Api/StockRegistry/AdaptGetStockStatusPlugin.php +++ b/InventoryCatalog/Plugin/CatalogInventory/Api/StockRegistry/AdaptGetStockStatusPlugin.php @@ -12,6 +12,7 @@ use Magento\Framework\Exception\InputException; use Magento\Framework\Exception\LocalizedException; use Magento\Framework\Exception\NoSuchEntityException; +use Magento\InventoryCatalogApi\Api\DefaultStockProviderInterface; use Magento\InventoryCatalogApi\Model\GetSkusByProductIdsInterface; use Magento\InventorySalesApi\Api\AreProductsSalableInterface; use Magento\InventorySalesApi\Api\Data\SalesChannelInterface; @@ -49,25 +50,33 @@ class AdaptGetStockStatusPlugin */ private $stockResolver; + /** + * @var DefaultStockProviderInterface + */ + private $defaultStockProvider; + /** * @param AreProductsSalableInterface $areProductsSalable * @param GetProductSalableQtyInterface $getProductSalableQty * @param GetSkusByProductIdsInterface $getSkusByProductIds * @param StoreManagerInterface $storeManager * @param StockResolverInterface $stockResolver + * @param DefaultStockProviderInterface $defaultStockProvider */ public function __construct( AreProductsSalableInterface $areProductsSalable, GetProductSalableQtyInterface $getProductSalableQty, GetSkusByProductIdsInterface $getSkusByProductIds, StoreManagerInterface $storeManager, - StockResolverInterface $stockResolver + StockResolverInterface $stockResolver, + DefaultStockProviderInterface $defaultStockProvider ) { $this->areProductsSalable = $areProductsSalable; $this->getProductSalableQty = $getProductSalableQty; $this->getSkusByProductIds = $getSkusByProductIds; $this->storeManager = $storeManager; $this->stockResolver = $stockResolver; + $this->defaultStockProvider = $defaultStockProvider; } /** @@ -92,6 +101,9 @@ public function afterGetStockStatus( ? $this->storeManager->getWebsite()->getCode() : $this->storeManager->getWebsite($scopeId)->getCode(); $stockId = $this->stockResolver->execute(SalesChannelInterface::TYPE_WEBSITE, $websiteCode)->getStockId(); + if ($this->defaultStockProvider->getId() === $stockId) { + return $stockStatus; + } $sku = $this->getSkusByProductIds->execute([$productId])[$productId]; $result = $this->areProductsSalable->execute([$sku], $stockId); diff --git a/InventoryCatalog/Plugin/Downloadable/Model/Product/Type/IsSalablePlugin.php b/InventoryCatalog/Plugin/Downloadable/Model/Product/Type/IsSalablePlugin.php new file mode 100644 index 000000000000..b4f41a6f021b --- /dev/null +++ b/InventoryCatalog/Plugin/Downloadable/Model/Product/Type/IsSalablePlugin.php @@ -0,0 +1,46 @@ +isProductSalable = $isProductSalable; + } + + /** + * Fetches is salable status from multi-stock. + * + * @param Type $subject + * @param \Closure $proceed + * @param Product $product + * @return bool + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function aroundIsSalable(Type $subject, \Closure $proceed, Product $product): bool + { + return $subject->hasLinks($product) && $this->isProductSalable->execute($product); + } +} diff --git a/InventoryCatalog/composer.json b/InventoryCatalog/composer.json index 9507fb63794a..cd4c29e362fe 100644 --- a/InventoryCatalog/composer.json +++ b/InventoryCatalog/composer.json @@ -5,6 +5,7 @@ "php": "~7.3.0||~7.4.0", "magento/framework": "*", "magento/module-catalog": "*", + "magento/module-downloadable": "*", "magento/module-catalog-inventory": "*", "magento/module-inventory-api": "*", "magento/module-inventory-catalog-api": "*", diff --git a/InventoryCatalog/etc/di.xml b/InventoryCatalog/etc/di.xml index 9a941f68e143..6068d703fa38 100644 --- a/InventoryCatalog/etc/di.xml +++ b/InventoryCatalog/etc/di.xml @@ -164,4 +164,10 @@ + + + + + + diff --git a/InventoryConfigurableProduct/Model/IsAnyConfigurableOptionSalable.php b/InventoryConfigurableProduct/Model/IsAnyConfigurableOptionSalable.php deleted file mode 100644 index fddda1042445..000000000000 --- a/InventoryConfigurableProduct/Model/IsAnyConfigurableOptionSalable.php +++ /dev/null @@ -1,69 +0,0 @@ -type = $type; - $this->areProductsSalable = $areProductsSalable; - } - - /** - * Verify if any configurable product options is salable for given stock. - * - * @param ProductInterface $product - * @param int $stockId - * @return bool - */ - public function execute(ProductInterface $product, int $stockId): bool - { - $status = false; - $options = $this->type->getConfigurableOptions($product); - $skus = [[]]; - foreach ($options as $attribute) { - $skus[] = array_column($attribute, 'sku'); - } - $skus = array_merge(...$skus); - $results = $this->areProductsSalable->execute($skus, $stockId); - foreach ($results as $result) { - if ($result->isSalable()) { - $status = true; - break; - } - } - - return $status; - } -} diff --git a/InventoryConfigurableProduct/Model/IsProductSalableCondition/ProductOptionsCondition.php b/InventoryConfigurableProduct/Model/IsProductSalableCondition/ProductOptionsCondition.php deleted file mode 100644 index 09b955f71b5e..000000000000 --- a/InventoryConfigurableProduct/Model/IsProductSalableCondition/ProductOptionsCondition.php +++ /dev/null @@ -1,54 +0,0 @@ -productRepository = $productRepository; - $this->isAnyConfigurableOptionSalable = $isAnyConfigurableOptionSalable; - } - - /** - * @inheritdoc - */ - public function execute(string $sku, int $stockId): bool - { - $status = true; - $product = $this->productRepository->get($sku); - - if ($product->getTypeId() === Configurable::TYPE_CODE) { - $status = $this->isAnyConfigurableOptionSalable->execute($product, $stockId); - } - return $status; - } -} diff --git a/InventorySales/Model/IsProductSalableCondition/StatusCondition.php b/InventorySales/Model/IsProductSalableCondition/StatusCondition.php deleted file mode 100644 index 6f0696057dbe..000000000000 --- a/InventorySales/Model/IsProductSalableCondition/StatusCondition.php +++ /dev/null @@ -1,38 +0,0 @@ -productRepository = $productRepository; - } - - /** - * @inheritdoc - */ - public function execute(string $sku, int $stockId): bool - { - return (int)$this->productRepository->get($sku)->getStatus() === Status::STATUS_ENABLED; - } -} diff --git a/InventorySales/Plugin/Quote/Model/Quote/Item/ValidateQtyBeforePersist.php b/InventorySales/Plugin/Quote/Model/Quote/Item/ValidateQtyBeforePersist.php deleted file mode 100644 index a3aad885926d..000000000000 --- a/InventorySales/Plugin/Quote/Model/Quote/Item/ValidateQtyBeforePersist.php +++ /dev/null @@ -1,62 +0,0 @@ -qtyValidator = $validator; - $this->observerFactory = $observerFactory; - } - - /** - * Validate item qty before save. - * - * @param Item $subject - * @return void - * @throws LocalizedException - */ - public function beforeBeforeSave(Item $subject): void - { - $quote = $subject->getQuote(); - if ($quote->getIsActive() === false) { - return; - } - $event = $this->observerFactory->create(Event::class, ['data' => ['item' => $subject]]); - $observer = $this->observerFactory->create(Observer::class, ['data' => ['event' => $event]]); - $this->qtyValidator->validate($observer); - if (!empty($subject->getMessage()) && $subject->getHasError()) { - throw new LocalizedException(__($subject->getMessage())); - } - } -} diff --git a/InventorySales/composer.json b/InventorySales/composer.json index f401f79a71e7..e6a579643343 100644 --- a/InventorySales/composer.json +++ b/InventorySales/composer.json @@ -19,8 +19,7 @@ "magento/module-sales": "*" }, "suggest": { - "magento/module-inventory-catalog": "*", - "magento/module-quote": "*" + "magento/module-inventory-catalog": "*" }, "require-dev": { "magento/module-inventory-indexer": "*" diff --git a/InventorySales/etc/di.xml b/InventorySales/etc/di.xml index 9c212d61b9d0..b94a1e61023e 100644 --- a/InventorySales/etc/di.xml +++ b/InventorySales/etc/di.xml @@ -57,10 +57,6 @@ - - true - Magento\InventorySales\Model\IsProductSalableCondition\StatusCondition - true Magento\InventorySales\Model\IsProductSalableCondition\IsSetInStockStatusForCompositeProductCondition @@ -198,7 +194,4 @@ - - - diff --git a/InventorySales/etc/events.xml b/InventorySales/etc/events.xml index 5d7a1bcbb668..63cfbdac4429 100644 --- a/InventorySales/etc/events.xml +++ b/InventorySales/etc/events.xml @@ -23,8 +23,4 @@ - - - - From 657ccca810cafcbf50d4cd98673791668bf8cbbc Mon Sep 17 00:00:00 2001 From: nmalevanec Date: Thu, 28 May 2020 17:10:52 +0300 Subject: [PATCH 32/50] Adapt isProductSalabe for bundle and configurable products. --- .../Model/GetBundleProductStockStatus.php | 6 +- ...Selection.php => GetProductSelections.php} | 5 +- .../Model/IsBundleProductSalable.php | 142 ++++++++++++++++++ .../ProductOptionsCondition.php | 63 ++++++++ .../Product/Type/AdaptIsSalablePlugin.php | 104 ------------- .../IsBundleProductSalablePlugin.php | 88 +++++++++++ InventoryBundleProduct/etc/di.xml | 16 +- .../AddBundleProductDataPlugin.php | 118 +++++++++++++++ InventoryBundleProductIndexer/etc/di.xml | 3 + InventoryCatalog/Model/IsProductSalable.php | 6 +- .../Simple => Product}/IsSalablePlugin.php | 7 +- .../Model/Type/Virtual/IsSalablePlugin.php | 45 ------ InventoryCatalog/etc/di.xml | 10 +- .../Model/IsConfigurableProductSalable.php | 65 ++++++++ .../ProductOptionsCondition.php | 54 +++++++ .../IsConfigurableProductSalablePlugin.php | 59 ++++++++ InventoryConfigurableProduct/etc/di.xml | 18 +++ .../AddConfigurableProductDataPlugin.php | 118 +++++++++++++++ .../etc/di.xml | 3 + .../IndexProcessor.php | 49 +----- .../IndexProcessor/GetDataForUpdate.php | 71 +++++++++ 21 files changed, 832 insertions(+), 218 deletions(-) rename InventoryBundleProduct/Model/{GetProductSelection.php => GetProductSelections.php} (96%) create mode 100644 InventoryBundleProduct/Model/IsBundleProductSalable.php create mode 100644 InventoryBundleProduct/Model/IsProductSalableCondition/ProductOptionsCondition.php delete mode 100644 InventoryBundleProduct/Plugin/Bundle/Model/Product/Type/AdaptIsSalablePlugin.php create mode 100644 InventoryBundleProduct/Plugin/InventoryCatalog/Model/IsProductSalable/IsBundleProductSalablePlugin.php create mode 100644 InventoryBundleProductIndexer/Plugin/InventoryIndexer/Indexer/Model/Queue/GetDataForUpdate/AddBundleProductDataPlugin.php rename InventoryCatalog/Plugin/Catalog/Model/{Type/Simple => Product}/IsSalablePlugin.php (83%) delete mode 100644 InventoryCatalog/Plugin/Catalog/Model/Type/Virtual/IsSalablePlugin.php create mode 100644 InventoryConfigurableProduct/Model/IsConfigurableProductSalable.php create mode 100644 InventoryConfigurableProduct/Model/IsProductSalableCondition/ProductOptionsCondition.php create mode 100644 InventoryConfigurableProduct/Plugin/InventoryCatalog/Model/IsProductSalable/IsConfigurableProductSalablePlugin.php create mode 100644 InventoryConfigurableProductIndexer/Plugin/InventoryIndexer/Model/Queue/GetDataForUpdate/AddConfigurableProductDataPlugin.php create mode 100644 InventoryIndexer/Model/Queue/UpdateIndexSalabilityStatus/IndexProcessor/GetDataForUpdate.php diff --git a/InventoryBundleProduct/Model/GetBundleProductStockStatus.php b/InventoryBundleProduct/Model/GetBundleProductStockStatus.php index d99449f503e5..f520f502c8e7 100644 --- a/InventoryBundleProduct/Model/GetBundleProductStockStatus.php +++ b/InventoryBundleProduct/Model/GetBundleProductStockStatus.php @@ -24,7 +24,7 @@ class GetBundleProductStockStatus { /** - * @var GetProductSelection + * @var GetProductSelections */ private $getProductSelection; @@ -44,13 +44,13 @@ class GetBundleProductStockStatus private $getStockItemConfiguration; /** - * @param GetProductSelection $getProductSelection + * @param GetProductSelections $getProductSelection * @param AreProductsSalableForRequestedQtyInterface $areProductsSalableForRequestedQty * @param IsProductSalableForRequestedQtyRequestInterfaceFactory $isProductSalableForRequestedQtyRequestFactory * @param GetStockItemConfigurationInterface $getStockItemConfiguration */ public function __construct( - GetProductSelection $getProductSelection, + GetProductSelections $getProductSelection, AreProductsSalableForRequestedQtyInterface $areProductsSalableForRequestedQty, IsProductSalableForRequestedQtyRequestInterfaceFactory $isProductSalableForRequestedQtyRequestFactory, GetStockItemConfigurationInterface $getStockItemConfiguration diff --git a/InventoryBundleProduct/Model/GetProductSelection.php b/InventoryBundleProduct/Model/GetProductSelections.php similarity index 96% rename from InventoryBundleProduct/Model/GetProductSelection.php rename to InventoryBundleProduct/Model/GetProductSelections.php index 04e16baee82f..2afc938c6df8 100644 --- a/InventoryBundleProduct/Model/GetProductSelection.php +++ b/InventoryBundleProduct/Model/GetProductSelections.php @@ -15,9 +15,9 @@ use Magento\Framework\EntityManager\MetadataPool; /** - * Retrieve bundle product selection service. + * Retrieve bundle product selections service. */ -class GetProductSelection +class GetProductSelections { /** * @var CollectionFactory @@ -65,7 +65,6 @@ public function execute(ProductInterface $product, OptionInterface $option): Col $selectionsCollection->setFlag('product_children', true); $selectionsCollection->addFilterByRequiredOptions(); $selectionsCollection->setOptionIdsFilter([$option->getId()]); - $this->selectionCollectionFilterApplier->apply( $selectionsCollection, 'parent_product_id', diff --git a/InventoryBundleProduct/Model/IsBundleProductSalable.php b/InventoryBundleProduct/Model/IsBundleProductSalable.php new file mode 100644 index 000000000000..74bf8e1654e9 --- /dev/null +++ b/InventoryBundleProduct/Model/IsBundleProductSalable.php @@ -0,0 +1,142 @@ +getProductSelection = $getProductSelection; + $this->areProductsSalableForRequestedQty = $areProductsSalableForRequestedQty; + $this->isProductSalableForRequestedQtyRequestFactory = $isProductSalableForRequestedQtyRequestFactory; + $this->getStockItemConfiguration = $getStockItemConfiguration; + } + + /** + * Provides bundle product stock status. + * + * @param ProductInterface $product + * @param OptionInterface[] $bundleOptions + * @param int $stockId + * @return bool + * @throws LocalizedException + * @throws SkuIsNotAssignedToStockException + */ + public function execute(ProductInterface $product, array $bundleOptions, int $stockId): bool + { + $isSalable = false; + foreach ($bundleOptions as $option) { + $hasSalable = false; + $results = $this->getAreSalableSelections($product, $option, $stockId); + foreach ($results as $result) { + if ($result->isSalable()) { + $hasSalable = true; + break; + } + } + if ($hasSalable) { + $isSalable = true; + } + + if (!$hasSalable && $option->getRequired()) { + $isSalable = false; + break; + } + } + + return $isSalable; + } + + /** + * Get are bundle product selections salable. + * + * @param ProductInterface $product + * @param OptionInterface $option + * @param int $stockId + * @return IsProductSalableForRequestedQtyResultInterface[] + * @throws LocalizedException + * @throws SkuIsNotAssignedToStockException + */ + private function getAreSalableSelections(ProductInterface $product, OptionInterface $option, int $stockId): array + { + $bundleSelections = $this->getProductSelection->execute($product, $option); + $skuRequests = []; + foreach ($bundleSelections->getItems() as $selection) { + $skuRequests[] = $this->isProductSalableForRequestedQtyRequestFactory->create( + [ + 'sku' => (string)$selection->getSku(), + 'qty' => $this->getRequestedQty($selection, $stockId), + ] + ); + } + + return $this->areProductsSalableForRequestedQty->execute($skuRequests, $stockId); + } + + /** + * Get bundle product selection qty. + * + * @param Product $product + * @param int $stockId + * @return float + * @throws LocalizedException + * @throws SkuIsNotAssignedToStockException + */ + private function getRequestedQty(Product $product, int $stockId): float + { + if ((int)$product->getSelectionCanChangeQty()) { + $stockItemConfiguration = $this->getStockItemConfiguration->execute((string)$product->getSku(), $stockId); + return $stockItemConfiguration->getMinSaleQty(); + } + + return (float)$product->getSelectionQty(); + } +} diff --git a/InventoryBundleProduct/Model/IsProductSalableCondition/ProductOptionsCondition.php b/InventoryBundleProduct/Model/IsProductSalableCondition/ProductOptionsCondition.php new file mode 100644 index 000000000000..1f6878b8a580 --- /dev/null +++ b/InventoryBundleProduct/Model/IsProductSalableCondition/ProductOptionsCondition.php @@ -0,0 +1,63 @@ +type = $type; + $this->productRepository = $productRepository; + $this->isBundleProductSalable = $isBundleProductSalable; + } + + /** + * @inheritDoc + */ + public function execute(string $sku, int $stockId): bool + { + $product = $this->productRepository->get($sku); + if ($product->getTypeId() !== Type::TYPE_CODE) { + return true; + } + $options = $this->type->getOptionsCollection($product); + + return $this->isBundleProductSalable->execute($product, $options->getItems(), $stockId); + } +} diff --git a/InventoryBundleProduct/Plugin/Bundle/Model/Product/Type/AdaptIsSalablePlugin.php b/InventoryBundleProduct/Plugin/Bundle/Model/Product/Type/AdaptIsSalablePlugin.php deleted file mode 100644 index 481881e3cd66..000000000000 --- a/InventoryBundleProduct/Plugin/Bundle/Model/Product/Type/AdaptIsSalablePlugin.php +++ /dev/null @@ -1,104 +0,0 @@ -isProductSalable = $isProductSalable; - $this->storeManager = $storeManager; - $this->stockByWebsiteIdResolver = $stockByWebsiteIdResolver; - $this->getBundleProductStockStatus = $getBundleProductStockStatus; - $this->defaultStockProvider = $defaultStockProvider; - } - - /** - * Verify, is product salable in multi stock environment. - * - * @param Type $subject - * @param \Closure $proceed - * @param Product $product - * @return bool - */ - public function aroundIsSalable(Type $subject, \Closure $proceed, Product $product): bool - { - $salable = $product->getStatus() == Status::STATUS_ENABLED; - if ($salable && $product->hasData('is_salable')) { - $salable = $product->getData('is_salable'); - } - - if (!(bool)(int)$salable) { - return false; - } - - if ($product->hasData('all_items_salable')) { - return $product->getData('all_items_salable'); - } - - $website = $this->storeManager->getWebsite(); - $stock = $this->stockByWebsiteIdResolver->execute((int)$website->getId()); - if ($this->defaultStockProvider->getId() === $stock->getStockId()) { - return $proceed($product); - } - $options = $subject->getOptionsCollection($product); - $isSalable = $this->getBundleProductStockStatus->execute($product, $options->getItems(), $stock->getStockId()); - $product->setData('all_items_salable', $isSalable); - - return $isSalable; - } -} diff --git a/InventoryBundleProduct/Plugin/InventoryCatalog/Model/IsProductSalable/IsBundleProductSalablePlugin.php b/InventoryBundleProduct/Plugin/InventoryCatalog/Model/IsProductSalable/IsBundleProductSalablePlugin.php new file mode 100644 index 000000000000..83906ea0754d --- /dev/null +++ b/InventoryBundleProduct/Plugin/InventoryCatalog/Model/IsProductSalable/IsBundleProductSalablePlugin.php @@ -0,0 +1,88 @@ +type = $type; + $this->getProductSelections = $getProductSelections; + } + + /** + * Get bundle product status. + * + * @param IsProductSalable $subject + * @param \Closure $proceed + * @param ProductInterface $product + * @return bool + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function aroundExecute(IsProductSalable $subject, \Closure $proceed, ProductInterface $product): bool + { + if ($product->getTypeId() !== Type::TYPE_CODE) { + return $proceed($product); + } + if ($product->hasData('all_items_salable')) { + return $product->getData('all_items_salable'); + } + + $isSalable = $proceed($product); + + if (!$isSalable) { + return false; + } + $bundleOptions = $this->type->getOptionsCollection($product); + $isSalable = false; + foreach ($bundleOptions as $option) { + $selections = $this->getProductSelections->execute($product, $option); + $hasSalable = false; + foreach ($selections as $selection) { + if ((int)$selection->getStatus() === Status::STATUS_ENABLED) { + $hasSalable = true; + break; + } + } + if ($hasSalable) { + $isSalable = true; + } + + if (!$hasSalable && $option->getRequired()) { + $isSalable = false; + break; + } + } + $product->setData('all_items_salable', $isSalable); + + return $isSalable; + } +} diff --git a/InventoryBundleProduct/etc/di.xml b/InventoryBundleProduct/etc/di.xml index e4ace09948a9..df7f66869360 100644 --- a/InventoryBundleProduct/etc/di.xml +++ b/InventoryBundleProduct/etc/di.xml @@ -9,9 +9,6 @@ - - - @@ -26,4 +23,17 @@ + + + + + + + + true + Magento\InventoryBundleProduct\Model\IsProductSalableCondition\ProductOptionsCondition + + + + diff --git a/InventoryBundleProductIndexer/Plugin/InventoryIndexer/Indexer/Model/Queue/GetDataForUpdate/AddBundleProductDataPlugin.php b/InventoryBundleProductIndexer/Plugin/InventoryIndexer/Indexer/Model/Queue/GetDataForUpdate/AddBundleProductDataPlugin.php new file mode 100644 index 000000000000..e9c1bcb09a41 --- /dev/null +++ b/InventoryBundleProductIndexer/Plugin/InventoryIndexer/Indexer/Model/Queue/GetDataForUpdate/AddBundleProductDataPlugin.php @@ -0,0 +1,118 @@ +type = $type; + $this->getProductIdsBySkus = $getProductIdsBySkus; + $this->getSkusByProductIds = $getSkusByProductIds; + $this->getStockItemData = $getStockItemData; + $this->logger = $logger; + } + + /** + * Add bundle product data to index data. + * + * @param GetDataForUpdate $subject + * @param array $result + * @param array $salabilityData + * @param int $stockId + * @return array + * @throws NoSuchEntityException + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function afterExecute(GetDataForUpdate $subject, array $result, array $salabilityData, int $stockId): array + { + $bundleData = []; + $skus = array_keys($result); + $childrenIds = $this->getProductIdsBySkus->execute($skus); + $bundleProductsIds = []; + foreach ($childrenIds as $childId) { + $bundleProductsIds[] = $this->type->getParentIdsByChild($childId); + } + + $bundleSkus = $this->getSkusByProductIds->execute($bundleProductsIds); + foreach ($bundleSkus as $bundleSku) { + $bundleData[$bundleSku] = $this->getIndexSalabilityStatus($bundleSku, $stockId); + } + + return array_merge($result, $bundleData); + } + + /** + * Get current index is_salable value. + * + * @param string $sku + * @param int $stockId + * @return bool|null + */ + private function getIndexSalabilityStatus(string $sku, int $stockId): ?bool + { + try { + $data = $this->getStockItemData->execute($sku, $stockId); + $isSalable = $data ? (bool)$data[GetStockItemDataInterface::IS_SALABLE] : false; + } catch (LocalizedException $e) { + $this->logger->error($e->getLogMessage()); + return null; + } + + return $isSalable; + } +} diff --git a/InventoryBundleProductIndexer/etc/di.xml b/InventoryBundleProductIndexer/etc/di.xml index 73b7a0bf459e..3c1dc488832b 100644 --- a/InventoryBundleProductIndexer/etc/di.xml +++ b/InventoryBundleProductIndexer/etc/di.xml @@ -30,4 +30,7 @@ + + + diff --git a/InventoryCatalog/Model/IsProductSalable.php b/InventoryCatalog/Model/IsProductSalable.php index 148006a0ef96..a099f663d8f4 100644 --- a/InventoryCatalog/Model/IsProductSalable.php +++ b/InventoryCatalog/Model/IsProductSalable.php @@ -8,7 +8,7 @@ namespace Magento\InventoryCatalog\Model; -use Magento\Catalog\Model\Product; +use Magento\Catalog\Api\Data\ProductInterface; use Magento\Catalog\Model\Product\Attribute\Source\Status; use Magento\InventorySalesApi\Api\AreProductsSalableInterface; @@ -47,10 +47,10 @@ public function __construct( /** * Verify product salable status. * - * @param Product $product + * @param ProductInterface $product * @return bool */ - public function execute(Product $product): bool + public function execute(ProductInterface $product): bool { if (null === $product->getSku() || (int)$product->getStatus() === Status::STATUS_DISABLED) { return false; diff --git a/InventoryCatalog/Plugin/Catalog/Model/Type/Simple/IsSalablePlugin.php b/InventoryCatalog/Plugin/Catalog/Model/Product/IsSalablePlugin.php similarity index 83% rename from InventoryCatalog/Plugin/Catalog/Model/Type/Simple/IsSalablePlugin.php rename to InventoryCatalog/Plugin/Catalog/Model/Product/IsSalablePlugin.php index 3a6ea88803ef..5b72f5dc8a08 100644 --- a/InventoryCatalog/Plugin/Catalog/Model/Type/Simple/IsSalablePlugin.php +++ b/InventoryCatalog/Plugin/Catalog/Model/Product/IsSalablePlugin.php @@ -5,7 +5,7 @@ */ declare(strict_types=1); -namespace Magento\InventoryCatalog\Plugin\Catalog\Model\Type\Simple; +namespace Magento\InventoryCatalog\Plugin\Catalog\Model\Product; use Magento\Catalog\Model\Product; use Magento\Catalog\Model\Product\Type\Simple; @@ -33,13 +33,12 @@ public function __construct( /** * Fetches is salable status from multi-stock. * - * @param Simple $subject - * @param \Closure $proceed * @param Product $product + * @param \Closure $proceed * @return bool * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ - public function aroundIsSalable(Simple $subject, \Closure $proceed, Product $product): bool + public function aroundIsSalable(Product $product, \Closure $proceed): bool { return $this->isProductSalable->execute($product); } diff --git a/InventoryCatalog/Plugin/Catalog/Model/Type/Virtual/IsSalablePlugin.php b/InventoryCatalog/Plugin/Catalog/Model/Type/Virtual/IsSalablePlugin.php deleted file mode 100644 index 2554d070a554..000000000000 --- a/InventoryCatalog/Plugin/Catalog/Model/Type/Virtual/IsSalablePlugin.php +++ /dev/null @@ -1,45 +0,0 @@ -isProductSalable = $isProductSalable; - } - - /** - * Fetches is salable status from multi-stock. - * - * @param Product\Type\Virtual $subject - * @param \Closure $proceed - * @param Product $product - * @return bool - * @SuppressWarnings(PHPMD.UnusedFormalParameter) - */ - public function aroundIsSalable(Product\Type\Virtual $subject, \Closure $proceed, Product $product): bool - { - return $this->isProductSalable->execute($product); - } -} diff --git a/InventoryCatalog/etc/di.xml b/InventoryCatalog/etc/di.xml index 6068d703fa38..6d0db77426d5 100644 --- a/InventoryCatalog/etc/di.xml +++ b/InventoryCatalog/etc/di.xml @@ -161,13 +161,7 @@ - - - - - - - - + + diff --git a/InventoryConfigurableProduct/Model/IsConfigurableProductSalable.php b/InventoryConfigurableProduct/Model/IsConfigurableProductSalable.php new file mode 100644 index 000000000000..c6eee7c32868 --- /dev/null +++ b/InventoryConfigurableProduct/Model/IsConfigurableProductSalable.php @@ -0,0 +1,65 @@ +type = $type; + $this->areProductsSalable = $areProductsSalable; + } + + /** + * Verify configurable product salable status considering configurable options. + * + * @param ProductInterface $product + * @param int $stockId + * @return bool + */ + public function execute(ProductInterface $product, int $stockId): bool + { + $salable = false; + $options = $this->type->getConfigurableOptions($product); + $skus = [[]]; + foreach ($options as $attribute) { + $skus[] = array_column($attribute, 'sku'); + } + $skus = array_merge(...$skus); + $results = $this->areProductsSalable->execute($skus, $stockId); + foreach ($results as $result) { + if ($result->isSalable()) { + $salable = true; + break; + } + } + + return $salable; + } +} diff --git a/InventoryConfigurableProduct/Model/IsProductSalableCondition/ProductOptionsCondition.php b/InventoryConfigurableProduct/Model/IsProductSalableCondition/ProductOptionsCondition.php new file mode 100644 index 000000000000..e66a42f75162 --- /dev/null +++ b/InventoryConfigurableProduct/Model/IsProductSalableCondition/ProductOptionsCondition.php @@ -0,0 +1,54 @@ +productRepository = $productRepository; + $this->isConfigurableProductSalable = $isConfigurableProductSalable; + } + + /** + * @inheritDoc + */ + public function execute(string $sku, int $stockId): bool + { + $product = $this->productRepository->get($sku); + if ($product->getTypeId() !== Configurable::TYPE_CODE) { + return true; + } + + return $this->isConfigurableProductSalable->execute($product, $stockId); + } +} diff --git a/InventoryConfigurableProduct/Plugin/InventoryCatalog/Model/IsProductSalable/IsConfigurableProductSalablePlugin.php b/InventoryConfigurableProduct/Plugin/InventoryCatalog/Model/IsProductSalable/IsConfigurableProductSalablePlugin.php new file mode 100644 index 000000000000..28fc95d9eb77 --- /dev/null +++ b/InventoryConfigurableProduct/Plugin/InventoryCatalog/Model/IsProductSalable/IsConfigurableProductSalablePlugin.php @@ -0,0 +1,59 @@ +type = $type; + $this->getProductSelections = $getProductSelections; + } + + /** + * Get configurable product status. + * + * @param IsProductSalable $subject + * @param bool $result + * @param ProductInterface $product + * @return bool + * @throws \Exception + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function afterExecute(IsProductSalable $subject, bool $result, ProductInterface $product): bool + { + if ($product->getTypeId() !== Configurable::TYPE_CODE || !$result) { + return $result; + } + $options = $this->type->getConfigurableOptions($product); + + return !empty($options); + } +} diff --git a/InventoryConfigurableProduct/etc/di.xml b/InventoryConfigurableProduct/etc/di.xml index 77358c2d991e..5c37996e93bb 100644 --- a/InventoryConfigurableProduct/etc/di.xml +++ b/InventoryConfigurableProduct/etc/di.xml @@ -26,4 +26,22 @@ + + + Magento\InventorySalesApi\Api\AreProductsSalableInterface\Proxy + + + + + + + + + + true + Magento\InventoryConfigurableProduct\Model\IsProductSalableCondition\ProductOptionsCondition + + + + diff --git a/InventoryConfigurableProductIndexer/Plugin/InventoryIndexer/Model/Queue/GetDataForUpdate/AddConfigurableProductDataPlugin.php b/InventoryConfigurableProductIndexer/Plugin/InventoryIndexer/Model/Queue/GetDataForUpdate/AddConfigurableProductDataPlugin.php new file mode 100644 index 000000000000..b40d76a3c49e --- /dev/null +++ b/InventoryConfigurableProductIndexer/Plugin/InventoryIndexer/Model/Queue/GetDataForUpdate/AddConfigurableProductDataPlugin.php @@ -0,0 +1,118 @@ +type = $type; + $this->getProductIdsBySkus = $getProductIdsBySkus; + $this->getSkusByProductIds = $getSkusByProductIds; + $this->getStockItemData = $getStockItemData; + $this->logger = $logger; + } + + /** + * Add configurable product to index data. + * + * @param GetDataForUpdate $subject + * @param array $result + * @param array $salabilityData + * @param int $stockId + * @return array + * @throws NoSuchEntityException + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function afterExecute(GetDataForUpdate $subject, array $result, array $salabilityData, int $stockId): array + { + $configurableData = []; + $skus = array_keys($result); + $childrenIds = $this->getProductIdsBySkus->execute($skus); + $configurableProductIds = []; + foreach ($childrenIds as $childId) { + $configurableProductIds[] = $this->type->getParentIdsByChild($childId); + } + + $configurableSkus = $this->getSkusByProductIds->execute($configurableProductIds); + foreach ($configurableSkus as $configurableSku) { + $configurableData[$configurableSku] = $this->getIndexSalabilityStatus($configurableSku, $stockId); + } + + return array_merge($result, $configurableData); + } + + /** + * Get current index is_salable value. + * + * @param string $sku + * @param int $stockId + * @return bool|null + */ + private function getIndexSalabilityStatus(string $sku, int $stockId): ?bool + { + try { + $data = $this->getStockItemData->execute($sku, $stockId); + $isSalable = $data ? (bool)$data[GetStockItemDataInterface::IS_SALABLE] : false; + } catch (LocalizedException $e) { + $this->logger->error($e->getLogMessage()); + return null; + } + + return $isSalable; + } +} diff --git a/InventoryConfigurableProductIndexer/etc/di.xml b/InventoryConfigurableProductIndexer/etc/di.xml index 9def048d6c77..8d871a095a3c 100644 --- a/InventoryConfigurableProductIndexer/etc/di.xml +++ b/InventoryConfigurableProductIndexer/etc/di.xml @@ -32,4 +32,7 @@ Magento\Inventory\Model\ResourceModel\StockSourceLink::TABLE_NAME_STOCK_SOURCE_LINK + + + diff --git a/InventoryIndexer/Model/Queue/UpdateIndexSalabilityStatus/IndexProcessor.php b/InventoryIndexer/Model/Queue/UpdateIndexSalabilityStatus/IndexProcessor.php index e2bd7623d8f1..ffb0a3b11af1 100644 --- a/InventoryIndexer/Model/Queue/UpdateIndexSalabilityStatus/IndexProcessor.php +++ b/InventoryIndexer/Model/Queue/UpdateIndexSalabilityStatus/IndexProcessor.php @@ -8,16 +8,15 @@ namespace Magento\InventoryIndexer\Model\Queue\UpdateIndexSalabilityStatus; use Magento\Framework\App\ResourceConnection; -use Magento\Framework\Exception\LocalizedException; use Magento\Framework\Exception\StateException; use Magento\InventoryIndexer\Indexer\InventoryIndexer; use Magento\InventoryIndexer\Model\Queue\ReservationData; +use Magento\InventoryIndexer\Model\Queue\UpdateIndexSalabilityStatus\IndexProcessor\GetDataForUpdate; use Magento\InventoryIndexer\Model\ResourceModel\UpdateIsSalable; use Magento\InventoryMultiDimensionalIndexerApi\Model\Alias; use Magento\InventoryMultiDimensionalIndexerApi\Model\IndexNameBuilder; use Magento\InventoryMultiDimensionalIndexerApi\Model\IndexStructureInterface; use Magento\InventorySalesApi\Api\AreProductsSalableInterface; -use Magento\InventorySalesApi\Api\Data\IsProductSalableResultInterface; use Magento\InventorySalesApi\Model\GetStockItemDataInterface; /** @@ -54,20 +53,20 @@ class IndexProcessor * @param IndexNameBuilder $indexNameBuilder * @param IndexStructureInterface $indexStructure * @param AreProductsSalableInterface $areProductsSalable - * @param GetStockItemDataInterface $getStockItemData + * @param GetStockItemDataInterface $getDataForUpdate * @param UpdateIsSalable $updateIsSalable */ public function __construct( IndexNameBuilder $indexNameBuilder, IndexStructureInterface $indexStructure, AreProductsSalableInterface $areProductsSalable, - GetStockItemDataInterface $getStockItemData, + GetDataForUpdate $getDataForUpdate, UpdateIsSalable $updateIsSalable ) { $this->indexNameBuilder = $indexNameBuilder; $this->indexStructure = $indexStructure; $this->areProductsSalable = $areProductsSalable; - $this->getStockItemData = $getStockItemData; + $this->getStockItemData = $getDataForUpdate; $this->updateIsSalable = $updateIsSalable; } @@ -104,44 +103,4 @@ public function execute(ReservationData $reservationData, int $stockId): array return $dataForUpdate; } - /** - * Build data for index update. - * - * @param IsProductSalableResultInterface[] $salabilityData - * @param int $stockId - * - * @return bool[] - ['sku' => bool] - */ - private function getDataForUpdate(array $salabilityData, int $stockId): array - { - $data = []; - foreach ($salabilityData as $isProductSalableResult) { - $currentStatus = $this->getIndexSalabilityStatus($isProductSalableResult->getSku(), $stockId); - if ($isProductSalableResult->isSalable() != $currentStatus && $currentStatus !== null) { - $data[$isProductSalableResult->getSku()] = $isProductSalableResult->isSalable(); - } - } - - return $data; - } - - /** - * Get current index is_salable value. - * - * @param string $sku - * @param int $stockId - * - * @return bool|null - */ - private function getIndexSalabilityStatus(string $sku, int $stockId): ?bool - { - try { - $data = $this->getStockItemData->execute($sku, $stockId); - $isSalable = $data ? (bool)$data[GetStockItemDataInterface::IS_SALABLE] : false; - } catch (LocalizedException $e) { - $isSalable = null; - } - - return $isSalable; - } } diff --git a/InventoryIndexer/Model/Queue/UpdateIndexSalabilityStatus/IndexProcessor/GetDataForUpdate.php b/InventoryIndexer/Model/Queue/UpdateIndexSalabilityStatus/IndexProcessor/GetDataForUpdate.php new file mode 100644 index 000000000000..348c1b170bd3 --- /dev/null +++ b/InventoryIndexer/Model/Queue/UpdateIndexSalabilityStatus/IndexProcessor/GetDataForUpdate.php @@ -0,0 +1,71 @@ +getStockItemData = $getStockItemData; + } + + /** + * Build data for index update. + * + * @param IsProductSalableResultInterface[] $salabilityData + * @param int $stockId + * @return bool[] - ['sku' => bool] + */ + public function execute(array $salabilityData, int $stockId): array + { + $data = []; + foreach ($salabilityData as $isProductSalableResult) { + $currentStatus = $this->getIndexSalabilityStatus($isProductSalableResult->getSku(), $stockId); + if ($isProductSalableResult->isSalable() != $currentStatus && $currentStatus !== null) { + $data[$isProductSalableResult->getSku()] = $isProductSalableResult->isSalable(); + } + } + + return $data; + } + + /** + * Get current index is_salable value. + * + * @param string $sku + * @param int $stockId + * + * @return bool|null + */ + private function getIndexSalabilityStatus(string $sku, int $stockId): ?bool + { + try { + $data = $this->getStockItemData->execute($sku, $stockId); + $isSalable = $data ? (bool)$data[GetStockItemDataInterface::IS_SALABLE] : false; + } catch (LocalizedException $e) { + $isSalable = null; + } + + return $isSalable; + } +} From 995d5aa3d61a2d6b8d0771580639835bd5d9f6ae Mon Sep 17 00:00:00 2001 From: nmalevanec Date: Thu, 28 May 2020 17:14:41 +0300 Subject: [PATCH 33/50] Remove redundant plugin. --- .../Model/Product/Type/IsSalablePlugin.php | 46 ------------------- 1 file changed, 46 deletions(-) delete mode 100644 InventoryCatalog/Plugin/Downloadable/Model/Product/Type/IsSalablePlugin.php diff --git a/InventoryCatalog/Plugin/Downloadable/Model/Product/Type/IsSalablePlugin.php b/InventoryCatalog/Plugin/Downloadable/Model/Product/Type/IsSalablePlugin.php deleted file mode 100644 index b4f41a6f021b..000000000000 --- a/InventoryCatalog/Plugin/Downloadable/Model/Product/Type/IsSalablePlugin.php +++ /dev/null @@ -1,46 +0,0 @@ -isProductSalable = $isProductSalable; - } - - /** - * Fetches is salable status from multi-stock. - * - * @param Type $subject - * @param \Closure $proceed - * @param Product $product - * @return bool - * @SuppressWarnings(PHPMD.UnusedFormalParameter) - */ - public function aroundIsSalable(Type $subject, \Closure $proceed, Product $product): bool - { - return $subject->hasLinks($product) && $this->isProductSalable->execute($product); - } -} From 74da6905cf7695cdca664676ee99e54c5b690c8d Mon Sep 17 00:00:00 2001 From: nmalevanec Date: Fri, 29 May 2020 16:33:44 +0300 Subject: [PATCH 34/50] Fix tests --- InventoryBundleProduct/composer.json | 1 + .../AddBundleProductDataPlugin.php | 20 +++++++-- InventoryBundleProductIndexer/composer.json | 1 + .../Model/Product/IsAvailablePlugin.php | 44 +++++++++++++++++++ .../Catalog/Model/Product/IsSalablePlugin.php | 1 - .../AdaptGetStockStatusPlugin.php | 14 +----- InventoryCatalog/etc/di.xml | 1 + .../IsConfigurableProductSalablePlugin.php | 10 +---- .../AddConfigurableProductDataPlugin.php | 20 +++++++-- .../composer.json | 1 + .../IndexProcessor.php | 11 +++-- 11 files changed, 87 insertions(+), 37 deletions(-) rename InventoryBundleProductIndexer/Plugin/InventoryIndexer/{Indexer => }/Model/Queue/GetDataForUpdate/AddBundleProductDataPlugin.php (79%) create mode 100644 InventoryCatalog/Plugin/Catalog/Model/Product/IsAvailablePlugin.php diff --git a/InventoryBundleProduct/composer.json b/InventoryBundleProduct/composer.json index 3c27572ebecc..c753818410f8 100644 --- a/InventoryBundleProduct/composer.json +++ b/InventoryBundleProduct/composer.json @@ -7,6 +7,7 @@ "magento/module-bundle": "*", "magento/module-catalog": "*", "magento/module-inventory-api": "*", + "magento/module-inventory-catalog": "*", "magento/module-inventory-catalog-api": "*", "magento/module-inventory-configuration-api": "*", "magento/module-inventory-sales-api": "*", diff --git a/InventoryBundleProductIndexer/Plugin/InventoryIndexer/Indexer/Model/Queue/GetDataForUpdate/AddBundleProductDataPlugin.php b/InventoryBundleProductIndexer/Plugin/InventoryIndexer/Model/Queue/GetDataForUpdate/AddBundleProductDataPlugin.php similarity index 79% rename from InventoryBundleProductIndexer/Plugin/InventoryIndexer/Indexer/Model/Queue/GetDataForUpdate/AddBundleProductDataPlugin.php rename to InventoryBundleProductIndexer/Plugin/InventoryIndexer/Model/Queue/GetDataForUpdate/AddBundleProductDataPlugin.php index e9c1bcb09a41..0055d267296b 100644 --- a/InventoryBundleProductIndexer/Plugin/InventoryIndexer/Indexer/Model/Queue/GetDataForUpdate/AddBundleProductDataPlugin.php +++ b/InventoryBundleProductIndexer/Plugin/InventoryIndexer/Model/Queue/GetDataForUpdate/AddBundleProductDataPlugin.php @@ -13,6 +13,7 @@ use Magento\InventoryCatalogApi\Model\GetProductIdsBySkusInterface; use Magento\InventoryCatalogApi\Model\GetSkusByProductIdsInterface; use Magento\InventoryIndexer\Model\Queue\UpdateIndexSalabilityStatus\IndexProcessor\GetDataForUpdate; +use Magento\InventorySalesApi\Api\AreProductsSalableInterface; use Magento\InventorySalesApi\Model\GetStockItemDataInterface; use Psr\Log\LoggerInterface; @@ -41,6 +42,11 @@ class AddBundleProductDataPlugin */ private $getStockItemData; + /** + * @var AreProductsSalableInterface + */ + private $areProductsSalable; + /** * @var LoggerInterface */ @@ -51,6 +57,7 @@ class AddBundleProductDataPlugin * @param GetProductIdsBySkusInterface $getProductIdsBySkus * @param GetSkusByProductIdsInterface $getSkusByProductIds * @param GetStockItemDataInterface $getStockItemData + * @param AreProductsSalableInterface $areProductsSalable * @param LoggerInterface $logger */ public function __construct( @@ -58,6 +65,7 @@ public function __construct( GetProductIdsBySkusInterface $getProductIdsBySkus, GetSkusByProductIdsInterface $getSkusByProductIds, GetStockItemDataInterface $getStockItemData, + AreProductsSalableInterface $areProductsSalable, LoggerInterface $logger ) { $this->type = $type; @@ -65,6 +73,7 @@ public function __construct( $this->getSkusByProductIds = $getSkusByProductIds; $this->getStockItemData = $getStockItemData; $this->logger = $logger; + $this->areProductsSalable = $areProductsSalable; } /** @@ -87,10 +96,13 @@ public function afterExecute(GetDataForUpdate $subject, array $result, array $sa foreach ($childrenIds as $childId) { $bundleProductsIds[] = $this->type->getParentIdsByChild($childId); } - - $bundleSkus = $this->getSkusByProductIds->execute($bundleProductsIds); - foreach ($bundleSkus as $bundleSku) { - $bundleData[$bundleSku] = $this->getIndexSalabilityStatus($bundleSku, $stockId); + $bundleProductsIds = array_merge(...$bundleProductsIds); + $bundleSkus = $bundleProductsIds ? $this->getSkusByProductIds->execute($bundleProductsIds) : []; + $areBundleProdcutsSalable = $this->areProductsSalable->execute($bundleSkus, $stockId); + foreach ($areBundleProdcutsSalable as $salableResult) { + if ($salableResult->isSalable() !== $this->getIndexSalabilityStatus($salableResult->getSku(), $stockId)) { + $bundleData[$salableResult->getSku()] = $salableResult->isSalable(); + } } return array_merge($result, $bundleData); diff --git a/InventoryBundleProductIndexer/composer.json b/InventoryBundleProductIndexer/composer.json index 9650c2c35df5..d9a1825be660 100644 --- a/InventoryBundleProductIndexer/composer.json +++ b/InventoryBundleProductIndexer/composer.json @@ -10,6 +10,7 @@ "magento/module-inventory-catalog-api": "*", "magento/module-inventory-indexer": "*", "magento/module-inventory-multi-dimensional-indexer-api": "*" + "magento/module-inventory-sales-api": "*" }, "suggest": { "magento/module-inventory": "*" diff --git a/InventoryCatalog/Plugin/Catalog/Model/Product/IsAvailablePlugin.php b/InventoryCatalog/Plugin/Catalog/Model/Product/IsAvailablePlugin.php new file mode 100644 index 000000000000..92592182305f --- /dev/null +++ b/InventoryCatalog/Plugin/Catalog/Model/Product/IsAvailablePlugin.php @@ -0,0 +1,44 @@ +isProductSalable = $isProductSalable; + } + + /** + * Fetches is salable status from multi-stock. + * + * @param Product $product + * @param \Closure $proceed + * @return bool + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function aroundIsAvailable(Product $product, \Closure $proceed): bool + { + return $this->isProductSalable->execute($product); + } +} diff --git a/InventoryCatalog/Plugin/Catalog/Model/Product/IsSalablePlugin.php b/InventoryCatalog/Plugin/Catalog/Model/Product/IsSalablePlugin.php index 5b72f5dc8a08..a9ceb147a342 100644 --- a/InventoryCatalog/Plugin/Catalog/Model/Product/IsSalablePlugin.php +++ b/InventoryCatalog/Plugin/Catalog/Model/Product/IsSalablePlugin.php @@ -8,7 +8,6 @@ namespace Magento\InventoryCatalog\Plugin\Catalog\Model\Product; use Magento\Catalog\Model\Product; -use Magento\Catalog\Model\Product\Type\Simple; use Magento\InventoryCatalog\Model\IsProductSalable; /** diff --git a/InventoryCatalog/Plugin/CatalogInventory/Api/StockRegistry/AdaptGetStockStatusPlugin.php b/InventoryCatalog/Plugin/CatalogInventory/Api/StockRegistry/AdaptGetStockStatusPlugin.php index 721fc72de5e1..6593389973a0 100644 --- a/InventoryCatalog/Plugin/CatalogInventory/Api/StockRegistry/AdaptGetStockStatusPlugin.php +++ b/InventoryCatalog/Plugin/CatalogInventory/Api/StockRegistry/AdaptGetStockStatusPlugin.php @@ -12,7 +12,6 @@ use Magento\Framework\Exception\InputException; use Magento\Framework\Exception\LocalizedException; use Magento\Framework\Exception\NoSuchEntityException; -use Magento\InventoryCatalogApi\Api\DefaultStockProviderInterface; use Magento\InventoryCatalogApi\Model\GetSkusByProductIdsInterface; use Magento\InventorySalesApi\Api\AreProductsSalableInterface; use Magento\InventorySalesApi\Api\Data\SalesChannelInterface; @@ -50,33 +49,25 @@ class AdaptGetStockStatusPlugin */ private $stockResolver; - /** - * @var DefaultStockProviderInterface - */ - private $defaultStockProvider; - /** * @param AreProductsSalableInterface $areProductsSalable * @param GetProductSalableQtyInterface $getProductSalableQty * @param GetSkusByProductIdsInterface $getSkusByProductIds * @param StoreManagerInterface $storeManager * @param StockResolverInterface $stockResolver - * @param DefaultStockProviderInterface $defaultStockProvider */ public function __construct( AreProductsSalableInterface $areProductsSalable, GetProductSalableQtyInterface $getProductSalableQty, GetSkusByProductIdsInterface $getSkusByProductIds, StoreManagerInterface $storeManager, - StockResolverInterface $stockResolver, - DefaultStockProviderInterface $defaultStockProvider + StockResolverInterface $stockResolver ) { $this->areProductsSalable = $areProductsSalable; $this->getProductSalableQty = $getProductSalableQty; $this->getSkusByProductIds = $getSkusByProductIds; $this->storeManager = $storeManager; $this->stockResolver = $stockResolver; - $this->defaultStockProvider = $defaultStockProvider; } /** @@ -101,9 +92,6 @@ public function afterGetStockStatus( ? $this->storeManager->getWebsite()->getCode() : $this->storeManager->getWebsite($scopeId)->getCode(); $stockId = $this->stockResolver->execute(SalesChannelInterface::TYPE_WEBSITE, $websiteCode)->getStockId(); - if ($this->defaultStockProvider->getId() === $stockId) { - return $stockStatus; - } $sku = $this->getSkusByProductIds->execute([$productId])[$productId]; $result = $this->areProductsSalable->execute([$sku], $stockId); diff --git a/InventoryCatalog/etc/di.xml b/InventoryCatalog/etc/di.xml index 6d0db77426d5..6f808f350e7f 100644 --- a/InventoryCatalog/etc/di.xml +++ b/InventoryCatalog/etc/di.xml @@ -163,5 +163,6 @@ + diff --git a/InventoryConfigurableProduct/Plugin/InventoryCatalog/Model/IsProductSalable/IsConfigurableProductSalablePlugin.php b/InventoryConfigurableProduct/Plugin/InventoryCatalog/Model/IsProductSalable/IsConfigurableProductSalablePlugin.php index 28fc95d9eb77..d8b31df9607c 100644 --- a/InventoryConfigurableProduct/Plugin/InventoryCatalog/Model/IsProductSalable/IsConfigurableProductSalablePlugin.php +++ b/InventoryConfigurableProduct/Plugin/InventoryCatalog/Model/IsProductSalable/IsConfigurableProductSalablePlugin.php @@ -9,7 +9,6 @@ use Magento\Catalog\Api\Data\ProductInterface; use Magento\ConfigurableProduct\Model\Product\Type\Configurable; -use Magento\InventoryBundleProduct\Model\GetProductSelections; use Magento\InventoryCatalog\Model\IsProductSalable; /** @@ -22,19 +21,12 @@ class IsConfigurableProductSalablePlugin */ private $type; - /** - * @var GetProductSelections - */ - private $getProductSelections; - /** * @param Configurable $type - * @param GetProductSelections $getProductSelections */ - public function __construct(Configurable $type, GetProductSelections $getProductSelections) + public function __construct(Configurable $type) { $this->type = $type; - $this->getProductSelections = $getProductSelections; } /** diff --git a/InventoryConfigurableProductIndexer/Plugin/InventoryIndexer/Model/Queue/GetDataForUpdate/AddConfigurableProductDataPlugin.php b/InventoryConfigurableProductIndexer/Plugin/InventoryIndexer/Model/Queue/GetDataForUpdate/AddConfigurableProductDataPlugin.php index b40d76a3c49e..0e62f8fcfb12 100644 --- a/InventoryConfigurableProductIndexer/Plugin/InventoryIndexer/Model/Queue/GetDataForUpdate/AddConfigurableProductDataPlugin.php +++ b/InventoryConfigurableProductIndexer/Plugin/InventoryIndexer/Model/Queue/GetDataForUpdate/AddConfigurableProductDataPlugin.php @@ -13,6 +13,7 @@ use Magento\InventoryCatalogApi\Model\GetProductIdsBySkusInterface; use Magento\InventoryCatalogApi\Model\GetSkusByProductIdsInterface; use Magento\InventoryIndexer\Model\Queue\UpdateIndexSalabilityStatus\IndexProcessor\GetDataForUpdate; +use Magento\InventorySalesApi\Api\AreProductsSalableInterface; use Magento\InventorySalesApi\Model\GetStockItemDataInterface; use Psr\Log\LoggerInterface; @@ -41,6 +42,11 @@ class AddConfigurableProductDataPlugin */ private $getStockItemData; + /** + * @var AreProductsSalableInterface + */ + private $areProductsSalable; + /** * @var LoggerInterface */ @@ -51,6 +57,7 @@ class AddConfigurableProductDataPlugin * @param GetProductIdsBySkusInterface $getProductIdsBySkus * @param GetSkusByProductIdsInterface $getSkusByProductIds * @param GetStockItemDataInterface $getStockItemData + * @param AreProductsSalableInterface $areProductsSalable * @param LoggerInterface $logger */ public function __construct( @@ -58,6 +65,7 @@ public function __construct( GetProductIdsBySkusInterface $getProductIdsBySkus, GetSkusByProductIdsInterface $getSkusByProductIds, GetStockItemDataInterface $getStockItemData, + AreProductsSalableInterface $areProductsSalable, LoggerInterface $logger ) { $this->type = $type; @@ -65,6 +73,7 @@ public function __construct( $this->getSkusByProductIds = $getSkusByProductIds; $this->getStockItemData = $getStockItemData; $this->logger = $logger; + $this->areProductsSalable = $areProductsSalable; } /** @@ -87,10 +96,13 @@ public function afterExecute(GetDataForUpdate $subject, array $result, array $sa foreach ($childrenIds as $childId) { $configurableProductIds[] = $this->type->getParentIdsByChild($childId); } - - $configurableSkus = $this->getSkusByProductIds->execute($configurableProductIds); - foreach ($configurableSkus as $configurableSku) { - $configurableData[$configurableSku] = $this->getIndexSalabilityStatus($configurableSku, $stockId); + $configurableProductIds = array_merge(...$configurableProductIds); + $configurableSkus = $configurableProductIds ? $this->getSkusByProductIds->execute($configurableProductIds) : []; + $areConfigurableProductsSalable = $this->areProductsSalable->execute($configurableSkus, $stockId); + foreach ($areConfigurableProductsSalable as $salableResult) { + if ($salableResult->isSalable() !== $this->getIndexSalabilityStatus($salableResult->getSku(), $stockId)) { + $configurableData[$salableResult->getSku()] = $salableResult->isSalable(); + } } return array_merge($result, $configurableData); diff --git a/InventoryConfigurableProductIndexer/composer.json b/InventoryConfigurableProductIndexer/composer.json index 7cddd52ebb9e..2079d1b645e0 100644 --- a/InventoryConfigurableProductIndexer/composer.json +++ b/InventoryConfigurableProductIndexer/composer.json @@ -5,6 +5,7 @@ "php": "~7.3.0||~7.4.0", "magento/framework": "*", "magento/module-catalog": "*", + "magento/module-configurable-product": "*", "magento/module-inventory-api": "*", "magento/module-inventory-catalog-api": "*", "magento/module-inventory-indexer": "*", diff --git a/InventoryIndexer/Model/Queue/UpdateIndexSalabilityStatus/IndexProcessor.php b/InventoryIndexer/Model/Queue/UpdateIndexSalabilityStatus/IndexProcessor.php index ffb0a3b11af1..d49974a59dc4 100644 --- a/InventoryIndexer/Model/Queue/UpdateIndexSalabilityStatus/IndexProcessor.php +++ b/InventoryIndexer/Model/Queue/UpdateIndexSalabilityStatus/IndexProcessor.php @@ -17,7 +17,6 @@ use Magento\InventoryMultiDimensionalIndexerApi\Model\IndexNameBuilder; use Magento\InventoryMultiDimensionalIndexerApi\Model\IndexStructureInterface; use Magento\InventorySalesApi\Api\AreProductsSalableInterface; -use Magento\InventorySalesApi\Model\GetStockItemDataInterface; /** * Update 'is salable' index data processor. @@ -40,9 +39,9 @@ class IndexProcessor private $areProductsSalable; /** - * @var GetStockItemDataInterface + * @var GetDataForUpdate */ - private $getStockItemData; + private $getDataForUpdate; /** * @var UpdateIsSalable @@ -53,7 +52,7 @@ class IndexProcessor * @param IndexNameBuilder $indexNameBuilder * @param IndexStructureInterface $indexStructure * @param AreProductsSalableInterface $areProductsSalable - * @param GetStockItemDataInterface $getDataForUpdate + * @param GetDataForUpdate $getDataForUpdate * @param UpdateIsSalable $updateIsSalable */ public function __construct( @@ -66,7 +65,7 @@ public function __construct( $this->indexNameBuilder = $indexNameBuilder; $this->indexStructure = $indexStructure; $this->areProductsSalable = $areProductsSalable; - $this->getStockItemData = $getDataForUpdate; + $this->getDataForUpdate = $getDataForUpdate; $this->updateIsSalable = $updateIsSalable; } @@ -93,7 +92,7 @@ public function execute(ReservationData $reservationData, int $stockId): array $reservationData->getStock() ); - $dataForUpdate = $this->getDataForUpdate($salabilityData, $stockId); + $dataForUpdate = $this->getDataForUpdate->execute($salabilityData, $stockId); $this->updateIsSalable->execute( $mainIndexName, $dataForUpdate, From 4d6eb6368d0138853b958691114bd579ffc6fda5 Mon Sep 17 00:00:00 2001 From: nmalevanec Date: Mon, 1 Jun 2020 17:03:50 +0300 Subject: [PATCH 35/50] Remove MySQL view. Re-work bundle product indexer. --- .../Integration/GetSourceCodesBySkusTest.php | 3 + .../Plugin/Model/AreProductsSalablePlugin.php | 13 --- .../AdaptAddQuantityFilterPlugin.php | 14 +-- .../Order/PlaceOrderOnDefaultStockTest.php | 4 +- .../AddSalesQuoteItemOnDefaultStockTest.php | 3 + InventoryBundleProduct/etc/di.xml | 2 +- .../Indexer/SelectBuilder.php | 2 - .../SourceItem/IndexDataBySkuListProvider.php | 23 ++++- .../Indexer/SourceItem/SourceItemIndexer.php | 15 +-- .../Indexer/StockIndexer.php | 13 --- .../ResourceModel/GetProductIdsByStockIds.php | 28 ++---- ...ptAddIsInStockFilterToCollectionPlugin.php | 12 +-- .../AdaptAddStockStatusToSelectPlugin.php | 17 +--- .../Setup/Operation/ReindexDefaultStock.php | 41 +++++++- .../Schema/CreateLegacyStockStatusView.php | 96 ------------------- .../Bulk/InventoryTransferTest.php | 8 +- .../Integration/Bulk/SourceAssignTest.php | 4 +- .../Integration/Bulk/SourceUnassignTest.php | 2 +- ...ductStockStatusBySkuOnDefaultStockTest.php | 3 + ...etProductStockStatusOnDefaultStockTest.php | 3 + .../GetStockStatusBySkuOnDefaultStockTest.php | 3 + .../GetStockStatusOnDefaultStockTest.php | 3 + ...ckFilterToCollectionOnDefaultStockTest.php | 1 + ...tockStatusToProductsOnDefaultStockTest.php | 1 + ...ssignStatusToProductOnDefaultStockTest.php | 3 + ...ckFilterToCollectionOnDefaultStockTest.php | 1 + ...tockDataToCollectionOnDefaultStockTest.php | 1 + ...dStockStatusToSelectOnDefaultStockTest.php | 1 + .../GetDefaultSourceItemBySkuTest.php | 3 + .../GetSourceItemsBySkuAndSourceCodesTest.php | 3 + ...ToLegacyStockItemAtSourceItemsSaveTest.php | 3 + ...LegacyStockStatusAtSourceItemsSaveTest.php | 2 + ...gacyStockStatusAtSourceItemsDeleteTest.php | 1 + ...LegacyStockItemAtSourceItemsDeleteTest.php | 1 + ...ultSourceItemAtLegacyStockItemSaveTest.php | 6 +- ...dateDefaultSourceItemAtProductSaveTest.php | 2 +- .../GetSourceItemsDataBySkuTest.php | 3 + .../AddSalesQuoteItemOnDefaultStockTest.php | 2 + InventoryConfigurableProduct/etc/di.xml | 2 +- .../Indexer/SourceItem/SourceItemIndexer.php | 17 +--- .../Indexer/Stock/StockIndexer.php | 13 --- .../StockedProductFilterByInventoryStock.php | 41 +------- .../Indexer/SourceItem/SourceItemIndexer.php | 17 +--- .../Indexer/Stock/StockIndexer.php | 13 --- .../Integration/Model/Export/SourcesTest.php | 3 + .../Indexer/SourceItem/Strategy/Sync.php | 21 +--- .../Indexer/Stock/Strategy/Sync.php | 15 +-- .../Model/ResourceModel/GetStockItemData.php | 50 +++------- .../BackorderConditionTest.php | 7 +- .../Stock/GetProductSalableQtyTest.php | 84 +++++++++++++++- .../GetNonCachedStockItemPlugin.php | 80 ++++++++++++++++ .../etc/frontend/di.xml | 3 + 52 files changed, 327 insertions(+), 385 deletions(-) delete mode 100644 InventoryCatalog/Setup/Patch/Schema/CreateLegacyStockStatusView.php create mode 100644 dev/tests/integration/_files/Magento/TestModuleInventoryStateCache/Plugin/CatalogInventory/Model/StockRegistryProvider/GetNonCachedStockItemPlugin.php diff --git a/Inventory/Test/Integration/GetSourceCodesBySkusTest.php b/Inventory/Test/Integration/GetSourceCodesBySkusTest.php index be649065b1f6..e0971d032fe4 100644 --- a/Inventory/Test/Integration/GetSourceCodesBySkusTest.php +++ b/Inventory/Test/Integration/GetSourceCodesBySkusTest.php @@ -11,6 +11,9 @@ use Magento\TestFramework\Helper\Bootstrap; use PHPUnit\Framework\TestCase; +/** + * @magentoDbIsolation disabled + */ class GetSourceCodesBySkusTest extends TestCase { /** diff --git a/InventoryAdvancedCheckout/Plugin/Model/AreProductsSalablePlugin.php b/InventoryAdvancedCheckout/Plugin/Model/AreProductsSalablePlugin.php index ed99695aae25..9ca7dae53e27 100644 --- a/InventoryAdvancedCheckout/Plugin/Model/AreProductsSalablePlugin.php +++ b/InventoryAdvancedCheckout/Plugin/Model/AreProductsSalablePlugin.php @@ -11,7 +11,6 @@ use Magento\AdvancedCheckout\Model\Data\IsProductsSalableForRequestedQtyResult; use Magento\Framework\Exception\NoSuchEntityException; use Magento\Framework\ObjectManagerInterface; -use Magento\InventoryCatalogApi\Api\DefaultStockProviderInterface; use Magento\InventorySalesApi\Api\AreProductsSalableInterface; use Magento\InventorySalesApi\Api\Data\SalesChannelInterface; use Magento\InventorySalesApi\Api\StockResolverInterface; @@ -37,11 +36,6 @@ class AreProductsSalablePlugin */ private $websiteRepository; - /** - * @var DefaultStockProviderInterface - */ - private $defaultStockProvider; - /** * @var ObjectManagerInterface */ @@ -51,20 +45,17 @@ class AreProductsSalablePlugin * @param AreProductsSalableInterface $areProductsSalable * @param StockResolverInterface $stockResolver * @param WebsiteRepositoryInterface $websiteRepository - * @param DefaultStockProviderInterface $defaultStockProvider * @param ObjectManagerInterface $objectManager */ public function __construct( AreProductsSalableInterface $areProductsSalable, StockResolverInterface $stockResolver, WebsiteRepositoryInterface $websiteRepository, - DefaultStockProviderInterface $defaultStockProvider, ObjectManagerInterface $objectManager ) { $this->areProductsSalable = $areProductsSalable; $this->stockResolver = $stockResolver; $this->websiteRepository = $websiteRepository; - $this->defaultStockProvider = $defaultStockProvider; $this->objectManager = $objectManager; } @@ -87,10 +78,6 @@ public function aroundExecute( ): array { $website = $this->websiteRepository->getById($websiteId); $stock = $this->stockResolver->execute(SalesChannelInterface::TYPE_WEBSITE, $website->getCode()); - if ($this->defaultStockProvider->getId() === $stock->getStockId()) { - return $proceed($productQuantities, $websiteId); - } - $skus = []; foreach ($productQuantities as $productQuantity) { $skus[] = $productQuantity->getSku(); diff --git a/InventoryBundleProduct/Plugin/Bundle/Model/ResourceModel/Selection/Collection/AdaptAddQuantityFilterPlugin.php b/InventoryBundleProduct/Plugin/Bundle/Model/ResourceModel/Selection/Collection/AdaptAddQuantityFilterPlugin.php index a3192b94b108..1eba8535e94c 100644 --- a/InventoryBundleProduct/Plugin/Bundle/Model/ResourceModel/Selection/Collection/AdaptAddQuantityFilterPlugin.php +++ b/InventoryBundleProduct/Plugin/Bundle/Model/ResourceModel/Selection/Collection/AdaptAddQuantityFilterPlugin.php @@ -8,7 +8,6 @@ namespace Magento\InventoryBundleProduct\Plugin\Bundle\Model\ResourceModel\Selection\Collection; use Magento\Bundle\Model\ResourceModel\Selection\Collection; -use Magento\InventoryCatalogApi\Api\DefaultStockProviderInterface; use Magento\InventorySalesApi\Api\AreProductsSalableInterface; use Magento\InventorySalesApi\Model\StockByWebsiteIdResolverInterface; use Magento\Store\Model\StoreManagerInterface; @@ -33,27 +32,19 @@ class AdaptAddQuantityFilterPlugin */ private $stockByWebsiteIdResolver; - /** - * @var DefaultStockProviderInterface - */ - private $defaultStockProvider; - /** * @param AreProductsSalableInterface $areProductsSalable * @param StoreManagerInterface $storeManager * @param StockByWebsiteIdResolverInterface $stockByWebsiteIdResolver - * @param DefaultStockProviderInterface $defaultStockProvider */ public function __construct( AreProductsSalableInterface $areProductsSalable, StoreManagerInterface $storeManager, - StockByWebsiteIdResolverInterface $stockByWebsiteIdResolver, - DefaultStockProviderInterface $defaultStockProvider + StockByWebsiteIdResolverInterface $stockByWebsiteIdResolver ) { $this->areProductsSalable = $areProductsSalable; $this->storeManager = $storeManager; $this->stockByWebsiteIdResolver = $stockByWebsiteIdResolver; - $this->defaultStockProvider = $defaultStockProvider; } /** @@ -69,9 +60,6 @@ public function aroundAddQuantityFilter( ): Collection { $website = $this->storeManager->getWebsite(); $stock = $this->stockByWebsiteIdResolver->execute((int)$website->getId()); - if ($this->defaultStockProvider->getId() === $stock->getStockId()) { - return $proceed(); - } $skus = []; $skusToExclude = []; foreach ($subject->getData() as $item) { diff --git a/InventoryBundleProduct/Test/Integration/Order/PlaceOrderOnDefaultStockTest.php b/InventoryBundleProduct/Test/Integration/Order/PlaceOrderOnDefaultStockTest.php index 5f32df6c82d9..a16918b01528 100644 --- a/InventoryBundleProduct/Test/Integration/Order/PlaceOrderOnDefaultStockTest.php +++ b/InventoryBundleProduct/Test/Integration/Order/PlaceOrderOnDefaultStockTest.php @@ -31,7 +31,9 @@ * @magentoDataFixture Magento_InventoryBundleProduct::Test/_files/default_stock_bundle_products.php * @magentoDataFixture Magento_InventoryBundleProduct::Test/_files/source_items_for_bundle_options_on_default_source.php * @magentoDataFixture Magento_InventorySalesApi::Test/_files/quote.php - * @magentoDataFixture Magento_InventoryIndexer::Test/_files/reindex_inventory.php + * @magentoDataFixture Magento_InventoryIndexer::Test/_files/reindex_inventory. + * + * @magentoDbIsolation disabled */ class PlaceOrderOnDefaultStockTest extends TestCase { diff --git a/InventoryBundleProduct/Test/Integration/SalesQuoteItem/AddSalesQuoteItemOnDefaultStockTest.php b/InventoryBundleProduct/Test/Integration/SalesQuoteItem/AddSalesQuoteItemOnDefaultStockTest.php index 3efe1fa18cc0..f29b9d89d3e9 100644 --- a/InventoryBundleProduct/Test/Integration/SalesQuoteItem/AddSalesQuoteItemOnDefaultStockTest.php +++ b/InventoryBundleProduct/Test/Integration/SalesQuoteItem/AddSalesQuoteItemOnDefaultStockTest.php @@ -21,6 +21,9 @@ use Magento\TestFramework\Helper\Bootstrap; use PHPUnit\Framework\TestCase; +/** + * @magentoDbIsolation disabled + */ class AddSalesQuoteItemOnDefaultStockTest extends TestCase { /** diff --git a/InventoryBundleProduct/etc/di.xml b/InventoryBundleProduct/etc/di.xml index df7f66869360..7108f0851596 100644 --- a/InventoryBundleProduct/etc/di.xml +++ b/InventoryBundleProduct/etc/di.xml @@ -29,7 +29,7 @@ - + true Magento\InventoryBundleProduct\Model\IsProductSalableCondition\ProductOptionsCondition diff --git a/InventoryBundleProductIndexer/Indexer/SelectBuilder.php b/InventoryBundleProductIndexer/Indexer/SelectBuilder.php index dc78c4bfdb8b..0a3e660a1725 100644 --- a/InventoryBundleProductIndexer/Indexer/SelectBuilder.php +++ b/InventoryBundleProductIndexer/Indexer/SelectBuilder.php @@ -79,7 +79,6 @@ public function execute(int $stockId): Select ->build(); $indexTableName = $this->indexNameResolver->resolveName($indexName); - $metadata = $this->metadataPool->getMetadata(ProductInterface::class); $linkField = $metadata->getLinkField(); @@ -89,7 +88,6 @@ public function execute(int $stockId): Select [ IndexStructure::SKU => 'parent_product_entity.sku', IndexStructure::QUANTITY => 'SUM(stock.quantity)', - IndexStructure::IS_SALABLE => 'MAX(stock.is_salable)', ] )->joinInner( ['product_entity' => $this->resourceConnection->getTableName('catalog_product_entity')], diff --git a/InventoryBundleProductIndexer/Indexer/SourceItem/IndexDataBySkuListProvider.php b/InventoryBundleProductIndexer/Indexer/SourceItem/IndexDataBySkuListProvider.php index c6b83c5a22bd..bc0f11eb85e8 100644 --- a/InventoryBundleProductIndexer/Indexer/SourceItem/IndexDataBySkuListProvider.php +++ b/InventoryBundleProductIndexer/Indexer/SourceItem/IndexDataBySkuListProvider.php @@ -10,6 +10,7 @@ use Magento\Framework\App\ResourceConnection; use Magento\InventoryBundleProductIndexer\Indexer\SelectBuilder; use Magento\InventoryIndexer\Indexer\IndexStructure; +use Magento\InventorySalesApi\Api\AreProductsSalableInterface; /** * Returns all data for the index by source item list condition. @@ -26,16 +27,24 @@ class IndexDataBySkuListProvider */ private $selectBuilder; + /** + * @var AreProductsSalableInterface + */ + private $areProductsSalable; + /** * @param ResourceConnection $resourceConnection * @param SelectBuilder $selectBuilder + * @param AreProductsSalableInterface $areProductsSalable */ public function __construct( ResourceConnection $resourceConnection, - SelectBuilder $selectBuilder + SelectBuilder $selectBuilder, + AreProductsSalableInterface $areProductsSalable ) { $this->resourceConnection = $resourceConnection; $this->selectBuilder = $selectBuilder; + $this->areProductsSalable = $areProductsSalable; } /** @@ -53,7 +62,17 @@ public function execute(int $stockId, array $skuList): \ArrayIterator $select->where('stock.' . IndexStructure::SKU . ' IN (?)', $skuList); } $connection = $this->resourceConnection->getConnection(); + $results = $connection->fetchAll($select); + $bundleSkus = array_column($results, 'sku'); + $salableResults = $this->areProductsSalable->execute($bundleSkus, $stockId); + foreach ($salableResults as $salableResult) { + foreach ($results as &$result) { + if ($salableResult->getSku() === $result['sku']) { + $result['is_salable'] = (string)(int)$salableResult->isSalable(); + } + } + } - return new \ArrayIterator($connection->fetchAll($select)); + return new \ArrayIterator(reset($results)); } } diff --git a/InventoryBundleProductIndexer/Indexer/SourceItem/SourceItemIndexer.php b/InventoryBundleProductIndexer/Indexer/SourceItem/SourceItemIndexer.php index 2c0d805ec8f9..8d2bc8f7790d 100644 --- a/InventoryBundleProductIndexer/Indexer/SourceItem/SourceItemIndexer.php +++ b/InventoryBundleProductIndexer/Indexer/SourceItem/SourceItemIndexer.php @@ -9,7 +9,6 @@ use Magento\Framework\App\ResourceConnection; use Magento\Framework\Exception\StateException; -use Magento\InventoryCatalogApi\Api\DefaultStockProviderInterface; use Magento\InventoryIndexer\Indexer\InventoryIndexer; use Magento\InventoryMultiDimensionalIndexerApi\Model\Alias; use Magento\InventoryMultiDimensionalIndexerApi\Model\IndexHandlerInterface; @@ -51,11 +50,6 @@ class SourceItemIndexer */ private $siblingSkuListInStockProvider; - /** - * @var DefaultStockProviderInterface - */ - private $defaultStockProvider; - /** * @param ResourceConnection $resourceConnection * @param IndexNameBuilder $indexNameBuilder @@ -63,7 +57,6 @@ class SourceItemIndexer * @param IndexStructureInterface $indexStructure * @param IndexDataBySkuListProvider $indexDataBySkuListProvider * @param SiblingSkuListInStockProvider $siblingSkuListInStockProvider - * @param DefaultStockProviderInterface $defaultStockProvider */ public function __construct( ResourceConnection $resourceConnection, @@ -71,8 +64,7 @@ public function __construct( IndexHandlerInterface $indexHandler, IndexStructureInterface $indexStructure, IndexDataBySkuListProvider $indexDataBySkuListProvider, - SiblingSkuListInStockProvider $siblingSkuListInStockProvider, - DefaultStockProviderInterface $defaultStockProvider + SiblingSkuListInStockProvider $siblingSkuListInStockProvider ) { $this->resourceConnection = $resourceConnection; $this->indexNameBuilder = $indexNameBuilder; @@ -80,7 +72,6 @@ public function __construct( $this->indexDataBySkuListProvider = $indexDataBySkuListProvider; $this->indexStructure = $indexStructure; $this->siblingSkuListInStockProvider = $siblingSkuListInStockProvider; - $this->defaultStockProvider = $defaultStockProvider; } /** @@ -97,10 +88,6 @@ public function executeList(array $sourceItemIds): void foreach ($skuListInStockList as $skuListInStock) { $stockId = $skuListInStock->getStockId(); - - if ($this->defaultStockProvider->getId() === $stockId) { - continue; - } $skuList = $skuListInStock->getSkuList(); $mainIndexName = $this->indexNameBuilder diff --git a/InventoryBundleProductIndexer/Indexer/StockIndexer.php b/InventoryBundleProductIndexer/Indexer/StockIndexer.php index 9ffc7e3145e6..106aa2618c87 100644 --- a/InventoryBundleProductIndexer/Indexer/StockIndexer.php +++ b/InventoryBundleProductIndexer/Indexer/StockIndexer.php @@ -10,7 +10,6 @@ use Magento\Framework\App\ResourceConnection; use Magento\Framework\Exception\StateException; use Magento\InventoryBundleProductIndexer\Indexer\Stock\IndexDataByStockIdProvider; -use Magento\InventoryCatalogApi\Api\DefaultStockProviderInterface; use Magento\InventoryIndexer\Indexer\InventoryIndexer; use Magento\InventoryIndexer\Indexer\Stock\GetAllStockIds; use Magento\InventoryIndexer\Indexer\Stock\PrepareIndexDataForClearingIndex; @@ -55,11 +54,6 @@ class StockIndexer */ private $indexTableSwitcher; - /** - * @var DefaultStockProviderInterface - */ - private $defaultStockProvider; - /** * @var PrepareIndexDataForClearingIndex */ @@ -74,7 +68,6 @@ class StockIndexer * @param IndexNameBuilder $indexNameBuilder * @param IndexDataByStockIdProvider $indexDataByStockIdProvider * @param IndexTableSwitcherInterface $indexTableSwitcher - * @param DefaultStockProviderInterface $defaultStockProvider * @param PrepareIndexDataForClearingIndex $prepareIndexDataForClearingIndex */ public function __construct( @@ -84,7 +77,6 @@ public function __construct( IndexNameBuilder $indexNameBuilder, IndexDataByStockIdProvider $indexDataByStockIdProvider, IndexTableSwitcherInterface $indexTableSwitcher, - DefaultStockProviderInterface $defaultStockProvider, PrepareIndexDataForClearingIndex $prepareIndexDataForClearingIndex ) { $this->getAllStockIds = $getAllStockIds; @@ -93,7 +85,6 @@ public function __construct( $this->indexNameBuilder = $indexNameBuilder; $this->indexDataByStockIdProvider = $indexDataByStockIdProvider; $this->indexTableSwitcher = $indexTableSwitcher; - $this->defaultStockProvider = $defaultStockProvider; $this->prepareIndexDataForClearingIndex = $prepareIndexDataForClearingIndex; } @@ -131,10 +122,6 @@ public function executeRow(int $stockId) public function executeList(array $stockIds) { foreach ($stockIds as $stockId) { - if ($this->defaultStockProvider->getId() === $stockId) { - continue; - } - $mainIndexName = $this->indexNameBuilder ->setIndexId(InventoryIndexer::INDEXER_ID) ->addDimension('stock_', (string)$stockId) diff --git a/InventoryCache/Model/ResourceModel/GetProductIdsByStockIds.php b/InventoryCache/Model/ResourceModel/GetProductIdsByStockIds.php index ec148eaba8cb..2228729b1d87 100644 --- a/InventoryCache/Model/ResourceModel/GetProductIdsByStockIds.php +++ b/InventoryCache/Model/ResourceModel/GetProductIdsByStockIds.php @@ -8,7 +8,6 @@ namespace Magento\InventoryCache\Model\ResourceModel; use Magento\Framework\App\ResourceConnection; -use Magento\InventoryCatalogApi\Api\DefaultStockProviderInterface; use Magento\InventoryIndexer\Indexer\IndexStructure; use Magento\InventoryIndexer\Model\StockIndexTableNameResolverInterface; @@ -27,11 +26,6 @@ class GetProductIdsByStockIds */ private $stockIndexTableNameResolver; - /** - * @var DefaultStockProviderInterface - */ - private $defaultStockProvider; - /** * @var string */ @@ -40,17 +34,14 @@ class GetProductIdsByStockIds /** * @param ResourceConnection $resource * @param StockIndexTableNameResolverInterface $stockIndexTableNameResolver - * @param DefaultStockProviderInterface $defaultStockProvider * @param string $productTableName */ public function __construct( ResourceConnection $resource, StockIndexTableNameResolverInterface $stockIndexTableNameResolver, - DefaultStockProviderInterface $defaultStockProvider, string $productTableName ) { $this->resource = $resource; - $this->defaultStockProvider = $defaultStockProvider; $this->stockIndexTableNameResolver = $stockIndexTableNameResolver; $this->productTableName = $productTableName; } @@ -65,20 +56,17 @@ public function execute(array $stockIds): array { $productIds = [[]]; foreach ($stockIds as $stockId) { - if ($this->defaultStockProvider->getId() === (int)$stockId) { - continue; - } $stockIndexTableName = $this->stockIndexTableNameResolver->execute($stockId); $connection = $this->resource->getConnection(); - $sql = $connection->select() - ->from(['stock_index' => $stockIndexTableName], []) - ->join( - ['product' => $this->resource->getTableName($this->productTableName)], - 'product.sku = stock_index.' . IndexStructure::SKU, - ['product.entity_id'] - ); - $productIds[] = $connection->fetchCol($sql); + $sql = $connection->select() + ->from(['stock_index' => $stockIndexTableName], []) + ->join( + ['product' => $this->resource->getTableName($this->productTableName)], + 'product.sku = stock_index.' . IndexStructure::SKU, + ['product.entity_id'] + ); + $productIds[] = $connection->fetchCol($sql); } $productIds = array_merge(...$productIds); diff --git a/InventoryCatalog/Plugin/CatalogInventory/Model/ResourceModel/Stock/Status/AdaptAddIsInStockFilterToCollectionPlugin.php b/InventoryCatalog/Plugin/CatalogInventory/Model/ResourceModel/Stock/Status/AdaptAddIsInStockFilterToCollectionPlugin.php index ae86cb2646fe..397b068ddf36 100644 --- a/InventoryCatalog/Plugin/CatalogInventory/Model/ResourceModel/Stock/Status/AdaptAddIsInStockFilterToCollectionPlugin.php +++ b/InventoryCatalog/Plugin/CatalogInventory/Model/ResourceModel/Stock/Status/AdaptAddIsInStockFilterToCollectionPlugin.php @@ -11,7 +11,6 @@ use Magento\CatalogInventory\Model\ResourceModel\Stock\Status; use Magento\InventoryCatalog\Model\GetStockIdForCurrentWebsite; use Magento\InventoryCatalog\Model\ResourceModel\AddIsInStockFilterToCollection; -use Magento\InventoryCatalogApi\Api\DefaultStockProviderInterface; /** * Adapt adding is in stock filter to collection for multi stocks. @@ -31,16 +30,13 @@ class AdaptAddIsInStockFilterToCollectionPlugin /** * @param GetStockIdForCurrentWebsite $getStockIdForCurrentWebsite * @param AddIsInStockFilterToCollection $addIsInStockFilterToCollection - * @param DefaultStockProviderInterface $defaultStockProvider */ public function __construct( GetStockIdForCurrentWebsite $getStockIdForCurrentWebsite, - AddIsInStockFilterToCollection $addIsInStockFilterToCollection, - DefaultStockProviderInterface $defaultStockProvider + AddIsInStockFilterToCollection $addIsInStockFilterToCollection ) { $this->getStockIdForCurrentWebsite = $getStockIdForCurrentWebsite; $this->addIsInStockFilterToCollection = $addIsInStockFilterToCollection; - $this->defaultStockProvider = $defaultStockProvider; } /** @@ -59,11 +55,7 @@ public function aroundAddIsInStockFilterToCollection( $collection ) { $stockId = $this->getStockIdForCurrentWebsite->execute(); - if ($this->defaultStockProvider->getId() === $stockId) { - return $proceed($collection); - } else { - $this->addIsInStockFilterToCollection->execute($collection, $stockId); - } + $this->addIsInStockFilterToCollection->execute($collection, $stockId); return $stockStatus; } diff --git a/InventoryCatalog/Plugin/CatalogInventory/Model/ResourceModel/Stock/Status/AdaptAddStockStatusToSelectPlugin.php b/InventoryCatalog/Plugin/CatalogInventory/Model/ResourceModel/Stock/Status/AdaptAddStockStatusToSelectPlugin.php index 2c051c39de77..438a6bcc6f73 100644 --- a/InventoryCatalog/Plugin/CatalogInventory/Model/ResourceModel/Stock/Status/AdaptAddStockStatusToSelectPlugin.php +++ b/InventoryCatalog/Plugin/CatalogInventory/Model/ResourceModel/Stock/Status/AdaptAddStockStatusToSelectPlugin.php @@ -11,7 +11,6 @@ use Magento\Framework\DB\Select; use Magento\Framework\Exception\LocalizedException; use Magento\InventoryCatalog\Model\ResourceModel\AddStockStatusToSelect; -use Magento\InventoryCatalogApi\Api\DefaultStockProviderInterface; use Magento\InventorySalesApi\Api\Data\SalesChannelInterface; use Magento\InventorySalesApi\Api\StockResolverInterface; use Magento\Store\Model\Website; @@ -31,24 +30,16 @@ class AdaptAddStockStatusToSelectPlugin */ private $addStockStatusToSelect; - /** - * @var DefaultStockProviderInterface - */ - private $defaultStockProvider; - /** * @param StockResolverInterface $stockResolver * @param AddStockStatusToSelect $addStockStatusToSelect - * @param DefaultStockProviderInterface $defaultStockProvider */ public function __construct( StockResolverInterface $stockResolver, - AddStockStatusToSelect $addStockStatusToSelect, - DefaultStockProviderInterface $defaultStockProvider + AddStockStatusToSelect $addStockStatusToSelect ) { $this->stockResolver = $stockResolver; $this->addStockStatusToSelect = $addStockStatusToSelect; - $this->defaultStockProvider = $defaultStockProvider; } /** @@ -75,11 +66,7 @@ public function aroundAddStockStatusToSelect( $stock = $this->stockResolver->execute(SalesChannelInterface::TYPE_WEBSITE, $websiteCode); $stockId = (int)$stock->getStockId(); - if ($this->defaultStockProvider->getId() === $stockId) { - return $proceed($select, $website); - } else { - $this->addStockStatusToSelect->execute($select, $stockId); - } + $this->addStockStatusToSelect->execute($select, $stockId); return $stockStatus; } diff --git a/InventoryCatalog/Setup/Operation/ReindexDefaultStock.php b/InventoryCatalog/Setup/Operation/ReindexDefaultStock.php index f4309ccce90b..95d2abdb7a4e 100644 --- a/InventoryCatalog/Setup/Operation/ReindexDefaultStock.php +++ b/InventoryCatalog/Setup/Operation/ReindexDefaultStock.php @@ -7,11 +7,17 @@ namespace Magento\InventoryCatalog\Setup\Operation; -use Magento\InventoryIndexer\Indexer\Stock\StockIndexer; +use Magento\Framework\App\ResourceConnection; +use Magento\Framework\Exception\StateException; use Magento\InventoryCatalogApi\Api\DefaultStockProviderInterface; +use Magento\InventoryIndexer\Indexer\InventoryIndexer; +use Magento\InventoryIndexer\Indexer\Stock\StockIndexer; +use Magento\InventoryMultiDimensionalIndexerApi\Model\Alias; +use Magento\InventoryMultiDimensionalIndexerApi\Model\IndexNameBuilder; +use Magento\InventoryMultiDimensionalIndexerApi\Model\IndexStructureInterface; /** - * CReindex default stock during installation + * Create default stock index during installation. */ class ReindexDefaultStock { @@ -25,25 +31,52 @@ class ReindexDefaultStock */ private $stockIndexer; + /** + * @var IndexNameBuilder + */ + private $indexNameBuilder; + + /** + * @var IndexStructureInterface + */ + private $indexStructure; + /** * @param DefaultStockProviderInterface $defaultStockProvider * @param StockIndexer $stockIndexer + * @param IndexNameBuilder $indexNameBuilder + * @param IndexStructureInterface $indexStructure */ public function __construct( DefaultStockProviderInterface $defaultStockProvider, - StockIndexer $stockIndexer + StockIndexer $stockIndexer, + IndexNameBuilder $indexNameBuilder, + IndexStructureInterface $indexStructure ) { $this->defaultStockProvider = $defaultStockProvider; $this->stockIndexer = $stockIndexer; + $this->indexNameBuilder = $indexNameBuilder; + $this->indexStructure = $indexStructure; } /** - * Create default stock + * Create default stock. * * @return void + * @throws StateException */ public function execute() { + $stockId = $this->defaultStockProvider->getId(); + $mainIndexName = $this->indexNameBuilder + ->setIndexId(InventoryIndexer::INDEXER_ID) + ->addDimension('stock_', (string)$stockId) + ->setAlias(Alias::ALIAS_MAIN) + ->build(); + + if (!$this->indexStructure->isExist($mainIndexName, ResourceConnection::DEFAULT_CONNECTION)) { + $this->indexStructure->create($mainIndexName, ResourceConnection::DEFAULT_CONNECTION); + } //$this->stockIndexer->executeRow($this->defaultStockProvider->getId()); } } diff --git a/InventoryCatalog/Setup/Patch/Schema/CreateLegacyStockStatusView.php b/InventoryCatalog/Setup/Patch/Schema/CreateLegacyStockStatusView.php deleted file mode 100644 index eec200ce0b00..000000000000 --- a/InventoryCatalog/Setup/Patch/Schema/CreateLegacyStockStatusView.php +++ /dev/null @@ -1,96 +0,0 @@ -schemaSetup = $schemaSetup; - $this->stockIndexTableNameResolver = $stockIndexTableNameResolver; - $this->defaultStockProvider = $defaultStockProvider; - } - - /** - * @inheritdoc - */ - public function getAliases() - { - return []; - } - - /** - * @inheritdoc - */ - public function apply() - { - $this->schemaSetup->startSetup(); - $defaultStockId = $this->defaultStockProvider->getId(); - $viewToLegacyIndex = $this->stockIndexTableNameResolver->execute($defaultStockId); - $legacyStockStatusTable = $this->schemaSetup->getTable('cataloginventory_stock_status'); - $productTable = $this->schemaSetup->getTable('catalog_product_entity'); - $sql = "CREATE - SQL SECURITY INVOKER - VIEW {$viewToLegacyIndex} - AS - SELECT - DISTINCT - legacy_stock_status.product_id, - legacy_stock_status.website_id, - legacy_stock_status.stock_id, - legacy_stock_status.qty quantity, - legacy_stock_status.stock_status is_salable, - product.sku - FROM {$legacyStockStatusTable} legacy_stock_status - INNER JOIN {$productTable} product - ON legacy_stock_status.product_id = product.entity_id;"; - $this->schemaSetup->getConnection()->query($sql); - $this->schemaSetup->endSetup(); - - return $this; - } - - /** - * @inheritdoc - */ - public static function getDependencies() - { - return []; - } -} diff --git a/InventoryCatalog/Test/Integration/Bulk/InventoryTransferTest.php b/InventoryCatalog/Test/Integration/Bulk/InventoryTransferTest.php index 0a7a93a5fdde..f607274c7478 100644 --- a/InventoryCatalog/Test/Integration/Bulk/InventoryTransferTest.php +++ b/InventoryCatalog/Test/Integration/Bulk/InventoryTransferTest.php @@ -15,6 +15,9 @@ use Magento\TestFramework\Helper\Bootstrap; use PHPUnit\Framework\TestCase; +/** + * @magentoDbIsolation disabled + */ class InventoryTransferTest extends TestCase { /** @@ -89,7 +92,6 @@ private function getSourceItem(string $sku, string $sourceCode): ?SourceItemInte * @magentoDataFixture Magento_InventoryApi::Test/_files/sources.php * @magentoDataFixture Magento_InventoryApi::Test/_files/products.php * @magentoDataFixture Magento_InventoryApi::Test/_files/source_items.php - * @magentoDbIsolation enabled */ public function testBulkInventoryTransferAndUnassign() { @@ -116,7 +118,6 @@ public function testBulkInventoryTransferAndUnassign() * @magentoDataFixture Magento_InventoryApi::Test/_files/sources.php * @magentoDataFixture Magento_InventoryApi::Test/_files/products.php * @magentoDataFixture Magento_InventoryApi::Test/_files/source_items.php - * @magentoDbIsolation enabled */ public function testBulkInventoryTransferWithOutOfStockOrigin() { @@ -150,7 +151,6 @@ public function testBulkInventoryTransferWithOutOfStockOrigin() * @magentoDataFixture Magento_InventoryApi::Test/_files/sources.php * @magentoDataFixture Magento_InventoryApi::Test/_files/products.php * @magentoDataFixture Magento_InventoryApi::Test/_files/source_items.php - * @magentoDbIsolation enabled */ public function testBulkInventoryTransferToNewSource() { @@ -190,7 +190,6 @@ public function testBulkInventoryTransferToNewSource() * @magentoDataFixture Magento_InventoryApi::Test/_files/sources.php * @magentoDataFixture Magento_InventoryApi::Test/_files/products.php * @magentoDataFixture Magento_InventoryApi::Test/_files/source_items.php - * @magentoDbIsolation enabled */ public function testBulkInventoryTransferFromUnassignedOriginSource() { @@ -224,7 +223,6 @@ public function testBulkInventoryTransferFromUnassignedOriginSource() * @magentoDataFixture Magento_InventoryApi::Test/_files/sources.php * @magentoDataFixture Magento_InventoryApi::Test/_files/products.php * @magentoDataFixture Magento_InventoryApi::Test/_files/source_items.php - * @magentoDbIsolation enabled */ public function testBulkInventoryTransferToAssignedSource() { diff --git a/InventoryCatalog/Test/Integration/Bulk/SourceAssignTest.php b/InventoryCatalog/Test/Integration/Bulk/SourceAssignTest.php index 7104720ffad5..37ddec25953c 100644 --- a/InventoryCatalog/Test/Integration/Bulk/SourceAssignTest.php +++ b/InventoryCatalog/Test/Integration/Bulk/SourceAssignTest.php @@ -62,7 +62,7 @@ private function getSourceItemCodesBySku(string $sku): array * @magentoDataFixture Magento_InventoryApi::Test/_files/sources.php * @magentoDataFixture Magento_InventoryApi::Test/_files/products.php * @magentoDataFixture Magento_InventoryCatalog::Test/_files/source_items_on_default_source.php - * @magentoDbIsolation enabled + * @magentoDbIsolation disabled */ public function testBulkSourceAssignment() { @@ -121,7 +121,7 @@ public function testBulkSourceAssignment() /** * @magentoDataFixture Magento_InventoryApi::Test/_files/sources.php * @magentoDataFixture Magento_InventoryCatalog::Test/_files/products_all_types.php - * @magentoDbIsolation enabled + * @magentoDbIsolation disabled */ public function testBulkSourceAssignmentOnMixedProducts() { diff --git a/InventoryCatalog/Test/Integration/Bulk/SourceUnassignTest.php b/InventoryCatalog/Test/Integration/Bulk/SourceUnassignTest.php index 36367e33ee41..a98c9b6d55c0 100644 --- a/InventoryCatalog/Test/Integration/Bulk/SourceUnassignTest.php +++ b/InventoryCatalog/Test/Integration/Bulk/SourceUnassignTest.php @@ -62,7 +62,7 @@ private function getSourceItemCodesBySku(string $sku): array * @magentoDataFixture Magento_InventoryApi::Test/_files/sources.php * @magentoDataFixture Magento_InventoryApi::Test/_files/products.php * @magentoDataFixture Magento_InventoryApi::Test/_files/source_items.php - * @magentoDbIsolation enabled + * @magentoDbIsolation disabled */ public function testBulkSourceUnassignment() { diff --git a/InventoryCatalog/Test/Integration/CatalogInventory/Api/StockRegistry/GetProductStockStatusBySkuOnDefaultStockTest.php b/InventoryCatalog/Test/Integration/CatalogInventory/Api/StockRegistry/GetProductStockStatusBySkuOnDefaultStockTest.php index d156512abc94..b813f7e61c1e 100644 --- a/InventoryCatalog/Test/Integration/CatalogInventory/Api/StockRegistry/GetProductStockStatusBySkuOnDefaultStockTest.php +++ b/InventoryCatalog/Test/Integration/CatalogInventory/Api/StockRegistry/GetProductStockStatusBySkuOnDefaultStockTest.php @@ -12,6 +12,9 @@ use Magento\TestFramework\Helper\Bootstrap; use PHPUnit\Framework\TestCase; +/** + * @magentoDbIsolation disabled + */ class GetProductStockStatusBySkuOnDefaultStockTest extends TestCase { /** diff --git a/InventoryCatalog/Test/Integration/CatalogInventory/Api/StockRegistry/GetProductStockStatusOnDefaultStockTest.php b/InventoryCatalog/Test/Integration/CatalogInventory/Api/StockRegistry/GetProductStockStatusOnDefaultStockTest.php index 5d4fc18323d2..3f3ff44d7f8a 100644 --- a/InventoryCatalog/Test/Integration/CatalogInventory/Api/StockRegistry/GetProductStockStatusOnDefaultStockTest.php +++ b/InventoryCatalog/Test/Integration/CatalogInventory/Api/StockRegistry/GetProductStockStatusOnDefaultStockTest.php @@ -13,6 +13,9 @@ use Magento\TestFramework\Helper\Bootstrap; use PHPUnit\Framework\TestCase; +/** + * @magentoDbIsolation disabled + */ class GetProductStockStatusOnDefaultStockTest extends TestCase { /** diff --git a/InventoryCatalog/Test/Integration/CatalogInventory/Api/StockRegistry/GetStockStatusBySkuOnDefaultStockTest.php b/InventoryCatalog/Test/Integration/CatalogInventory/Api/StockRegistry/GetStockStatusBySkuOnDefaultStockTest.php index bbe8aa01d9af..c958de766e88 100644 --- a/InventoryCatalog/Test/Integration/CatalogInventory/Api/StockRegistry/GetStockStatusBySkuOnDefaultStockTest.php +++ b/InventoryCatalog/Test/Integration/CatalogInventory/Api/StockRegistry/GetStockStatusBySkuOnDefaultStockTest.php @@ -13,6 +13,9 @@ use Magento\TestFramework\Helper\Bootstrap; use PHPUnit\Framework\TestCase; +/** + * @magentoDbIsolation disabled + */ class GetStockStatusBySkuOnDefaultStockTest extends TestCase { /** diff --git a/InventoryCatalog/Test/Integration/CatalogInventory/Api/StockRegistry/GetStockStatusOnDefaultStockTest.php b/InventoryCatalog/Test/Integration/CatalogInventory/Api/StockRegistry/GetStockStatusOnDefaultStockTest.php index 6c444988daa2..066c7f080e71 100644 --- a/InventoryCatalog/Test/Integration/CatalogInventory/Api/StockRegistry/GetStockStatusOnDefaultStockTest.php +++ b/InventoryCatalog/Test/Integration/CatalogInventory/Api/StockRegistry/GetStockStatusOnDefaultStockTest.php @@ -13,6 +13,9 @@ use Magento\TestFramework\Helper\Bootstrap; use PHPUnit\Framework\TestCase; +/** + * @magentoDbIsolation disabled + */ class GetStockStatusOnDefaultStockTest extends TestCase { /** diff --git a/InventoryCatalog/Test/Integration/CatalogInventory/Helper/Stock/AddInStockFilterToCollectionOnDefaultStockTest.php b/InventoryCatalog/Test/Integration/CatalogInventory/Helper/Stock/AddInStockFilterToCollectionOnDefaultStockTest.php index 9d63158a9ff9..e027760a68ba 100644 --- a/InventoryCatalog/Test/Integration/CatalogInventory/Helper/Stock/AddInStockFilterToCollectionOnDefaultStockTest.php +++ b/InventoryCatalog/Test/Integration/CatalogInventory/Helper/Stock/AddInStockFilterToCollectionOnDefaultStockTest.php @@ -32,6 +32,7 @@ protected function setUp(): void /** * @magentoDataFixture Magento_InventoryApi::Test/_files/products.php * @magentoDataFixture Magento_InventoryCatalog::Test/_files/source_items_on_default_source.php + * @magentoDbIsolation disabled */ public function testAddInStockFilterToCollection() { diff --git a/InventoryCatalog/Test/Integration/CatalogInventory/Helper/Stock/AddStockStatusToProductsOnDefaultStockTest.php b/InventoryCatalog/Test/Integration/CatalogInventory/Helper/Stock/AddStockStatusToProductsOnDefaultStockTest.php index 268fac12015f..016d6fd2ffe8 100644 --- a/InventoryCatalog/Test/Integration/CatalogInventory/Helper/Stock/AddStockStatusToProductsOnDefaultStockTest.php +++ b/InventoryCatalog/Test/Integration/CatalogInventory/Helper/Stock/AddStockStatusToProductsOnDefaultStockTest.php @@ -33,6 +33,7 @@ protected function setUp(): void /** * @magentoDataFixture Magento_InventoryApi::Test/_files/products.php * @magentoDataFixture Magento_InventoryCatalog::Test/_files/source_items_on_default_source.php + * @magentoDbIsolation disabled */ public function testAddStockStatusToProducts() { diff --git a/InventoryCatalog/Test/Integration/CatalogInventory/Helper/Stock/AssignStatusToProductOnDefaultStockTest.php b/InventoryCatalog/Test/Integration/CatalogInventory/Helper/Stock/AssignStatusToProductOnDefaultStockTest.php index 7dd74b9fb3aa..aadcd16b58f0 100644 --- a/InventoryCatalog/Test/Integration/CatalogInventory/Helper/Stock/AssignStatusToProductOnDefaultStockTest.php +++ b/InventoryCatalog/Test/Integration/CatalogInventory/Helper/Stock/AssignStatusToProductOnDefaultStockTest.php @@ -13,6 +13,9 @@ use Magento\TestFramework\Helper\Bootstrap; use PHPUnit\Framework\TestCase; +/** + * @magentoDbIsolation disabled + */ class AssignStatusToProductOnDefaultStockTest extends TestCase { /** diff --git a/InventoryCatalog/Test/Integration/CatalogInventory/Model/ResourceModel/Stock/Status/AddIsInStockFilterToCollectionOnDefaultStockTest.php b/InventoryCatalog/Test/Integration/CatalogInventory/Model/ResourceModel/Stock/Status/AddIsInStockFilterToCollectionOnDefaultStockTest.php index 3deaecd66d62..52aeb76d896a 100644 --- a/InventoryCatalog/Test/Integration/CatalogInventory/Model/ResourceModel/Stock/Status/AddIsInStockFilterToCollectionOnDefaultStockTest.php +++ b/InventoryCatalog/Test/Integration/CatalogInventory/Model/ResourceModel/Stock/Status/AddIsInStockFilterToCollectionOnDefaultStockTest.php @@ -35,6 +35,7 @@ protected function setUp(): void /** * @magentoDataFixture Magento_InventoryApi::Test/_files/products.php * @magentoDataFixture Magento_InventoryCatalog::Test/_files/source_items_on_default_source.php + * @magentoDbIsolation disabled */ public function testAddIsInStockFilterToCollection() { diff --git a/InventoryCatalog/Test/Integration/CatalogInventory/Model/ResourceModel/Stock/Status/AddStockDataToCollectionOnDefaultStockTest.php b/InventoryCatalog/Test/Integration/CatalogInventory/Model/ResourceModel/Stock/Status/AddStockDataToCollectionOnDefaultStockTest.php index 7294cbf05c59..b060512d5aef 100644 --- a/InventoryCatalog/Test/Integration/CatalogInventory/Model/ResourceModel/Stock/Status/AddStockDataToCollectionOnDefaultStockTest.php +++ b/InventoryCatalog/Test/Integration/CatalogInventory/Model/ResourceModel/Stock/Status/AddStockDataToCollectionOnDefaultStockTest.php @@ -32,6 +32,7 @@ protected function setUp(): void /** * @magentoDataFixture Magento_InventoryApi::Test/_files/products.php * @magentoDataFixture Magento_InventoryCatalog::Test/_files/source_items_on_default_source.php + * @magentoDbIsolation disabled * * @param int $expectedSize * @param bool $isFilterInStock diff --git a/InventoryCatalog/Test/Integration/CatalogInventory/Model/ResourceModel/Stock/Status/AddStockStatusToSelectOnDefaultStockTest.php b/InventoryCatalog/Test/Integration/CatalogInventory/Model/ResourceModel/Stock/Status/AddStockStatusToSelectOnDefaultStockTest.php index e4a53d61b16d..2051596670bb 100644 --- a/InventoryCatalog/Test/Integration/CatalogInventory/Model/ResourceModel/Stock/Status/AddStockStatusToSelectOnDefaultStockTest.php +++ b/InventoryCatalog/Test/Integration/CatalogInventory/Model/ResourceModel/Stock/Status/AddStockStatusToSelectOnDefaultStockTest.php @@ -42,6 +42,7 @@ protected function setUp(): void /** * @magentoDataFixture Magento_InventoryApi::Test/_files/products.php * @magentoDataFixture Magento_InventoryCatalog::Test/_files/source_items_on_default_source.php + * @magentoDbIsolation disabled */ public function testAddStockStatusToSelect() { diff --git a/InventoryCatalog/Test/Integration/GetDefaultSourceItemBySkuTest.php b/InventoryCatalog/Test/Integration/GetDefaultSourceItemBySkuTest.php index 67c288c0b614..d569a610bb13 100644 --- a/InventoryCatalog/Test/Integration/GetDefaultSourceItemBySkuTest.php +++ b/InventoryCatalog/Test/Integration/GetDefaultSourceItemBySkuTest.php @@ -11,6 +11,9 @@ use Magento\TestFramework\Helper\Bootstrap; use PHPUnit\Framework\TestCase; +/** + * @magentoDbIsolation disabled + */ class GetDefaultSourceItemBySkuTest extends TestCase { /** diff --git a/InventoryCatalog/Test/Integration/GetSourceItemsBySkuAndSourceCodesTest.php b/InventoryCatalog/Test/Integration/GetSourceItemsBySkuAndSourceCodesTest.php index 23d02c517f1c..b90f4b2e976e 100644 --- a/InventoryCatalog/Test/Integration/GetSourceItemsBySkuAndSourceCodesTest.php +++ b/InventoryCatalog/Test/Integration/GetSourceItemsBySkuAndSourceCodesTest.php @@ -11,6 +11,9 @@ use Magento\TestFramework\Helper\Bootstrap; use PHPUnit\Framework\TestCase; +/** + * @magentoDbIsolation disabled + */ class GetSourceItemsBySkuAndSourceCodesTest extends TestCase { /** diff --git a/InventoryCatalog/Test/Integration/SetDataToLegacyStockItemAtSourceItemsSaveTest.php b/InventoryCatalog/Test/Integration/SetDataToLegacyStockItemAtSourceItemsSaveTest.php index a2155262ce02..4da0160215b6 100644 --- a/InventoryCatalog/Test/Integration/SetDataToLegacyStockItemAtSourceItemsSaveTest.php +++ b/InventoryCatalog/Test/Integration/SetDataToLegacyStockItemAtSourceItemsSaveTest.php @@ -19,6 +19,9 @@ use Magento\CatalogInventory\Api\StockItemCriteriaInterface; use Magento\CatalogInventory\Api\StockItemCriteriaInterfaceFactory; +/** + * @magentoDbIsolation disabled + */ class SetDataToLegacyStockItemAtSourceItemsSaveTest extends TestCase { /** diff --git a/InventoryCatalog/Test/Integration/SetDataToLegacyStockStatusAtSourceItemsSaveTest.php b/InventoryCatalog/Test/Integration/SetDataToLegacyStockStatusAtSourceItemsSaveTest.php index 21461ffb5108..9d736b8f19c7 100644 --- a/InventoryCatalog/Test/Integration/SetDataToLegacyStockStatusAtSourceItemsSaveTest.php +++ b/InventoryCatalog/Test/Integration/SetDataToLegacyStockStatusAtSourceItemsSaveTest.php @@ -25,6 +25,8 @@ /** * Tests legacy stock information synchronized with MSI's. * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + * + * @magentoDbIsolation disabled */ class SetDataToLegacyStockStatusAtSourceItemsSaveTest extends TestCase { diff --git a/InventoryCatalog/Test/Integration/SetOutOfStockToLegacyStockStatusAtSourceItemsDeleteTest.php b/InventoryCatalog/Test/Integration/SetOutOfStockToLegacyStockStatusAtSourceItemsDeleteTest.php index d4f9a788da30..1aacc09a46a3 100644 --- a/InventoryCatalog/Test/Integration/SetOutOfStockToLegacyStockStatusAtSourceItemsDeleteTest.php +++ b/InventoryCatalog/Test/Integration/SetOutOfStockToLegacyStockStatusAtSourceItemsDeleteTest.php @@ -77,6 +77,7 @@ protected function setUp(): void * @magentoDataFixture Magento_InventoryApi::Test/_files/products.php * @magentoDataFixture Magento_InventoryCatalog::Test/_files/source_items_on_default_source.php * @magentoDataFixture Magento_InventoryIndexer::Test/_files/reindex_inventory.php + * @magentoDbIsolation disabled */ public function testSetOutOfStock() { diff --git a/InventoryCatalog/Test/Integration/SetToZeroLegacyStockItemAtSourceItemsDeleteTest.php b/InventoryCatalog/Test/Integration/SetToZeroLegacyStockItemAtSourceItemsDeleteTest.php index 47eef006d6de..645b71255cb6 100644 --- a/InventoryCatalog/Test/Integration/SetToZeroLegacyStockItemAtSourceItemsDeleteTest.php +++ b/InventoryCatalog/Test/Integration/SetToZeroLegacyStockItemAtSourceItemsDeleteTest.php @@ -76,6 +76,7 @@ protected function setUp(): void * @magentoDataFixture Magento_InventoryApi::Test/_files/products.php * @magentoDataFixture Magento_InventoryCatalog::Test/_files/source_items_on_default_source.php * @magentoDataFixture Magento_InventoryIndexer::Test/_files/reindex_inventory.php + * @magentoDbIsolation disabled */ public function testSetToZero() { diff --git a/InventoryCatalog/Test/Integration/UpdateDefaultSourceItemAtLegacyStockItemSaveTest.php b/InventoryCatalog/Test/Integration/UpdateDefaultSourceItemAtLegacyStockItemSaveTest.php index 111f9ecc8039..9d21fdc8def2 100644 --- a/InventoryCatalog/Test/Integration/UpdateDefaultSourceItemAtLegacyStockItemSaveTest.php +++ b/InventoryCatalog/Test/Integration/UpdateDefaultSourceItemAtLegacyStockItemSaveTest.php @@ -37,7 +37,7 @@ protected function setUp(): void * @magentoDataFixture Magento_InventoryApi::Test/_files/products.php * @magentoDataFixture Magento_InventoryApi::Test/_files/source_items.php * @magentoDataFixture Magento_InventoryCatalog::Test/_files/source_items_on_default_source.php - * @magentoDbIsolation enabled + * @magentoDbIsolation disabled * @throws \Magento\Framework\Exception\NoSuchEntityException */ public function testSaveLegacyStockItemAssignedToDefaultSource() @@ -60,7 +60,7 @@ public function testSaveLegacyStockItemAssignedToDefaultSource() * @magentoDataFixture Magento_InventoryApi::Test/_files/products.php * @magentoDataFixture Magento_InventoryApi::Test/_files/source_items.php * @magentoDataFixture Magento_InventoryCatalog::Test/_files/source_items_on_default_source.php - * @magentoDbIsolation enabled + * @magentoDbIsolation disabled * @throws \Magento\Framework\Exception\NoSuchEntityException */ public function testSaveLegacyStockItemNotAssignedToDefaultSource() @@ -94,7 +94,7 @@ public function testSaveLegacyStockItemNotAssignedToDefaultSource() * @magentoDataFixture Magento_InventoryApi::Test/_files/sources.php * @magentoDataFixture Magento_InventoryApi::Test/_files/products.php * @magentoDataFixture Magento_InventoryApi::Test/_files/source_items.php - * @magentoDbIsolation enabled + * @magentoDbIsolation disabled * @throws \Magento\Framework\Exception\NoSuchEntityException */ public function testSaveLegacyStockItemWithoutDefaultSourceAssignment() diff --git a/InventoryCatalog/Test/Integration/UpdateDefaultSourceItemAtProductSaveTest.php b/InventoryCatalog/Test/Integration/UpdateDefaultSourceItemAtProductSaveTest.php index 5f85b63e1b0a..23ae8432cfcd 100644 --- a/InventoryCatalog/Test/Integration/UpdateDefaultSourceItemAtProductSaveTest.php +++ b/InventoryCatalog/Test/Integration/UpdateDefaultSourceItemAtProductSaveTest.php @@ -36,7 +36,7 @@ protected function setUp(): void * @magentoDataFixture Magento_InventoryApi::Test/_files/sources.php * @magentoDataFixture Magento_InventoryApi::Test/_files/products.php * @magentoDataFixture Magento_InventoryApi::Test/_files/source_items.php - * @magentoDbIsolation enabled + * @magentoDbIsolation disabled */ public function testSaveOutOfStockProductNotAssignedToDefaultSource() { diff --git a/InventoryCatalogAdminUi/Test/Integration/GetSourceItemsDataBySkuTest.php b/InventoryCatalogAdminUi/Test/Integration/GetSourceItemsDataBySkuTest.php index 15efe8dcb808..a87752eb469c 100644 --- a/InventoryCatalogAdminUi/Test/Integration/GetSourceItemsDataBySkuTest.php +++ b/InventoryCatalogAdminUi/Test/Integration/GetSourceItemsDataBySkuTest.php @@ -12,6 +12,9 @@ use Magento\TestFramework\Helper\Bootstrap; use PHPUnit\Framework\TestCase; +/** + * @magentoDbIsolation disabled + */ class GetSourceItemsDataBySkuTest extends TestCase { /** diff --git a/InventoryConfigurableProduct/Test/Integration/SalesQuoteItem/AddSalesQuoteItemOnDefaultStockTest.php b/InventoryConfigurableProduct/Test/Integration/SalesQuoteItem/AddSalesQuoteItemOnDefaultStockTest.php index 837d4759a096..54a6dcd9b7b0 100644 --- a/InventoryConfigurableProduct/Test/Integration/SalesQuoteItem/AddSalesQuoteItemOnDefaultStockTest.php +++ b/InventoryConfigurableProduct/Test/Integration/SalesQuoteItem/AddSalesQuoteItemOnDefaultStockTest.php @@ -22,6 +22,8 @@ /** * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + * + * @magentoDbIsolation disabled */ class AddSalesQuoteItemOnDefaultStockTest extends TestCase { diff --git a/InventoryConfigurableProduct/etc/di.xml b/InventoryConfigurableProduct/etc/di.xml index 5c37996e93bb..c8c1ff6dfae3 100644 --- a/InventoryConfigurableProduct/etc/di.xml +++ b/InventoryConfigurableProduct/etc/di.xml @@ -37,7 +37,7 @@ - + true Magento\InventoryConfigurableProduct\Model\IsProductSalableCondition\ProductOptionsCondition diff --git a/InventoryConfigurableProductIndexer/Indexer/SourceItem/SourceItemIndexer.php b/InventoryConfigurableProductIndexer/Indexer/SourceItem/SourceItemIndexer.php index c6a798592ada..97685ddd6c2e 100644 --- a/InventoryConfigurableProductIndexer/Indexer/SourceItem/SourceItemIndexer.php +++ b/InventoryConfigurableProductIndexer/Indexer/SourceItem/SourceItemIndexer.php @@ -8,12 +8,11 @@ namespace Magento\InventoryConfigurableProductIndexer\Indexer\SourceItem; use Magento\Framework\App\ResourceConnection; +use Magento\InventoryIndexer\Indexer\InventoryIndexer; use Magento\InventoryMultiDimensionalIndexerApi\Model\Alias; use Magento\InventoryMultiDimensionalIndexerApi\Model\IndexHandlerInterface; use Magento\InventoryMultiDimensionalIndexerApi\Model\IndexNameBuilder; use Magento\InventoryMultiDimensionalIndexerApi\Model\IndexStructureInterface; -use Magento\InventoryCatalogApi\Api\DefaultStockProviderInterface; -use Magento\InventoryIndexer\Indexer\InventoryIndexer; class SourceItemIndexer { @@ -47,11 +46,6 @@ class SourceItemIndexer */ private $siblingSkuListInStockProvider; - /** - * @var DefaultStockProviderInterface - */ - private $defaultStockProvider; - /** * @param ResourceConnection $resourceConnection * @param IndexNameBuilder $indexNameBuilder @@ -59,7 +53,6 @@ class SourceItemIndexer * @param IndexStructureInterface $indexStructure * @param IndexDataBySkuListProvider $indexDataBySkuListProvider * @param SiblingSkuListInStockProvider $siblingSkuListInStockProvider - * @param DefaultStockProviderInterface $defaultStockProvider */ public function __construct( ResourceConnection $resourceConnection, @@ -67,8 +60,7 @@ public function __construct( IndexHandlerInterface $indexHandler, IndexStructureInterface $indexStructure, IndexDataBySkuListProvider $indexDataBySkuListProvider, - SiblingSkuListInStockProvider $siblingSkuListInStockProvider, - DefaultStockProviderInterface $defaultStockProvider + SiblingSkuListInStockProvider $siblingSkuListInStockProvider ) { $this->resourceConnection = $resourceConnection; $this->indexNameBuilder = $indexNameBuilder; @@ -76,7 +68,6 @@ public function __construct( $this->indexDataBySkuListProvider = $indexDataBySkuListProvider; $this->indexStructure = $indexStructure; $this->siblingSkuListInStockProvider = $siblingSkuListInStockProvider; - $this->defaultStockProvider = $defaultStockProvider; } /** @@ -88,10 +79,6 @@ public function executeList(array $sourceItemIds) foreach ($skuListInStockList as $skuListInStock) { $stockId = $skuListInStock->getStockId(); - - if ($this->defaultStockProvider->getId() === $stockId) { - continue; - } $skuList = $skuListInStock->getSkuList(); $mainIndexName = $this->indexNameBuilder diff --git a/InventoryConfigurableProductIndexer/Indexer/Stock/StockIndexer.php b/InventoryConfigurableProductIndexer/Indexer/Stock/StockIndexer.php index 68bba4793de9..9b3064f4222c 100644 --- a/InventoryConfigurableProductIndexer/Indexer/Stock/StockIndexer.php +++ b/InventoryConfigurableProductIndexer/Indexer/Stock/StockIndexer.php @@ -10,7 +10,6 @@ use Magento\Framework\App\ObjectManager; use Magento\Framework\App\ResourceConnection; use Magento\Framework\Exception\StateException; -use Magento\InventoryCatalogApi\Api\DefaultStockProviderInterface; use Magento\InventoryIndexer\Indexer\InventoryIndexer; use Magento\InventoryIndexer\Indexer\Stock\GetAllStockIds; use Magento\InventoryIndexer\Indexer\Stock\PrepareIndexDataForClearingIndex; @@ -57,11 +56,6 @@ class StockIndexer */ private $indexTableSwitcher; - /** - * @var DefaultStockProviderInterface - */ - private $defaultStockProvider; - /** * @var PrepareIndexDataForClearingIndex */ @@ -76,7 +70,6 @@ class StockIndexer * @param IndexNameBuilder $indexNameBuilder * @param IndexDataByStockIdProvider $indexDataByStockIdProvider * @param IndexTableSwitcherInterface $indexTableSwitcher - * @param DefaultStockProviderInterface $defaultStockProvider * @param PrepareIndexDataForClearingIndex|null $prepareIndexDataForClearingIndex */ public function __construct( @@ -86,7 +79,6 @@ public function __construct( IndexNameBuilder $indexNameBuilder, IndexDataByStockIdProvider $indexDataByStockIdProvider, IndexTableSwitcherInterface $indexTableSwitcher, - DefaultStockProviderInterface $defaultStockProvider, PrepareIndexDataForClearingIndex $prepareIndexDataForClearingIndex = null ) { $this->getAllStockIds = $getAllStockIds; @@ -95,7 +87,6 @@ public function __construct( $this->indexNameBuilder = $indexNameBuilder; $this->indexDataByStockIdProvider = $indexDataByStockIdProvider; $this->indexTableSwitcher = $indexTableSwitcher; - $this->defaultStockProvider = $defaultStockProvider; $this->prepareIndexDataForClearingIndex = $prepareIndexDataForClearingIndex ?: ObjectManager::getInstance() ->get(PrepareIndexDataForClearingIndex::class); } @@ -134,10 +125,6 @@ public function executeRow(int $stockId): void public function executeList(array $stockIds): void { foreach ($stockIds as $stockId) { - if ($this->defaultStockProvider->getId() === $stockId) { - continue; - } - $mainIndexName = $this->indexNameBuilder ->setIndexId(InventoryIndexer::INDEXER_ID) ->addDimension('stock_', (string)$stockId) diff --git a/InventoryElasticsearch/Plugin/CatalogSearch/Model/Indexer/Fulltext/Action/DataProvider/StockedProductFilterByInventoryStock.php b/InventoryElasticsearch/Plugin/CatalogSearch/Model/Indexer/Fulltext/Action/DataProvider/StockedProductFilterByInventoryStock.php index 00e38f931433..66f4f82b570d 100644 --- a/InventoryElasticsearch/Plugin/CatalogSearch/Model/Indexer/Fulltext/Action/DataProvider/StockedProductFilterByInventoryStock.php +++ b/InventoryElasticsearch/Plugin/CatalogSearch/Model/Indexer/Fulltext/Action/DataProvider/StockedProductFilterByInventoryStock.php @@ -7,13 +7,11 @@ namespace Magento\InventoryElasticsearch\Plugin\CatalogSearch\Model\Indexer\Fulltext\Action\DataProvider; -use Magento\CatalogInventory\Api\Data\StockStatusInterface; use Magento\CatalogInventory\Api\StockConfigurationInterface; use Magento\CatalogInventory\Api\StockStatusCriteriaInterfaceFactory; use Magento\CatalogInventory\Api\StockStatusRepositoryInterface; use Magento\CatalogSearch\Model\Indexer\Fulltext\Action\DataProvider; use Magento\Framework\App\ResourceConnection; -use Magento\InventoryCatalogApi\Api\DefaultStockProviderInterface; use Magento\InventoryIndexer\Model\StockIndexTableNameResolverInterface; use Magento\InventorySalesApi\Model\StockByWebsiteIdResolverInterface; use Magento\Store\Api\StoreRepositoryInterface; @@ -53,11 +51,6 @@ class StockedProductFilterByInventoryStock */ private $stockStatusRepository; - /** - * @var DefaultStockProviderInterface - */ - private $defaultStockProvider; - /** * @var StoreRepositoryInterface */ @@ -70,7 +63,6 @@ class StockedProductFilterByInventoryStock * @param StockByWebsiteIdResolverInterface $stockByWebsiteIdResolver * @param StockStatusCriteriaInterfaceFactory $stockStatusCriteriaFactory * @param StockStatusRepositoryInterface $stockStatusRepository - * @param DefaultStockProviderInterface $defaultStockProvider * @param StoreRepositoryInterface $storeRepository */ public function __construct( @@ -80,7 +72,6 @@ public function __construct( StockByWebsiteIdResolverInterface $stockByWebsiteIdResolver, StockStatusCriteriaInterfaceFactory $stockStatusCriteriaFactory, StockStatusRepositoryInterface $stockStatusRepository, - DefaultStockProviderInterface $defaultStockProvider, StoreRepositoryInterface $storeRepository ) { $this->stockConfiguration = $stockConfiguration; @@ -89,7 +80,6 @@ public function __construct( $this->stockByWebsiteIdResolver = $stockByWebsiteIdResolver; $this->stockStatusCriteriaFactory = $stockStatusCriteriaFactory; $this->stockStatusRepository = $stockStatusRepository; - $this->defaultStockProvider = $defaultStockProvider; $this->storeRepository = $storeRepository; } @@ -114,13 +104,7 @@ public function beforePrepareProductIndex( $store = $this->storeRepository->getById($storeId); $stock = $this->stockByWebsiteIdResolver->execute((int)$store->getWebsiteId()); $stockId = $stock->getStockId(); - - if ($this->defaultStockProvider->getId() === $stockId) { - $stockStatuses = $this->getStockStatusesFromDefaultStock($productIds); - } else { - $stockStatuses = $this->getStockStatusesFromCustomStock($productIds, $stockId); - } - + $stockStatuses = $this->getStockStatusesFromStock($productIds, $stockId); $indexData = array_intersect_key($indexData, $stockStatuses); } @@ -131,27 +115,6 @@ public function beforePrepareProductIndex( ]; } - /** - * Get product stock statuses on default stock. - * - * @param array $productIds - * @return array - */ - private function getStockStatusesFromDefaultStock(array $productIds): array - { - $stockStatusCriteria = $this->stockStatusCriteriaFactory->create(); - $stockStatusCriteria->setProductsFilter($productIds); - $stockStatusCollection = $this->stockStatusRepository->getList($stockStatusCriteria); - $stockStatuses = $stockStatusCollection->getItems(); - - return array_filter( - $stockStatuses, - function (StockStatusInterface $stockStatus) { - return StockStatusInterface::STATUS_IN_STOCK === (int)$stockStatus->getStockStatus(); - } - ); - } - /** * Get product stock statuses on custom stock. * @@ -159,7 +122,7 @@ function (StockStatusInterface $stockStatus) { * @param int $stockId * @return array */ - private function getStockStatusesFromCustomStock(array $productIds, int $stockId): array + private function getStockStatusesFromStock(array $productIds, int $stockId): array { $stockTable = $this->stockIndexTableNameResolver->execute($stockId); $connection = $this->resourceConnection->getConnection(); diff --git a/InventoryGroupedProductIndexer/Indexer/SourceItem/SourceItemIndexer.php b/InventoryGroupedProductIndexer/Indexer/SourceItem/SourceItemIndexer.php index ff27210d6f29..b1a34fc46151 100644 --- a/InventoryGroupedProductIndexer/Indexer/SourceItem/SourceItemIndexer.php +++ b/InventoryGroupedProductIndexer/Indexer/SourceItem/SourceItemIndexer.php @@ -8,12 +8,11 @@ namespace Magento\InventoryGroupedProductIndexer\Indexer\SourceItem; use Magento\Framework\App\ResourceConnection; +use Magento\InventoryIndexer\Indexer\InventoryIndexer; use Magento\InventoryMultiDimensionalIndexerApi\Model\Alias; use Magento\InventoryMultiDimensionalIndexerApi\Model\IndexHandlerInterface; use Magento\InventoryMultiDimensionalIndexerApi\Model\IndexNameBuilder; use Magento\InventoryMultiDimensionalIndexerApi\Model\IndexStructureInterface; -use Magento\InventoryCatalogApi\Api\DefaultStockProviderInterface; -use Magento\InventoryIndexer\Indexer\InventoryIndexer; class SourceItemIndexer { @@ -47,11 +46,6 @@ class SourceItemIndexer */ private $siblingSkuListInStockProvider; - /** - * @var DefaultStockProviderInterface - */ - private $defaultStockProvider; - /** * @param ResourceConnection $resourceConnection * @param IndexNameBuilder $indexNameBuilder @@ -59,7 +53,6 @@ class SourceItemIndexer * @param IndexStructureInterface $indexStructure * @param IndexDataBySkuListProvider $indexDataBySkuListProvider * @param SiblingSkuListInStockProvider $siblingSkuListInStockProvider - * @param DefaultStockProviderInterface $defaultStockProvider */ public function __construct( ResourceConnection $resourceConnection, @@ -67,8 +60,7 @@ public function __construct( IndexHandlerInterface $indexHandler, IndexStructureInterface $indexStructure, IndexDataBySkuListProvider $indexDataBySkuListProvider, - SiblingSkuListInStockProvider $siblingSkuListInStockProvider, - DefaultStockProviderInterface $defaultStockProvider + SiblingSkuListInStockProvider $siblingSkuListInStockProvider ) { $this->resourceConnection = $resourceConnection; $this->indexNameBuilder = $indexNameBuilder; @@ -76,7 +68,6 @@ public function __construct( $this->indexDataBySkuListProvider = $indexDataBySkuListProvider; $this->indexStructure = $indexStructure; $this->siblingSkuListInStockProvider = $siblingSkuListInStockProvider; - $this->defaultStockProvider = $defaultStockProvider; } /** @@ -88,10 +79,6 @@ public function executeList(array $sourceItemIds) foreach ($skuListInStockList as $skuListInStock) { $stockId = $skuListInStock->getStockId(); - - if ($this->defaultStockProvider->getId() === $stockId) { - continue; - } $skuList = $skuListInStock->getSkuList(); $mainIndexName = $this->indexNameBuilder diff --git a/InventoryGroupedProductIndexer/Indexer/Stock/StockIndexer.php b/InventoryGroupedProductIndexer/Indexer/Stock/StockIndexer.php index 5cded3aa5306..c812611c7040 100644 --- a/InventoryGroupedProductIndexer/Indexer/Stock/StockIndexer.php +++ b/InventoryGroupedProductIndexer/Indexer/Stock/StockIndexer.php @@ -10,7 +10,6 @@ use Magento\Framework\App\ObjectManager; use Magento\Framework\App\ResourceConnection; use Magento\Framework\Exception\StateException; -use Magento\InventoryCatalogApi\Api\DefaultStockProviderInterface; use Magento\InventoryIndexer\Indexer\InventoryIndexer; use Magento\InventoryIndexer\Indexer\Stock\GetAllStockIds; use Magento\InventoryIndexer\Indexer\Stock\PrepareIndexDataForClearingIndex; @@ -57,11 +56,6 @@ class StockIndexer */ private $indexTableSwitcher; - /** - * @var DefaultStockProviderInterface - */ - private $defaultStockProvider; - /** * @var PrepareIndexDataForClearingIndex */ @@ -76,7 +70,6 @@ class StockIndexer * @param IndexNameBuilder $indexNameBuilder * @param IndexDataByStockIdProvider $indexDataByStockIdProvider * @param IndexTableSwitcherInterface $indexTableSwitcher - * @param DefaultStockProviderInterface $defaultStockProvider * @param PrepareIndexDataForClearingIndex|null $prepareIndexDataForClearingIndex */ public function __construct( @@ -86,7 +79,6 @@ public function __construct( IndexNameBuilder $indexNameBuilder, IndexDataByStockIdProvider $indexDataByStockIdProvider, IndexTableSwitcherInterface $indexTableSwitcher, - DefaultStockProviderInterface $defaultStockProvider, PrepareIndexDataForClearingIndex $prepareIndexDataForClearingIndex = null ) { $this->getAllStockIds = $getAllStockIds; @@ -95,7 +87,6 @@ public function __construct( $this->indexNameBuilder = $indexNameBuilder; $this->indexDataByStockIdProvider = $indexDataByStockIdProvider; $this->indexTableSwitcher = $indexTableSwitcher; - $this->defaultStockProvider = $defaultStockProvider; $this->prepareIndexDataForClearingIndex = $prepareIndexDataForClearingIndex ?: ObjectManager::getInstance() ->get(PrepareIndexDataForClearingIndex::class); } @@ -134,10 +125,6 @@ public function executeRow(int $stockId): void public function executeList(array $stockIds): void { foreach ($stockIds as $stockId) { - if ($this->defaultStockProvider->getId() === $stockId) { - continue; - } - $mainIndexName = $this->indexNameBuilder ->setIndexId(InventoryIndexer::INDEXER_ID) ->addDimension('stock_', (string)$stockId) diff --git a/InventoryImportExport/Test/Integration/Model/Export/SourcesTest.php b/InventoryImportExport/Test/Integration/Model/Export/SourcesTest.php index 9959aab207fc..baad856a9cc3 100644 --- a/InventoryImportExport/Test/Integration/Model/Export/SourcesTest.php +++ b/InventoryImportExport/Test/Integration/Model/Export/SourcesTest.php @@ -13,6 +13,9 @@ use Magento\TestFramework\Helper\Bootstrap; use PHPUnit\Framework\TestCase; +/** + * @magentoDbIsolation disabled + */ class SourcesTest extends TestCase { /** diff --git a/InventoryIndexer/Indexer/SourceItem/Strategy/Sync.php b/InventoryIndexer/Indexer/SourceItem/Strategy/Sync.php index 85851a5942e7..54c9427356dc 100644 --- a/InventoryIndexer/Indexer/SourceItem/Strategy/Sync.php +++ b/InventoryIndexer/Indexer/SourceItem/Strategy/Sync.php @@ -8,7 +8,6 @@ namespace Magento\InventoryIndexer\Indexer\SourceItem\Strategy; use Magento\Framework\App\ResourceConnection; -use Magento\InventoryCatalogApi\Api\DefaultStockProviderInterface; use Magento\InventoryIndexer\Indexer\InventoryIndexer; use Magento\InventoryIndexer\Indexer\SourceItem\GetSkuListInStock; use Magento\InventoryIndexer\Indexer\SourceItem\IndexDataBySkuListProvider; @@ -53,11 +52,6 @@ class Sync */ private $stockIndexer; - /** - * @var DefaultStockProviderInterface - */ - private $defaultStockProvider; - /** * $indexStructure is reserved name for construct variable (in index internal mechanism) * @@ -67,7 +61,6 @@ class Sync * @param IndexDataBySkuListProvider $indexDataBySkuListProvider * @param IndexNameBuilder $indexNameBuilder * @param StockIndexer $stockIndexer - * @param DefaultStockProviderInterface $defaultStockProvider */ public function __construct( GetSkuListInStock $getSkuListInStockToUpdate, @@ -75,8 +68,7 @@ public function __construct( IndexHandlerInterface $indexHandler, IndexDataBySkuListProvider $indexDataBySkuListProvider, IndexNameBuilder $indexNameBuilder, - StockIndexer $stockIndexer, - DefaultStockProviderInterface $defaultStockProvider + StockIndexer $stockIndexer ) { $this->getSkuListInStock = $getSkuListInStockToUpdate; $this->indexStructure = $indexStructureHandler; @@ -84,7 +76,6 @@ public function __construct( $this->indexDataBySkuListProvider = $indexDataBySkuListProvider; $this->indexNameBuilder = $indexNameBuilder; $this->stockIndexer = $stockIndexer; - $this->defaultStockProvider = $defaultStockProvider; } /** @@ -92,16 +83,12 @@ public function __construct( * * @param int[] $sourceItemIds */ - public function executeList(array $sourceItemIds) : void + public function executeList(array $sourceItemIds): void { $skuListInStockList = $this->getSkuListInStock->execute($sourceItemIds); foreach ($skuListInStockList as $skuListInStock) { $stockId = $skuListInStock->getStockId(); - if ($this->defaultStockProvider->getId() === $stockId) { - continue; - } - $skuList = $skuListInStock->getSkuList(); $mainIndexName = $this->indexNameBuilder @@ -134,7 +121,7 @@ public function executeList(array $sourceItemIds) : void * * @return void */ - public function executeFull() : void + public function executeFull(): void { $this->stockIndexer->executeFull(); } @@ -145,7 +132,7 @@ public function executeFull() : void * @param int $sourceItemId * @return void */ - public function executeRow(int $sourceItemId) : void + public function executeRow(int $sourceItemId): void { $this->executeList([$sourceItemId]); } diff --git a/InventoryIndexer/Indexer/Stock/Strategy/Sync.php b/InventoryIndexer/Indexer/Stock/Strategy/Sync.php index fb5d6506a320..6ae098e783f6 100644 --- a/InventoryIndexer/Indexer/Stock/Strategy/Sync.php +++ b/InventoryIndexer/Indexer/Stock/Strategy/Sync.php @@ -7,7 +7,6 @@ namespace Magento\InventoryIndexer\Indexer\Stock\Strategy; use Magento\Framework\App\ResourceConnection; -use Magento\InventoryCatalogApi\Api\DefaultStockProviderInterface; use Magento\InventoryIndexer\Indexer\InventoryIndexer; use Magento\InventoryIndexer\Indexer\Stock\GetAllStockIds; use Magento\InventoryIndexer\Indexer\Stock\IndexDataProviderByStockId; @@ -52,11 +51,6 @@ class Sync */ private $indexTableSwitcher; - /** - * @var DefaultStockProviderInterface - */ - private $defaultStockProvider; - /** * $indexStructure is reserved name for construct variable in index internal mechanism * @@ -66,7 +60,6 @@ class Sync * @param IndexNameBuilder $indexNameBuilder * @param IndexDataProviderByStockId $indexDataProviderByStockId * @param IndexTableSwitcherInterface $indexTableSwitcher - * @param DefaultStockProviderInterface $defaultStockProvider */ public function __construct( GetAllStockIds $getAllStockIds, @@ -74,8 +67,7 @@ public function __construct( IndexHandlerInterface $indexHandler, IndexNameBuilder $indexNameBuilder, IndexDataProviderByStockId $indexDataProviderByStockId, - IndexTableSwitcherInterface $indexTableSwitcher, - DefaultStockProviderInterface $defaultStockProvider + IndexTableSwitcherInterface $indexTableSwitcher ) { $this->getAllStockIds = $getAllStockIds; $this->indexStructure = $indexStructureHandler; @@ -83,7 +75,6 @@ public function __construct( $this->indexNameBuilder = $indexNameBuilder; $this->indexDataProviderByStockId = $indexDataProviderByStockId; $this->indexTableSwitcher = $indexTableSwitcher; - $this->defaultStockProvider = $defaultStockProvider; } /** @@ -117,10 +108,6 @@ public function executeRow(int $stockId): void public function executeList(array $stockIds): void { foreach ($stockIds as $stockId) { - if ($this->defaultStockProvider->getId() === (int)$stockId) { - continue; - } - $replicaIndexName = $this->indexNameBuilder ->setIndexId(InventoryIndexer::INDEXER_ID) ->addDimension('stock_', (string)$stockId) diff --git a/InventoryIndexer/Model/ResourceModel/GetStockItemData.php b/InventoryIndexer/Model/ResourceModel/GetStockItemData.php index ddc4917c6715..d703481d5958 100644 --- a/InventoryIndexer/Model/ResourceModel/GetStockItemData.php +++ b/InventoryIndexer/Model/ResourceModel/GetStockItemData.php @@ -9,11 +9,10 @@ use Magento\Framework\App\ResourceConnection; use Magento\Framework\Exception\LocalizedException; +use Magento\InventoryCatalogApi\Model\GetProductIdsBySkusInterface; +use Magento\InventoryIndexer\Indexer\IndexStructure; use Magento\InventoryIndexer\Model\StockIndexTableNameResolverInterface; use Magento\InventorySalesApi\Model\GetStockItemDataInterface; -use Magento\InventoryIndexer\Indexer\IndexStructure; -use Magento\InventoryCatalogApi\Api\DefaultStockProviderInterface; -use Magento\InventoryCatalogApi\Model\GetProductIdsBySkusInterface; /** * @inheritdoc @@ -30,11 +29,6 @@ class GetStockItemData implements GetStockItemDataInterface */ private $stockIndexTableNameResolver; - /** - * @var DefaultStockProviderInterface - */ - private $defaultStockProvider; - /** * @var GetProductIdsBySkusInterface */ @@ -43,18 +37,15 @@ class GetStockItemData implements GetStockItemDataInterface /** * @param ResourceConnection $resource * @param StockIndexTableNameResolverInterface $stockIndexTableNameResolver - * @param DefaultStockProviderInterface $defaultStockProvider * @param GetProductIdsBySkusInterface $getProductIdsBySkus */ public function __construct( ResourceConnection $resource, StockIndexTableNameResolverInterface $stockIndexTableNameResolver, - DefaultStockProviderInterface $defaultStockProvider, GetProductIdsBySkusInterface $getProductIdsBySkus ) { $this->resource = $resource; $this->stockIndexTableNameResolver = $stockIndexTableNameResolver; - $this->defaultStockProvider = $defaultStockProvider; $this->getProductIdsBySkus = $getProductIdsBySkus; } @@ -65,34 +56,19 @@ public function execute(string $sku, int $stockId): ?array { $connection = $this->resource->getConnection(); $select = $connection->select(); + $stockItemTableName = $this->stockIndexTableNameResolver->execute($stockId); + $select->from( + $stockItemTableName, + [ + GetStockItemDataInterface::QUANTITY => IndexStructure::QUANTITY, + GetStockItemDataInterface::IS_SALABLE => IndexStructure::IS_SALABLE, + ] + )->where(IndexStructure::SKU . ' = ?', $sku); - if ($this->defaultStockProvider->getId() === $stockId) { - $productId = current($this->getProductIdsBySkus->execute([$sku])); - $stockItemTableName = $this->resource->getTableName('cataloginventory_stock_status'); - $select->from( - $stockItemTableName, - [ - GetStockItemDataInterface::QUANTITY => 'qty', - GetStockItemDataInterface::IS_SALABLE => 'stock_status', - ] - )->where('product_id = ?', $productId); - + try { return $connection->fetchRow($select) ?: null; - } else { - $stockItemTableName = $this->stockIndexTableNameResolver->execute($stockId); - $select->from( - $stockItemTableName, - [ - GetStockItemDataInterface::QUANTITY => IndexStructure::QUANTITY, - GetStockItemDataInterface::IS_SALABLE => IndexStructure::IS_SALABLE, - ] - )->where(IndexStructure::SKU . ' = ?', $sku); - - try { - return $connection->fetchRow($select) ?: null; - } catch (\Exception $e) { - throw new LocalizedException(__('Could not receive Stock Item data'), $e); - } + } catch (\Exception $e) { + throw new LocalizedException(__('Could not receive Stock Item data'), $e); } } } diff --git a/InventorySales/Test/Integration/GetStockItemData/BackorderConditionTest.php b/InventorySales/Test/Integration/GetStockItemData/BackorderConditionTest.php index 8ba8afeb0caa..e2f1f188387c 100644 --- a/InventorySales/Test/Integration/GetStockItemData/BackorderConditionTest.php +++ b/InventorySales/Test/Integration/GetStockItemData/BackorderConditionTest.php @@ -185,7 +185,7 @@ public function backordersGlobalEnabledDataProvider(): array return [ ['SKU-1', 10, [GetStockItemDataInterface::QUANTITY => 8.5, GetStockItemDataInterface::IS_SALABLE => 1]], ['SKU-2', 10, null], - ['SKU-3', 10, [GetStockItemDataInterface::QUANTITY => 0, GetStockItemDataInterface::IS_SALABLE => 1]], + ['SKU-3', 10, [GetStockItemDataInterface::QUANTITY => 0, GetStockItemDataInterface::IS_SALABLE => 0]], ]; } @@ -230,7 +230,7 @@ public function backordersEnabledDataProvider(): array 10, StockItemConfigurationInterface::BACKORDERS_YES_NONOTIFY, [ - GetStockItemDataInterface::QUANTITY => 0, GetStockItemDataInterface::IS_SALABLE => 1 + GetStockItemDataInterface::QUANTITY => 0, GetStockItemDataInterface::IS_SALABLE => 0 ] ], [ @@ -238,7 +238,7 @@ public function backordersEnabledDataProvider(): array 10, StockItemConfigurationInterface::BACKORDERS_YES_NOTIFY, [ - GetStockItemDataInterface::QUANTITY => 0, GetStockItemDataInterface::IS_SALABLE => 1 + GetStockItemDataInterface::QUANTITY => 0, GetStockItemDataInterface::IS_SALABLE => 0 ] ], ]; @@ -271,7 +271,6 @@ private function setStockItemBackorders(string $sku, int $backordersStatus): voi $stockItemSearchCriteria->setProductsFilter($product->getId()); $stockItemsCollection = $this->stockItemRepository->getList($stockItemSearchCriteria); - /** @var StockItemInterface $legacyStockItem */ $legacyStockItem = current($stockItemsCollection->getItems()); $legacyStockItem->setBackorders($backordersStatus); $legacyStockItem->setUseConfigBackorders(false); diff --git a/InventorySales/Test/Integration/Stock/GetProductSalableQtyTest.php b/InventorySales/Test/Integration/Stock/GetProductSalableQtyTest.php index 11e0e6f226fa..1ee21419101b 100644 --- a/InventorySales/Test/Integration/Stock/GetProductSalableQtyTest.php +++ b/InventorySales/Test/Integration/Stock/GetProductSalableQtyTest.php @@ -7,8 +7,12 @@ namespace Magento\InventorySales\Test\Integration\Stock; -use Magento\InventoryReservationsApi\Model\CleanupReservationsInterface; +use Magento\CatalogInventory\Api\StockItemRepositoryInterface; +use Magento\InventoryApi\Api\GetSourceItemsBySkuInterface; +use Magento\InventoryApi\Api\SourceItemsSaveInterface; +use Magento\InventoryConfiguration\Model\GetLegacyStockItem; use Magento\InventoryReservationsApi\Model\AppendReservationsInterface; +use Magento\InventoryReservationsApi\Model\CleanupReservationsInterface; use Magento\InventoryReservationsApi\Model\ReservationBuilderInterface; use Magento\InventorySalesApi\Api\GetProductSalableQtyInterface; use Magento\TestFramework\Helper\Bootstrap; @@ -119,4 +123,82 @@ public function testGetProductQuantityIfReservationsArePresent() $this->reservationBuilder->setStockId(10)->setSku('SKU-1')->setQuantity(3.5)->build(), ]); } + + /** + * Verify 'Out of stock' source items will show '0' salable qty in case global 'out of stock' threshold is negative. + * + * @magentoDataFixture ../../../../app/code/Magento/InventoryApi/Test/_files/products.php + * @magentoDataFixture ../../../../app/code/Magento/InventoryApi/Test/_files/sources.php + * @magentoDataFixture ../../../../app/code/Magento/InventoryApi/Test/_files/stocks.php + * @magentoDataFixture ../../../../app/code/Magento/InventoryApi/Test/_files/stock_source_links.php + * @magentoDataFixture ../../../../app/code/Magento/InventoryApi/Test/_files/source_items.php + * @magentoDataFixture ../../../../app/code/Magento/InventoryIndexer/Test/_files/reindex_inventory.php + * + * @magentoConfigFixture default_store cataloginventory/item_options/min_qty -10 + * @magentoConfigFixture default_store cataloginventory/item_options/backorders 1 + * + * @magentoDbIsolation disabled + */ + public function testGetSalableQuantityWithGlobalBackordersAndOutOfStockSourceItems() + { + $sku = 'SKU-2'; + self::assertEquals(15, $this->getProductSalableQty->execute($sku, 20)); + $this->setSourceItemsToOutOfStock($sku); + self::assertEquals(0, $this->getProductSalableQty->execute($sku, 20)); + } + + /** + * Verify 'Out of stock' source items will show '0' salable qty if stock item 'out of stock' threshold is negative. + * + * @magentoDataFixture ../../../../app/code/Magento/InventoryApi/Test/_files/products.php + * @magentoDataFixture ../../../../app/code/Magento/InventoryApi/Test/_files/sources.php + * @magentoDataFixture ../../../../app/code/Magento/InventoryApi/Test/_files/stocks.php + * @magentoDataFixture ../../../../app/code/Magento/InventoryApi/Test/_files/stock_source_links.php + * @magentoDataFixture ../../../../app/code/Magento/InventoryApi/Test/_files/source_items.php + * @magentoDataFixture ../../../../app/code/Magento/InventoryIndexer/Test/_files/reindex_inventory.php + * + * @magentoDbIsolation disabled + */ + public function testGetSalableQuantityWithBackordersAndOutOfStockSourceItems() + { + $sku = 'SKU-2'; + $this->enableBackorders(); + self::assertEquals(15, $this->getProductSalableQty->execute($sku, 20)); + $this->setSourceItemsToOutOfStock($sku); + self::assertEquals(0, $this->getProductSalableQty->execute($sku, 20)); + } + + /** + * Enable backorders and negative 'out or stock' threshold for stock item. + * + * @return void + */ + private function enableBackorders(): void + { + $getLegacyItem = Bootstrap::getObjectManager()->get(GetLegacyStockItem::class); + $stockItemRepository = Bootstrap::getObjectManager()->get(StockItemRepositoryInterface::class); + $legacyStockItem = $getLegacyItem->execute('SKU-2'); + $legacyStockItem->setBackorders(1); + $legacyStockItem->setUseConfigBackorders(false); + $legacyStockItem->setMinQty(-10); + $legacyStockItem->setUseConfigMinQty(false); + $stockItemRepository->save($legacyStockItem); + } + + /** + * Set source items for given product 'out of stock' status. + * + * @param string $sku + * @return void + */ + private function setSourceItemsToOutOfStock(string $sku): void + { + $sourceItemsSave = Bootstrap::getObjectManager()->get(SourceItemsSaveInterface::class); + $getSourceItems = Bootstrap::getObjectManager()->get(GetSourceItemsBySkuInterface::class); + $sourceItems = $getSourceItems->execute($sku); + foreach ($sourceItems as $sourceItem) { + $sourceItem->setStatus(0); + } + $sourceItemsSave->execute($sourceItems); + } } diff --git a/dev/tests/integration/_files/Magento/TestModuleInventoryStateCache/Plugin/CatalogInventory/Model/StockRegistryProvider/GetNonCachedStockItemPlugin.php b/dev/tests/integration/_files/Magento/TestModuleInventoryStateCache/Plugin/CatalogInventory/Model/StockRegistryProvider/GetNonCachedStockItemPlugin.php new file mode 100644 index 000000000000..7479a621ecf2 --- /dev/null +++ b/dev/tests/integration/_files/Magento/TestModuleInventoryStateCache/Plugin/CatalogInventory/Model/StockRegistryProvider/GetNonCachedStockItemPlugin.php @@ -0,0 +1,80 @@ +stockItemCriteriaFactory = $stockItemCriteriaFactory; + $this->stockItemRepository = $stockItemRepository; + $this->stockItemFactory = $stockItemFactory; + } + + /** + * Get non cached stock items for product. + * + * @param StockRegistryProviderInterface $subject + * @param \Closure $proceed + * @param int|null $productId + * @param int|null $stockId + * @return StockItemInterface + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function aroundGetStockItem( + StockRegistryProviderInterface $subject, + \Closure $proceed, + ?int $productId, + ?int $stockId + ): StockItemInterface { + $criteria = $this->stockItemCriteriaFactory->create(); + $criteria->setProductsFilter($productId); + $collection = $this->stockItemRepository->getList($criteria); + $stockItem = current($collection->getItems()); + if (!$stockItem || !$stockItem->getItemId()) { + $stockItem = $this->stockItemFactory->create(); + } + + return $stockItem; + } +} diff --git a/dev/tests/integration/_files/Magento/TestModuleInventoryStateCache/etc/frontend/di.xml b/dev/tests/integration/_files/Magento/TestModuleInventoryStateCache/etc/frontend/di.xml index 1dba1542b79d..30c34c0c4002 100644 --- a/dev/tests/integration/_files/Magento/TestModuleInventoryStateCache/etc/frontend/di.xml +++ b/dev/tests/integration/_files/Magento/TestModuleInventoryStateCache/etc/frontend/di.xml @@ -7,4 +7,7 @@ --> + + + From 7e0e09de83e9a0ea07972172831f38c04f09831d Mon Sep 17 00:00:00 2001 From: nmalevanec Date: Thu, 4 Jun 2020 14:23:58 +0300 Subject: [PATCH 36/50] Re-work configurable product indexer. Modify is salable condition. --- .../Product/ReindexSourceItemsPlugin.php | 89 +++++++++++++++++++ .../etc/di.xml | 3 + .../IsSalableWithReservationsCondition.php | 9 +- .../UpdateCustomTableMapPlugin.php | 22 +++++ 4 files changed, 118 insertions(+), 5 deletions(-) create mode 100644 InventoryConfigurableProductIndexer/Plugin/Catalog/Model/ResourceModel/Product/ReindexSourceItemsPlugin.php diff --git a/InventoryConfigurableProductIndexer/Plugin/Catalog/Model/ResourceModel/Product/ReindexSourceItemsPlugin.php b/InventoryConfigurableProductIndexer/Plugin/Catalog/Model/ResourceModel/Product/ReindexSourceItemsPlugin.php new file mode 100644 index 000000000000..56b4d418ca7d --- /dev/null +++ b/InventoryConfigurableProductIndexer/Plugin/Catalog/Model/ResourceModel/Product/ReindexSourceItemsPlugin.php @@ -0,0 +1,89 @@ +getSourceItemsBySku = $getSourceItemsBySku; + $this->getSkusByProductIds = $getSkusByProductIds; + $this->getSourceItemIds = $getSourceItemIds; + $this->sourceItemIndexer = $sourceItemIndexer; + } + + /** + * Reindex configurable source items after product save. + * + * @param Product $subject + * @param Product $result + * @param AbstractModel $product + * @return Product + * @throws NoSuchEntityException + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function afterSave(Product $subject, Product $result, AbstractModel $product): Product + { + if ($product->getTypeId() !== Configurable::TYPE_CODE) { + return $result; + } + $childrenIds = $product->getExtensionAttributes()->getConfigurableProductLinks() ?: []; + $skus = $this->getSkusByProductIds->execute($childrenIds); + $sourceItems = [[]]; + foreach ($skus as $sku) { + $sourceItems[] = $this->getSourceItemsBySku->execute($sku); + } + $sourceItems = array_merge(...$sourceItems); + $sourceItemIds = $this->getSourceItemIds->execute($sourceItems); + $this->sourceItemIndexer->executeList($sourceItemIds); + + return $result; + } +} diff --git a/InventoryConfigurableProductIndexer/etc/di.xml b/InventoryConfigurableProductIndexer/etc/di.xml index 8d871a095a3c..3e614edc3e4f 100644 --- a/InventoryConfigurableProductIndexer/etc/di.xml +++ b/InventoryConfigurableProductIndexer/etc/di.xml @@ -35,4 +35,7 @@ + + + diff --git a/InventorySales/Model/IsProductSalableCondition/IsSalableWithReservationsCondition.php b/InventorySales/Model/IsProductSalableCondition/IsSalableWithReservationsCondition.php index cc8dee8b5ba2..be9dfdb59999 100644 --- a/InventorySales/Model/IsProductSalableCondition/IsSalableWithReservationsCondition.php +++ b/InventorySales/Model/IsProductSalableCondition/IsSalableWithReservationsCondition.php @@ -71,17 +71,16 @@ public function __construct( */ public function execute(string $sku, int $stockId): bool { + $productType = $this->getProductTypesBySkus->execute([$sku])[$sku]; + if (false === $this->isSourceItemManagementAllowedForProductType->execute($productType)) { + return true; + } $stockItemData = $this->getStockItemData->execute($sku, $stockId); if (null === $stockItemData) { // Sku is not assigned to Stock return false; } - $productType = $this->getProductTypesBySkus->execute([$sku])[$sku]; - if (false === $this->isSourceItemManagementAllowedForProductType->execute($productType)) { - return (bool)$stockItemData[GetStockItemDataInterface::IS_SALABLE]; - } - /** @var StockItemConfigurationInterface $stockItemConfiguration */ $stockItemConfiguration = $this->getStockItemConfiguration->execute($sku, $stockId); $qtyWithReservation = $stockItemData[GetStockItemDataInterface::QUANTITY] + diff --git a/InventorySetupFixtureGenerator/Plugin/Setup/Model/FixtureGenerator/EntityGeneratorFactory/UpdateCustomTableMapPlugin.php b/InventorySetupFixtureGenerator/Plugin/Setup/Model/FixtureGenerator/EntityGeneratorFactory/UpdateCustomTableMapPlugin.php index 11349256c774..e9a13d247cbc 100644 --- a/InventorySetupFixtureGenerator/Plugin/Setup/Model/FixtureGenerator/EntityGeneratorFactory/UpdateCustomTableMapPlugin.php +++ b/InventorySetupFixtureGenerator/Plugin/Setup/Model/FixtureGenerator/EntityGeneratorFactory/UpdateCustomTableMapPlugin.php @@ -22,6 +22,13 @@ class UpdateCustomTableMapPlugin */ private $sourceItems = []; + /** + * Processed stock statuses. + * + * @var array + */ + private $stockStatuses = []; + /** * Inject inventory_source_item table data to FixtureGenerator\EntityGeneratorFactory arguments. * @@ -49,6 +56,21 @@ public function beforeCreate( return $binds; }, ]; + $data['customTableMap']['inventory_stock_1'] = [ + 'entity_id_field' => EntityGenerator::SKIP_ENTITY_ID_BINDING, + 'handler' => function ($productId, $entityNumber, $fixture, $binds) { + foreach ($binds as &$bind) { + $sku = $fixture['sku']($productId, $entityNumber); + if (in_array($sku, $this->stockStatuses)) { + return []; + } + $bind['sku'] = $sku; + $this->stockStatuses[] = $sku; + } + + return $binds; + }, + ]; return [$data]; } From 58889f057e491fa32df02270ab22e104d68ead52 Mon Sep 17 00:00:00 2001 From: nmalevanec Date: Thu, 4 Jun 2020 17:04:47 +0300 Subject: [PATCH 37/50] Re-work bundle product indexer. --- .../SourceItem/IndexDataBySkuListProvider.php | 2 +- .../Indexer/SourceItem/SourceItemIndexer.php | 13 +++++++-- .../Stock/IndexDataByStockIdProvider.php | 28 ++++++++++++++++--- InventoryBundleProductIndexer/composer.json | 2 +- 4 files changed, 37 insertions(+), 8 deletions(-) diff --git a/InventoryBundleProductIndexer/Indexer/SourceItem/IndexDataBySkuListProvider.php b/InventoryBundleProductIndexer/Indexer/SourceItem/IndexDataBySkuListProvider.php index bc0f11eb85e8..4638d0d4b2d2 100644 --- a/InventoryBundleProductIndexer/Indexer/SourceItem/IndexDataBySkuListProvider.php +++ b/InventoryBundleProductIndexer/Indexer/SourceItem/IndexDataBySkuListProvider.php @@ -73,6 +73,6 @@ public function execute(int $stockId, array $skuList): \ArrayIterator } } - return new \ArrayIterator(reset($results)); + return new \ArrayIterator($results); } } diff --git a/InventoryBundleProductIndexer/Indexer/SourceItem/SourceItemIndexer.php b/InventoryBundleProductIndexer/Indexer/SourceItem/SourceItemIndexer.php index 8d2bc8f7790d..0ba622500574 100644 --- a/InventoryBundleProductIndexer/Indexer/SourceItem/SourceItemIndexer.php +++ b/InventoryBundleProductIndexer/Indexer/SourceItem/SourceItemIndexer.php @@ -10,6 +10,7 @@ use Magento\Framework\App\ResourceConnection; use Magento\Framework\Exception\StateException; use Magento\InventoryIndexer\Indexer\InventoryIndexer; +use Magento\InventoryIndexer\Indexer\Stock\PrepareIndexDataForClearingIndex; use Magento\InventoryMultiDimensionalIndexerApi\Model\Alias; use Magento\InventoryMultiDimensionalIndexerApi\Model\IndexHandlerInterface; use Magento\InventoryMultiDimensionalIndexerApi\Model\IndexNameBuilder; @@ -50,6 +51,11 @@ class SourceItemIndexer */ private $siblingSkuListInStockProvider; + /** + * @var PrepareIndexDataForClearingIndex + */ + private $prepareIndexDataForClearingIndex; + /** * @param ResourceConnection $resourceConnection * @param IndexNameBuilder $indexNameBuilder @@ -57,6 +63,7 @@ class SourceItemIndexer * @param IndexStructureInterface $indexStructure * @param IndexDataBySkuListProvider $indexDataBySkuListProvider * @param SiblingSkuListInStockProvider $siblingSkuListInStockProvider + * @param PrepareIndexDataForClearingIndex $prepareIndexDataForClearingIndex */ public function __construct( ResourceConnection $resourceConnection, @@ -64,7 +71,8 @@ public function __construct( IndexHandlerInterface $indexHandler, IndexStructureInterface $indexStructure, IndexDataBySkuListProvider $indexDataBySkuListProvider, - SiblingSkuListInStockProvider $siblingSkuListInStockProvider + SiblingSkuListInStockProvider $siblingSkuListInStockProvider, + PrepareIndexDataForClearingIndex $prepareIndexDataForClearingIndex ) { $this->resourceConnection = $resourceConnection; $this->indexNameBuilder = $indexNameBuilder; @@ -72,6 +80,7 @@ public function __construct( $this->indexDataBySkuListProvider = $indexDataBySkuListProvider; $this->indexStructure = $indexStructure; $this->siblingSkuListInStockProvider = $siblingSkuListInStockProvider; + $this->prepareIndexDataForClearingIndex = $prepareIndexDataForClearingIndex; } /** @@ -104,7 +113,7 @@ public function executeList(array $sourceItemIds): void $this->indexHandler->cleanIndex( $mainIndexName, - $indexData, + $this->prepareIndexDataForClearingIndex->execute($indexData), ResourceConnection::DEFAULT_CONNECTION ); diff --git a/InventoryBundleProductIndexer/Indexer/Stock/IndexDataByStockIdProvider.php b/InventoryBundleProductIndexer/Indexer/Stock/IndexDataByStockIdProvider.php index f2c35d9f2f72..26c25b92b4af 100644 --- a/InventoryBundleProductIndexer/Indexer/Stock/IndexDataByStockIdProvider.php +++ b/InventoryBundleProductIndexer/Indexer/Stock/IndexDataByStockIdProvider.php @@ -9,6 +9,7 @@ use Magento\Framework\App\ResourceConnection; use Magento\InventoryBundleProductIndexer\Indexer\SelectBuilder; +use Magento\InventorySalesApi\Api\AreProductsSalableInterface; /** * Bundle products for given stock provider. @@ -25,21 +26,30 @@ class IndexDataByStockIdProvider */ private $resourceConnection; + /** + * @var AreProductsSalableInterface + */ + private $areProductsSalable; + /** * @param SelectBuilder $selectBuilder * @param ResourceConnection $resourceConnection + * @param AreProductsSalableInterface $areProductsSalable */ - public function __construct(SelectBuilder $selectBuilder, ResourceConnection $resourceConnection) - { + public function __construct( + SelectBuilder $selectBuilder, + ResourceConnection $resourceConnection, + AreProductsSalableInterface $areProductsSalable + ) { $this->selectBuilder = $selectBuilder; $this->resourceConnection = $resourceConnection; + $this->areProductsSalable = $areProductsSalable; } /** * Get bundle products for given stock id. * * @param int $stockId - * * @return \ArrayIterator * @throws \Exception */ @@ -47,7 +57,17 @@ public function execute(int $stockId): \ArrayIterator { $select = $this->selectBuilder->execute($stockId); $connection = $this->resourceConnection->getConnection(); + $results = $connection->fetchAll($select); + $bundleSkus = array_column($results, 'sku'); + $salableResults = $this->areProductsSalable->execute($bundleSkus, $stockId); + foreach ($salableResults as $salableResult) { + foreach ($results as &$result) { + if ($salableResult->getSku() === $result['sku']) { + $result['is_salable'] = (string)(int)$salableResult->isSalable(); + } + } + } - return new \ArrayIterator($connection->fetchAll($select)); + return new \ArrayIterator($results); } } diff --git a/InventoryBundleProductIndexer/composer.json b/InventoryBundleProductIndexer/composer.json index d9a1825be660..f06ad139d1a6 100644 --- a/InventoryBundleProductIndexer/composer.json +++ b/InventoryBundleProductIndexer/composer.json @@ -9,7 +9,7 @@ "magento/module-inventory-api": "*", "magento/module-inventory-catalog-api": "*", "magento/module-inventory-indexer": "*", - "magento/module-inventory-multi-dimensional-indexer-api": "*" + "magento/module-inventory-multi-dimensional-indexer-api": "*", "magento/module-inventory-sales-api": "*" }, "suggest": { From 8d6a3ece6d7ec430ba0a9ecb98afbbe5b332a7a7 Mon Sep 17 00:00:00 2001 From: nmalevanec Date: Fri, 5 Jun 2020 09:59:40 +0300 Subject: [PATCH 38/50] Fix merge conflicts. --- InventoryIndexer/etc/communication.xml | 3 --- InventoryIndexer/etc/queue_topology.xml | 1 - 2 files changed, 4 deletions(-) diff --git a/InventoryIndexer/etc/communication.xml b/InventoryIndexer/etc/communication.xml index e64fe11b61fa..b97f171a8316 100644 --- a/InventoryIndexer/etc/communication.xml +++ b/InventoryIndexer/etc/communication.xml @@ -15,7 +15,4 @@ - - - diff --git a/InventoryIndexer/etc/queue_topology.xml b/InventoryIndexer/etc/queue_topology.xml index 906db4353d2d..ef83ac53cfea 100644 --- a/InventoryIndexer/etc/queue_topology.xml +++ b/InventoryIndexer/etc/queue_topology.xml @@ -10,6 +10,5 @@ - From 41fbb07a82ce13e88531580ed34ccfc24342862b Mon Sep 17 00:00:00 2001 From: nmalevanec Date: Fri, 5 Jun 2020 16:06:41 +0300 Subject: [PATCH 39/50] Fix configurable product is salable verification. --- InventoryCatalog/Model/IsProductSalable.php | 7 ++++--- .../IsConfigurableProductSalablePlugin.php | 9 +++++++-- InventoryIndexer/Model/IsProductSalable.php | 14 +++++++++++++- InventoryIndexer/etc/queue_publisher.xml | 3 --- 4 files changed, 24 insertions(+), 9 deletions(-) diff --git a/InventoryCatalog/Model/IsProductSalable.php b/InventoryCatalog/Model/IsProductSalable.php index a099f663d8f4..cdd4112b2f3f 100644 --- a/InventoryCatalog/Model/IsProductSalable.php +++ b/InventoryCatalog/Model/IsProductSalable.php @@ -59,14 +59,15 @@ public function execute(ProductInterface $product): bool return (bool)$product->getData('is_salable'); } $stockId = $this->getStockIdForCurrentWebsite->execute(); - if (isset($this->productStatusCache[$stockId][$product->getSku()])) { + //use getData('sku') to get non processed product sku for complex products. + if (isset($this->productStatusCache[$stockId][$product->getData('sku')])) { return $this->productStatusCache[$stockId][$product->getSku()]; } $stockId = $this->getStockIdForCurrentWebsite->execute(); - $result = current($this->areProductsSalable->execute([$product->getSku()], $stockId)); + $result = current($this->areProductsSalable->execute([$product->getData('sku')], $stockId)); $salabilityStatus = $result->isSalable(); - $this->productStatusCache[$stockId][$product->getSku()] = $salabilityStatus; + $this->productStatusCache[$stockId][$product->getData('sku')] = $salabilityStatus; return $salabilityStatus; } diff --git a/InventoryConfigurableProduct/Plugin/InventoryCatalog/Model/IsProductSalable/IsConfigurableProductSalablePlugin.php b/InventoryConfigurableProduct/Plugin/InventoryCatalog/Model/IsProductSalable/IsConfigurableProductSalablePlugin.php index d8b31df9607c..8768901e0dfd 100644 --- a/InventoryConfigurableProduct/Plugin/InventoryCatalog/Model/IsProductSalable/IsConfigurableProductSalablePlugin.php +++ b/InventoryConfigurableProduct/Plugin/InventoryCatalog/Model/IsProductSalable/IsConfigurableProductSalablePlugin.php @@ -8,6 +8,7 @@ namespace Magento\InventoryConfigurableProduct\Plugin\InventoryCatalog\Model\IsProductSalable; use Magento\Catalog\Api\Data\ProductInterface; +use Magento\Catalog\Model\Product\Attribute\Source\Status; use Magento\ConfigurableProduct\Model\Product\Type\Configurable; use Magento\InventoryCatalog\Model\IsProductSalable; @@ -44,8 +45,12 @@ public function afterExecute(IsProductSalable $subject, bool $result, ProductInt if ($product->getTypeId() !== Configurable::TYPE_CODE || !$result) { return $result; } - $options = $this->type->getConfigurableOptions($product); - return !empty($options); + $collection = $this->type->getUsedProductCollection($product)->addAttributeToFilter( + ProductInterface::STATUS, + Status::STATUS_ENABLED + ); + + return $collection->count() > 0; } } diff --git a/InventoryIndexer/Model/IsProductSalable.php b/InventoryIndexer/Model/IsProductSalable.php index 608029118a02..c7f7f59afd25 100644 --- a/InventoryIndexer/Model/IsProductSalable.php +++ b/InventoryIndexer/Model/IsProductSalable.php @@ -7,6 +7,8 @@ namespace Magento\InventoryIndexer\Model; +use Magento\CatalogInventory\Model\Configuration; +use Magento\Framework\App\Config\ScopeConfigInterface; use Magento\Framework\Exception\LocalizedException; use Magento\InventorySalesApi\Api\IsProductSalableInterface; use Magento\InventorySalesApi\Model\GetStockItemDataInterface; @@ -21,21 +23,30 @@ class IsProductSalable implements IsProductSalableInterface * @var GetStockItemDataInterface */ private $getStockItemData; + /** * @var LoggerInterface */ private $logger; + /** + * @var ScopeConfigInterface + */ + private $config; + /** * @param GetStockItemDataInterface $getStockItemData + * @param ScopeConfigInterface $config * @param LoggerInterface $logger */ public function __construct( GetStockItemDataInterface $getStockItemData, + ScopeConfigInterface $config, LoggerInterface $logger ) { $this->getStockItemData = $getStockItemData; $this->logger = $logger; + $this->config = $config; } /** @@ -44,8 +55,9 @@ public function __construct( public function execute(string $sku, int $stockId): bool { try { + $showOutOfStock = (int)$this->config->getValue(Configuration::XML_PATH_SHOW_OUT_OF_STOCK); $stockItem = $this->getStockItemData->execute($sku, $stockId); - $isSalable = (bool)($stockItem[GetStockItemDataInterface::IS_SALABLE] ?? false); + $isSalable = $showOutOfStock ? true : (bool)($stockItem[GetStockItemDataInterface::IS_SALABLE] ?? false); } catch (LocalizedException $exception) { $this->logger->warning( sprintf( diff --git a/InventoryIndexer/etc/queue_publisher.xml b/InventoryIndexer/etc/queue_publisher.xml index b3273fa9b5e1..7500e484259d 100644 --- a/InventoryIndexer/etc/queue_publisher.xml +++ b/InventoryIndexer/etc/queue_publisher.xml @@ -15,7 +15,4 @@ - - - From c0e5cdf6761267843c2fe5bc9e5cf736c4862f6b Mon Sep 17 00:00:00 2001 From: nmalevanec Date: Tue, 9 Jun 2020 15:12:43 +0300 Subject: [PATCH 40/50] Fis bundle product indexation. --- .../Product/ReindexSourceItemsPlugin.php | 82 +++++++++++++++++++ InventoryBundleProductIndexer/etc/di.xml | 8 +- .../etc/webapi_rest/di.xml | 14 ++++ .../etc/webapi_soap/di.xml | 14 ++++ 4 files changed, 113 insertions(+), 5 deletions(-) create mode 100644 InventoryBundleProductIndexer/Plugin/Catalog/Model/Product/ReindexSourceItemsPlugin.php create mode 100644 InventoryBundleProductIndexer/etc/webapi_rest/di.xml create mode 100644 InventoryBundleProductIndexer/etc/webapi_soap/di.xml diff --git a/InventoryBundleProductIndexer/Plugin/Catalog/Model/Product/ReindexSourceItemsPlugin.php b/InventoryBundleProductIndexer/Plugin/Catalog/Model/Product/ReindexSourceItemsPlugin.php new file mode 100644 index 000000000000..746f1c91b8a9 --- /dev/null +++ b/InventoryBundleProductIndexer/Plugin/Catalog/Model/Product/ReindexSourceItemsPlugin.php @@ -0,0 +1,82 @@ +getSourceItemsBySku = $getSourceItemsBySku; + $this->getSourceItemIds = $getSourceItemIds; + $this->sourceItemIndexer = $sourceItemIndexer; + } + + /** + * Reindex bundle source items after product save. + * + * @param Product $subject + * @param Product $result + * @return Product + * @throws LocalizedException + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function afterSave(Product $subject, Product $result): Product + { + if ($result->getTypeId() !== Type::TYPE_CODE) { + return $result; + } + $bundleSelectionsData = $result->getBundleSelectionsData() ?: []; + $skus = []; + foreach ($bundleSelectionsData as $option) { + $skus[] = array_column($option, 'sku'); + } + $skus = $skus ? array_merge(...$skus) : $skus; + $sourceItems = [[]]; + foreach ($skus as $sku) { + $sourceItems[] = $this->getSourceItemsBySku->execute($sku); + } + $sourceItems = array_merge(...$sourceItems); + $sourceItemIds = $this->getSourceItemIds->execute($sourceItems); + $this->sourceItemIndexer->executeList($sourceItemIds); + + return $result; + } +} diff --git a/InventoryBundleProductIndexer/etc/di.xml b/InventoryBundleProductIndexer/etc/di.xml index 3c1dc488832b..1232eba41a50 100644 --- a/InventoryBundleProductIndexer/etc/di.xml +++ b/InventoryBundleProductIndexer/etc/di.xml @@ -25,12 +25,10 @@ Magento\InventoryIndexer\Indexer\IndexStructure - - - - - + + + diff --git a/InventoryBundleProductIndexer/etc/webapi_rest/di.xml b/InventoryBundleProductIndexer/etc/webapi_rest/di.xml new file mode 100644 index 000000000000..d8d2a041908c --- /dev/null +++ b/InventoryBundleProductIndexer/etc/webapi_rest/di.xml @@ -0,0 +1,14 @@ + + + + + + + + + diff --git a/InventoryBundleProductIndexer/etc/webapi_soap/di.xml b/InventoryBundleProductIndexer/etc/webapi_soap/di.xml new file mode 100644 index 000000000000..d8d2a041908c --- /dev/null +++ b/InventoryBundleProductIndexer/etc/webapi_soap/di.xml @@ -0,0 +1,14 @@ + + + + + + + + + From 674df267feb2447573e3c9b3a0f114f0071f5532 Mon Sep 17 00:00:00 2001 From: nmalevanec Date: Wed, 10 Jun 2020 16:30:03 +0300 Subject: [PATCH 41/50] Fix website value for IsSalable service. --- InventoryCatalog/Model/IsProductSalable.php | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/InventoryCatalog/Model/IsProductSalable.php b/InventoryCatalog/Model/IsProductSalable.php index cdd4112b2f3f..4866b2460339 100644 --- a/InventoryCatalog/Model/IsProductSalable.php +++ b/InventoryCatalog/Model/IsProductSalable.php @@ -11,17 +11,13 @@ use Magento\Catalog\Api\Data\ProductInterface; use Magento\Catalog\Model\Product\Attribute\Source\Status; use Magento\InventorySalesApi\Api\AreProductsSalableInterface; +use Magento\InventorySalesApi\Model\StockByWebsiteIdResolverInterface; /** * Get salable product status service. */ class IsProductSalable { - /** - * @var GetStockIdForCurrentWebsite - */ - private $getStockIdForCurrentWebsite; - /** * @var AreProductsSalableInterface */ @@ -33,14 +29,19 @@ class IsProductSalable private $productStatusCache; /** - * @param GetStockIdForCurrentWebsite $getStockIdForCurrentWebsite + * @var StockByWebsiteIdResolverInterface + */ + private $stockByWebsiteIdResolver; + + /** + * @param StockByWebsiteIdResolverInterface $stockByWebsiteIdResolver * @param AreProductsSalableInterface $areProductsSalable */ public function __construct( - GetStockIdForCurrentWebsite $getStockIdForCurrentWebsite, + StockByWebsiteIdResolverInterface $stockByWebsiteIdResolver, AreProductsSalableInterface $areProductsSalable ) { - $this->getStockIdForCurrentWebsite = $getStockIdForCurrentWebsite; + $this->stockByWebsiteIdResolver = $stockByWebsiteIdResolver; $this->areProductsSalable = $areProductsSalable; } @@ -58,13 +59,13 @@ public function execute(ProductInterface $product): bool if ($product->getData('is_salable') !== null) { return (bool)$product->getData('is_salable'); } - $stockId = $this->getStockIdForCurrentWebsite->execute(); + $websiteId = (int)$product->getStore()->getWebsite()->getId(); + $stockId = $this->stockByWebsiteIdResolver->execute($websiteId)->getStockId(); //use getData('sku') to get non processed product sku for complex products. if (isset($this->productStatusCache[$stockId][$product->getData('sku')])) { return $this->productStatusCache[$stockId][$product->getSku()]; } - $stockId = $this->getStockIdForCurrentWebsite->execute(); $result = current($this->areProductsSalable->execute([$product->getData('sku')], $stockId)); $salabilityStatus = $result->isSalable(); $this->productStatusCache[$stockId][$product->getData('sku')] = $salabilityStatus; From ad4ff2e1462fed37104d29ea27f645e48d4ab3a6 Mon Sep 17 00:00:00 2001 From: nmalevanec Date: Thu, 11 Jun 2020 17:10:53 +0300 Subject: [PATCH 42/50] Rework configurable product salable verification. Rework AreProductsSalable advance checkout plugin. --- .../Plugin/Model/AreProductsSalablePlugin.php | 51 ++++++++----------- .../IsConfigurableProductSalablePlugin.php | 7 ++- 2 files changed, 26 insertions(+), 32 deletions(-) diff --git a/InventoryAdvancedCheckout/Plugin/Model/AreProductsSalablePlugin.php b/InventoryAdvancedCheckout/Plugin/Model/AreProductsSalablePlugin.php index 9ca7dae53e27..125ccd30190b 100644 --- a/InventoryAdvancedCheckout/Plugin/Model/AreProductsSalablePlugin.php +++ b/InventoryAdvancedCheckout/Plugin/Model/AreProductsSalablePlugin.php @@ -9,12 +9,10 @@ use Magento\AdvancedCheckout\Model\AreProductsSalableForRequestedQtyInterface; use Magento\AdvancedCheckout\Model\Data\IsProductsSalableForRequestedQtyResult; -use Magento\Framework\Exception\NoSuchEntityException; +use Magento\AdvancedCheckout\Model\Data\ProductQuantity; +use Magento\Catalog\Api\ProductRepositoryInterface; +use Magento\Framework\Api\SearchCriteriaBuilder; use Magento\Framework\ObjectManagerInterface; -use Magento\InventorySalesApi\Api\AreProductsSalableInterface; -use Magento\InventorySalesApi\Api\Data\SalesChannelInterface; -use Magento\InventorySalesApi\Api\StockResolverInterface; -use Magento\Store\Api\WebsiteRepositoryInterface; /** * Provides multi-sourcing capabilities for Advanced Checkout Order By SKU feature. @@ -22,41 +20,33 @@ class AreProductsSalablePlugin { /** - * @var AreProductsSalableInterface - */ - private $areProductsSalable; - - /** - * @var StockResolverInterface + * @var ObjectManagerInterface */ - private $stockResolver; + private $objectManager; /** - * @var WebsiteRepositoryInterface + * @var ProductRepositoryInterface */ - private $websiteRepository; + private $productRepository; /** - * @var ObjectManagerInterface + * @var SearchCriteriaBuilder */ - private $objectManager; + private $searchCriteriaBuilder; /** - * @param AreProductsSalableInterface $areProductsSalable - * @param StockResolverInterface $stockResolver - * @param WebsiteRepositoryInterface $websiteRepository + * @param SearchCriteriaBuilder $searchCriteriaBuilder + * @param ProductRepositoryInterface $productRepository * @param ObjectManagerInterface $objectManager */ public function __construct( - AreProductsSalableInterface $areProductsSalable, - StockResolverInterface $stockResolver, - WebsiteRepositoryInterface $websiteRepository, + SearchCriteriaBuilder $searchCriteriaBuilder, + ProductRepositoryInterface $productRepository, ObjectManagerInterface $objectManager ) { - $this->areProductsSalable = $areProductsSalable; - $this->stockResolver = $stockResolver; - $this->websiteRepository = $websiteRepository; $this->objectManager = $objectManager; + $this->productRepository = $productRepository; + $this->searchCriteriaBuilder = $searchCriteriaBuilder; } /** @@ -64,10 +54,9 @@ public function __construct( * * @param AreProductsSalableForRequestedQtyInterface $subject * @param callable $proceed - * @param \Magento\AdvancedCheckout\Model\Data\ProductQuantity[] $productQuantities + * @param ProductQuantity[] $productQuantities * @param int $websiteId * @return array - * @throws NoSuchEntityException * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function aroundExecute( @@ -76,17 +65,17 @@ public function aroundExecute( array $productQuantities, int $websiteId ): array { - $website = $this->websiteRepository->getById($websiteId); - $stock = $this->stockResolver->execute(SalesChannelInterface::TYPE_WEBSITE, $website->getCode()); $skus = []; foreach ($productQuantities as $productQuantity) { $skus[] = $productQuantity->getSku(); } + $searchCriteria = $this->searchCriteriaBuilder->addFilter('sku', $skus, 'in')->create(); + $products = $this->productRepository->getList($searchCriteria); $result = []; - foreach ($this->areProductsSalable->execute($skus, $stock->getStockId()) as $productStock) { + foreach ($products->getItems() as $product) { $result[] = $this->objectManager->create( IsProductsSalableForRequestedQtyResult::class, - ['sku' => $productStock->getSku(), 'isSalable' => $productStock->isSalable()] + ['sku' => $product->getSku(), 'isSalable' => $product->isSalable()] ); } diff --git a/InventoryConfigurableProduct/Plugin/InventoryCatalog/Model/IsProductSalable/IsConfigurableProductSalablePlugin.php b/InventoryConfigurableProduct/Plugin/InventoryCatalog/Model/IsProductSalable/IsConfigurableProductSalablePlugin.php index 8768901e0dfd..7b3576480c32 100644 --- a/InventoryConfigurableProduct/Plugin/InventoryCatalog/Model/IsProductSalable/IsConfigurableProductSalablePlugin.php +++ b/InventoryConfigurableProduct/Plugin/InventoryCatalog/Model/IsProductSalable/IsConfigurableProductSalablePlugin.php @@ -50,7 +50,12 @@ public function afterExecute(IsProductSalable $subject, bool $result, ProductInt ProductInterface::STATUS, Status::STATUS_ENABLED ); + foreach ($collection->getItems() as $item) { + if ($item->isSalable()) { + return true; + } + } - return $collection->count() > 0; + return false; } } From a1ff3269ebf445725f916e37e6bbb7d39539170f Mon Sep 17 00:00:00 2001 From: nmalevanec Date: Fri, 12 Jun 2020 16:48:17 +0300 Subject: [PATCH 43/50] Fix 'is_salable' and 'is_available' plugins. Make index to consider manage stock system configuration. Fix MFTF test. --- ...ionTurnedOffForDownloadableProductTest.xml | 4 ++-- .../Plugin/Model/AreProductsSalablePlugin.php | 22 +++++-------------- .../Model/Product/IsAvailablePlugin.php | 15 ++++++++++++- .../Catalog/Model/Product/IsSalablePlugin.php | 15 ++++++++++++- InventoryIndexer/Indexer/SelectBuilder.php | 3 ++- .../IsStockItemSalableConditionChain.php | 15 ++++++++----- 6 files changed, 47 insertions(+), 27 deletions(-) diff --git a/InventoryAdminUi/Test/Mftf/Test/AdminManageStockInConfigurationTurnedOffForDownloadableProductTest.xml b/InventoryAdminUi/Test/Mftf/Test/AdminManageStockInConfigurationTurnedOffForDownloadableProductTest.xml index 42ba567b3c32..ded4c92b1e09 100644 --- a/InventoryAdminUi/Test/Mftf/Test/AdminManageStockInConfigurationTurnedOffForDownloadableProductTest.xml +++ b/InventoryAdminUi/Test/Mftf/Test/AdminManageStockInConfigurationTurnedOffForDownloadableProductTest.xml @@ -23,7 +23,7 @@ - + @@ -76,7 +76,7 @@ - + diff --git a/InventoryAdvancedCheckout/Plugin/Model/AreProductsSalablePlugin.php b/InventoryAdvancedCheckout/Plugin/Model/AreProductsSalablePlugin.php index 125ccd30190b..cc43ddf3683b 100644 --- a/InventoryAdvancedCheckout/Plugin/Model/AreProductsSalablePlugin.php +++ b/InventoryAdvancedCheckout/Plugin/Model/AreProductsSalablePlugin.php @@ -11,7 +11,7 @@ use Magento\AdvancedCheckout\Model\Data\IsProductsSalableForRequestedQtyResult; use Magento\AdvancedCheckout\Model\Data\ProductQuantity; use Magento\Catalog\Api\ProductRepositoryInterface; -use Magento\Framework\Api\SearchCriteriaBuilder; +use Magento\Framework\Exception\NoSuchEntityException; use Magento\Framework\ObjectManagerInterface; /** @@ -30,27 +30,19 @@ class AreProductsSalablePlugin private $productRepository; /** - * @var SearchCriteriaBuilder - */ - private $searchCriteriaBuilder; - - /** - * @param SearchCriteriaBuilder $searchCriteriaBuilder * @param ProductRepositoryInterface $productRepository * @param ObjectManagerInterface $objectManager */ public function __construct( - SearchCriteriaBuilder $searchCriteriaBuilder, ProductRepositoryInterface $productRepository, ObjectManagerInterface $objectManager ) { $this->objectManager = $objectManager; $this->productRepository = $productRepository; - $this->searchCriteriaBuilder = $searchCriteriaBuilder; } /** - * Get is product out of stock for given Product id in a given Website id in MSI context. + * Get products salable status for given sku requests. * * @param AreProductsSalableForRequestedQtyInterface $subject * @param callable $proceed @@ -58,6 +50,7 @@ public function __construct( * @param int $websiteId * @return array * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * @throws NoSuchEntityException in case product doesn't exists */ public function aroundExecute( AreProductsSalableForRequestedQtyInterface $subject, @@ -65,14 +58,9 @@ public function aroundExecute( array $productQuantities, int $websiteId ): array { - $skus = []; - foreach ($productQuantities as $productQuantity) { - $skus[] = $productQuantity->getSku(); - } - $searchCriteria = $this->searchCriteriaBuilder->addFilter('sku', $skus, 'in')->create(); - $products = $this->productRepository->getList($searchCriteria); $result = []; - foreach ($products->getItems() as $product) { + foreach ($productQuantities as $productQuantity) { + $product = $this->productRepository->get($productQuantity->getSku()); $result[] = $this->objectManager->create( IsProductsSalableForRequestedQtyResult::class, ['sku' => $product->getSku(), 'isSalable' => $product->isSalable()] diff --git a/InventoryCatalog/Plugin/Catalog/Model/Product/IsAvailablePlugin.php b/InventoryCatalog/Plugin/Catalog/Model/Product/IsAvailablePlugin.php index 92592182305f..59f50753dd35 100644 --- a/InventoryCatalog/Plugin/Catalog/Model/Product/IsAvailablePlugin.php +++ b/InventoryCatalog/Plugin/Catalog/Model/Product/IsAvailablePlugin.php @@ -7,6 +7,7 @@ namespace Magento\InventoryCatalog\Plugin\Catalog\Model\Product; +use Magento\Catalog\Helper\Product as ProductHelper; use Magento\Catalog\Model\Product; use Magento\InventoryCatalog\Model\IsProductSalable; @@ -20,13 +21,21 @@ class IsAvailablePlugin */ private $isProductSalable; + /** + * @var ProductHelper + */ + private $product; + /** * @param IsProductSalable $isProductSalable + * @param ProductHelper $product */ public function __construct( - IsProductSalable $isProductSalable + IsProductSalable $isProductSalable, + ProductHelper $product ) { $this->isProductSalable = $isProductSalable; + $this->product = $product; } /** @@ -39,6 +48,10 @@ public function __construct( */ public function aroundIsAvailable(Product $product, \Closure $proceed): bool { + if ($this->product->getSkipSaleableCheck()) { + return true; + } + return $this->isProductSalable->execute($product); } } diff --git a/InventoryCatalog/Plugin/Catalog/Model/Product/IsSalablePlugin.php b/InventoryCatalog/Plugin/Catalog/Model/Product/IsSalablePlugin.php index a9ceb147a342..0baa7c8011fd 100644 --- a/InventoryCatalog/Plugin/Catalog/Model/Product/IsSalablePlugin.php +++ b/InventoryCatalog/Plugin/Catalog/Model/Product/IsSalablePlugin.php @@ -7,6 +7,7 @@ namespace Magento\InventoryCatalog\Plugin\Catalog\Model\Product; +use Magento\Catalog\Helper\Product as ProductHelper; use Magento\Catalog\Model\Product; use Magento\InventoryCatalog\Model\IsProductSalable; @@ -20,13 +21,21 @@ class IsSalablePlugin */ private $isProductSalable; + /** + * @var ProductHelper + */ + private $product; + /** * @param IsProductSalable $isProductSalable + * @param ProductHelper $product */ public function __construct( - IsProductSalable $isProductSalable + IsProductSalable $isProductSalable, + ProductHelper $product ) { $this->isProductSalable = $isProductSalable; + $this->product = $product; } /** @@ -39,6 +48,10 @@ public function __construct( */ public function aroundIsSalable(Product $product, \Closure $proceed): bool { + if ($this->product->getSkipSaleableCheck()) { + return true; + } + return $this->isProductSalable->execute($product); } } diff --git a/InventoryIndexer/Indexer/SelectBuilder.php b/InventoryIndexer/Indexer/SelectBuilder.php index ac1beea684bb..c455d61eb82a 100644 --- a/InventoryIndexer/Indexer/SelectBuilder.php +++ b/InventoryIndexer/Indexer/SelectBuilder.php @@ -79,12 +79,13 @@ public function execute(int $stockId): Select [] ); + $isSalableExpression = new \Zend_Db_Expr($this->getIsStockItemSalableCondition->execute($select)); $select->from( ['source_item' => $sourceItemTable], [ SourceItemInterface::SKU, IndexStructure::QUANTITY => 'SUM(' . $quantityExpression . ')', - IndexStructure::IS_SALABLE => $this->getIsStockItemSalableCondition->execute($select), + IndexStructure::IS_SALABLE => $isSalableExpression ] ) ->where('source_item.' . SourceItemInterface::SOURCE_CODE . ' IN (?)', $sourceCodes) diff --git a/InventorySales/Model/ResourceModel/IsStockItemSalableCondition/IsStockItemSalableConditionChain.php b/InventorySales/Model/ResourceModel/IsStockItemSalableCondition/IsStockItemSalableConditionChain.php index fb93eb8a3b5c..0dd085a82a8c 100644 --- a/InventorySales/Model/ResourceModel/IsStockItemSalableCondition/IsStockItemSalableConditionChain.php +++ b/InventorySales/Model/ResourceModel/IsStockItemSalableCondition/IsStockItemSalableConditionChain.php @@ -7,6 +7,7 @@ namespace Magento\InventorySales\Model\ResourceModel\IsStockItemSalableCondition; +use Magento\CatalogInventory\Api\StockConfigurationInterface; use Magento\Framework\App\ResourceConnection; use Magento\Framework\DB\Select; use Magento\Framework\Exception\LocalizedException; @@ -26,14 +27,18 @@ class IsStockItemSalableConditionChain implements GetIsStockItemSalableCondition */ private $resourceConnection; + /** + * @var StockConfigurationInterface + */ + private $configuration; + /** * @param ResourceConnection $resourceConnection - * @param array $conditions - * - * @throws LocalizedException + * @param StockConfigurationInterface $configuration */ public function __construct( ResourceConnection $resourceConnection, + StockConfigurationInterface $configuration, array $conditions = [] ) { foreach ($conditions as $getIsSalableCondition) { @@ -45,15 +50,15 @@ public function __construct( } $this->resourceConnection = $resourceConnection; $this->conditions = $conditions; + $this->configuration = $configuration; } /** * @inheritdoc - * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function execute(Select $select): string { - if (empty($this->conditions)) { + if (empty($this->conditions) || !$this->configuration->getManageStock()) { return '1'; } From 5eafe309584a67c34faa308c970bc11844cab9b3 Mon Sep 17 00:00:00 2001 From: nmalevanec Date: Fri, 12 Jun 2020 17:09:59 +0300 Subject: [PATCH 44/50] Try to remove plugin blocked used events. --- InventoryCatalog/etc/di.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/InventoryCatalog/etc/di.xml b/InventoryCatalog/etc/di.xml index 5e231811a3d5..44497f96176a 100644 --- a/InventoryCatalog/etc/di.xml +++ b/InventoryCatalog/etc/di.xml @@ -165,7 +165,6 @@ - From 8cffa9e05aeced0b87f757c1f795307ab91ca6d0 Mon Sep 17 00:00:00 2001 From: nmalevanec Date: Mon, 15 Jun 2020 16:36:55 +0300 Subject: [PATCH 45/50] Fix test. --- .../Plugin/Model/AreProductsSalablePlugin.php | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/InventoryAdvancedCheckout/Plugin/Model/AreProductsSalablePlugin.php b/InventoryAdvancedCheckout/Plugin/Model/AreProductsSalablePlugin.php index cc43ddf3683b..b0332ac78b22 100644 --- a/InventoryAdvancedCheckout/Plugin/Model/AreProductsSalablePlugin.php +++ b/InventoryAdvancedCheckout/Plugin/Model/AreProductsSalablePlugin.php @@ -50,7 +50,6 @@ public function __construct( * @param int $websiteId * @return array * @SuppressWarnings(PHPMD.UnusedFormalParameter) - * @throws NoSuchEntityException in case product doesn't exists */ public function aroundExecute( AreProductsSalableForRequestedQtyInterface $subject, @@ -60,11 +59,18 @@ public function aroundExecute( ): array { $result = []; foreach ($productQuantities as $productQuantity) { - $product = $this->productRepository->get($productQuantity->getSku()); - $result[] = $this->objectManager->create( - IsProductsSalableForRequestedQtyResult::class, - ['sku' => $product->getSku(), 'isSalable' => $product->isSalable()] - ); + try { + $product = $this->productRepository->get($productQuantity->getSku()); + $result[] = $this->objectManager->create( + IsProductsSalableForRequestedQtyResult::class, + ['sku' => $product->getSku(), 'isSalable' => $product->isSalable()] + ); + } catch (NoSuchEntityException $e) { + $result[] = $this->objectManager->create( + IsProductsSalableForRequestedQtyResult::class, + ['sku' => $productQuantity->getSku(), 'isSalable' => false] + ); + } } return $result; From 53f6bc5b4c9cfd65e518f3f08a77b4f9e2c920e1 Mon Sep 17 00:00:00 2001 From: nmalevanec Date: Tue, 16 Jun 2020 15:48:21 +0300 Subject: [PATCH 46/50] Fix bundle product index. Fix adapt get product stock status plugins. --- .../Order/PlaceOrderOnDefaultStockTest.php | 2 +- .../Product/ReindexSourceItemsPlugin.php | 46 ++++++++++++--- InventoryCache/etc/di.xml | 3 - InventoryCatalog/Model/IsProductSalable.php | 5 +- .../Model/Product/IsAvailablePlugin.php | 15 +---- .../Catalog/Model/Product/IsSalablePlugin.php | 57 ------------------- .../AdaptGetProductStockStatusBySkuPlugin.php | 43 +++----------- .../AdaptGetProductStockStatusPlugin.php | 53 +++-------------- .../AdaptGetStockStatusBySkuPlugin.php | 29 +++++----- .../AdaptGetStockStatusPlugin.php | 27 +++++---- .../Strategy/Sync/PriceIndexUpdatePlugin.php | 2 +- .../AddSalesQuoteItemOnDefaultStockTest.php | 3 + 12 files changed, 89 insertions(+), 196 deletions(-) delete mode 100644 InventoryCatalog/Plugin/Catalog/Model/Product/IsSalablePlugin.php diff --git a/InventoryBundleProduct/Test/Integration/Order/PlaceOrderOnDefaultStockTest.php b/InventoryBundleProduct/Test/Integration/Order/PlaceOrderOnDefaultStockTest.php index a16918b01528..5624c2452353 100644 --- a/InventoryBundleProduct/Test/Integration/Order/PlaceOrderOnDefaultStockTest.php +++ b/InventoryBundleProduct/Test/Integration/Order/PlaceOrderOnDefaultStockTest.php @@ -31,7 +31,7 @@ * @magentoDataFixture Magento_InventoryBundleProduct::Test/_files/default_stock_bundle_products.php * @magentoDataFixture Magento_InventoryBundleProduct::Test/_files/source_items_for_bundle_options_on_default_source.php * @magentoDataFixture Magento_InventorySalesApi::Test/_files/quote.php - * @magentoDataFixture Magento_InventoryIndexer::Test/_files/reindex_inventory. + * @magentoDataFixture Magento_InventoryIndexer::Test/_files/reindex_inventory.php * * @magentoDbIsolation disabled */ diff --git a/InventoryBundleProductIndexer/Plugin/Catalog/Model/Product/ReindexSourceItemsPlugin.php b/InventoryBundleProductIndexer/Plugin/Catalog/Model/Product/ReindexSourceItemsPlugin.php index 746f1c91b8a9..2a2fd2ee69f1 100644 --- a/InventoryBundleProductIndexer/Plugin/Catalog/Model/Product/ReindexSourceItemsPlugin.php +++ b/InventoryBundleProductIndexer/Plugin/Catalog/Model/Product/ReindexSourceItemsPlugin.php @@ -11,6 +11,7 @@ use Magento\Catalog\Model\Product; use Magento\Framework\Exception\LocalizedException; use Magento\InventoryApi\Api\GetSourceItemsBySkuInterface; +use Magento\InventoryCatalogApi\Model\GetSkusByProductIdsInterface; use Magento\InventoryIndexer\Indexer\SourceItem\GetSourceItemIds; use Magento\InventoryIndexer\Indexer\SourceItem\SourceItemIndexer; @@ -34,19 +35,27 @@ class ReindexSourceItemsPlugin */ private $sourceItemIndexer; + /** + * @var GetSkusByProductIdsInterface + */ + private $getSkusByProductIds; + /** * @param GetSourceItemsBySkuInterface $getSourceItemsBySku * @param GetSourceItemIds $getSourceItemIds * @param SourceItemIndexer $sourceItemIndexer + * @param GetSkusByProductIdsInterface $getSkusByProductIds */ public function __construct( GetSourceItemsBySkuInterface $getSourceItemsBySku, GetSourceItemIds $getSourceItemIds, - SourceItemIndexer $sourceItemIndexer + SourceItemIndexer $sourceItemIndexer, + GetSkusByProductIdsInterface $getSkusByProductIds ) { $this->getSourceItemsBySku = $getSourceItemsBySku; $this->getSourceItemIds = $getSourceItemIds; $this->sourceItemIndexer = $sourceItemIndexer; + $this->getSkusByProductIds = $getSkusByProductIds; } /** @@ -58,17 +67,12 @@ public function __construct( * @throws LocalizedException * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ - public function afterSave(Product $subject, Product $result): Product + public function afterAfterSave(Product $subject, Product $result): Product { if ($result->getTypeId() !== Type::TYPE_CODE) { return $result; } - $bundleSelectionsData = $result->getBundleSelectionsData() ?: []; - $skus = []; - foreach ($bundleSelectionsData as $option) { - $skus[] = array_column($option, 'sku'); - } - $skus = $skus ? array_merge(...$skus) : $skus; + $skus = $this->getSelectionsSku($result); $sourceItems = [[]]; foreach ($skus as $sku) { $sourceItems[] = $this->getSourceItemsBySku->execute($sku); @@ -79,4 +83,30 @@ public function afterSave(Product $subject, Product $result): Product return $result; } + + /** + * Retrieve bundle selections skus. + * + * @param Product $result + * @return array + */ + private function getSelectionsSku(Product $result): array + { + $bundleSelectionsData = $result->getBundleSelectionsData() ?: []; + $skus = []; + foreach ($bundleSelectionsData as $option) { + $skus[] = array_column($option, 'sku'); + } + $skus = $skus ? array_merge(...$skus) : $skus; + if ($skus) { + return $skus; + } + $ids = []; + foreach ($bundleSelectionsData as $option) { + $ids[] = array_column($option, 'product_id'); + } + $ids = $ids ? array_merge(...$ids) : $ids; + + return $this->getSkusByProductIds->execute($ids); + } } diff --git a/InventoryCache/etc/di.xml b/InventoryCache/etc/di.xml index 7eb903ca9a2d..706222f90b8a 100644 --- a/InventoryCache/etc/di.xml +++ b/InventoryCache/etc/di.xml @@ -20,7 +20,4 @@ Magento\Catalog\Model\Product::CACHE_TAG - - - diff --git a/InventoryCatalog/Model/IsProductSalable.php b/InventoryCatalog/Model/IsProductSalable.php index 4866b2460339..2ab90931bad4 100644 --- a/InventoryCatalog/Model/IsProductSalable.php +++ b/InventoryCatalog/Model/IsProductSalable.php @@ -53,7 +53,8 @@ public function __construct( */ public function execute(ProductInterface $product): bool { - if (null === $product->getSku() || (int)$product->getStatus() === Status::STATUS_DISABLED) { + if (null === $product->getSku() || + (null !== $product->getStatus() && (int)$product->getStatus() !== Status::STATUS_ENABLED)) { return false; } if ($product->getData('is_salable') !== null) { @@ -63,7 +64,7 @@ public function execute(ProductInterface $product): bool $stockId = $this->stockByWebsiteIdResolver->execute($websiteId)->getStockId(); //use getData('sku') to get non processed product sku for complex products. if (isset($this->productStatusCache[$stockId][$product->getData('sku')])) { - return $this->productStatusCache[$stockId][$product->getSku()]; + return $this->productStatusCache[$stockId][$product->getData('sku')]; } $result = current($this->areProductsSalable->execute([$product->getData('sku')], $stockId)); diff --git a/InventoryCatalog/Plugin/Catalog/Model/Product/IsAvailablePlugin.php b/InventoryCatalog/Plugin/Catalog/Model/Product/IsAvailablePlugin.php index 59f50753dd35..92592182305f 100644 --- a/InventoryCatalog/Plugin/Catalog/Model/Product/IsAvailablePlugin.php +++ b/InventoryCatalog/Plugin/Catalog/Model/Product/IsAvailablePlugin.php @@ -7,7 +7,6 @@ namespace Magento\InventoryCatalog\Plugin\Catalog\Model\Product; -use Magento\Catalog\Helper\Product as ProductHelper; use Magento\Catalog\Model\Product; use Magento\InventoryCatalog\Model\IsProductSalable; @@ -21,21 +20,13 @@ class IsAvailablePlugin */ private $isProductSalable; - /** - * @var ProductHelper - */ - private $product; - /** * @param IsProductSalable $isProductSalable - * @param ProductHelper $product */ public function __construct( - IsProductSalable $isProductSalable, - ProductHelper $product + IsProductSalable $isProductSalable ) { $this->isProductSalable = $isProductSalable; - $this->product = $product; } /** @@ -48,10 +39,6 @@ public function __construct( */ public function aroundIsAvailable(Product $product, \Closure $proceed): bool { - if ($this->product->getSkipSaleableCheck()) { - return true; - } - return $this->isProductSalable->execute($product); } } diff --git a/InventoryCatalog/Plugin/Catalog/Model/Product/IsSalablePlugin.php b/InventoryCatalog/Plugin/Catalog/Model/Product/IsSalablePlugin.php deleted file mode 100644 index 0baa7c8011fd..000000000000 --- a/InventoryCatalog/Plugin/Catalog/Model/Product/IsSalablePlugin.php +++ /dev/null @@ -1,57 +0,0 @@ -isProductSalable = $isProductSalable; - $this->product = $product; - } - - /** - * Fetches is salable status from multi-stock. - * - * @param Product $product - * @param \Closure $proceed - * @return bool - * @SuppressWarnings(PHPMD.UnusedFormalParameter) - */ - public function aroundIsSalable(Product $product, \Closure $proceed): bool - { - if ($this->product->getSkipSaleableCheck()) { - return true; - } - - return $this->isProductSalable->execute($product); - } -} diff --git a/InventoryCatalog/Plugin/CatalogInventory/Api/StockRegistry/AdaptGetProductStockStatusBySkuPlugin.php b/InventoryCatalog/Plugin/CatalogInventory/Api/StockRegistry/AdaptGetProductStockStatusBySkuPlugin.php index 532db9d8ff58..10032d2ff0ff 100644 --- a/InventoryCatalog/Plugin/CatalogInventory/Api/StockRegistry/AdaptGetProductStockStatusBySkuPlugin.php +++ b/InventoryCatalog/Plugin/CatalogInventory/Api/StockRegistry/AdaptGetProductStockStatusBySkuPlugin.php @@ -7,13 +7,9 @@ namespace Magento\InventoryCatalog\Plugin\CatalogInventory\Api\StockRegistry; +use Magento\Catalog\Api\ProductRepositoryInterface; use Magento\CatalogInventory\Api\StockRegistryInterface; -use Magento\Framework\Exception\LocalizedException; use Magento\Framework\Exception\NoSuchEntityException; -use Magento\InventorySalesApi\Api\AreProductsSalableInterface; -use Magento\InventorySalesApi\Api\Data\SalesChannelInterface; -use Magento\InventorySalesApi\Api\StockResolverInterface; -use Magento\Store\Model\StoreManagerInterface; /** * Adapt getProductStockStatusBySku for multi stocks. @@ -21,33 +17,17 @@ class AdaptGetProductStockStatusBySkuPlugin { /** - * @var AreProductsSalableInterface + * @var ProductRepositoryInterface */ - private $areProductsSalable; + private $productRepository; /** - * @var StoreManagerInterface - */ - private $storeManager; - - /** - * @var StockResolverInterface - */ - private $stockResolver; - - /** - * @param AreProductsSalableInterface $areProductsSalable - * @param StoreManagerInterface $storeManager - * @param StockResolverInterface $stockResolver + * @param ProductRepositoryInterface $productRepository */ public function __construct( - AreProductsSalableInterface $areProductsSalable, - StoreManagerInterface $storeManager, - StockResolverInterface $stockResolver + ProductRepositoryInterface $productRepository ) { - $this->areProductsSalable = $areProductsSalable; - $this->storeManager = $storeManager; - $this->stockResolver = $stockResolver; + $this->productRepository = $productRepository; } /** @@ -58,7 +38,6 @@ public function __construct( * @param string $productSku * @param int $scopeId * @return int - * @throws LocalizedException * @throws NoSuchEntityException * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ @@ -68,14 +47,8 @@ public function aroundGetProductStockStatusBySku( $productSku, $scopeId = null ): int { - $websiteCode = null === $scopeId - ? $this->storeManager->getWebsite()->getCode() - : $this->storeManager->getWebsite($scopeId)->getCode(); - $stockId = $this->stockResolver->execute(SalesChannelInterface::TYPE_WEBSITE, $websiteCode)->getStockId(); - - $result = $this->areProductsSalable->execute([$productSku], $stockId); - $result = current($result); + $product = $this->productRepository->get($productSku); - return (int)$result->isSalable(); + return (int)$product->isAvailable(); } } diff --git a/InventoryCatalog/Plugin/CatalogInventory/Api/StockRegistry/AdaptGetProductStockStatusPlugin.php b/InventoryCatalog/Plugin/CatalogInventory/Api/StockRegistry/AdaptGetProductStockStatusPlugin.php index 59c3d9f291df..dec3b44a654e 100644 --- a/InventoryCatalog/Plugin/CatalogInventory/Api/StockRegistry/AdaptGetProductStockStatusPlugin.php +++ b/InventoryCatalog/Plugin/CatalogInventory/Api/StockRegistry/AdaptGetProductStockStatusPlugin.php @@ -7,14 +7,9 @@ namespace Magento\InventoryCatalog\Plugin\CatalogInventory\Api\StockRegistry; +use Magento\Catalog\Api\ProductRepositoryInterface; use Magento\CatalogInventory\Api\StockRegistryInterface; -use Magento\Framework\Exception\LocalizedException; use Magento\Framework\Exception\NoSuchEntityException; -use Magento\InventoryCatalogApi\Model\GetSkusByProductIdsInterface; -use Magento\InventorySalesApi\Api\AreProductsSalableInterface; -use Magento\InventorySalesApi\Api\Data\SalesChannelInterface; -use Magento\InventorySalesApi\Api\StockResolverInterface; -use Magento\Store\Model\StoreManagerInterface; /** * Adapt getProductStockStatus for multi stocks. @@ -22,41 +17,17 @@ class AdaptGetProductStockStatusPlugin { /** - * @var AreProductsSalableInterface + * @var ProductRepositoryInterface */ - private $areProductsSalable; + private $productRepository; /** - * @var GetSkusByProductIdsInterface - */ - private $getSkusByProductIds; - - /** - * @var StoreManagerInterface - */ - private $storeManager; - - /** - * @var StockResolverInterface - */ - private $stockResolver; - - /** - * @param AreProductsSalableInterface $areProductsSalable - * @param GetSkusByProductIdsInterface $getSkusByProductIds - * @param StoreManagerInterface $storeManager - * @param StockResolverInterface $stockResolver + * @param ProductRepositoryInterface $productRepository */ public function __construct( - AreProductsSalableInterface $areProductsSalable, - GetSkusByProductIdsInterface $getSkusByProductIds, - StoreManagerInterface $storeManager, - StockResolverInterface $stockResolver + ProductRepositoryInterface $productRepository ) { - $this->areProductsSalable = $areProductsSalable; - $this->getSkusByProductIds = $getSkusByProductIds; - $this->storeManager = $storeManager; - $this->stockResolver = $stockResolver; + $this->productRepository = $productRepository; } /** @@ -67,7 +38,6 @@ public function __construct( * @param int $productId * @param int $scopeId * @return int - * @throws LocalizedException * @throws NoSuchEntityException * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ @@ -77,15 +47,8 @@ public function aroundGetProductStockStatus( $productId, $scopeId = null ): int { - $websiteCode = null === $scopeId - ? $this->storeManager->getWebsite()->getCode() - : $this->storeManager->getWebsite($scopeId)->getCode(); - $stockId = $this->stockResolver->execute(SalesChannelInterface::TYPE_WEBSITE, $websiteCode)->getStockId(); - $sku = $this->getSkusByProductIds->execute([$productId])[$productId]; - - $result = $this->areProductsSalable->execute([$sku], $stockId); - $result = current($result); + $product = $this->productRepository->getById($productId); - return (int)$result->isSalable(); + return (int)$product->isAvailable(); } } diff --git a/InventoryCatalog/Plugin/CatalogInventory/Api/StockRegistry/AdaptGetStockStatusBySkuPlugin.php b/InventoryCatalog/Plugin/CatalogInventory/Api/StockRegistry/AdaptGetStockStatusBySkuPlugin.php index 60929a190f36..d581b460586c 100644 --- a/InventoryCatalog/Plugin/CatalogInventory/Api/StockRegistry/AdaptGetStockStatusBySkuPlugin.php +++ b/InventoryCatalog/Plugin/CatalogInventory/Api/StockRegistry/AdaptGetStockStatusBySkuPlugin.php @@ -7,12 +7,12 @@ namespace Magento\InventoryCatalog\Plugin\CatalogInventory\Api\StockRegistry; +use Magento\Catalog\Api\ProductRepositoryInterface; use Magento\CatalogInventory\Api\Data\StockStatusInterface; use Magento\CatalogInventory\Api\StockRegistryInterface; use Magento\Framework\Exception\InputException; use Magento\Framework\Exception\LocalizedException; use Magento\Framework\Exception\NoSuchEntityException; -use Magento\InventorySalesApi\Api\AreProductsSalableInterface; use Magento\InventorySalesApi\Api\Data\SalesChannelInterface; use Magento\InventorySalesApi\Api\GetProductSalableQtyInterface; use Magento\InventorySalesApi\Api\StockResolverInterface; @@ -23,11 +23,6 @@ */ class AdaptGetStockStatusBySkuPlugin { - /** - * @var AreProductsSalableInterface - */ - private $areProductsSalable; - /** * @var GetProductSalableQtyInterface */ @@ -44,21 +39,26 @@ class AdaptGetStockStatusBySkuPlugin private $stockResolver; /** - * @param AreProductsSalableInterface $areProductsSalable + * @var ProductRepositoryInterface + */ + private $productRepository; + + /** * @param GetProductSalableQtyInterface $getProductSalableQty * @param StoreManagerInterface $storeManager * @param StockResolverInterface $stockResolver + * @param ProductRepositoryInterface $productRepository */ public function __construct( - AreProductsSalableInterface $areProductsSalable, GetProductSalableQtyInterface $getProductSalableQty, StoreManagerInterface $storeManager, - StockResolverInterface $stockResolver + StockResolverInterface $stockResolver, + ProductRepositoryInterface $productRepository ) { - $this->areProductsSalable = $areProductsSalable; $this->getProductSalableQty = $getProductSalableQty; $this->storeManager = $storeManager; $this->stockResolver = $stockResolver; + $this->productRepository = $productRepository; } /** @@ -79,22 +79,19 @@ public function afterGetStockStatusBySku( $productSku, $scopeId = null ): StockStatusInterface { + $product = $this->productRepository->get($productSku); $websiteCode = null === $scopeId ? $this->storeManager->getWebsite()->getCode() : $this->storeManager->getWebsite($scopeId)->getCode(); $stockId = $this->stockResolver->execute(SalesChannelInterface::TYPE_WEBSITE, $websiteCode)->getStockId(); - - $result = $this->areProductsSalable->execute([$productSku], $stockId); - $result = current($result); - try { $qty = $this->getProductSalableQty->execute($productSku, $stockId); } catch (InputException $e) { $qty = 0; } - - $stockStatus->setStockStatus((int)$result->isSalable()); + $stockStatus->setStockStatus((int)$product->isAvailable()); $stockStatus->setQty($qty); + return $stockStatus; } } diff --git a/InventoryCatalog/Plugin/CatalogInventory/Api/StockRegistry/AdaptGetStockStatusPlugin.php b/InventoryCatalog/Plugin/CatalogInventory/Api/StockRegistry/AdaptGetStockStatusPlugin.php index 6593389973a0..c009ac3b9493 100644 --- a/InventoryCatalog/Plugin/CatalogInventory/Api/StockRegistry/AdaptGetStockStatusPlugin.php +++ b/InventoryCatalog/Plugin/CatalogInventory/Api/StockRegistry/AdaptGetStockStatusPlugin.php @@ -7,13 +7,13 @@ namespace Magento\InventoryCatalog\Plugin\CatalogInventory\Api\StockRegistry; +use Magento\Catalog\Api\ProductRepositoryInterface; use Magento\CatalogInventory\Api\Data\StockStatusInterface; use Magento\CatalogInventory\Api\StockRegistryInterface; use Magento\Framework\Exception\InputException; use Magento\Framework\Exception\LocalizedException; use Magento\Framework\Exception\NoSuchEntityException; use Magento\InventoryCatalogApi\Model\GetSkusByProductIdsInterface; -use Magento\InventorySalesApi\Api\AreProductsSalableInterface; use Magento\InventorySalesApi\Api\Data\SalesChannelInterface; use Magento\InventorySalesApi\Api\GetProductSalableQtyInterface; use Magento\InventorySalesApi\Api\StockResolverInterface; @@ -24,11 +24,6 @@ */ class AdaptGetStockStatusPlugin { - /** - * @var AreProductsSalableInterface - */ - private $areProductsSalable; - /** * @var GetProductSalableQtyInterface */ @@ -50,24 +45,29 @@ class AdaptGetStockStatusPlugin private $stockResolver; /** - * @param AreProductsSalableInterface $areProductsSalable + * @var ProductRepositoryInterface + */ + private $productRepository; + + /** * @param GetProductSalableQtyInterface $getProductSalableQty * @param GetSkusByProductIdsInterface $getSkusByProductIds * @param StoreManagerInterface $storeManager * @param StockResolverInterface $stockResolver + * @param ProductRepositoryInterface $productRepository */ public function __construct( - AreProductsSalableInterface $areProductsSalable, GetProductSalableQtyInterface $getProductSalableQty, GetSkusByProductIdsInterface $getSkusByProductIds, StoreManagerInterface $storeManager, - StockResolverInterface $stockResolver + StockResolverInterface $stockResolver, + ProductRepositoryInterface $productRepository ) { - $this->areProductsSalable = $areProductsSalable; $this->getProductSalableQty = $getProductSalableQty; $this->getSkusByProductIds = $getSkusByProductIds; $this->storeManager = $storeManager; $this->stockResolver = $stockResolver; + $this->productRepository = $productRepository; } /** @@ -93,9 +93,7 @@ public function afterGetStockStatus( : $this->storeManager->getWebsite($scopeId)->getCode(); $stockId = $this->stockResolver->execute(SalesChannelInterface::TYPE_WEBSITE, $websiteCode)->getStockId(); $sku = $this->getSkusByProductIds->execute([$productId])[$productId]; - - $result = $this->areProductsSalable->execute([$sku], $stockId); - $result = current($result); + $product = $this->productRepository->get($sku); try { $qty = $this->getProductSalableQty->execute($sku, $stockId); @@ -103,8 +101,9 @@ public function afterGetStockStatus( $qty = 0; } - $stockStatus->setStockStatus((int)$result->isSalable()); + $stockStatus->setStockStatus((int)$product->isAvailable()); $stockStatus->setQty($qty); + return $stockStatus; } } diff --git a/InventoryCatalog/Plugin/InventoryIndexer/Indexer/Stock/Strategy/Sync/PriceIndexUpdatePlugin.php b/InventoryCatalog/Plugin/InventoryIndexer/Indexer/Stock/Strategy/Sync/PriceIndexUpdatePlugin.php index 77e2f3e12a23..62d942bc511a 100644 --- a/InventoryCatalog/Plugin/InventoryIndexer/Indexer/Stock/Strategy/Sync/PriceIndexUpdatePlugin.php +++ b/InventoryCatalog/Plugin/InventoryIndexer/Indexer/Stock/Strategy/Sync/PriceIndexUpdatePlugin.php @@ -47,7 +47,7 @@ public function __construct( * @return void * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ - public function afterExecuteList(Sync $subject, $result, array $stockIds) + public function afterExecuteList(Sync $subject, $result, array $stockIds): void { $productIds = $this->getProductIdsByStockIds->execute($stockIds); if (!empty($productIds)) { diff --git a/InventoryGroupedProduct/Test/Integration/SalesQuoteItem/AddSalesQuoteItemOnDefaultStockTest.php b/InventoryGroupedProduct/Test/Integration/SalesQuoteItem/AddSalesQuoteItemOnDefaultStockTest.php index cd2b4ddbf1c4..5bea0831fce1 100644 --- a/InventoryGroupedProduct/Test/Integration/SalesQuoteItem/AddSalesQuoteItemOnDefaultStockTest.php +++ b/InventoryGroupedProduct/Test/Integration/SalesQuoteItem/AddSalesQuoteItemOnDefaultStockTest.php @@ -19,6 +19,9 @@ use PHPUnit\Framework\TestCase; use Magento\Framework\DataObject\Factory as DataObjectFactory; +/** + * @magentoDbIsolation disabled + */ class AddSalesQuoteItemOnDefaultStockTest extends TestCase { /** From 5e9bccaf6f8340f662bfbef2b197c85487815e5d Mon Sep 17 00:00:00 2001 From: nmalevanec Date: Wed, 17 Jun 2020 18:36:43 +0300 Subject: [PATCH 47/50] Fix tests. --- .../Plugin/Model/AreProductsSalablePlugin.php | 23 +++--- .../AdaptAddQuantityFilterPlugin.php | 82 +++++++++++++------ InventoryCatalog/Model/IsProductSalable.php | 20 +++-- .../IsProductSalableDataStorage.php | 65 +++++++++++++++ .../AddStockDataToCollection.php | 50 ++++------- .../AdaptGetProductStockStatusBySkuPlugin.php | 20 ++++- .../AdaptGetProductStockStatusPlugin.php | 20 ++++- .../AdaptGetStockStatusBySkuPlugin.php | 14 ++-- .../AdaptGetStockStatusPlugin.php | 14 ++-- .../AdaptAssignStatusToProductPlugin.php | 0 .../CleanIsSalableDataStoragePlugin.php | 41 ++++++++++ InventoryCatalog/etc/di.xml | 3 + .../Order/PlaceOrderOnDefaultStockTest.php | 3 + .../GetNonCachedProductsPlugin.php | 40 +++++++++ .../TestModuleInventoryStateCache/etc/di.xml | 3 + .../etc/frontend/di.xml | 4 + 16 files changed, 305 insertions(+), 97 deletions(-) create mode 100644 InventoryCatalog/Model/IsProductSalable/IsProductSalableDataStorage.php delete mode 100644 InventoryCatalog/Plugin/CatalogInventory/Helper/Stock/AdaptAssignStatusToProductPlugin.php create mode 100644 InventoryCatalog/Plugin/CatalogInventory/Model/StockRegistryStorage/CleanIsSalableDataStoragePlugin.php create mode 100644 dev/tests/integration/_files/Magento/TestModuleInventoryStateCache/Plugin/Catalog/Model/ProductRepository/GetNonCachedProductsPlugin.php diff --git a/InventoryAdvancedCheckout/Plugin/Model/AreProductsSalablePlugin.php b/InventoryAdvancedCheckout/Plugin/Model/AreProductsSalablePlugin.php index b0332ac78b22..55e5996244b2 100644 --- a/InventoryAdvancedCheckout/Plugin/Model/AreProductsSalablePlugin.php +++ b/InventoryAdvancedCheckout/Plugin/Model/AreProductsSalablePlugin.php @@ -8,11 +8,10 @@ namespace Magento\InventoryAdvancedCheckout\Plugin\Model; use Magento\AdvancedCheckout\Model\AreProductsSalableForRequestedQtyInterface; -use Magento\AdvancedCheckout\Model\Data\IsProductsSalableForRequestedQtyResult; +use Magento\AdvancedCheckout\Model\Data\IsProductsSalableForRequestedQtyResultFactory; use Magento\AdvancedCheckout\Model\Data\ProductQuantity; use Magento\Catalog\Api\ProductRepositoryInterface; use Magento\Framework\Exception\NoSuchEntityException; -use Magento\Framework\ObjectManagerInterface; /** * Provides multi-sourcing capabilities for Advanced Checkout Order By SKU feature. @@ -20,25 +19,25 @@ class AreProductsSalablePlugin { /** - * @var ObjectManagerInterface + * @var ProductRepositoryInterface */ - private $objectManager; + private $productRepository; /** - * @var ProductRepositoryInterface + * @var IsProductsSalableForRequestedQtyResultFactory */ - private $productRepository; + private $isProductsSalableForRequestedQtyResultFactory; /** * @param ProductRepositoryInterface $productRepository - * @param ObjectManagerInterface $objectManager + * @param IsProductsSalableForRequestedQtyResultFactory $isProductsSalableForRequestedQtyResultFactory */ public function __construct( ProductRepositoryInterface $productRepository, - ObjectManagerInterface $objectManager + IsProductsSalableForRequestedQtyResultFactory $isProductsSalableForRequestedQtyResultFactory ) { - $this->objectManager = $objectManager; $this->productRepository = $productRepository; + $this->isProductsSalableForRequestedQtyResultFactory = $isProductsSalableForRequestedQtyResultFactory; } /** @@ -61,13 +60,11 @@ public function aroundExecute( foreach ($productQuantities as $productQuantity) { try { $product = $this->productRepository->get($productQuantity->getSku()); - $result[] = $this->objectManager->create( - IsProductsSalableForRequestedQtyResult::class, + $result[] = $this->isProductsSalableForRequestedQtyResultFactory->create( ['sku' => $product->getSku(), 'isSalable' => $product->isSalable()] ); } catch (NoSuchEntityException $e) { - $result[] = $this->objectManager->create( - IsProductsSalableForRequestedQtyResult::class, + $result[] = $this->isProductsSalableForRequestedQtyResultFactory->create( ['sku' => $productQuantity->getSku(), 'isSalable' => false] ); } diff --git a/InventoryBundleProduct/Plugin/Bundle/Model/ResourceModel/Selection/Collection/AdaptAddQuantityFilterPlugin.php b/InventoryBundleProduct/Plugin/Bundle/Model/ResourceModel/Selection/Collection/AdaptAddQuantityFilterPlugin.php index 1eba8535e94c..59877f0de093 100644 --- a/InventoryBundleProduct/Plugin/Bundle/Model/ResourceModel/Selection/Collection/AdaptAddQuantityFilterPlugin.php +++ b/InventoryBundleProduct/Plugin/Bundle/Model/ResourceModel/Selection/Collection/AdaptAddQuantityFilterPlugin.php @@ -8,7 +8,10 @@ namespace Magento\InventoryBundleProduct\Plugin\Bundle\Model\ResourceModel\Selection\Collection; use Magento\Bundle\Model\ResourceModel\Selection\Collection; -use Magento\InventorySalesApi\Api\AreProductsSalableInterface; +use Magento\CatalogInventory\Model\ResourceModel\Stock\Item; +use Magento\CatalogInventory\Model\Stock; +use Magento\InventoryIndexer\Indexer\IndexStructure; +use Magento\InventoryIndexer\Model\StockIndexTableNameResolverInterface; use Magento\InventorySalesApi\Model\StockByWebsiteIdResolverInterface; use Magento\Store\Model\StoreManagerInterface; @@ -18,9 +21,9 @@ class AdaptAddQuantityFilterPlugin { /** - * @var AreProductsSalableInterface + * @var Item */ - private $areProductsSalable; + private $stockItem; /** * @var StoreManagerInterface @@ -33,18 +36,26 @@ class AdaptAddQuantityFilterPlugin private $stockByWebsiteIdResolver; /** - * @param AreProductsSalableInterface $areProductsSalable + * @var StockIndexTableNameResolverInterface + */ + private $stockIndexTableNameResolver; + + /** + * @param Item $stockItem * @param StoreManagerInterface $storeManager * @param StockByWebsiteIdResolverInterface $stockByWebsiteIdResolver + * @param StockIndexTableNameResolverInterface $stockIndexTableNameResolver */ public function __construct( - AreProductsSalableInterface $areProductsSalable, + Item $stockItem, StoreManagerInterface $storeManager, - StockByWebsiteIdResolverInterface $stockByWebsiteIdResolver + StockByWebsiteIdResolverInterface $stockByWebsiteIdResolver, + StockIndexTableNameResolverInterface $stockIndexTableNameResolver ) { - $this->areProductsSalable = $areProductsSalable; + $this->stockItem = $stockItem; $this->storeManager = $storeManager; $this->stockByWebsiteIdResolver = $stockByWebsiteIdResolver; + $this->stockIndexTableNameResolver = $stockIndexTableNameResolver; } /** @@ -53,28 +64,51 @@ public function __construct( * @param Collection $subject * @param \Closure $proceed * @return Collection + * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function aroundAddQuantityFilter( Collection $subject, \Closure $proceed ): Collection { - $website = $this->storeManager->getWebsite(); - $stock = $this->stockByWebsiteIdResolver->execute((int)$website->getId()); - $skus = []; - $skusToExclude = []; - foreach ($subject->getData() as $item) { - $skus[] = (string)$item['sku']; - } - $results = $this->areProductsSalable->execute($skus, $stock->getStockId()); - foreach ($results as $result) { - if (!$result->isSalable()) { - $skusToExclude[] = $result->getSku(); - } - } - if ($skusToExclude) { - $subject->getSelect()->where('e.sku NOT IN(?)', implode(',', $skusToExclude)); - } - $subject->resetData(); + $store = $this->storeManager->getStore($subject->getStoreId()); + $stock = $this->stockByWebsiteIdResolver->execute((int)$store->getWebsiteId()); + $stockIndexTableName = $this->stockIndexTableNameResolver->execute($stock->getStockId()); + $resource = $subject->getResource(); + $subject->getSelect()->join( + ['product_entity' => $resource->getTable('catalog_product_entity')], + sprintf('product_entity.entity_id = %s.entity_id', Collection::MAIN_TABLE_ALIAS), + [] + ); + $isSalableColumnName = IndexStructure::IS_SALABLE; + $subject->getSelect() + ->join( + ['inventory_stock' => $stockIndexTableName], + 'product_entity.sku = inventory_stock.' . IndexStructure::SKU, + [$isSalableColumnName] + ); + $manageStockExpr = $this->stockItem->getManageStockExpr('stock_item'); + $backordersExpr = $this->stockItem->getBackordersExpr('stock_item'); + $minQtyExpr = $subject->getConnection()->getCheckSql( + 'selection.selection_can_change_qty', + $this->stockItem->getMinSaleQtyExpr('stock_item'), + 'selection.selection_qty' + ); + $where = $manageStockExpr . ' = 0'; + $where .= ' OR (' + . 'inventory_stock.is_salable = ' . Stock::STOCK_IN_STOCK + . ' AND (' + . $backordersExpr . ' != ' . Stock::BACKORDERS_NO + . ' OR ' + . $minQtyExpr . ' <= inventory_stock.quantity' + . ')' + . ')'; + $subject->getSelect() + ->joinInner( + ['stock_item' => $this->stockItem->getMainTable()], + 'selection.product_id = stock_item.product_id', + [] + ) + ->where($where); return $subject; } diff --git a/InventoryCatalog/Model/IsProductSalable.php b/InventoryCatalog/Model/IsProductSalable.php index 2ab90931bad4..7499d66e4cb2 100644 --- a/InventoryCatalog/Model/IsProductSalable.php +++ b/InventoryCatalog/Model/IsProductSalable.php @@ -10,6 +10,7 @@ use Magento\Catalog\Api\Data\ProductInterface; use Magento\Catalog\Model\Product\Attribute\Source\Status; +use Magento\InventoryCatalog\Model\IsProductSalable\IsProductSalableDataStorage; use Magento\InventorySalesApi\Api\AreProductsSalableInterface; use Magento\InventorySalesApi\Model\StockByWebsiteIdResolverInterface; @@ -24,25 +25,28 @@ class IsProductSalable private $areProductsSalable; /** - * @var array + * @var StockByWebsiteIdResolverInterface */ - private $productStatusCache; + private $stockByWebsiteIdResolver; /** - * @var StockByWebsiteIdResolverInterface + * @var IsProductSalableDataStorage */ - private $stockByWebsiteIdResolver; + private $isProductSalableDataStorage; /** * @param StockByWebsiteIdResolverInterface $stockByWebsiteIdResolver * @param AreProductsSalableInterface $areProductsSalable + * @param IsProductSalableDataStorage $isProductSalableDataStorage */ public function __construct( StockByWebsiteIdResolverInterface $stockByWebsiteIdResolver, - AreProductsSalableInterface $areProductsSalable + AreProductsSalableInterface $areProductsSalable, + IsProductSalableDataStorage $isProductSalableDataStorage ) { $this->stockByWebsiteIdResolver = $stockByWebsiteIdResolver; $this->areProductsSalable = $areProductsSalable; + $this->isProductSalableDataStorage = $isProductSalableDataStorage; } /** @@ -63,13 +67,13 @@ public function execute(ProductInterface $product): bool $websiteId = (int)$product->getStore()->getWebsite()->getId(); $stockId = $this->stockByWebsiteIdResolver->execute($websiteId)->getStockId(); //use getData('sku') to get non processed product sku for complex products. - if (isset($this->productStatusCache[$stockId][$product->getData('sku')])) { - return $this->productStatusCache[$stockId][$product->getData('sku')]; + if (null !== $this->isProductSalableDataStorage->getIsSalable($product->getData('sku'), $stockId)) { + return $this->isProductSalableDataStorage->getIsSalable($product->getData('sku'), $stockId); } $result = current($this->areProductsSalable->execute([$product->getData('sku')], $stockId)); $salabilityStatus = $result->isSalable(); - $this->productStatusCache[$stockId][$product->getData('sku')] = $salabilityStatus; + $this->isProductSalableDataStorage->setIsSalable($product->getData('sku'), $stockId, $salabilityStatus); return $salabilityStatus; } diff --git a/InventoryCatalog/Model/IsProductSalable/IsProductSalableDataStorage.php b/InventoryCatalog/Model/IsProductSalable/IsProductSalableDataStorage.php new file mode 100644 index 000000000000..76bac6f45e11 --- /dev/null +++ b/InventoryCatalog/Model/IsProductSalable/IsProductSalableDataStorage.php @@ -0,0 +1,65 @@ +statuses[$sku][$stockId] = $status; + } + + /** + * Get is salable status for given product and stock. + * + * @param string $sku + * @param int $stockId + * @return bool|null + */ + public function getIsSalable(string $sku, int $stockId): ?bool + { + return $this->statuses[$sku][$stockId] ?? null; + } + + /** + * Clean is salable status for given product and stock. + * @param string $sku + * @param int $stockId + * @return void + */ + public function removeIsSalable(string $sku, int $stockId): void + { + unset($this->statuses[$sku][$stockId]); + } + + /** + * Clean is salable statuses for all saved products and stocks. + * + * @return void + */ + public function cleanIsSalable(): void + { + $this->statuses = []; + } +} diff --git a/InventoryCatalog/Model/ResourceModel/AddStockDataToCollection.php b/InventoryCatalog/Model/ResourceModel/AddStockDataToCollection.php index 4edaa61f88a4..178dc92c45b2 100644 --- a/InventoryCatalog/Model/ResourceModel/AddStockDataToCollection.php +++ b/InventoryCatalog/Model/ResourceModel/AddStockDataToCollection.php @@ -8,8 +8,6 @@ namespace Magento\InventoryCatalog\Model\ResourceModel; use Magento\Catalog\Model\ResourceModel\Product\Collection; -use Magento\Framework\App\ObjectManager; -use Magento\InventoryCatalogApi\Api\DefaultStockProviderInterface; use Magento\InventoryIndexer\Indexer\IndexStructure; use Magento\InventoryIndexer\Model\StockIndexTableNameResolverInterface; @@ -23,22 +21,13 @@ class AddStockDataToCollection */ private $stockIndexTableNameResolver; - /** - * @var DefaultStockProviderInterface - */ - private $defaultStockProvider; - /** * @param StockIndexTableNameResolverInterface $stockIndexTableNameResolver - * @param DefaultStockProviderInterface $defaultStockProvider */ public function __construct( - StockIndexTableNameResolverInterface $stockIndexTableNameResolver, - DefaultStockProviderInterface $defaultStockProvider = null + StockIndexTableNameResolverInterface $stockIndexTableNameResolver ) { $this->stockIndexTableNameResolver = $stockIndexTableNameResolver; - $this->defaultStockProvider = $defaultStockProvider ?: ObjectManager::getInstance() - ->get(DefaultStockProviderInterface::class); } /** @@ -49,31 +38,20 @@ public function __construct( */ public function execute(Collection $collection, bool $isFilterInStock, int $stockId) { - if ($stockId === $this->defaultStockProvider->getId()) { - $isSalableColumnName = 'stock_status'; - $resource = $collection->getResource(); - $collection->getSelect() - ->join( - ['stock_status_index' => $resource->getTable('cataloginventory_stock_status')], - sprintf('%s.entity_id = stock_status_index.product_id', Collection::MAIN_TABLE_ALIAS), - [IndexStructure::IS_SALABLE => $isSalableColumnName] - ); - } else { - $stockIndexTableName = $this->stockIndexTableNameResolver->execute($stockId); - $resource = $collection->getResource(); - $collection->getSelect()->join( - ['product' => $resource->getTable('catalog_product_entity')], - sprintf('product.entity_id = %s.entity_id', Collection::MAIN_TABLE_ALIAS), - [] + $stockIndexTableName = $this->stockIndexTableNameResolver->execute($stockId); + $resource = $collection->getResource(); + $collection->getSelect()->join( + ['product' => $resource->getTable('catalog_product_entity')], + sprintf('product.entity_id = %s.entity_id', Collection::MAIN_TABLE_ALIAS), + [] + ); + $isSalableColumnName = IndexStructure::IS_SALABLE; + $collection->getSelect() + ->join( + ['stock_status_index' => $stockIndexTableName], + 'product.sku = stock_status_index.' . IndexStructure::SKU, + [$isSalableColumnName] ); - $isSalableColumnName = IndexStructure::IS_SALABLE; - $collection->getSelect() - ->join( - ['stock_status_index' => $stockIndexTableName], - 'product.sku = stock_status_index.' . IndexStructure::SKU, - [$isSalableColumnName] - ); - } if ($isFilterInStock) { $collection->getSelect() diff --git a/InventoryCatalog/Plugin/CatalogInventory/Api/StockRegistry/AdaptGetProductStockStatusBySkuPlugin.php b/InventoryCatalog/Plugin/CatalogInventory/Api/StockRegistry/AdaptGetProductStockStatusBySkuPlugin.php index 10032d2ff0ff..55a2d56988c1 100644 --- a/InventoryCatalog/Plugin/CatalogInventory/Api/StockRegistry/AdaptGetProductStockStatusBySkuPlugin.php +++ b/InventoryCatalog/Plugin/CatalogInventory/Api/StockRegistry/AdaptGetProductStockStatusBySkuPlugin.php @@ -9,7 +9,9 @@ use Magento\Catalog\Api\ProductRepositoryInterface; use Magento\CatalogInventory\Api\StockRegistryInterface; +use Magento\Framework\Exception\LocalizedException; use Magento\Framework\Exception\NoSuchEntityException; +use Magento\Store\Model\StoreManagerInterface; /** * Adapt getProductStockStatusBySku for multi stocks. @@ -21,13 +23,21 @@ class AdaptGetProductStockStatusBySkuPlugin */ private $productRepository; + /** + * @var StoreManagerInterface + */ + private $storeManager; + /** * @param ProductRepositoryInterface $productRepository + * @param StoreManagerInterface $storeManager */ public function __construct( - ProductRepositoryInterface $productRepository + ProductRepositoryInterface $productRepository, + StoreManagerInterface $storeManager ) { $this->productRepository = $productRepository; + $this->storeManager = $storeManager; } /** @@ -38,7 +48,7 @@ public function __construct( * @param string $productSku * @param int $scopeId * @return int - * @throws NoSuchEntityException + * @throws NoSuchEntityException|LocalizedException * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function aroundGetProductStockStatusBySku( @@ -47,7 +57,11 @@ public function aroundGetProductStockStatusBySku( $productSku, $scopeId = null ): int { - $product = $this->productRepository->get($productSku); + $storeId = null === $scopeId + ? $this->storeManager->getWebsite()->getDefaultStore()->getId() + : $this->storeManager->getWebsite($scopeId)->getDefaultStore()->getId(); + + $product = $this->productRepository->get($productSku, false, (int)$storeId); return (int)$product->isAvailable(); } diff --git a/InventoryCatalog/Plugin/CatalogInventory/Api/StockRegistry/AdaptGetProductStockStatusPlugin.php b/InventoryCatalog/Plugin/CatalogInventory/Api/StockRegistry/AdaptGetProductStockStatusPlugin.php index dec3b44a654e..5c6cc57d66f5 100644 --- a/InventoryCatalog/Plugin/CatalogInventory/Api/StockRegistry/AdaptGetProductStockStatusPlugin.php +++ b/InventoryCatalog/Plugin/CatalogInventory/Api/StockRegistry/AdaptGetProductStockStatusPlugin.php @@ -9,7 +9,9 @@ use Magento\Catalog\Api\ProductRepositoryInterface; use Magento\CatalogInventory\Api\StockRegistryInterface; +use Magento\Framework\Exception\LocalizedException; use Magento\Framework\Exception\NoSuchEntityException; +use Magento\Store\Model\StoreManagerInterface; /** * Adapt getProductStockStatus for multi stocks. @@ -21,13 +23,21 @@ class AdaptGetProductStockStatusPlugin */ private $productRepository; + /** + * @var StoreManagerInterface + */ + private $storeManager; + /** * @param ProductRepositoryInterface $productRepository + * @param StoreManagerInterface $storeManager */ public function __construct( - ProductRepositoryInterface $productRepository + ProductRepositoryInterface $productRepository, + StoreManagerInterface $storeManager ) { $this->productRepository = $productRepository; + $this->storeManager = $storeManager; } /** @@ -38,8 +48,8 @@ public function __construct( * @param int $productId * @param int $scopeId * @return int - * @throws NoSuchEntityException * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * @throws NoSuchEntityException|LocalizedException */ public function aroundGetProductStockStatus( StockRegistryInterface $subject, @@ -47,7 +57,11 @@ public function aroundGetProductStockStatus( $productId, $scopeId = null ): int { - $product = $this->productRepository->getById($productId); + $storeId = null === $scopeId + ? $this->storeManager->getWebsite()->getDefaultStore()->getId() + : $this->storeManager->getWebsite($scopeId)->getDefaultStore()->getId(); + + $product = $this->productRepository->getById($productId, false, (int)$storeId); return (int)$product->isAvailable(); } diff --git a/InventoryCatalog/Plugin/CatalogInventory/Api/StockRegistry/AdaptGetStockStatusBySkuPlugin.php b/InventoryCatalog/Plugin/CatalogInventory/Api/StockRegistry/AdaptGetStockStatusBySkuPlugin.php index d581b460586c..ab5dac9708e1 100644 --- a/InventoryCatalog/Plugin/CatalogInventory/Api/StockRegistry/AdaptGetStockStatusBySkuPlugin.php +++ b/InventoryCatalog/Plugin/CatalogInventory/Api/StockRegistry/AdaptGetStockStatusBySkuPlugin.php @@ -79,16 +79,20 @@ public function afterGetStockStatusBySku( $productSku, $scopeId = null ): StockStatusInterface { - $product = $this->productRepository->get($productSku); - $websiteCode = null === $scopeId - ? $this->storeManager->getWebsite()->getCode() - : $this->storeManager->getWebsite($scopeId)->getCode(); - $stockId = $this->stockResolver->execute(SalesChannelInterface::TYPE_WEBSITE, $websiteCode)->getStockId(); + $website = null === $scopeId + ? $this->storeManager->getWebsite() + : $this->storeManager->getWebsite($scopeId); + $stockId = $this->stockResolver->execute( + SalesChannelInterface::TYPE_WEBSITE, + $website->getCode() + )->getStockId(); try { $qty = $this->getProductSalableQty->execute($productSku, $stockId); } catch (InputException $e) { $qty = 0; } + $storeId = $website->getDefaultStore()->getId(); + $product = $this->productRepository->get($productSku, false, (int)$storeId); $stockStatus->setStockStatus((int)$product->isAvailable()); $stockStatus->setQty($qty); diff --git a/InventoryCatalog/Plugin/CatalogInventory/Api/StockRegistry/AdaptGetStockStatusPlugin.php b/InventoryCatalog/Plugin/CatalogInventory/Api/StockRegistry/AdaptGetStockStatusPlugin.php index c009ac3b9493..09326933d2a2 100644 --- a/InventoryCatalog/Plugin/CatalogInventory/Api/StockRegistry/AdaptGetStockStatusPlugin.php +++ b/InventoryCatalog/Plugin/CatalogInventory/Api/StockRegistry/AdaptGetStockStatusPlugin.php @@ -88,12 +88,16 @@ public function afterGetStockStatus( $productId, $scopeId = null ): StockStatusInterface { - $websiteCode = null === $scopeId - ? $this->storeManager->getWebsite()->getCode() - : $this->storeManager->getWebsite($scopeId)->getCode(); - $stockId = $this->stockResolver->execute(SalesChannelInterface::TYPE_WEBSITE, $websiteCode)->getStockId(); + $website = null === $scopeId + ? $this->storeManager->getWebsite() + : $this->storeManager->getWebsite($scopeId); + $stockId = $this->stockResolver->execute( + SalesChannelInterface::TYPE_WEBSITE, + $website->getCode() + )->getStockId(); $sku = $this->getSkusByProductIds->execute([$productId])[$productId]; - $product = $this->productRepository->get($sku); + $storeId = $website->getDefaultStore()->getId(); + $product = $this->productRepository->get($sku, (int)$storeId); try { $qty = $this->getProductSalableQty->execute($sku, $stockId); diff --git a/InventoryCatalog/Plugin/CatalogInventory/Helper/Stock/AdaptAssignStatusToProductPlugin.php b/InventoryCatalog/Plugin/CatalogInventory/Helper/Stock/AdaptAssignStatusToProductPlugin.php deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/InventoryCatalog/Plugin/CatalogInventory/Model/StockRegistryStorage/CleanIsSalableDataStoragePlugin.php b/InventoryCatalog/Plugin/CatalogInventory/Model/StockRegistryStorage/CleanIsSalableDataStoragePlugin.php new file mode 100644 index 000000000000..cb678ac925ee --- /dev/null +++ b/InventoryCatalog/Plugin/CatalogInventory/Model/StockRegistryStorage/CleanIsSalableDataStoragePlugin.php @@ -0,0 +1,41 @@ +isProductSalableDataStorage = $isProductSalableDataStorage; + } + + /** + * Clean is product salable storage after stock registry storage has been cleaned. + * + * @param StockRegistryStorage $subject + * @param void $result + */ + public function afterClean(StockRegistryStorage $subject, $result): void + { + $this->isProductSalableDataStorage->cleanIsSalable(); + } +} diff --git a/InventoryCatalog/etc/di.xml b/InventoryCatalog/etc/di.xml index 44497f96176a..ed61ae53a9b1 100644 --- a/InventoryCatalog/etc/di.xml +++ b/InventoryCatalog/etc/di.xml @@ -167,4 +167,7 @@ + + + diff --git a/InventoryGroupedProduct/Test/Integration/Order/PlaceOrderOnDefaultStockTest.php b/InventoryGroupedProduct/Test/Integration/Order/PlaceOrderOnDefaultStockTest.php index 3413b9b3b47a..31465b58ae64 100644 --- a/InventoryGroupedProduct/Test/Integration/Order/PlaceOrderOnDefaultStockTest.php +++ b/InventoryGroupedProduct/Test/Integration/Order/PlaceOrderOnDefaultStockTest.php @@ -10,6 +10,9 @@ use Magento\Framework\Exception\LocalizedException; use Magento\InventorySales\Test\Integration\Order\PlaceOrderOnDefaultStockTest as PlaceOrderTest; +/** + * @magentoDbIsolation disabled + */ class PlaceOrderOnDefaultStockTest extends PlaceOrderTest { /** diff --git a/dev/tests/integration/_files/Magento/TestModuleInventoryStateCache/Plugin/Catalog/Model/ProductRepository/GetNonCachedProductsPlugin.php b/dev/tests/integration/_files/Magento/TestModuleInventoryStateCache/Plugin/Catalog/Model/ProductRepository/GetNonCachedProductsPlugin.php new file mode 100644 index 000000000000..3b712ddd9cfc --- /dev/null +++ b/dev/tests/integration/_files/Magento/TestModuleInventoryStateCache/Plugin/Catalog/Model/ProductRepository/GetNonCachedProductsPlugin.php @@ -0,0 +1,40 @@ + + + + diff --git a/dev/tests/integration/_files/Magento/TestModuleInventoryStateCache/etc/frontend/di.xml b/dev/tests/integration/_files/Magento/TestModuleInventoryStateCache/etc/frontend/di.xml index 30c34c0c4002..b2db5d70ab16 100644 --- a/dev/tests/integration/_files/Magento/TestModuleInventoryStateCache/etc/frontend/di.xml +++ b/dev/tests/integration/_files/Magento/TestModuleInventoryStateCache/etc/frontend/di.xml @@ -10,4 +10,8 @@ + + + From b2fae8985dc5999e73b35a17886cef98ed4c0287 Mon Sep 17 00:00:00 2001 From: nmalevanec Date: Thu, 18 Jun 2020 16:23:47 +0300 Subject: [PATCH 48/50] Fix adapt get product stock status plugins. --- .../AdaptAddQuantityFilterPlugin.php | 19 +++++-------------- .../AdaptGetProductStockStatusBySkuPlugin.php | 9 ++++----- .../AdaptGetProductStockStatusPlugin.php | 9 ++++----- .../AdaptGetStockStatusBySkuPlugin.php | 15 ++++++--------- .../AdaptGetStockStatusPlugin.php | 15 ++++++--------- 5 files changed, 25 insertions(+), 42 deletions(-) diff --git a/InventoryBundleProduct/Plugin/Bundle/Model/ResourceModel/Selection/Collection/AdaptAddQuantityFilterPlugin.php b/InventoryBundleProduct/Plugin/Bundle/Model/ResourceModel/Selection/Collection/AdaptAddQuantityFilterPlugin.php index 59877f0de093..bab6006cc510 100644 --- a/InventoryBundleProduct/Plugin/Bundle/Model/ResourceModel/Selection/Collection/AdaptAddQuantityFilterPlugin.php +++ b/InventoryBundleProduct/Plugin/Bundle/Model/ResourceModel/Selection/Collection/AdaptAddQuantityFilterPlugin.php @@ -10,7 +10,6 @@ use Magento\Bundle\Model\ResourceModel\Selection\Collection; use Magento\CatalogInventory\Model\ResourceModel\Stock\Item; use Magento\CatalogInventory\Model\Stock; -use Magento\InventoryIndexer\Indexer\IndexStructure; use Magento\InventoryIndexer\Model\StockIndexTableNameResolverInterface; use Magento\InventorySalesApi\Model\StockByWebsiteIdResolverInterface; use Magento\Store\Model\StoreManagerInterface; @@ -73,19 +72,6 @@ public function aroundAddQuantityFilter( $store = $this->storeManager->getStore($subject->getStoreId()); $stock = $this->stockByWebsiteIdResolver->execute((int)$store->getWebsiteId()); $stockIndexTableName = $this->stockIndexTableNameResolver->execute($stock->getStockId()); - $resource = $subject->getResource(); - $subject->getSelect()->join( - ['product_entity' => $resource->getTable('catalog_product_entity')], - sprintf('product_entity.entity_id = %s.entity_id', Collection::MAIN_TABLE_ALIAS), - [] - ); - $isSalableColumnName = IndexStructure::IS_SALABLE; - $subject->getSelect() - ->join( - ['inventory_stock' => $stockIndexTableName], - 'product_entity.sku = inventory_stock.' . IndexStructure::SKU, - [$isSalableColumnName] - ); $manageStockExpr = $this->stockItem->getManageStockExpr('stock_item'); $backordersExpr = $this->stockItem->getBackordersExpr('stock_item'); $minQtyExpr = $subject->getConnection()->getCheckSql( @@ -103,6 +89,11 @@ public function aroundAddQuantityFilter( . ')' . ')'; $subject->getSelect() + ->joinInner( + ['inventory_stock' => $stockIndexTableName], + 'e.sku = inventory_stock.sku', + [] + ) ->joinInner( ['stock_item' => $this->stockItem->getMainTable()], 'selection.product_id = stock_item.product_id', diff --git a/InventoryCatalog/Plugin/CatalogInventory/Api/StockRegistry/AdaptGetProductStockStatusBySkuPlugin.php b/InventoryCatalog/Plugin/CatalogInventory/Api/StockRegistry/AdaptGetProductStockStatusBySkuPlugin.php index 55a2d56988c1..772862bc7020 100644 --- a/InventoryCatalog/Plugin/CatalogInventory/Api/StockRegistry/AdaptGetProductStockStatusBySkuPlugin.php +++ b/InventoryCatalog/Plugin/CatalogInventory/Api/StockRegistry/AdaptGetProductStockStatusBySkuPlugin.php @@ -57,11 +57,10 @@ public function aroundGetProductStockStatusBySku( $productSku, $scopeId = null ): int { - $storeId = null === $scopeId - ? $this->storeManager->getWebsite()->getDefaultStore()->getId() - : $this->storeManager->getWebsite($scopeId)->getDefaultStore()->getId(); - - $product = $this->productRepository->get($productSku, false, (int)$storeId); + $store = $this->storeManager->getWebsite($scopeId)->getDefaultStore(); + $product = $store + ? $this->productRepository->get($productSku, false, (int)$store->getId()) + : $this->productRepository->get($productSku); return (int)$product->isAvailable(); } diff --git a/InventoryCatalog/Plugin/CatalogInventory/Api/StockRegistry/AdaptGetProductStockStatusPlugin.php b/InventoryCatalog/Plugin/CatalogInventory/Api/StockRegistry/AdaptGetProductStockStatusPlugin.php index 5c6cc57d66f5..2cb7b077cf8f 100644 --- a/InventoryCatalog/Plugin/CatalogInventory/Api/StockRegistry/AdaptGetProductStockStatusPlugin.php +++ b/InventoryCatalog/Plugin/CatalogInventory/Api/StockRegistry/AdaptGetProductStockStatusPlugin.php @@ -57,11 +57,10 @@ public function aroundGetProductStockStatus( $productId, $scopeId = null ): int { - $storeId = null === $scopeId - ? $this->storeManager->getWebsite()->getDefaultStore()->getId() - : $this->storeManager->getWebsite($scopeId)->getDefaultStore()->getId(); - - $product = $this->productRepository->getById($productId, false, (int)$storeId); + $store = $this->storeManager->getWebsite($scopeId)->getDefaultStore(); + $product = $store + ? $this->productRepository->getById($productId, false, (int)$store->getId()) + : $this->productRepository->getById($productId); return (int)$product->isAvailable(); } diff --git a/InventoryCatalog/Plugin/CatalogInventory/Api/StockRegistry/AdaptGetStockStatusBySkuPlugin.php b/InventoryCatalog/Plugin/CatalogInventory/Api/StockRegistry/AdaptGetStockStatusBySkuPlugin.php index ab5dac9708e1..ee77e8049356 100644 --- a/InventoryCatalog/Plugin/CatalogInventory/Api/StockRegistry/AdaptGetStockStatusBySkuPlugin.php +++ b/InventoryCatalog/Plugin/CatalogInventory/Api/StockRegistry/AdaptGetStockStatusBySkuPlugin.php @@ -79,20 +79,17 @@ public function afterGetStockStatusBySku( $productSku, $scopeId = null ): StockStatusInterface { - $website = null === $scopeId - ? $this->storeManager->getWebsite() - : $this->storeManager->getWebsite($scopeId); - $stockId = $this->stockResolver->execute( - SalesChannelInterface::TYPE_WEBSITE, - $website->getCode() - )->getStockId(); + $website = $this->storeManager->getWebsite($scopeId); + $stockId = $this->stockResolver->execute(SalesChannelInterface::TYPE_WEBSITE, $website->getCode()) + ->getStockId(); try { $qty = $this->getProductSalableQty->execute($productSku, $stockId); } catch (InputException $e) { $qty = 0; } - $storeId = $website->getDefaultStore()->getId(); - $product = $this->productRepository->get($productSku, false, (int)$storeId); + $product = $website->getDefaultStore() + ? $this->productRepository->get($productSku, false, (int)$website->getDefaultStore()->getId()) + : $this->productRepository->get($productSku); $stockStatus->setStockStatus((int)$product->isAvailable()); $stockStatus->setQty($qty); diff --git a/InventoryCatalog/Plugin/CatalogInventory/Api/StockRegistry/AdaptGetStockStatusPlugin.php b/InventoryCatalog/Plugin/CatalogInventory/Api/StockRegistry/AdaptGetStockStatusPlugin.php index 09326933d2a2..d01dcfdee51a 100644 --- a/InventoryCatalog/Plugin/CatalogInventory/Api/StockRegistry/AdaptGetStockStatusPlugin.php +++ b/InventoryCatalog/Plugin/CatalogInventory/Api/StockRegistry/AdaptGetStockStatusPlugin.php @@ -88,16 +88,13 @@ public function afterGetStockStatus( $productId, $scopeId = null ): StockStatusInterface { - $website = null === $scopeId - ? $this->storeManager->getWebsite() - : $this->storeManager->getWebsite($scopeId); - $stockId = $this->stockResolver->execute( - SalesChannelInterface::TYPE_WEBSITE, - $website->getCode() - )->getStockId(); + $website = $this->storeManager->getWebsite($scopeId); + $stockId = $this->stockResolver->execute(SalesChannelInterface::TYPE_WEBSITE, $website->getCode()) + ->getStockId(); $sku = $this->getSkusByProductIds->execute([$productId])[$productId]; - $storeId = $website->getDefaultStore()->getId(); - $product = $this->productRepository->get($sku, (int)$storeId); + $product = $website->getCurrentStore() === null + ? $this->productRepository->get($sku) + : $this->productRepository->get($sku, false, (int)$website->getDefaultStore()->getId()); try { $qty = $this->getProductSalableQty->execute($sku, $stockId); From a42afd39985cc3e0ea4eabae732302b609ba83f7 Mon Sep 17 00:00:00 2001 From: nmalevanec Date: Fri, 19 Jun 2020 19:32:16 +0300 Subject: [PATCH 49/50] Fix tests. --- .../ResourceModel/AddStatusFilterToSelect.php | 65 ++++++++ .../Model/Product/GetIsSalablePlugin.php | 47 ++++++ ...ptAddIsInStockFilterToCollectionPlugin.php | 3 + .../AdaptAddStockDataToCollectionPlugin.php | 5 + .../AdaptAddStockStatusToSelectPlugin.php | 15 +- .../Stock/AssignStatusToProductTest.php | 151 ------------------ ...tockDataToCollectionOnDefaultStockTest.php | 2 +- .../Status/AddStockStatusToSelectTest.php | 2 +- InventoryCatalog/etc/di.xml | 1 + .../DisableStoragePlugin.php | 35 ++++ .../TestModuleInventoryStateCache/etc/di.xml | 3 + 11 files changed, 175 insertions(+), 154 deletions(-) create mode 100644 InventoryCatalog/Model/ResourceModel/AddStatusFilterToSelect.php create mode 100644 InventoryCatalog/Plugin/Catalog/Model/Product/GetIsSalablePlugin.php delete mode 100644 InventoryCatalog/Test/Integration/CatalogInventory/Helper/Stock/AssignStatusToProductTest.php create mode 100644 dev/tests/integration/_files/Magento/TestModuleInventoryStateCache/Plugin/InventoryCatalog/Model/IsProductSalableDataStorage/DisableStoragePlugin.php diff --git a/InventoryCatalog/Model/ResourceModel/AddStatusFilterToSelect.php b/InventoryCatalog/Model/ResourceModel/AddStatusFilterToSelect.php new file mode 100644 index 000000000000..a4e8caaf4efa --- /dev/null +++ b/InventoryCatalog/Model/ResourceModel/AddStatusFilterToSelect.php @@ -0,0 +1,65 @@ +connection = $connection; + $this->joinAttributeProcessor = $joinAttributeProcessor; + } + + /** + * Add product status filter to select. + * + * @param Select $select + * @return Select + * @throws LocalizedException + * @throws \Zend_Db_Select_Exception + */ + public function execute(Select $select): Select + { + $select->joinInner( + ['pw' => $this->connection->getTableName('catalog_product_website')], + 'pw.product_id = e.entity_id', + ['pw.website_id'] + )->joinInner( + ['cwd' => $this->connection->getTableName('catalog_product_index_website')], + 'pw.website_id = cwd.website_id', + [] + ); + $this->joinAttributeProcessor->process($select, ProductInterface::STATUS, ProductStatus::STATUS_ENABLED); + + return $select; + } +} diff --git a/InventoryCatalog/Plugin/Catalog/Model/Product/GetIsSalablePlugin.php b/InventoryCatalog/Plugin/Catalog/Model/Product/GetIsSalablePlugin.php new file mode 100644 index 000000000000..3b8f26cc9a6d --- /dev/null +++ b/InventoryCatalog/Plugin/Catalog/Model/Product/GetIsSalablePlugin.php @@ -0,0 +1,47 @@ +isProductSalable = $isProductSalable; + } + + /** + * Fetches is salable status for multi-stock environment. + * + * @param Product $product + * @param \Closure $proceed + * @return bool + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function aroundGetIsSalable(Product $product, \Closure $proceed): bool + { + if ($product->hasData('is_saleable')) { + return (bool)$product->getData('is_saleable'); + } + return $this->isProductSalable->execute($product); + } +} diff --git a/InventoryCatalog/Plugin/CatalogInventory/Model/ResourceModel/Stock/Status/AdaptAddIsInStockFilterToCollectionPlugin.php b/InventoryCatalog/Plugin/CatalogInventory/Model/ResourceModel/Stock/Status/AdaptAddIsInStockFilterToCollectionPlugin.php index 397b068ddf36..ddb0efbfa014 100644 --- a/InventoryCatalog/Plugin/CatalogInventory/Model/ResourceModel/Stock/Status/AdaptAddIsInStockFilterToCollectionPlugin.php +++ b/InventoryCatalog/Plugin/CatalogInventory/Model/ResourceModel/Stock/Status/AdaptAddIsInStockFilterToCollectionPlugin.php @@ -7,6 +7,8 @@ namespace Magento\InventoryCatalog\Plugin\CatalogInventory\Model\ResourceModel\Stock\Status; +use Magento\Catalog\Api\Data\ProductInterface; +use Magento\Catalog\Model\Product\Attribute\Source\Status as ProductStatus; use Magento\Catalog\Model\ResourceModel\Product\Collection; use Magento\CatalogInventory\Model\ResourceModel\Stock\Status; use Magento\InventoryCatalog\Model\GetStockIdForCurrentWebsite; @@ -54,6 +56,7 @@ public function aroundAddIsInStockFilterToCollection( callable $proceed, $collection ) { + $collection->addAttributeToFilter(ProductInterface::STATUS, ProductStatus::STATUS_ENABLED); $stockId = $this->getStockIdForCurrentWebsite->execute(); $this->addIsInStockFilterToCollection->execute($collection, $stockId); diff --git a/InventoryCatalog/Plugin/CatalogInventory/Model/ResourceModel/Stock/Status/AdaptAddStockDataToCollectionPlugin.php b/InventoryCatalog/Plugin/CatalogInventory/Model/ResourceModel/Stock/Status/AdaptAddStockDataToCollectionPlugin.php index 342c4adb0d25..78f60179a0fd 100644 --- a/InventoryCatalog/Plugin/CatalogInventory/Model/ResourceModel/Stock/Status/AdaptAddStockDataToCollectionPlugin.php +++ b/InventoryCatalog/Plugin/CatalogInventory/Model/ResourceModel/Stock/Status/AdaptAddStockDataToCollectionPlugin.php @@ -7,6 +7,8 @@ namespace Magento\InventoryCatalog\Plugin\CatalogInventory\Model\ResourceModel\Stock\Status; +use Magento\Catalog\Api\Data\ProductInterface; +use Magento\Catalog\Model\Product\Attribute\Source\Status as ProductStatus; use Magento\Catalog\Model\ResourceModel\Product\Collection; use Magento\CatalogInventory\Model\ResourceModel\Stock\Status; use Magento\InventoryCatalog\Model\GetStockIdForCurrentWebsite; @@ -40,6 +42,8 @@ public function __construct( } /** + * Adapt add stock data for collection for multi stock environment. + * * @param Status $stockStatus * @param callable $proceed * @param Collection $collection @@ -54,6 +58,7 @@ public function aroundAddStockDataToCollection( $collection, $isFilterInStock ) { + $collection->addAttributeToFilter(ProductInterface::STATUS, ProductStatus::STATUS_ENABLED); $stockId = $this->getStockIdForCurrentWebsite->execute(); $this->addStockDataToCollection->execute($collection, (bool)$isFilterInStock, $stockId); diff --git a/InventoryCatalog/Plugin/CatalogInventory/Model/ResourceModel/Stock/Status/AdaptAddStockStatusToSelectPlugin.php b/InventoryCatalog/Plugin/CatalogInventory/Model/ResourceModel/Stock/Status/AdaptAddStockStatusToSelectPlugin.php index 438a6bcc6f73..038224f03923 100644 --- a/InventoryCatalog/Plugin/CatalogInventory/Model/ResourceModel/Stock/Status/AdaptAddStockStatusToSelectPlugin.php +++ b/InventoryCatalog/Plugin/CatalogInventory/Model/ResourceModel/Stock/Status/AdaptAddStockStatusToSelectPlugin.php @@ -10,6 +10,8 @@ use Magento\CatalogInventory\Model\ResourceModel\Stock\Status; use Magento\Framework\DB\Select; use Magento\Framework\Exception\LocalizedException; +use Magento\Framework\Exception\NoSuchEntityException; +use Magento\InventoryCatalog\Model\ResourceModel\AddStatusFilterToSelect; use Magento\InventoryCatalog\Model\ResourceModel\AddStockStatusToSelect; use Magento\InventorySalesApi\Api\Data\SalesChannelInterface; use Magento\InventorySalesApi\Api\StockResolverInterface; @@ -30,16 +32,24 @@ class AdaptAddStockStatusToSelectPlugin */ private $addStockStatusToSelect; + /** + * @var AddStatusFilterToSelect + */ + private $addStatusFilterToSelect; + /** * @param StockResolverInterface $stockResolver * @param AddStockStatusToSelect $addStockStatusToSelect + * @param AddStatusFilterToSelect $addStatusFilterToSelect */ public function __construct( StockResolverInterface $stockResolver, - AddStockStatusToSelect $addStockStatusToSelect + AddStockStatusToSelect $addStockStatusToSelect, + AddStatusFilterToSelect $addStatusFilterToSelect ) { $this->stockResolver = $stockResolver; $this->addStockStatusToSelect = $addStockStatusToSelect; + $this->addStatusFilterToSelect = $addStatusFilterToSelect; } /** @@ -51,6 +61,8 @@ public function __construct( * @param Website $website * @return Status * @throws LocalizedException + * @throws NoSuchEntityException + * @throws \Zend_Db_Select_Exception * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function aroundAddStockStatusToSelect( @@ -67,6 +79,7 @@ public function aroundAddStockStatusToSelect( $stock = $this->stockResolver->execute(SalesChannelInterface::TYPE_WEBSITE, $websiteCode); $stockId = (int)$stock->getStockId(); $this->addStockStatusToSelect->execute($select, $stockId); + $this->addStatusFilterToSelect->execute($select); return $stockStatus; } diff --git a/InventoryCatalog/Test/Integration/CatalogInventory/Helper/Stock/AssignStatusToProductTest.php b/InventoryCatalog/Test/Integration/CatalogInventory/Helper/Stock/AssignStatusToProductTest.php deleted file mode 100644 index 79b535cb86ce..000000000000 --- a/InventoryCatalog/Test/Integration/CatalogInventory/Helper/Stock/AssignStatusToProductTest.php +++ /dev/null @@ -1,151 +0,0 @@ -stockHelper = Bootstrap::getObjectManager()->get(Stock::class); - $this->productRepository = Bootstrap::getObjectManager()->get(ProductRepositoryInterface::class); - $this->storeManager = Bootstrap::getObjectManager()->get(StoreManagerInterface::class); - $this->storeCodeBefore = $this->storeManager->getStore()->getCode(); - } - - /** - * @magentoDataFixture Magento_InventoryApi::Test/_files/products.php - * @magentoDataFixture Magento_InventoryApi::Test/_files/sources.php - * @magentoDataFixture Magento_InventoryApi::Test/_files/stocks.php - * @magentoDataFixture Magento_InventoryApi::Test/_files/stock_source_links.php - * @magentoDataFixture Magento_InventoryApi::Test/_files/source_items.php - * @magentoDataFixture Magento_InventorySalesApi::Test/_files/websites_with_stores.php - * @magentoDataFixture Magento_InventorySalesApi::Test/_files/stock_website_sales_channels.php - * @magentoDataFixture Magento_InventoryIndexer::Test/_files/reindex_inventory.php - * @dataProvider assignStatusToProductDataProvider - * @param string $storeCode - * @param array $productsData - * - * @magentoDbIsolation disabled - */ - public function testAssignStatusToProductIfStatusParameterIsNotPassed(string $storeCode, array $productsData) - { - $this->storeManager->setCurrentStore($storeCode); - - foreach ($productsData as $sku => $expectedStatus) { - $product = $this->productRepository->get($sku); - /** @var Product $product */ - $this->stockHelper->assignStatusToProduct($product); - - self::assertEquals($expectedStatus, $product->isSalable()); - } - } - - /** - * @magentoDataFixture Magento_InventoryApi::Test/_files/products.php - * @magentoDataFixture Magento_InventoryApi::Test/_files/sources.php - * @magentoDataFixture Magento_InventoryApi::Test/_files/stocks.php - * @magentoDataFixture Magento_InventoryApi::Test/_files/stock_source_links.php - * @magentoDataFixture Magento_InventoryApi::Test/_files/source_items.php - * @magentoDataFixture Magento_InventorySalesApi::Test/_files/websites_with_stores.php - * @magentoDataFixture Magento_InventorySalesApi::Test/_files/stock_website_sales_channels.php - * @magentoDataFixture Magento_InventoryIndexer::Test/_files/reindex_inventory.php - * @dataProvider assignStatusToProductDataProvider - * @param string $storeCode - * @param array $productsData - * - * @magentoDbIsolation disabled - */ - public function testAssignStatusToProductIfStatusParameterIsPassed(string $storeCode, array $productsData) - { - $expectedStatus = 1; - $this->storeManager->setCurrentStore($storeCode); - - foreach (array_keys($productsData) as $sku) { - $product = $this->productRepository->get($sku); - /** @var Product $product */ - $this->stockHelper->assignStatusToProduct($product, $expectedStatus); - - self::assertEquals($expectedStatus, $product->isSalable()); - } - } - - /** - * @return array - */ - public function assignStatusToProductDataProvider(): array - { - return [ - 'eu_website' => [ - 'store_for_eu_website', - [ - 'SKU-1' => 1, - 'SKU-2' => 0, - 'SKU-3' => 0, - ], - ], - 'us_website' => [ - 'store_for_us_website', - [ - 'SKU-1' => 0, - 'SKU-2' => 1, - 'SKU-3' => 0, - ], - ], - 'global_website' => [ - 'store_for_global_website', - [ - 'SKU-1' => 1, - 'SKU-2' => 1, - 'SKU-3' => 0, - ], - ], - ]; - } - - /** - * @inheritdoc - */ - protected function tearDown(): void - { - $this->storeManager->setCurrentStore($this->storeCodeBefore); - - parent::tearDown(); - } -} diff --git a/InventoryCatalog/Test/Integration/CatalogInventory/Model/ResourceModel/Stock/Status/AddStockDataToCollectionOnDefaultStockTest.php b/InventoryCatalog/Test/Integration/CatalogInventory/Model/ResourceModel/Stock/Status/AddStockDataToCollectionOnDefaultStockTest.php index b060512d5aef..86d22e82bdce 100644 --- a/InventoryCatalog/Test/Integration/CatalogInventory/Model/ResourceModel/Stock/Status/AddStockDataToCollectionOnDefaultStockTest.php +++ b/InventoryCatalog/Test/Integration/CatalogInventory/Model/ResourceModel/Stock/Status/AddStockDataToCollectionOnDefaultStockTest.php @@ -55,7 +55,7 @@ public function addStockDataToCollectionDataProvider(): array { return [ [4, true], - [6, false], + [5, false], ]; } } diff --git a/InventoryCatalog/Test/Integration/CatalogInventory/Model/ResourceModel/Stock/Status/AddStockStatusToSelectTest.php b/InventoryCatalog/Test/Integration/CatalogInventory/Model/ResourceModel/Stock/Status/AddStockStatusToSelectTest.php index 786bae1a5ca8..72ae4a590721 100644 --- a/InventoryCatalog/Test/Integration/CatalogInventory/Model/ResourceModel/Stock/Status/AddStockStatusToSelectTest.php +++ b/InventoryCatalog/Test/Integration/CatalogInventory/Model/ResourceModel/Stock/Status/AddStockStatusToSelectTest.php @@ -70,7 +70,7 @@ public function testAddStockStatusToSelect( $this->stockStatus->addStockStatusToSelect($collection->getSelect(), $this->website); foreach ($collection as $item) { - $item->getIsSalable() == 1 ? $actualIsSalableCount++ : $actualNotSalableCount++; + $item->getData('is_salable') == 1 ? $actualIsSalableCount++ : $actualNotSalableCount++; } self::assertEquals($expectedIsSalableCount, $actualIsSalableCount); diff --git a/InventoryCatalog/etc/di.xml b/InventoryCatalog/etc/di.xml index ed61ae53a9b1..b9737b18770d 100644 --- a/InventoryCatalog/etc/di.xml +++ b/InventoryCatalog/etc/di.xml @@ -166,6 +166,7 @@ + diff --git a/dev/tests/integration/_files/Magento/TestModuleInventoryStateCache/Plugin/InventoryCatalog/Model/IsProductSalableDataStorage/DisableStoragePlugin.php b/dev/tests/integration/_files/Magento/TestModuleInventoryStateCache/Plugin/InventoryCatalog/Model/IsProductSalableDataStorage/DisableStoragePlugin.php new file mode 100644 index 000000000000..86f8b4e326d4 --- /dev/null +++ b/dev/tests/integration/_files/Magento/TestModuleInventoryStateCache/Plugin/InventoryCatalog/Model/IsProductSalableDataStorage/DisableStoragePlugin.php @@ -0,0 +1,35 @@ + + + + From 7e7f12f26d1413e0cdd6af61210b02b3c6bf65b6 Mon Sep 17 00:00:00 2001 From: nmalevanec Date: Mon, 22 Jun 2020 13:42:17 +0300 Subject: [PATCH 50/50] Fix tests. --- InventoryAdvancedCheckout/composer.json | 4 +- .../IsBundleProductSalablePlugin.php | 19 +++++- InventoryBundleProduct/composer.json | 5 +- .../Product/ReindexSourceItemsPlugin.php | 24 ++++++- .../AddBundleProductDataPlugin.php | 2 +- .../IsProductSalableDataStorage.php | 1 + .../ResourceModel/AddStatusFilterToSelect.php | 65 ------------------- .../AddStockDataToCollection.php | 4 +- .../Search/FilterDisabledProductsPlugin.php | 34 ++++++++++ ...ptAddIsInStockFilterToCollectionPlugin.php | 3 - .../AdaptAddStockDataToCollectionPlugin.php | 3 - .../AdaptAddStockStatusToSelectPlugin.php | 13 +--- .../CleanIsSalableDataStoragePlugin.php | 1 + InventoryCatalog/composer.json | 3 +- InventoryCatalog/etc/adminhtml/di.xml | 12 ++++ InventoryConfigurableProduct/composer.json | 4 ++ .../Indexer/SourceItem/SourceItemIndexer.php | 5 ++ .../composer.json | 3 +- InventoryElasticsearch/composer.json | 1 - .../Indexer/SourceItem/SourceItemIndexer.php | 5 ++ InventoryGroupedProductIndexer/composer.json | 1 - InventoryIndexer/Indexer/SelectBuilder.php | 4 +- InventoryIndexer/Model/IsProductSalable.php | 3 +- .../IsStockItemSalableConditionChain.php | 2 + 24 files changed, 122 insertions(+), 99 deletions(-) delete mode 100644 InventoryCatalog/Model/ResourceModel/AddStatusFilterToSelect.php create mode 100644 InventoryCatalog/Plugin/Catalog/Model/ProductLink/Search/FilterDisabledProductsPlugin.php create mode 100644 InventoryCatalog/etc/adminhtml/di.xml diff --git a/InventoryAdvancedCheckout/composer.json b/InventoryAdvancedCheckout/composer.json index 0e60183b67fa..42df77216c9a 100644 --- a/InventoryAdvancedCheckout/composer.json +++ b/InventoryAdvancedCheckout/composer.json @@ -4,9 +4,7 @@ "require": { "php": "~7.3.0||~7.4.0", "magento/framework": "*", - "magento/module-store": "*", - "magento/module-inventory-catalog-api": "*", - "magento/module-inventory-sales-api": "*" + "magento/module-catalog": "*" }, "suggest": { "magento/module-advanced-checkout": "*" diff --git a/InventoryBundleProduct/Plugin/InventoryCatalog/Model/IsProductSalable/IsBundleProductSalablePlugin.php b/InventoryBundleProduct/Plugin/InventoryCatalog/Model/IsProductSalable/IsBundleProductSalablePlugin.php index 83906ea0754d..896474d88142 100644 --- a/InventoryBundleProduct/Plugin/InventoryCatalog/Model/IsProductSalable/IsBundleProductSalablePlugin.php +++ b/InventoryBundleProduct/Plugin/InventoryCatalog/Model/IsProductSalable/IsBundleProductSalablePlugin.php @@ -8,6 +8,7 @@ namespace Magento\InventoryBundleProduct\Plugin\InventoryCatalog\Model\IsProductSalable; use Magento\Bundle\Model\Product\Type; +use Magento\Bundle\Model\ResourceModel\Option\Collection; use Magento\Catalog\Api\Data\ProductInterface; use Magento\Catalog\Model\Product\Attribute\Source\Status; use Magento\InventoryBundleProduct\Model\GetProductSelections; @@ -62,6 +63,22 @@ public function aroundExecute(IsProductSalable $subject, \Closure $proceed, Prod return false; } $bundleOptions = $this->type->getOptionsCollection($product); + $isSalable = $this->isSalable($bundleOptions, $product); + $product->setData('all_items_salable', $isSalable); + + return $isSalable; + } + + /** + * Verify bundle product has salable option. + * + * @param Collection $bundleOptions + * @param ProductInterface $product + * @return bool + * @throws \Exception + */ + private function isSalable(Collection $bundleOptions, ProductInterface $product): bool + { $isSalable = false; foreach ($bundleOptions as $option) { $selections = $this->getProductSelections->execute($product, $option); @@ -75,13 +92,11 @@ public function aroundExecute(IsProductSalable $subject, \Closure $proceed, Prod if ($hasSalable) { $isSalable = true; } - if (!$hasSalable && $option->getRequired()) { $isSalable = false; break; } } - $product->setData('all_items_salable', $isSalable); return $isSalable; } diff --git a/InventoryBundleProduct/composer.json b/InventoryBundleProduct/composer.json index c753818410f8..f4aff7254a0c 100644 --- a/InventoryBundleProduct/composer.json +++ b/InventoryBundleProduct/composer.json @@ -6,15 +6,18 @@ "magento/framework": "*", "magento/module-bundle": "*", "magento/module-catalog": "*", + "magento/module-catalog-inventory": "*", "magento/module-inventory-api": "*", "magento/module-inventory-catalog": "*", "magento/module-inventory-catalog-api": "*", "magento/module-inventory-configuration-api": "*", + "magento/module-inventory-indexer": "*", "magento/module-inventory-sales-api": "*", "magento/module-store": "*" }, "suggest": { - "magento/module-catalog-inventory": "*" + "magento/module-catalog-inventory": "*", + "magento/module-inventory-sales": "*" }, "type": "magento2-module", "license": [ diff --git a/InventoryBundleProductIndexer/Plugin/Catalog/Model/Product/ReindexSourceItemsPlugin.php b/InventoryBundleProductIndexer/Plugin/Catalog/Model/Product/ReindexSourceItemsPlugin.php index 2a2fd2ee69f1..dd1ca6267b7c 100644 --- a/InventoryBundleProductIndexer/Plugin/Catalog/Model/Product/ReindexSourceItemsPlugin.php +++ b/InventoryBundleProductIndexer/Plugin/Catalog/Model/Product/ReindexSourceItemsPlugin.php @@ -92,8 +92,11 @@ public function afterAfterSave(Product $subject, Product $result): Product */ private function getSelectionsSku(Product $result): array { + $skus = $this->getSkusFromOptions($result); + if ($skus) { + return $skus; + } $bundleSelectionsData = $result->getBundleSelectionsData() ?: []; - $skus = []; foreach ($bundleSelectionsData as $option) { $skus[] = array_column($option, 'sku'); } @@ -109,4 +112,23 @@ private function getSelectionsSku(Product $result): array return $this->getSkusByProductIds->execute($ids); } + + /** + * Retrieve selection's skus from bundle product options. + * + * @param Product $result + * @return array + */ + private function getSkusFromOptions(Product $result): array + { + $skus = []; + $options = $result->getExtensionAttributes()->getBundleProductOptions() ?: []; + foreach ($options as $option) { + $links = $option->getProductLinks(); + foreach ($links as $link) { + $skus[] = $link->getSku(); + } + } + return $skus; + } } diff --git a/InventoryBundleProductIndexer/Plugin/InventoryIndexer/Model/Queue/GetDataForUpdate/AddBundleProductDataPlugin.php b/InventoryBundleProductIndexer/Plugin/InventoryIndexer/Model/Queue/GetDataForUpdate/AddBundleProductDataPlugin.php index 0055d267296b..8271e3e786ef 100644 --- a/InventoryBundleProductIndexer/Plugin/InventoryIndexer/Model/Queue/GetDataForUpdate/AddBundleProductDataPlugin.php +++ b/InventoryBundleProductIndexer/Plugin/InventoryIndexer/Model/Queue/GetDataForUpdate/AddBundleProductDataPlugin.php @@ -18,7 +18,7 @@ use Psr\Log\LoggerInterface; /** - * Add bundle product data plugin. + * Add bundle product data to index data plugin. */ class AddBundleProductDataPlugin { diff --git a/InventoryCatalog/Model/IsProductSalable/IsProductSalableDataStorage.php b/InventoryCatalog/Model/IsProductSalable/IsProductSalableDataStorage.php index 76bac6f45e11..24e68b52045d 100644 --- a/InventoryCatalog/Model/IsProductSalable/IsProductSalableDataStorage.php +++ b/InventoryCatalog/Model/IsProductSalable/IsProductSalableDataStorage.php @@ -44,6 +44,7 @@ public function getIsSalable(string $sku, int $stockId): ?bool /** * Clean is salable status for given product and stock. + * * @param string $sku * @param int $stockId * @return void diff --git a/InventoryCatalog/Model/ResourceModel/AddStatusFilterToSelect.php b/InventoryCatalog/Model/ResourceModel/AddStatusFilterToSelect.php deleted file mode 100644 index a4e8caaf4efa..000000000000 --- a/InventoryCatalog/Model/ResourceModel/AddStatusFilterToSelect.php +++ /dev/null @@ -1,65 +0,0 @@ -connection = $connection; - $this->joinAttributeProcessor = $joinAttributeProcessor; - } - - /** - * Add product status filter to select. - * - * @param Select $select - * @return Select - * @throws LocalizedException - * @throws \Zend_Db_Select_Exception - */ - public function execute(Select $select): Select - { - $select->joinInner( - ['pw' => $this->connection->getTableName('catalog_product_website')], - 'pw.product_id = e.entity_id', - ['pw.website_id'] - )->joinInner( - ['cwd' => $this->connection->getTableName('catalog_product_index_website')], - 'pw.website_id = cwd.website_id', - [] - ); - $this->joinAttributeProcessor->process($select, ProductInterface::STATUS, ProductStatus::STATUS_ENABLED); - - return $select; - } -} diff --git a/InventoryCatalog/Model/ResourceModel/AddStockDataToCollection.php b/InventoryCatalog/Model/ResourceModel/AddStockDataToCollection.php index 178dc92c45b2..38a4dad8b2b5 100644 --- a/InventoryCatalog/Model/ResourceModel/AddStockDataToCollection.php +++ b/InventoryCatalog/Model/ResourceModel/AddStockDataToCollection.php @@ -12,7 +12,7 @@ use Magento\InventoryIndexer\Model\StockIndexTableNameResolverInterface; /** - * Add Stock data to collection + * Add inventory stock data to collection resource. */ class AddStockDataToCollection { @@ -31,6 +31,8 @@ public function __construct( } /** + * Add inventory stock data for multi stock environment. + * * @param Collection $collection * @param bool $isFilterInStock * @param int $stockId diff --git a/InventoryCatalog/Plugin/Catalog/Model/ProductLink/Search/FilterDisabledProductsPlugin.php b/InventoryCatalog/Plugin/Catalog/Model/ProductLink/Search/FilterDisabledProductsPlugin.php new file mode 100644 index 000000000000..6d89a0ec6bdc --- /dev/null +++ b/InventoryCatalog/Plugin/Catalog/Model/ProductLink/Search/FilterDisabledProductsPlugin.php @@ -0,0 +1,34 @@ +addAttributeToFilter(ProductInterface::STATUS, ['eq' => Status::STATUS_ENABLED]); + + return $collection; + } +} diff --git a/InventoryCatalog/Plugin/CatalogInventory/Model/ResourceModel/Stock/Status/AdaptAddIsInStockFilterToCollectionPlugin.php b/InventoryCatalog/Plugin/CatalogInventory/Model/ResourceModel/Stock/Status/AdaptAddIsInStockFilterToCollectionPlugin.php index ddb0efbfa014..397b068ddf36 100644 --- a/InventoryCatalog/Plugin/CatalogInventory/Model/ResourceModel/Stock/Status/AdaptAddIsInStockFilterToCollectionPlugin.php +++ b/InventoryCatalog/Plugin/CatalogInventory/Model/ResourceModel/Stock/Status/AdaptAddIsInStockFilterToCollectionPlugin.php @@ -7,8 +7,6 @@ namespace Magento\InventoryCatalog\Plugin\CatalogInventory\Model\ResourceModel\Stock\Status; -use Magento\Catalog\Api\Data\ProductInterface; -use Magento\Catalog\Model\Product\Attribute\Source\Status as ProductStatus; use Magento\Catalog\Model\ResourceModel\Product\Collection; use Magento\CatalogInventory\Model\ResourceModel\Stock\Status; use Magento\InventoryCatalog\Model\GetStockIdForCurrentWebsite; @@ -56,7 +54,6 @@ public function aroundAddIsInStockFilterToCollection( callable $proceed, $collection ) { - $collection->addAttributeToFilter(ProductInterface::STATUS, ProductStatus::STATUS_ENABLED); $stockId = $this->getStockIdForCurrentWebsite->execute(); $this->addIsInStockFilterToCollection->execute($collection, $stockId); diff --git a/InventoryCatalog/Plugin/CatalogInventory/Model/ResourceModel/Stock/Status/AdaptAddStockDataToCollectionPlugin.php b/InventoryCatalog/Plugin/CatalogInventory/Model/ResourceModel/Stock/Status/AdaptAddStockDataToCollectionPlugin.php index 78f60179a0fd..0e4fb9d485b0 100644 --- a/InventoryCatalog/Plugin/CatalogInventory/Model/ResourceModel/Stock/Status/AdaptAddStockDataToCollectionPlugin.php +++ b/InventoryCatalog/Plugin/CatalogInventory/Model/ResourceModel/Stock/Status/AdaptAddStockDataToCollectionPlugin.php @@ -7,8 +7,6 @@ namespace Magento\InventoryCatalog\Plugin\CatalogInventory\Model\ResourceModel\Stock\Status; -use Magento\Catalog\Api\Data\ProductInterface; -use Magento\Catalog\Model\Product\Attribute\Source\Status as ProductStatus; use Magento\Catalog\Model\ResourceModel\Product\Collection; use Magento\CatalogInventory\Model\ResourceModel\Stock\Status; use Magento\InventoryCatalog\Model\GetStockIdForCurrentWebsite; @@ -58,7 +56,6 @@ public function aroundAddStockDataToCollection( $collection, $isFilterInStock ) { - $collection->addAttributeToFilter(ProductInterface::STATUS, ProductStatus::STATUS_ENABLED); $stockId = $this->getStockIdForCurrentWebsite->execute(); $this->addStockDataToCollection->execute($collection, (bool)$isFilterInStock, $stockId); diff --git a/InventoryCatalog/Plugin/CatalogInventory/Model/ResourceModel/Stock/Status/AdaptAddStockStatusToSelectPlugin.php b/InventoryCatalog/Plugin/CatalogInventory/Model/ResourceModel/Stock/Status/AdaptAddStockStatusToSelectPlugin.php index 038224f03923..99bac2255083 100644 --- a/InventoryCatalog/Plugin/CatalogInventory/Model/ResourceModel/Stock/Status/AdaptAddStockStatusToSelectPlugin.php +++ b/InventoryCatalog/Plugin/CatalogInventory/Model/ResourceModel/Stock/Status/AdaptAddStockStatusToSelectPlugin.php @@ -11,7 +11,6 @@ use Magento\Framework\DB\Select; use Magento\Framework\Exception\LocalizedException; use Magento\Framework\Exception\NoSuchEntityException; -use Magento\InventoryCatalog\Model\ResourceModel\AddStatusFilterToSelect; use Magento\InventoryCatalog\Model\ResourceModel\AddStockStatusToSelect; use Magento\InventorySalesApi\Api\Data\SalesChannelInterface; use Magento\InventorySalesApi\Api\StockResolverInterface; @@ -32,24 +31,16 @@ class AdaptAddStockStatusToSelectPlugin */ private $addStockStatusToSelect; - /** - * @var AddStatusFilterToSelect - */ - private $addStatusFilterToSelect; - /** * @param StockResolverInterface $stockResolver * @param AddStockStatusToSelect $addStockStatusToSelect - * @param AddStatusFilterToSelect $addStatusFilterToSelect */ public function __construct( StockResolverInterface $stockResolver, - AddStockStatusToSelect $addStockStatusToSelect, - AddStatusFilterToSelect $addStatusFilterToSelect + AddStockStatusToSelect $addStockStatusToSelect ) { $this->stockResolver = $stockResolver; $this->addStockStatusToSelect = $addStockStatusToSelect; - $this->addStatusFilterToSelect = $addStatusFilterToSelect; } /** @@ -62,7 +53,6 @@ public function __construct( * @return Status * @throws LocalizedException * @throws NoSuchEntityException - * @throws \Zend_Db_Select_Exception * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function aroundAddStockStatusToSelect( @@ -79,7 +69,6 @@ public function aroundAddStockStatusToSelect( $stock = $this->stockResolver->execute(SalesChannelInterface::TYPE_WEBSITE, $websiteCode); $stockId = (int)$stock->getStockId(); $this->addStockStatusToSelect->execute($select, $stockId); - $this->addStatusFilterToSelect->execute($select); return $stockStatus; } diff --git a/InventoryCatalog/Plugin/CatalogInventory/Model/StockRegistryStorage/CleanIsSalableDataStoragePlugin.php b/InventoryCatalog/Plugin/CatalogInventory/Model/StockRegistryStorage/CleanIsSalableDataStoragePlugin.php index cb678ac925ee..0a86d2db21f9 100644 --- a/InventoryCatalog/Plugin/CatalogInventory/Model/StockRegistryStorage/CleanIsSalableDataStoragePlugin.php +++ b/InventoryCatalog/Plugin/CatalogInventory/Model/StockRegistryStorage/CleanIsSalableDataStoragePlugin.php @@ -33,6 +33,7 @@ public function __construct(IsProductSalableDataStorage $isProductSalableDataSto * * @param StockRegistryStorage $subject * @param void $result + * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function afterClean(StockRegistryStorage $subject, $result): void { diff --git a/InventoryCatalog/composer.json b/InventoryCatalog/composer.json index c3651026905c..1a5c872ba15e 100644 --- a/InventoryCatalog/composer.json +++ b/InventoryCatalog/composer.json @@ -13,7 +13,8 @@ "magento/module-inventory-configuration-api": "*", "magento/module-inventory-indexer": "*", "magento/module-inventory-sales-api": "*", - "magento/module-inventory-configuration": "*" + "magento/module-inventory-configuration": "*", + "magento/module-inventory-multi-dimensional-indexer-api": "*" }, "suggest": { "magento/module-inventory-reservations-api": "*" diff --git a/InventoryCatalog/etc/adminhtml/di.xml b/InventoryCatalog/etc/adminhtml/di.xml new file mode 100644 index 000000000000..07204db2bf2d --- /dev/null +++ b/InventoryCatalog/etc/adminhtml/di.xml @@ -0,0 +1,12 @@ + + + + + + + diff --git a/InventoryConfigurableProduct/composer.json b/InventoryConfigurableProduct/composer.json index 5a3e350f7cb3..bcf5b46c7c1a 100644 --- a/InventoryConfigurableProduct/composer.json +++ b/InventoryConfigurableProduct/composer.json @@ -13,6 +13,10 @@ "magento/module-sales": "*", "magento/module-configurable-product": "*" }, + "suggest": { + "magento/module-inventory-catalog": "*", + "magento/module-inventory-sales": "*" + }, "type": "magento2-module", "license": [ "OSL-3.0", diff --git a/InventoryConfigurableProductIndexer/Indexer/SourceItem/SourceItemIndexer.php b/InventoryConfigurableProductIndexer/Indexer/SourceItem/SourceItemIndexer.php index 97685ddd6c2e..03e93320c084 100644 --- a/InventoryConfigurableProductIndexer/Indexer/SourceItem/SourceItemIndexer.php +++ b/InventoryConfigurableProductIndexer/Indexer/SourceItem/SourceItemIndexer.php @@ -14,6 +14,9 @@ use Magento\InventoryMultiDimensionalIndexerApi\Model\IndexNameBuilder; use Magento\InventoryMultiDimensionalIndexerApi\Model\IndexStructureInterface; +/** + * Configurable product source item indexer. + */ class SourceItemIndexer { /** @@ -71,6 +74,8 @@ public function __construct( } /** + * Reindex given source items. + * * @param array $sourceItemIds */ public function executeList(array $sourceItemIds) diff --git a/InventoryConfigurableProductIndexer/composer.json b/InventoryConfigurableProductIndexer/composer.json index 2079d1b645e0..1bfa284d0bf5 100644 --- a/InventoryConfigurableProductIndexer/composer.json +++ b/InventoryConfigurableProductIndexer/composer.json @@ -9,7 +9,8 @@ "magento/module-inventory-api": "*", "magento/module-inventory-catalog-api": "*", "magento/module-inventory-indexer": "*", - "magento/module-inventory-multi-dimensional-indexer-api": "*" + "magento/module-inventory-multi-dimensional-indexer-api": "*", + "magento/module-inventory-sales-api": "*" }, "suggest": { "magento/module-inventory": "*" diff --git a/InventoryElasticsearch/composer.json b/InventoryElasticsearch/composer.json index bc435956cb52..478629f005bf 100644 --- a/InventoryElasticsearch/composer.json +++ b/InventoryElasticsearch/composer.json @@ -6,7 +6,6 @@ "magento/framework": "*", "magento/module-catalog-inventory": "*", "magento/module-catalog-search": "*", - "magento/module-inventory-catalog-api": "*", "magento/module-inventory-indexer": "*", "magento/module-inventory-sales-api": "*", "magento/module-store": "*" diff --git a/InventoryGroupedProductIndexer/Indexer/SourceItem/SourceItemIndexer.php b/InventoryGroupedProductIndexer/Indexer/SourceItem/SourceItemIndexer.php index b1a34fc46151..17142a6df648 100644 --- a/InventoryGroupedProductIndexer/Indexer/SourceItem/SourceItemIndexer.php +++ b/InventoryGroupedProductIndexer/Indexer/SourceItem/SourceItemIndexer.php @@ -14,6 +14,9 @@ use Magento\InventoryMultiDimensionalIndexerApi\Model\IndexNameBuilder; use Magento\InventoryMultiDimensionalIndexerApi\Model\IndexStructureInterface; +/** + * Grouped product source item indexer. + */ class SourceItemIndexer { /** @@ -71,6 +74,8 @@ public function __construct( } /** + * Reindex given source items. + * * @param array $sourceItemIds */ public function executeList(array $sourceItemIds) diff --git a/InventoryGroupedProductIndexer/composer.json b/InventoryGroupedProductIndexer/composer.json index 7c746bd140b9..18fe1d252e3f 100644 --- a/InventoryGroupedProductIndexer/composer.json +++ b/InventoryGroupedProductIndexer/composer.json @@ -6,7 +6,6 @@ "magento/framework": "*", "magento/module-catalog": "*", "magento/module-inventory-api": "*", - "magento/module-inventory-catalog-api": "*", "magento/module-inventory-indexer": "*", "magento/module-inventory-multi-dimensional-indexer-api": "*", "magento/module-grouped-product": "*" diff --git a/InventoryIndexer/Indexer/SelectBuilder.php b/InventoryIndexer/Indexer/SelectBuilder.php index c455d61eb82a..13af262568d3 100644 --- a/InventoryIndexer/Indexer/SelectBuilder.php +++ b/InventoryIndexer/Indexer/SelectBuilder.php @@ -18,7 +18,7 @@ use Magento\InventorySales\Model\ResourceModel\IsStockItemSalableCondition\GetIsStockItemSalableConditionInterface; /** - * Select builder + * Inventory select builder. */ class SelectBuilder { @@ -53,6 +53,8 @@ public function __construct( } /** + * Build inventory select for given stock. + * * @param int $stockId * @return Select */ diff --git a/InventoryIndexer/Model/IsProductSalable.php b/InventoryIndexer/Model/IsProductSalable.php index c7f7f59afd25..9c06aefc9b52 100644 --- a/InventoryIndexer/Model/IsProductSalable.php +++ b/InventoryIndexer/Model/IsProductSalable.php @@ -7,7 +7,6 @@ namespace Magento\InventoryIndexer\Model; -use Magento\CatalogInventory\Model\Configuration; use Magento\Framework\App\Config\ScopeConfigInterface; use Magento\Framework\Exception\LocalizedException; use Magento\InventorySalesApi\Api\IsProductSalableInterface; @@ -55,7 +54,7 @@ public function __construct( public function execute(string $sku, int $stockId): bool { try { - $showOutOfStock = (int)$this->config->getValue(Configuration::XML_PATH_SHOW_OUT_OF_STOCK); + $showOutOfStock = (int)$this->config->getValue('cataloginventory/options/show_out_of_stock'); $stockItem = $this->getStockItemData->execute($sku, $stockId); $isSalable = $showOutOfStock ? true : (bool)($stockItem[GetStockItemDataInterface::IS_SALABLE] ?? false); } catch (LocalizedException $exception) { diff --git a/InventorySales/Model/ResourceModel/IsStockItemSalableCondition/IsStockItemSalableConditionChain.php b/InventorySales/Model/ResourceModel/IsStockItemSalableCondition/IsStockItemSalableConditionChain.php index 0dd085a82a8c..d549cfd60795 100644 --- a/InventorySales/Model/ResourceModel/IsStockItemSalableCondition/IsStockItemSalableConditionChain.php +++ b/InventorySales/Model/ResourceModel/IsStockItemSalableCondition/IsStockItemSalableConditionChain.php @@ -35,6 +35,8 @@ class IsStockItemSalableConditionChain implements GetIsStockItemSalableCondition /** * @param ResourceConnection $resourceConnection * @param StockConfigurationInterface $configuration + * @param array $conditions + * @throws LocalizedException */ public function __construct( ResourceConnection $resourceConnection,