diff --git a/InventoryDataExporter/Model/Provider/StockStatus.php b/InventoryDataExporter/Model/Provider/StockStatus.php index c8f698f0..75304444 100644 --- a/InventoryDataExporter/Model/Provider/StockStatus.php +++ b/InventoryDataExporter/Model/Provider/StockStatus.php @@ -9,6 +9,7 @@ namespace Magento\InventoryDataExporter\Model\Provider; use Magento\Framework\App\ResourceConnection; +use Magento\Framework\Stdlib\DateTime; use Magento\InventoryDataExporter\Model\Query\InventoryStockQuery; use Psr\Log\LoggerInterface; @@ -35,6 +36,11 @@ class StockStatus */ private $query; + /** + * @var DateTime + */ + private $dateTime; + /** * @var LoggerInterface */ @@ -43,16 +49,19 @@ class StockStatus /** * @param ResourceConnection $resourceConnection * @param InventoryStockQuery $query + * @param DateTime $dateTime * @param LoggerInterface $logger */ public function __construct( ResourceConnection $resourceConnection, InventoryStockQuery $query, + DateTime $dateTime, LoggerInterface $logger ) { $this->resourceConnection = $resourceConnection; $this->query = $query; $this->logger = $logger; + $this->dateTime = $dateTime; } /** @@ -103,6 +112,9 @@ private function fillWithDefaultValues(array $row): array throw new \RuntimeException("missed required field: " . \var_export($row, true)); } $row['id'] = StockStatusIdBuilder::build($row); + + // set updated at + $row['updatedAt'] = $this->dateTime->formatDate(time()); // set default values $row['infiniteStock'] = false; $row['qtyForSale'] = $row['qty']; diff --git a/InventoryDataExporter/Model/Query/StockStatusDeleteQuery.php b/InventoryDataExporter/Model/Query/StockStatusDeleteQuery.php new file mode 100644 index 00000000..1a505cdc --- /dev/null +++ b/InventoryDataExporter/Model/Query/StockStatusDeleteQuery.php @@ -0,0 +1,86 @@ +resourceConnection = $resourceConnection; + $this->metadata = $metadata; + } + + /** + * Get stocks which are assigned to the list of provided SKUs + * + * @param array $skus + * @return array + */ + public function getStocksAssignedToSkus(array $skus): array + { + $connection = $this->resourceConnection->getConnection(); + $select = $connection->select() + ->from( + ['source_item' => $this->resourceConnection->getTableName('inventory_source_item')], + ['source_item.sku', 'source_stock_link.stock_id'] + )->joinLeft( + ['source_stock_link' => $this->resourceConnection->getTableName('inventory_source_stock_link')], + 'source_item.source_code = source_stock_link.source_code' + )->where('source_item.sku IN (?)', $skus); + + $fetchedSourceItems = []; + foreach ($connection->fetchAll($select) as $sourceItem) { + $fetchedSourceItems[$sourceItem['sku']][$sourceItem['stock_id']][] = $sourceItem['source_code']; + } + + return $fetchedSourceItems; + } + + /** + * Mark stock statuses as deleted + * + * @param array $stocksToDelete + */ + public function markStockStatusesAsDeleted(array $stocksToDelete): void + { + $connection = $this->resourceConnection->getConnection(); + $feedTableName = $this->resourceConnection->getTableName($this->metadata->getFeedTableName()); + foreach ($stocksToDelete as $stockId => $skus) { + $connection->update( + $feedTableName, + ['is_deleted' => new \Zend_Db_Expr('1')], + [ + 'sku IN (?)' => $skus, + 'stock_id = ?' => $stockId + ] + ); + } + } +} diff --git a/InventoryDataExporter/Plugin/BulkSourceUnassign.php b/InventoryDataExporter/Plugin/BulkSourceUnassign.php new file mode 100644 index 00000000..bb6fbd22 --- /dev/null +++ b/InventoryDataExporter/Plugin/BulkSourceUnassign.php @@ -0,0 +1,80 @@ +stockStatusDeleteQuery = $stockStatusDeleteQuery; + } + + /** + * Check which stocks will be unassigned from products and mark them as deleted in feed table + * + * @param \Magento\InventoryCatalog\Model\ResourceModel\BulkSourceUnassign $subject + * @param array $skus + * @param array $sourceCodes + * @return void + * + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function beforeExecute( + \Magento\InventoryCatalog\Model\ResourceModel\BulkSourceUnassign $subject, + array $skus, + array $sourceCodes + ): void { + $fetchedSourceItems = $this->stockStatusDeleteQuery->getStocksAssignedToSkus($skus); + $stocksToDelete = $this->getStocksToDelete($skus, $sourceCodes, $fetchedSourceItems); + + if (!empty($stocksToDelete)) { + $this->stockStatusDeleteQuery->markStockStatusesAsDeleted($stocksToDelete); + } + } + + /** + * @param array $affectedSkus + * @param array $deletedSources + * @return array + */ + private function getStocksToDelete(array $affectedSkus, array $deletedSources, $fetchedSourceItems): array + { + $stocksToDelete = []; + foreach ($affectedSkus as $deletedItemSku) { + foreach ($fetchedSourceItems[$deletedItemSku] as $fetchedItemStockId => $fetchedItemSources) { + if ($this->getContainsAllKeys($fetchedItemSources, $deletedSources)) { + $stocksToDelete[(string)$fetchedItemStockId][] = $deletedItemSku; + } + } + } + + return $stocksToDelete; + } + + /** + * @param array $fetchedSources + * @param array $deletedSources + * @return bool + */ + private function getContainsAllKeys(array $fetchedSources, array $deletedSources): bool + { + return empty(\array_diff($fetchedSources, $deletedSources)); + } +} diff --git a/InventoryDataExporter/Plugin/MarkItemsAsDeleted.php b/InventoryDataExporter/Plugin/MarkItemsAsDeleted.php new file mode 100644 index 00000000..493793a1 --- /dev/null +++ b/InventoryDataExporter/Plugin/MarkItemsAsDeleted.php @@ -0,0 +1,85 @@ +stockStatusDeleteQuery = $stockStatusDeleteQuery; + } + + /** + * Set is_deleted value to 1 for deleted stock statuses + * + * @param DeleteMultiple $subject + * @param SourceItemInterface[] $sourceItems + * @return void + * + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function beforeExecute( + DeleteMultiple $subject, + array $sourceItems + ): void { + $deletedSourceItems = []; + foreach ($sourceItems as $sourceItem) { + $deletedSourceItems[$sourceItem->getSku()][] = $sourceItem->getSourceCode(); + } + + $fetchedSourceItems = $this->stockStatusDeleteQuery->getStocksAssignedToSkus(array_keys($deletedSourceItems)); + + $stocksToDelete = $this->getStocksToDelete($deletedSourceItems, $fetchedSourceItems); + if (!empty($stocksToDelete)) { + $this->stockStatusDeleteQuery->markStockStatusesAsDeleted($stocksToDelete); + } + } + + /** + * @param array $deletedSourceItems + * @param $fetchedSourceItems + * @return array + */ + private function getStocksToDelete(array $deletedSourceItems, $fetchedSourceItems): array + { + $stocksToDelete = []; + foreach ($deletedSourceItems as $deletedItemSku => $deletedItemSources) { + foreach ($fetchedSourceItems[$deletedItemSku] as $fetchedItemStockId => $fetchedItemSources) { + if ($this->getContainsAllKeys($fetchedItemSources, $deletedItemSources)) { + $stocksToDelete[(string)$fetchedItemStockId][] = $deletedItemSku; + } + } + } + + return $stocksToDelete; + } + + /** + * @param array $fetchedSources + * @param array $deletedSources + * @return bool + */ + private function getContainsAllKeys(array $fetchedSources, array $deletedSources): bool + { + return empty(\array_diff($fetchedSources, $deletedSources)); + } +} diff --git a/InventoryDataExporter/etc/db_schema.xml b/InventoryDataExporter/etc/db_schema.xml index 417618f3..118ecc1b 100644 --- a/InventoryDataExporter/etc/db_schema.xml +++ b/InventoryDataExporter/etc/db_schema.xml @@ -51,7 +51,6 @@ /> - diff --git a/InventoryDataExporter/etc/di.xml b/InventoryDataExporter/etc/di.xml index 2414ae1d..36db5e76 100644 --- a/InventoryDataExporter/etc/di.xml +++ b/InventoryDataExporter/etc/di.xml @@ -6,11 +6,6 @@ */ --> - - - catalog_product_entity - - stockStatus @@ -26,10 +21,10 @@ stock_statuses sku - catalog_product_entity + inventory_source_item sku inventory_data_exporter_stock_status - id + sku feed_data is_deleted @@ -45,21 +40,10 @@ - - - Magento\InventoryDataExporter\Model\Indexer\StockStatusMarkRemovedEntities - - - - - Magento\InventoryDataExporter\Model\Query\MarkRemovedEntitiesQuery - - Magento\InventoryDataExporter\Model\Indexer\StockStatusFeedIndexMetadata Magento\InventoryDataExporter\Model\Indexer\StockStatusDataSerializer - @@ -72,4 +56,19 @@ + + + + + + + + + + Magento\InventoryDataExporter\Model\Indexer\StockStatusFeedIndexMetadata + + +