Skip to content

Create a single point of stock data processing #19

@naydav

Description

@naydav

Full context in documentation

[HLD] Inconsistent saving of Stock Data

Description

1. Unite logic in a single processing point

The logic of the following classes:

  • \Magento\CatalogInventory\Model\Plugin\AroundProductRepositorySave
  • \Magento\CatalogInventory\Observer\SaveInventoryDataObserver
    should be united in a single "processing" point. It could be a SaveInventoryProcessor class, like in the example below.

PAY ATTENTION: this logic is needed ONLY for BI (saving stock item data on product save). In proper way, we need to save StockItem only via StockItemRepositoryInterface
Also, we now save via stockregistry only for BI.

/**
 *  Dockblock like as "this logic is needed ONLY for BI (saving stock item data on product save). In propel way, we need to save StockItem only via StockItemRepository"
 */
class SaveInventoryProcessor (NOT INTERFACE)
{
    /**
     * Saving product inventory data
     *
     * @param Product $product
     * @return $this
     * @throws LocalizedException
     */
    public function execute(Product $product)
    {
        $stockItem = $this->getStockItemToBeUpdated($product);
        if (null !== $stockItem) {
            $stockItem->setProductId($product->getId());
            $stockItem->setWebsiteId($this->stockConfiguration->getDefaultScopeId());
            $this->stockItemValidator->validate($product, $stockItem);
            $this->stockRegistry->updateStockItemBySku($product->getSku(), $stockItem);
        }
        return $this;
    }
    
    /**
     * Return the stock item that needs to be updated
     *
     * @param ProductInterface $product
     * @return StockItemInterface|null
     */
    private function getStockItemToBeUpdated($product)
    {
        $stockItem = null;
        $extendedAttributes = $product->getExtensionAttributes();
        if ($extendedAttributes !== null) {
            $stockItem = $extendedAttributes->getStockItem();
        }
    
        if ($stockItem === null) {
            $stockItem = $this->stockRegistry->getStockItem($product->getId());
        }
        return $stockItem;
    }
}

The processing logic of saving data via model and via product repository must be the same!

2. Move validation logic from ProductRepositoryPlugin to a separate class.

For example:

<?php
/**
 * Copyright © 2016 Magento. All rights reserved.
 * See COPYING.txt for license details.
 */
namespace Magento\CatalogInventory\Model;

use Magento\Catalog\Api\Data\ProductInterface;
use Magento\CatalogInventory\Api\Data\StockItemInterface;
use Magento\CatalogInventory\Api\StockConfigurationInterface;
use Magento\CatalogInventory\Api\StockRegistryInterface;
use Magento\Framework\Exception\LocalizedException;

/**
 * StockItemValidator
 */
class StockItemValidator (NOT INTERFACE)
{
    /**
     * @var StockConfigurationInterface
     */
    private $stockConfiguration;

    /**
     * @var StockRegistryInterface
     */
    private $stockRegistry;

    /**
     * @param StockConfigurationInterface $stockConfiguration
     * @param StockRegistryInterface $stockRegistry
     */
    public function _construct(
        StockConfigurationInterface $stockConfiguration,
        StockRegistryInterface $stockRegistry
    ) {
        $this->stockConfiguration = $stockConfiguration;
        $this->stockRegistry = $stockRegistry;
    }

    /**
     * @param ProductInterface $product
     * @param StockItemInterface $stockItem
     * @throws LocalizedException
     * @return void
     */
    public function validate(ProductInterface $product, StockItemInterface $stockItem)
    {
        $defaultScopeId = $this->stockConfiguration->getDefaultScopeId();
        $defaultStockId = (int)$this->stockRegistry->getStock($defaultScopeId)->getStockId();
        $stockId = (int)$stockItem->getStockId();
        if ($stockId !== null && $stockId !== $defaultStockId) {
            throw new LocalizedException(
                __('Invalid stock id: %1. Only default stock with id %2 allowed', $stockId, $defaultStockId)
            );
        }

        $stockItemId = $stockItem->getItemId();
        if ($stockItemId !== null && (!is_numeric($stockItemId) || $stockItemId <= 0)) {
            throw new LocalizedException(
                __('Invalid stock item id: %1. Should be null or numeric value greater than 0', $stockItemId)
            );
        }

        $defaultStockItemId = $this->stockRegistry->getStockItem($product->getId())->getItemId();
        if ($defaultStockItemId && $stockItemId !== null && $defaultStockItemId !== $stockItemId) {
            throw new LocalizedException(
                __('Invalid stock item id: %1. Assigned stock item id is %2', $stockItemId, $defaultStockItemId)
            );
        }
    }
}

Also need to investigate about moving this logic in StockItemRepository

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions