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

Inventory sales backorder functionality #156

Merged
merged 8 commits into from
Nov 7, 2017
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/code/Magento/InventoryApi/Test/_files/products.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
$productFactory = $objectManager->get(ProductInterfaceFactory::class);
/** @var ProductRepositoryInterface $productRepository */
$productRepository = $objectManager->get(ProductRepositoryInterface::class);
$productRepository->cleanCache();

for ($i = 1; $i <= 3; $i++) {
$product = $productFactory->create();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);

namespace Magento\InventorySales\Plugin\Model;

use Magento\CatalogInventory\Model\Stock\Item;
use Magento\InventoryApi\Api\IsProductInStockInterface;
use Magento\CatalogInventory\Model\Stock\StockItemRepository;
use Magento\CatalogInventory\Api\StockItemCriteriaInterfaceFactory;
use Magento\Catalog\Model\ProductRepository;

class BackorderStockStatusPlugin
{
/**
* @var StockItemRepository
*/
private $stockItemRepository;

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

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

public function __construct(
StockItemRepository $stockItemRepository,
StockItemCriteriaInterfaceFactory $stockItemCriteriaFactory,
ProductRepository $productRepository
) {
$this->stockItemRepository = $stockItemRepository;
$this->stockItemCriteriaFactory = $stockItemCriteriaFactory;
$this->productRepository = $productRepository;
}

/**
* Return true status if backorders is enabled for the item
*
* @param IsProductInStockInterface $subject
* @param callable $proceed
* @param string $sku
* @param int $stockId
* @return bool
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
public function aroundExecute(
IsProductInStockInterface $subject,
callable $proceed,
string $sku,
int $stockId
): bool {
$productData = $this->productRepository->get($sku);
$productId = $productData->getId();

$stockItemCriteria = $this->stockItemCriteriaFactory->create();
$stockItemCriteria->setProductsFilter($productId);
$stockItemsCollection = $this->stockItemRepository->getList($stockItemCriteria);

/** @var Item $stockItem */
$stockItem = current($stockItemsCollection->getItems());

if ($stockItem->getData('backorders') > 0) {
Copy link

Choose a reason for hiding this comment

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

Use methods from interface but not from implementation
\Magento\CatalogInventory\Api\Data\StockItemInterface::getBackorders

return true;
}

return $proceed($sku, $stockId);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\InventorySales\Test\Integration\Stock;
Copy link

Choose a reason for hiding this comment

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

Fix code style


use Magento\Catalog\Api\Data\ProductInterface;
use Magento\Catalog\Api\ProductRepositoryInterface;
use Magento\Catalog\Model\ProductRepository;
Copy link

Choose a reason for hiding this comment

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

Looks like unused dependency

use Magento\CatalogInventory\Api\Data\StockItemInterface;
use Magento\CatalogInventory\Api\StockItemCriteriaInterfaceFactory;
use Magento\CatalogInventory\Api\StockItemRepositoryInterface;
use Magento\Framework\Api\SearchCriteriaBuilder;
use Magento\Framework\Api\SearchCriteriaInterface;
use Magento\Framework\Indexer\IndexerInterface;
use Magento\Inventory\Indexer\StockItemIndexerInterface;
use Magento\InventoryApi\Api\Data\SourceItemInterface;
use Magento\InventoryApi\Api\GetProductQuantityInStockInterface;
use Magento\InventoryApi\Api\IsProductInStockInterface;
use Magento\InventoryApi\Api\SourceItemRepositoryInterface;
use Magento\InventoryApi\Api\SourceItemsSaveInterface;
use Magento\TestFramework\Helper\Bootstrap;
use PHPUnit\Framework\TestCase;

class IsBackorderedProductInStockTest extends TestCase
{
const PRODUCT_SKU = 'SKU-2';

/**
* @var SourceItemRepositoryInterface
*/
private $sourceItemRepository;

/**
* @var SearchCriteriaBuilder
*/
private $searchCriteriaBuilder;

/**
* @var SourceItemsSaveInterface
*/
private $sourceItemsSaveInterface;

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

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

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

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

/**
* @var StockItemCriteriaInterfaceFactory
*/
protected $stockItemCriteriaInterfaceFactory;

protected function setUp()
{
$this->productRepository = Bootstrap::getObjectManager()->create(ProductRepositoryInterface::class);
$this->stockItemRepository = Bootstrap::getObjectManager()->create(StockItemRepositoryInterface::class);
$this->stockItemCriteriaInterfaceFactory = Bootstrap::getObjectManager()->create(
StockItemCriteriaInterfaceFactory::class
);
$this->sourceItemRepository = Bootstrap::getObjectManager()->create(SourceItemRepositoryInterface::class);
$this->searchCriteriaBuilder = Bootstrap::getObjectManager()->create(SearchCriteriaBuilder::class);
$this->sourceItemsSaveInterface = Bootstrap::getObjectManager()->create(SourceItemsSaveInterface::class);
$this->indexer = Bootstrap::getObjectManager()->create(IndexerInterface::class);
$this->indexer->load(StockItemIndexerInterface::INDEXER_ID);
$this->isProductInStock = Bootstrap::getObjectManager()->create(
IsProductInStockInterface::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
* @magentoDbIsolation disabled
*/
public function testBackorderedZeroQtyProductIsInStock()
{
/** @var ProductInterface $product */
$product = $this->productRepository->get(self::PRODUCT_SKU);
$stockItemSearchCriteria = $this->stockItemCriteriaInterfaceFactory->create();
$stockItemSearchCriteria->setProductsFilter($product->getId());
$stockItemsCollection = $this->stockItemRepository->getList($stockItemSearchCriteria);

/** @var StockItemInterface $stockItem */
$stockItem = current($stockItemsCollection->getItems());
$stockItem->setBackorders(1);
$this->stockItemRepository->save($stockItem);

$sourceItem = $this->getSourceItemBySKU(self::PRODUCT_SKU);
$this->changeSourceItemQty($sourceItem, -15);

$this->assertTrue($this->isProductInStock->execute(self::PRODUCT_SKU, 1));
}

/**
* @magentoDbIsolation disabled
* @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 testZeroQtyProductIsOutOfStock()
{
$sourceItem = $this->getSourceItemBySKU(self::PRODUCT_SKU);
$this->changeSourceItemQty($sourceItem, 0);

$this->assertFalse($this->isProductInStock->execute(self::PRODUCT_SKU, 1));
}

/**
* @param string $sku
* @return SourceItemInterface
*/
private function getSourceItemBySKU(string $sku)
Copy link

Choose a reason for hiding this comment

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

Provide return typing

{
/** @var SearchCriteriaInterface $sourceItemSearchCriteria */
$sourceItemSearchCriteria = $this->searchCriteriaBuilder->addFilter('sku', $sku)->create();
$sourceItemSearchResult = $this->sourceItemRepository->getList($sourceItemSearchCriteria);

/** @var SourceItemInterface $sourceItem */
return current($sourceItemSearchResult->getItems());
}

/**
* @param SourceItemInterface $sourceItem
* @param $qty
Copy link

Choose a reason for hiding this comment

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

Specify type

*/
private function changeSourceItemQty(SourceItemInterface $sourceItem, $qty)
{
$sourceItem->setQuantity($qty);
$this->sourceItemsSaveInterface->execute([$sourceItem]);
$this->indexer->reindexRow(5);
}
}
12 changes: 12 additions & 0 deletions app/code/Magento/InventorySales/etc/di.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?xml version="1.0"?>
<!--
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
-->
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<type name="Magento\InventoryApi\Api\IsProductInStockInterface">
<plugin name="backorderInventoryStockStatus" type="Magento\InventorySales\Plugin\Model\BackorderStockStatusPlugin"/>
Copy link

Choose a reason for hiding this comment

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

Use underscore for mane separating

</type>
</config>