Skip to content

Commit

Permalink
Merge pull request magento#1077 from magento-engcom/793
Browse files Browse the repository at this point in the history
MSI-793: Incorrect process of Out-of-Stock Threshold
  • Loading branch information
Valeriy Nayda committed May 15, 2018
2 parents 048c043 + 049e2cb commit 5a39a61
Show file tree
Hide file tree
Showing 7 changed files with 262 additions and 128 deletions.

This file was deleted.

@@ -0,0 +1,74 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);

namespace Magento\InventoryCatalog\Model\SourceItem;

use Magento\Framework\Exception\CouldNotSaveException;
use Magento\Framework\Exception\InputException;
use Magento\Framework\Validation\ValidationException;
use Magento\Inventory\Model\ResourceModel\SourceItem\SaveMultiple;
use Magento\Inventory\Model\SourceItem\Validator\SourceItemsValidator;
use Magento\InventoryApi\Api\SourceItemsSaveInterface;
use Psr\Log\LoggerInterface;

/**
* @inheritdoc
*/
class SourceItemsSave implements SourceItemsSaveInterface
{
/**
* @var SourceItemsValidator
*/
private $sourceItemsValidator;

/**
* @var SaveMultiple
*/
private $saveMultiple;

/**
* @var LoggerInterface
*/
private $logger;

/**
* @param SourceItemsValidator $sourceItemsValidator
* @param SaveMultiple $saveMultiple
* @param LoggerInterface $logger
*/
public function __construct(
SourceItemsValidator $sourceItemsValidator,
SaveMultiple $saveMultiple,
LoggerInterface $logger
) {
$this->sourceItemsValidator = $sourceItemsValidator;
$this->saveMultiple = $saveMultiple;
$this->logger = $logger;
}

/**
* @inheritdoc
*/
public function execute(array $sourceItems)
{
if (empty($sourceItems)) {
throw new InputException(__('Input data is empty'));
}

$validationResult = $this->sourceItemsValidator->validate($sourceItems);
if (!$validationResult->isValid()) {
throw new ValidationException(__('Validation Failed'), null, 0, $validationResult);
}

try {
$this->saveMultiple->execute($sourceItems);
} catch (\Exception $e) {
$this->logger->error($e->getMessage());
throw new CouldNotSaveException(__('Could not save Source Item'), $e);
}
}
}
Expand Up @@ -7,17 +7,27 @@

namespace Magento\InventoryCatalog\Plugin\InventoryApi;

use Magento\CatalogInventory\Api\Data\StockItemInterface;
use Magento\CatalogInventory\Api\StockItemRepositoryInterface;
use Magento\CatalogInventory\Api\StockItemCriteriaInterfaceFactory;
use Magento\CatalogInventory\Model\Indexer\Stock\Processor;
use Magento\CatalogInventory\Model\Spi\StockStateProviderInterface;
use Magento\CatalogInventory\Model\Stock;
use Magento\Framework\Exception\InputException;
use Magento\InventoryApi\Api\Data\SourceItemInterface;
use Magento\InventoryApi\Api\SourceItemsSaveInterface;
use Magento\InventoryCatalogApi\Api\DefaultSourceProviderInterface;
use Magento\InventoryCatalogApi\Model\GetProductIdsBySkusInterface;
use Magento\InventoryCatalogApi\Model\GetProductTypesBySkusInterface;
use Magento\InventoryCatalog\Model\ResourceModel\SetDataToLegacyStockItem;
use Magento\InventoryCatalog\Model\ResourceModel\SetDataToLegacyStockStatus;
use Magento\InventorySalesApi\Api\IsProductSalableInterface;
use Magento\InventoryCatalogApi\Api\DefaultStockProviderInterface;
use Magento\InventoryConfigurationApi\Model\IsSourceItemManagementAllowedForProductTypeInterface;

/**
* Set Qty and status for legacy CatalogInventory Stock Status and Stock Item DB tables,
* if corresponding MSI SourceItem assigned to Default Source has been saved
*
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
* TODO: https://github.com/magento-engcom/msi/pull/1082/
*/
class SetDataToLegacyCatalogInventoryAtSourceItemsSavePlugin
{
Expand All @@ -32,75 +42,149 @@ class SetDataToLegacyCatalogInventoryAtSourceItemsSavePlugin
private $setDataToLegacyStockItem;

/**
* @var SetDataToLegacyStockStatus
* @var StockItemCriteriaInterfaceFactory
*/
private $setDataToLegacyStockStatus;
private $legacyStockItemCriteriaFactory;

/**
* @var IsProductSalableInterface
* @var StockItemRepositoryInterface
*/
private $isProductSalable;
private $legacyStockItemRepository;

/**
* @var DefaultStockProviderInterface
* @var GetProductIdsBySkusInterface
*/
private $defaultStockProvider;
private $getProductIdsBySkus;

/**
* @var StockStateProviderInterface
*/
private $stockStateProvider;

/**
* @var Processor
*/
private $indexerProcessor;

/**
* @var IsSourceItemManagementAllowedForProductTypeInterface
*/
private $isSourceItemsAllowedForProductType;

/**
* @var GetProductTypesBySkusInterface
*/
private $getProductTypeBySku;

/**
* @param DefaultSourceProviderInterface $defaultSourceProvider
* @param SetDataToLegacyStockItem $setDataToLegacyStockItem
* @param SetDataToLegacyStockStatus $setDataToLegacyStockStatus
* @param IsProductSalableInterface $isProductSalable
* @param DefaultStockProviderInterface $defaultStockProvider
* @param StockItemCriteriaInterfaceFactory $legacyStockItemCriteriaFactory
* @param StockItemRepositoryInterface $legacyStockItemRepository
* @param GetProductIdsBySkusInterface $getProductIdsBySkus
* @param StockStateProviderInterface $stockStateProvider
* @param Processor $indexerProcessor
* @param IsSourceItemManagementAllowedForProductTypeInterface $isSourceItemsAllowedForProductType
* @param GetProductTypesBySkusInterface $getProductTypeBySku
*/
public function __construct(
DefaultSourceProviderInterface $defaultSourceProvider,
SetDataToLegacyStockItem $setDataToLegacyStockItem,
SetDataToLegacyStockStatus $setDataToLegacyStockStatus,
IsProductSalableInterface $isProductSalable,
DefaultStockProviderInterface $defaultStockProvider
StockItemCriteriaInterfaceFactory $legacyStockItemCriteriaFactory,
StockItemRepositoryInterface $legacyStockItemRepository,
GetProductIdsBySkusInterface $getProductIdsBySkus,
StockStateProviderInterface $stockStateProvider,
Processor $indexerProcessor,
IsSourceItemManagementAllowedForProductTypeInterface $isSourceItemsAllowedForProductType,
GetProductTypesBySkusInterface $getProductTypeBySku
) {
$this->defaultSourceProvider = $defaultSourceProvider;
$this->setDataToLegacyStockItem = $setDataToLegacyStockItem;
$this->setDataToLegacyStockStatus = $setDataToLegacyStockStatus;
$this->isProductSalable = $isProductSalable;
$this->defaultStockProvider = $defaultStockProvider;
$this->legacyStockItemCriteriaFactory = $legacyStockItemCriteriaFactory;
$this->legacyStockItemRepository = $legacyStockItemRepository;
$this->getProductIdsBySkus = $getProductIdsBySkus;
$this->stockStateProvider = $stockStateProvider;
$this->indexerProcessor = $indexerProcessor;
$this->isSourceItemsAllowedForProductType = $isSourceItemsAllowedForProductType;
$this->getProductTypeBySku = $getProductTypeBySku;
}

/**
* @param SourceItemsSaveInterface $subject
* @param void $result
* @param SourceItemInterface[] $sourceItems
* @return void
* @see SourceItemsSaveInterface::execute
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
public function afterExecute(SourceItemsSaveInterface $subject, $result, array $sourceItems)
public function afterExecute(SourceItemsSaveInterface $subject, $result, array $sourceItems): void
{
$productIds = [];
foreach ($sourceItems as $sourceItem) {
if ($sourceItem->getSourceCode() !== $this->defaultSourceProvider->getCode()) {
continue;
}

$sku = $sourceItem->getSku();

try {
$productId = (int)$this->getProductIdsBySkus->execute([$sku])[$sku];
} catch (InputException $e) {
// Saving source item data for not existed product
continue;
}

$typeId = $this->getProductTypeBySku->execute([$sku])[$sku];
if (false === $this->isSourceItemsAllowedForProductType->execute($typeId)) {
continue;
}

$legacyStockItem = $this->getLegacyStockItem($productId);
if (null === $legacyStockItem) {
continue;
}

$isInStock = (int)$sourceItem->getStatus();

if ($legacyStockItem->getManageStock()) {
$legacyStockItem->setIsInStock($isInStock);
$legacyStockItem->setQty((float)$sourceItem->getQuantity());

if (false === $this->stockStateProvider->verifyStock($legacyStockItem)) {
$isInStock = 0;
}
}

$this->setDataToLegacyStockItem->execute(
$sourceItem->getSku(),
(float)$sourceItem->getQuantity(),
(int)$sourceItem->getStatus()
);
$this->setDataToLegacyStockStatus->execute(
$sourceItem->getSku(),
(float)$sourceItem->getQuantity(),
(int)$sourceItem->getStatus()
);
/**
* We need to call setDataToLegacyStockStatus second time because we don't have On Save re-indexation
* as cataloginventory_stock_item table updated with plane SQL queries
* Thus, initially we put the raw data there, and after that persist the calculated value
*/
$this->setDataToLegacyStockStatus->execute(
$sourceItem->getSku(),
(float)$sourceItem->getQuantity(),
(int)$this->isProductSalable->execute($sourceItem->getSku(), $this->defaultStockProvider->getId())
$isInStock
);
$productIds[] = $productId;
}

if ($productIds) {
$this->indexerProcessor->reindexList($productIds);
}
}

/**
* @param int $productId
* @return null|StockItemInterface
*/
private function getLegacyStockItem(int $productId): ?StockItemInterface
{
$searchCriteria = $this->legacyStockItemCriteriaFactory->create();

$searchCriteria->addFilter(StockItemInterface::PRODUCT_ID, StockItemInterface::PRODUCT_ID, $productId);
$searchCriteria->addFilter(StockItemInterface::STOCK_ID, StockItemInterface::STOCK_ID, Stock::DEFAULT_STOCK_ID);

$stockItemCollection = $this->legacyStockItemRepository->getList($searchCriteria);
if ($stockItemCollection->getTotalCount() === 0) {
return null;
}

$stockItems = $stockItemCollection->getItems();
$stockItem = reset($stockItems);
return $stockItem;
}
}

0 comments on commit 5a39a61

Please sign in to comment.