Skip to content

Commit

Permalink
Merge branch '2.4-develop' into issue-26437-customer-shopping-cart-tab
Browse files Browse the repository at this point in the history
  • Loading branch information
novikor authored Jan 22, 2020
2 parents 2312289 + 27076ca commit e9cb043
Show file tree
Hide file tree
Showing 40 changed files with 1,151 additions and 196 deletions.
78 changes: 77 additions & 1 deletion app/code/Magento/CatalogImportExport/Model/Import/Product.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
use Magento\CatalogImportExport\Model\Import\Product\ImageTypeProcessor;
use Magento\CatalogImportExport\Model\Import\Product\MediaGalleryProcessor;
use Magento\CatalogImportExport\Model\Import\Product\RowValidatorInterface as ValidatorInterface;
use Magento\CatalogImportExport\Model\Import\Product\StatusProcessor;
use Magento\CatalogImportExport\Model\Import\Product\StockProcessor;
use Magento\CatalogImportExport\Model\StockItemImporterInterface;
use Magento\CatalogInventory\Api\Data\StockItemInterface;
use Magento\Framework\App\Filesystem\DirectoryList;
Expand Down Expand Up @@ -746,6 +748,15 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity
*/
private $productRepository;

/**
* @var StatusProcessor
*/
private $statusProcessor;
/**
* @var StockProcessor
*/
private $stockProcessor;

/**
* @param \Magento\Framework\Json\Helper\Data $jsonHelper
* @param \Magento\ImportExport\Helper\Data $importExportData
Expand Down Expand Up @@ -791,6 +802,8 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity
* @param StockItemImporterInterface|null $stockItemImporter
* @param DateTimeFactory $dateTimeFactory
* @param ProductRepositoryInterface|null $productRepository
* @param StatusProcessor|null $statusProcessor
* @param StockProcessor|null $stockProcessor
* @throws LocalizedException
* @throws \Magento\Framework\Exception\FileSystemException
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
Expand Down Expand Up @@ -840,7 +853,9 @@ public function __construct(
MediaGalleryProcessor $mediaProcessor = null,
StockItemImporterInterface $stockItemImporter = null,
DateTimeFactory $dateTimeFactory = null,
ProductRepositoryInterface $productRepository = null
ProductRepositoryInterface $productRepository = null,
StatusProcessor $statusProcessor = null,
StockProcessor $stockProcessor = null
) {
$this->_eventManager = $eventManager;
$this->stockRegistry = $stockRegistry;
Expand Down Expand Up @@ -876,6 +891,10 @@ public function __construct(
$this->mediaProcessor = $mediaProcessor ?: ObjectManager::getInstance()->get(MediaGalleryProcessor::class);
$this->stockItemImporter = $stockItemImporter ?: ObjectManager::getInstance()
->get(StockItemImporterInterface::class);
$this->statusProcessor = $statusProcessor ?: ObjectManager::getInstance()
->get(StatusProcessor::class);
$this->stockProcessor = $stockProcessor ?: ObjectManager::getInstance()
->get(StockProcessor::class);
parent::__construct(
$jsonHelper,
$importExportData,
Expand Down Expand Up @@ -1290,12 +1309,18 @@ protected function _saveLinks()
protected function _saveProductAttributes(array $attributesData)
{
$linkField = $this->getProductEntityLinkField();
$statusAttributeId = (int) $this->retrieveAttributeByCode('status')->getId();
foreach ($attributesData as $tableName => $skuData) {
$linkIdBySkuForStatusChanged = [];
$tableData = [];
foreach ($skuData as $sku => $attributes) {
$linkId = $this->_oldSku[strtolower($sku)][$linkField];
foreach ($attributes as $attributeId => $storeValues) {
foreach ($storeValues as $storeId => $storeValue) {
if ($attributeId === $statusAttributeId) {
$this->statusProcessor->setStatus($sku, $storeId, $storeValue);
$linkIdBySkuForStatusChanged[strtolower($sku)] = $linkId;
}
$tableData[] = [
$linkField => $linkId,
'attribute_id' => $attributeId,
Expand All @@ -1305,6 +1330,9 @@ protected function _saveProductAttributes(array $attributesData)
}
}
}
if ($linkIdBySkuForStatusChanged) {
$this->statusProcessor->loadOldStatus($linkIdBySkuForStatusChanged);
}
$this->_connection->insertOnDuplicate($tableName, $tableData, ['value']);
}

Expand Down Expand Up @@ -2188,6 +2216,7 @@ protected function _saveStockItem()
while ($bunch = $this->_dataSourceModel->getNextBunch()) {
$stockData = [];
$productIdsToReindex = [];
$stockChangedProductIds = [];
// Format bunch to stock data rows
foreach ($bunch as $rowNum => $rowData) {
if (!$this->isRowAllowedToImport($rowData, $rowNum)) {
Expand All @@ -2197,8 +2226,16 @@ protected function _saveStockItem()
$row = [];
$sku = $rowData[self::COL_SKU];
if ($this->skuProcessor->getNewSku($sku) !== null) {
$stockItem = $this->getRowExistingStockItem($rowData);
$existingStockItemData = $stockItem->getData();
$row = $this->formatStockDataForRow($rowData);
$productIdsToReindex[] = $row['product_id'];
$storeId = $this->getRowStoreId($rowData);
if (!empty(array_diff_assoc($row, $existingStockItemData))
|| $this->statusProcessor->isStatusChanged($sku, $storeId)
) {
$stockChangedProductIds[] = $row['product_id'];
}
}

if (!isset($stockData[$sku])) {
Expand All @@ -2211,11 +2248,24 @@ protected function _saveStockItem()
$this->stockItemImporter->import($stockData);
}

$this->reindexStockStatus($stockChangedProductIds);
$this->reindexProducts($productIdsToReindex);
}
return $this;
}

/**
* Reindex stock status for provided product IDs
*
* @param array $productIds
*/
private function reindexStockStatus(array $productIds): void
{
if ($productIds) {
$this->stockProcessor->reindexList($productIds);
}
}

/**
* Initiate product reindex by product ids
*
Expand Down Expand Up @@ -3259,4 +3309,30 @@ private function composeLinkKey(int $productId, int $linkedId, int $linkTypeId)
{
return "{$productId}-{$linkedId}-{$linkTypeId}";
}

/**
* Get row store ID
*
* @param array $rowData
* @return int
*/
private function getRowStoreId(array $rowData): int
{
return !empty($rowData[self::COL_STORE])
? (int) $this->getStoreIdByCode($rowData[self::COL_STORE])
: Store::DEFAULT_STORE_ID;
}

/**
* Get row stock item model
*
* @param array $rowData
* @return StockItemInterface
*/
private function getRowExistingStockItem(array $rowData): StockItemInterface
{
$productId = $this->skuProcessor->getNewSku($rowData[self::COL_SKU])['entity_id'];
$websiteId = $this->stockConfiguration->getDefaultScopeId();
return $this->stockRegistry->getStockItem($productId, $websiteId);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);

namespace Magento\CatalogImportExport\Model\Import\Product;

use Magento\Catalog\Api\Data\ProductInterface;
use Magento\CatalogImportExport\Model\Import\Proxy\Product\ResourceModelFactory;
use Magento\Eav\Model\Entity\Attribute\AbstractAttribute;
use Magento\Framework\App\ResourceConnection;
use Magento\Framework\EntityManager\MetadataPool;

/**
* Imported product status state manager
*/
class StatusProcessor
{
private const ATTRIBUTE_CODE = 'status';
/**
* @var array
*/
private $oldData;
/**
* @var array
*/
private $newData;
/**
* @var ResourceModelFactory
*/
private $resourceFactory;
/**
* @var ResourceConnection
*/
private $resourceConnection;
/**
* @var MetadataPool
*/
private $metadataPool;
/**
* @var string
*/
private $productEntityLinkField;
/**
* @var AbstractAttribute
*/
private $attribute;

/**
* Initializes dependencies.
*
* @param MetadataPool $metadataPool
* @param ResourceModelFactory $resourceFactory
* @param ResourceConnection $resourceConnection
*/
public function __construct(
MetadataPool $metadataPool,
ResourceModelFactory $resourceFactory,
ResourceConnection $resourceConnection
) {
$this->oldData = [];
$this->newData = [];
$this->resourceFactory = $resourceFactory;
$this->resourceConnection = $resourceConnection;
$this->metadataPool = $metadataPool;
}

/**
* Check if status has changed for given (sku, storeId)
*
* @param string $sku
* @param int $storeId
* @return bool
*/
public function isStatusChanged(string $sku, int $storeId): bool
{
$sku = strtolower($sku);
if (!isset($this->newData[$sku][$storeId])) {
$changed = false;
} elseif (!isset($this->oldData[$sku][$storeId])) {
$changed = true;
} else {
$oldStatus = (int) $this->oldData[$sku][$storeId];
$newStatus = (int) $this->newData[$sku][$storeId];
$changed = $oldStatus !== $newStatus;
}
return $changed;
}

/**
* Load old status data
*
* @param array $linkIdBySku
*/
public function loadOldStatus(array $linkIdBySku): void
{
$connection = $this->resourceConnection->getConnection();
$linkId = $this->getProductEntityLinkField();
$select = $connection->select()
->from($this->getAttribute()->getBackend()->getTable())
->columns([$linkId, 'store_id', 'value'])
->where(sprintf('%s IN (?)', $linkId), array_values($linkIdBySku));
$skuByLinkId = array_flip($linkIdBySku);

foreach ($connection->fetchAll($select) as $item) {
if (isset($skuByLinkId[$item[$linkId]])) {
$this->oldData[$skuByLinkId[$item[$linkId]]][$item['store_id']] = $item['value'];
}
}
}

/**
* Set SKU status for given storeId
*
* @param string $sku
* @param string $storeId
* @param int $value
*/
public function setStatus(string $sku, string $storeId, int $value): void
{
$sku = strtolower($sku);
$this->newData[$sku][$storeId] = $value;
}

/**
* Get product entity link field.
*
* @return string
*/
private function getProductEntityLinkField()
{
if (!$this->productEntityLinkField) {
$this->productEntityLinkField = $this->metadataPool->getMetadata(ProductInterface::class)->getLinkField();
}

return $this->productEntityLinkField;
}

/**
* Get Attribute model
*
* @return AbstractAttribute
*/
private function getAttribute(): AbstractAttribute
{
if ($this->attribute === null) {
$this->attribute = $this->resourceFactory->create()->getAttribute(self::ATTRIBUTE_CODE);
}
return $this->attribute;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);

namespace Magento\CatalogImportExport\Model\Import\Product;

use Magento\Framework\Indexer\IndexerRegistry;

/**
* Imported product stock manager
*/
class StockProcessor
{
/**
* @var IndexerRegistry
*/
private $indexerRegistry;
/**
* @var array
*/
private $indexers;

/**
* Initializes dependencies.
*
* @param IndexerRegistry $indexerRegistry
* @param array $indexers
*/
public function __construct(
IndexerRegistry $indexerRegistry,
array $indexers = []
) {
$this->indexerRegistry = $indexerRegistry;
$this->indexers = array_filter($indexers);
}

/**
* Reindex products by ids
*
* @param array $ids
* @return void
*/
public function reindexList(array $ids = []): void
{
if ($ids) {
foreach ($this->indexers as $indexerName) {
$indexer = $this->indexerRegistry->get($indexerName);
if (!$indexer->isScheduled()) {
$indexer->reindexList($ids);
}
}
}
}
}
Loading

0 comments on commit e9cb043

Please sign in to comment.