Skip to content

Commit

Permalink
Merge pull request magento#171 from magento-engcom/prevent-delete-sto…
Browse files Browse the repository at this point in the history
…ck-sales-channel

Stock Removal. Throw an exception and allow to delete just unassigned stocks
  • Loading branch information
Valeriy Nayda authored Nov 10, 2017
2 parents ad75612 + ca0caa2 commit fc4a71b
Show file tree
Hide file tree
Showing 8 changed files with 136 additions and 17 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);

namespace Magento\InventoryCatalog\Plugin\InventoryApi\StockRepository\PreventDeleting;

use Magento\Framework\Exception\CouldNotDeleteException;
use Magento\InventoryApi\Api\StockRepositoryInterface;
use Magento\InventorySales\Model\GetAssignedSalesChannelsForStockInterface;

/**
* Prevent deleting of Stock which assigned at least one Sales Channel
*/
class AssignedToSalesChannelsStockPlugin
{
/**
* @var GetAssignedSalesChannelsForStockInterface
*/
private $assignedSalesChannelsForStock;

/**
* @param GetAssignedSalesChannelsForStockInterface $assignedSalesChannelsForStock
*/
public function __construct(
GetAssignedSalesChannelsForStockInterface $assignedSalesChannelsForStock
) {
$this->assignedSalesChannelsForStock = $assignedSalesChannelsForStock;
}

/**
* Prevent deleting of Stock which assigned at least one Sales Channel
*
* @param StockRepositoryInterface $subject
* @param int $stockId
* @return void
* @throws CouldNotDeleteException
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
public function beforeDeleteById(StockRepositoryInterface $subject, int $stockId)
{
$assignSalesChannels = $this->assignedSalesChannelsForStock->execute($stockId);
if (count($assignSalesChannels)) {
throw new CouldNotDeleteException(__('Stock has at least one sale channel and could not be deleted.'));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,18 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);

namespace Magento\InventoryCatalog\Plugin\Model;
namespace Magento\InventoryCatalog\Plugin\InventoryApi\StockRepository\PreventDeleting;

use Magento\Framework\Exception\CouldNotDeleteException;
use Magento\InventoryApi\Api\StockRepositoryInterface;
use Magento\InventoryCatalog\Api\DefaultStockProviderInterface;

/**
* Class provide Before Plugin on StockRepositoryInterface::deleteByItem to prevent default stock could be deleted
* Prevent deleting of Default Stock
*/
class StockRepositoryPlugin
class DefaultStockPlugin
{
/**
* @var DefaultStockProviderInterface
Expand All @@ -23,17 +24,17 @@ class StockRepositoryPlugin
/**
* @param DefaultStockProviderInterface $defaultStockProvider
*/
public function __construct(DefaultStockProviderInterface $defaultStockProvider)
{
public function __construct(
DefaultStockProviderInterface $defaultStockProvider
) {
$this->defaultStockProvider = $defaultStockProvider;
}

/**
* Prevent default source to be deleted
* Prevent deleting of Default Stock
*
* @param StockRepositoryInterface $subject
* @param int $stockId
*
* @return void
* @throws CouldNotDeleteException
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);

namespace Magento\InventoryCatalog\Test\Api\StockRepository;

use Magento\Framework\Webapi\Exception;
use Magento\Framework\Webapi\Rest\Request;
use Magento\TestFramework\TestCase\WebapiAbstract;

class PreventAssignedToSalesChannelsStockDeletingTest extends WebapiAbstract
{
/**
* @magentoApiDataFixture ../../../../app/code/Magento/InventorySalesApi/Test/_files/stock_with_sales_channels.php
* @throws \Exception
*/
public function testCouldNotDeleteException()
{
$stockId = 10;
$serviceInfo = [
'rest' => [
'resourcePath' => '/V1/inventory/stock/' . $stockId,
'httpMethod' => Request::HTTP_METHOD_DELETE,
],
'soap' => [
'service' => 'inventoryApiStockRepositoryV1',
'operation' => 'inventoryApiStockRepositoryV1DeleteById',
],
];
$expectedMessage = 'Stock has at least one sale channel and could not be deleted.';
try {
(TESTS_WEB_API_ADAPTER == self::ADAPTER_REST)
? $this->_webApiCall($serviceInfo)
: $this->_webApiCall($serviceInfo, ['stockId' => $stockId]);
$this->fail('Expected throwing exception');
} catch (\Exception $e) {
if (TESTS_WEB_API_ADAPTER == self::ADAPTER_REST) {
$errorData = $this->processRestExceptionResult($e);
self::assertEquals($expectedMessage, $errorData['message']);
self::assertEquals(Exception::HTTP_BAD_REQUEST, $e->getCode());
} elseif (TESTS_WEB_API_ADAPTER == self::ADAPTER_SOAP) {
$this->assertInstanceOf('SoapFault', $e);
$this->checkSoapFault($e, $expectedMessage, 'env:Sender');
} else {
throw $e;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);

namespace Magento\InventoryCatalog\Test\Api\StockRepository;

Expand All @@ -12,10 +13,7 @@
use Magento\TestFramework\Helper\Bootstrap;
use Magento\InventoryCatalog\Api\DefaultStockProviderInterface;

/**
* Class CouldNotDeleteDefaultStockExceptionTest
*/
class CouldNotDeleteDefaultStockExceptionTest extends WebapiAbstract
class PreventDefaultStockDeletingTest extends WebapiAbstract
{
/**
* @var DefaultStockProviderInterface
Expand All @@ -32,8 +30,6 @@ protected function setUp()
}

/**
* Test that default Stock could not be deleted
*
* @throws \Exception
*/
public function testCouldNotDeleteException()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);

namespace Magento\InventoryCatalog\Ui\Component\Control\Stock;

Expand All @@ -11,10 +12,11 @@
use Magento\InventoryApi\Api\Data\StockInterface;
use Magento\InventoryCatalog\Api\DefaultStockProviderInterface;
use Magento\Framework\App\RequestInterface;
use Magento\InventorySales\Model\GetAssignedSalesChannelsForStockInterface;

/**
* Represents delete button with pre-configured options
* Provide an ability to show delete button only when stock id is not default
* Provide an ability to show delete button only when stock id is not default or doesn't have assigned sales channels
*/
class DeleteButton implements ButtonProviderInterface
{
Expand All @@ -28,6 +30,11 @@ class DeleteButton implements ButtonProviderInterface
*/
private $defaultStockProvider;

/**
* @var GetAssignedSalesChannelsForStockInterface
*/
private $assignedSalesChannelsForStock;

/**
* @var RequestInterface
*/
Expand All @@ -36,15 +43,18 @@ class DeleteButton implements ButtonProviderInterface
/**
* @param StockDeleteButton $deleteButton
* @param DefaultStockProviderInterface $defaultStockProvider
* @param GetAssignedSalesChannelsForStockInterface $assignedSalesChannelsForStock
* @param RequestInterface $request
*/
public function __construct(
StockDeleteButton $deleteButton,
DefaultStockProviderInterface $defaultStockProvider,
GetAssignedSalesChannelsForStockInterface $assignedSalesChannelsForStock,
RequestInterface $request
) {
$this->deleteButton = $deleteButton;
$this->defaultStockProvider = $defaultStockProvider;
$this->assignedSalesChannelsForStock = $assignedSalesChannelsForStock;
$this->request = $request;
}

Expand All @@ -53,7 +63,9 @@ public function __construct(
*/
public function getButtonData()
{
if ((int)$this->request->getParam(StockInterface::STOCK_ID) === $this->defaultStockProvider->getId()) {
$stockId = (int)$this->request->getParam(StockInterface::STOCK_ID);
$assignSalesChannels = $this->assignedSalesChannelsForStock->execute($stockId);
if ($stockId === $this->defaultStockProvider->getId() || count($assignSalesChannels)) {
return [];
}

Expand Down
5 changes: 4 additions & 1 deletion app/code/Magento/InventoryCatalog/etc/di.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
<preference for="Magento\InventoryCatalog\Api\DefaultStockProviderInterface" type="Magento\InventoryCatalog\Model\DefaultStockProvider"/>
<preference for="Magento\InventoryCatalog\Api\DefaultSourceProviderInterface" type="Magento\InventoryCatalog\Model\DefaultSourceProvider"/>
<type name="Magento\InventoryApi\Api\StockRepositoryInterface">
<plugin name="prevent_default_stock_deletion" type="Magento\InventoryCatalog\Plugin\Model\StockRepositoryPlugin" sortOrder="1"/>
<plugin name="prevent_default_stock_deleting"
type="Magento\InventoryCatalog\Plugin\InventoryApi\StockRepository\PreventDeleting\DefaultStockPlugin"/>
<plugin name="prevent_assigned_to_sales_channels_stock_deleting"
type="Magento\InventoryCatalog\Plugin\InventoryApi\StockRepository\PreventDeleting\AssignedToSalesChannelsStockPlugin"/>
</type>
</config>
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,10 @@

/** @var StockRepositoryInterface $stockRepository */
$stockRepository = Bootstrap::getObjectManager()->get(StockRepositoryInterface::class);

// Firstly clear relations with sales channels
$stock = $stockRepository->get(10);
$stock->getExtensionAttributes()->setSalesChannels([]);
$stockRepository->save($stock);

$stockRepository->deleteById(10);
2 changes: 1 addition & 1 deletion dev/tests/integration/phpunit.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
<!-- Semicolon-separated 'glob' patterns, that match global XML configuration files -->
<const name="TESTS_GLOBAL_CONFIG_DIR" value="../../../app/etc"/>
<!-- Whether to cleanup the application before running tests or not -->
<const name="TESTS_CLEANUP" value="0"/>
<const name="TESTS_CLEANUP" value="enabled"/>
<!-- Memory usage and estimated leaks thresholds -->
<!--<const name="TESTS_MEM_USAGE_LIMIT" value="1024M"/>-->
<const name="TESTS_MEM_LEAK_LIMIT" value=""/>
Expand Down

0 comments on commit fc4a71b

Please sign in to comment.