Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MSI: Update old StockItem and Stock Status DB table at the time of Reservation appended #170

Merged
merged 13 commits into from
Nov 22, 2017
Merged
19 changes: 19 additions & 0 deletions app/code/Magento/InventoryApi/Test/_files/products.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,32 @@
$productRepository = $objectManager->get(ProductRepositoryInterface::class);
$productRepository->cleanCache();

$stockData = [
'SKU-1' => [
'qty' => 8.5,
'is_in_stock' => true,
'manage_stock' => true
],
'SKU-2' => [
'qty' => 5,
'is_in_stock' => true,
'manage_stock' => true
],
'SKU-3' => [
'qty' => 0,
'is_in_stock' => false,
'manage_stock' => true
]
];

for ($i = 1; $i <= 3; $i++) {
$product = $productFactory->create();
$product->setTypeId(Type::TYPE_SIMPLE)
->setAttributeSetId(4)
->setName('Simple Product ' . $i)
->setSku('SKU-' . $i)
->setPrice(10)
->setStockData($stockData['SKU-' . $i])
->setStatus(Status::STATUS_ENABLED);
$productRepository->save($product);
}
15 changes: 15 additions & 0 deletions app/code/Magento/InventoryApi/Test/_files/products_rollback.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
* See COPYING.txt for license details.
*/
use Magento\Catalog\Api\ProductRepositoryInterface;
use Magento\CatalogInventory\Api\StockStatusCriteriaInterfaceFactory;
use Magento\CatalogInventory\Api\StockStatusRepositoryInterface;
use Magento\Framework\Registry;
use Magento\TestFramework\Helper\Bootstrap;

Expand All @@ -12,12 +14,25 @@
$productRepository = $objectManager->create(ProductRepositoryInterface::class);
/** @var Registry $registry */
$registry = $objectManager->get(Registry::class);
/** @var StockStatusRepositoryInterface $stockStatusRepository */
$stockStatusRepository = $objectManager->create(StockStatusRepositoryInterface::class);
/** @var StockStatusCriteriaInterfaceFactory $stockStatusCriteriaFactory */
$stockStatusCriteriaFactory = $objectManager->create(StockStatusCriteriaInterfaceFactory::class);

$currentArea = $registry->registry('isSecureArea');
$registry->unregister('isSecureArea');
$registry->register('isSecureArea', true);

for ($i = 1; $i <= 3; $i++) {
$product = $productRepository->get('SKU-' . $i);
/** @var \Magento\CatalogInventory\Api\StockStatusCriteriaInterfaceFactory $stockStatusCriteriaFactory **/
$criteria = $stockStatusCriteriaFactory->create();
$criteria->setProductsFilter($product->getId());

$result = $stockStatusRepository->getList($criteria);
$stockStatus = current($result->getItems());
$stockStatusRepository->delete($stockStatus);

$productRepository->deleteById('SKU-' . $i);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/

namespace Magento\InventoryCatalog\Plugin\Model;

use Magento\Framework\App\ResourceConnection;
use Magento\InventoryApi\Api\Data\ReservationInterface;
use Magento\InventoryApi\Api\ReservationsAppendInterface;
use Magento\Catalog\Api\ProductRepositoryInterface;
use Magento\CatalogInventory\Api\StockRegistryInterface;

/**
* Plugin help to fill the legacy catalog inventory tables cataloginventory_stock_status and
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

helpS

* cataloginventory_stock_item to don't break the backward compatible.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to don't break the backward compatible. ->
to prevent breaking the backward compatibility

*/
class UpdateLegacyCatalogInventoryPlugin
{

/**
* @var ResourceConnection
*/
private $resourceConnection;

/**
* @var ProductRepositoryInterface
*/
private $productRepository;

/**
* @var \Magento\CatalogInventory\Api\StockRegistryInterface
*/
private $stockRegistry;

/**
* @param ResourceConnection $resourceConnection
* @param ProductRepositoryInterface $productRepository
* @param StockRegistryInterface $stockRegistry
*/
public function __construct(
ResourceConnection $resourceConnection,
ProductRepositoryInterface $productRepository,
StockRegistryInterface $stockRegistry
) {
$this->resourceConnection = $resourceConnection;
$this->productRepository = $productRepository;
$this->stockRegistry = $stockRegistry;
}

/**
* Plugin method to fill the legacy tables.
*
* @param ReservationsAppendInterface $subject
* @param void $result
* @param ReservationInterface[] $reservations
*
* @see ReservationsAppendInterface::execute
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
* @return void
*/
public function afterExecute(ReservationsAppendInterface $subject, $result, array $reservations)
{
$this->updateStockItemAndStatusTable($reservations);
return $result;
}

/**
* Updates cataloginventory_stock_item and cataloginventory_stock_status qty with reservation information.
*
* @param ReservationInterface[] $reservations
* @return void
*/
private function updateStockItemAndStatusTable(array $reservations)
{
foreach ($reservations as $reservation) {
$sku = $reservation->getSku();
$stockItem = $this->stockRegistry->getStockItemBySku($sku);
$stockItem->setQty($stockItem->getQty() + $reservation->getQuantity());
$this->stockRegistry->updateStockItemBySku($sku, $stockItem);

$stockStatus = $this->stockRegistry->getStockStatus($stockItem->getProductId());
$stockStatus->setQty($stockStatus->getQty() + $reservation->getQuantity());
$stockStatus->save();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/

namespace Magento\InventoryCatalog\Test\Integration;

use Magento\Catalog\Api\ProductRepositoryInterface;
use Magento\Catalog\Model\Product;
use Magento\InventoryApi\Api\ReservationBuilderInterface;
use Magento\InventoryApi\Api\ReservationsAppendInterface;
use PHPUnit\Framework\TestCase;
use Magento\TestFramework\Helper\Bootstrap;
use Magento\CatalogInventory\Api\StockItemRepositoryInterface;
use Magento\CatalogInventory\Api\StockItemCriteriaInterface;
use Magento\CatalogInventory\Api\StockItemCriteriaInterfaceFactory;
use Magento\CatalogInventory\Api\Data\StockItemCollectionInterface;
use Magento\CatalogInventory\Api\Data\StockItemInterface;
use Magento\InventoryApi\Api\GetProductQuantityInStockInterface;
use Magento\Indexer\Model\Indexer;
use Magento\Inventory\Indexer\SourceItem\SourceItemIndexer;

class UpdateLegacyCatalogInventoryPluginTest extends TestCase
{
/**
* @var ReservationBuilderInterface
*/
private $reservationBuilder;

/**
* @var ReservationsAppendInterface
*/
private $reservationsAppend;

/**
* @var StockItemRepositoryInterface
*/
private $oldStockItemRepository;

/**
* @var StockItemCriteriaInterfaceFactory
*/
private $stockItemCriteriaFactory;

/**
* @var GetProductQuantityInStockInterface
*/
private $getProductQtyInStock;

/**
* @var IndexerInterface
*/
private $indexer;

/**
* @var ProductRepositoryInterface
*/
private $productRepository;

protected function setUp()
{
$this->reservationBuilder = Bootstrap::getObjectManager()->get(ReservationBuilderInterface::class);
$this->reservationsAppend = Bootstrap::getObjectManager()->get(ReservationsAppendInterface::class);
$this->oldStockItemRepository = Bootstrap::getObjectManager()->get(StockItemRepositoryInterface::class);
$this->stockItemCriteriaFactory = Bootstrap::getObjectManager()->get(StockItemCriteriaInterfaceFactory::class);

$this->indexer = Bootstrap::getObjectManager()->get(Indexer::class);
$this->indexer->load(SourceItemIndexer::INDEXER_ID);
$this->getProductQtyInStock = Bootstrap::getObjectManager()->get(GetProductQuantityInStockInterface::class);
$this->productRepository = Bootstrap::getObjectManager()->get(ProductRepositoryInterface::class);
}

/**
* @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/source_items.php
* @magentoDataFixture ../../../../app/code/Magento/InventoryApi/Test/_files/stock_source_link.php
*/
public function testUpdateStockItemTable()
{
$reservationQuantity = -5;

/** @var Product $product */
$product = $this->productRepository->get('SKU-1');

/** @var StockItemCriteriaInterface $criteria */
$criteria = $this->stockItemCriteriaFactory->create();
$criteria->setProductsFilter([$product->getId()]);

/** @var StockItemCollectionInterface $collectionBeforeChange */
$collectionBeforeChange = $this->oldStockItemRepository->getList($criteria);
/** @var StockItemInterface $oldStockItem */
$oldStockItem = current($collectionBeforeChange->getItems());
$initialQuantity = $oldStockItem->getQty();

$this->reservationsAppend->execute([
$this->reservationBuilder->setStockId(1)->setSku('SKU-1')->setQuantity($reservationQuantity)->build()
]);

/** @var StockItemCollectionInterface $collectionAfterChange */
$collectionAfterChange = $this->oldStockItemRepository->getList($criteria);
$oldStockItem = current($collectionAfterChange->getItems());
$quantityAfterCheck = $oldStockItem->getQty();

$this->assertEquals($initialQuantity + $reservationQuantity, $quantityAfterCheck);
}

/**
* @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/source_items.php
* @magentoDataFixture ../../../../app/code/Magento/InventoryApi/Test/_files/stock_source_link.php
*/
public function testThatReservationPlacedUpdatesBothOldAndNewStocks()
{
$this->productRepository = Bootstrap::getObjectManager()->get(ProductRepositoryInterface::class);
$reservationQuantity = -5;

$this->indexer->reindexAll();
$this->assertEquals(8.5, $this->getProductQtyInStock->execute('SKU-1', 10));

/** @var Product $product */
$product = $this->productRepository->get('SKU-1');

/** @var StockItemCriteriaInterface $criteria */
$criteria = $this->stockItemCriteriaFactory->create();
$criteria->setProductsFilter([$product->getId()]);

/** @var StockItemCollectionInterface $collectionBeforeChange */
$collectionBeforeChange = $this->oldStockItemRepository->getList($criteria);

/** @var StockItemInterface $oldStockItem */
$oldStockItem = current($collectionBeforeChange->getItems());
$initialQuantity = $oldStockItem->getQty();
$this->assertEquals(8.5, $initialQuantity);

$this->reservationsAppend->execute([
$this->reservationBuilder->setStockId(10)->setSku('SKU-1')->setQuantity($reservationQuantity)->build()
]);

/** @var StockItemCollectionInterface $collectionAfterChange */
$collectionAfterChange = $this->oldStockItemRepository->getList($criteria);
$oldStockItem = current($collectionAfterChange->getItems());
$quantityAfterCheck = $oldStockItem->getQty();

$this->assertEquals(8.5 - 5, $this->getProductQtyInStock->execute('SKU-1', 10));
$this->assertEquals($this->getProductQtyInStock->execute('SKU-1', 10), $quantityAfterCheck);
}
}
3 changes: 3 additions & 0 deletions app/code/Magento/InventoryCatalog/etc/di.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,7 @@
<plugin name="prevent_assigned_to_sales_channels_stock_deleting"
type="Magento\InventoryCatalog\Plugin\InventoryApi\StockRepository\PreventDeleting\AssignedToSalesChannelsStockPlugin"/>
</type>
<type name="Magento\InventoryApi\Api\ReservationsAppendInterface">
<plugin name="update_legacy_catalog_inventory_plugin" type="Magento\InventoryCatalog\Plugin\Model\UpdateLegacyCatalogInventoryPlugin"/>
</type>
</config>