From effe9c335044fcf9b8b060f339d456630a3bbc96 Mon Sep 17 00:00:00 2001 From: Volodymyr Vygovskyi Date: Mon, 3 May 2021 17:39:43 +0300 Subject: [PATCH] #32540 Throw error when updating stock when auto increment is exceeded in inventory_source_item --- .../ResourceModel/SourceItem/SaveMultiple.php | 11 +- .../Handler/SourceItemsSaveHandler.php | 10 ++ .../Handler/SourceItemsSaveHandlerTest.php | 110 ++++++++++++++++++ 3 files changed, 124 insertions(+), 7 deletions(-) create mode 100644 Inventory/Test/Integration/Model/SourceItem/Command/Handler/SourceItemsSaveHandlerTest.php diff --git a/Inventory/Model/ResourceModel/SourceItem/SaveMultiple.php b/Inventory/Model/ResourceModel/SourceItem/SaveMultiple.php index 5875cfe9fed6..3f0005bef350 100755 --- a/Inventory/Model/ResourceModel/SourceItem/SaveMultiple.php +++ b/Inventory/Model/ResourceModel/SourceItem/SaveMultiple.php @@ -53,18 +53,15 @@ public function execute(array $sourceItems) SourceItemInterface::STATUS ]); $valuesSql = $this->buildValuesSqlPart($sourceItems); - $onDuplicateSql = $this->buildOnDuplicateSqlPart([ - SourceItemInterface::QUANTITY, - SourceItemInterface::STATUS, - ]); $bind = $this->getSqlBindData($sourceItems); + /* can not use "INSERT ... ON DUPLICATE KEY UPDATE" statement against a table having more than one unique + or primary key because it is unsafe */ $insertSql = sprintf( - 'INSERT INTO `%s` (%s) VALUES %s %s', + 'INSERT INTO `%s` (%s) VALUES %s', $tableName, $columnsSql, - $valuesSql, - $onDuplicateSql + $valuesSql ); $connection->query($insertSql, $bind); } diff --git a/Inventory/Model/SourceItem/Command/Handler/SourceItemsSaveHandler.php b/Inventory/Model/SourceItem/Command/Handler/SourceItemsSaveHandler.php index be2c639fd286..1bebfbd842f7 100644 --- a/Inventory/Model/SourceItem/Command/Handler/SourceItemsSaveHandler.php +++ b/Inventory/Model/SourceItem/Command/Handler/SourceItemsSaveHandler.php @@ -11,6 +11,7 @@ use Magento\Framework\Exception\CouldNotSaveException; use Magento\Framework\Exception\InputException; use Magento\Framework\Validation\ValidationException; +use Magento\Inventory\Model\ResourceModel\SourceItem\DeleteMultiple; use Magento\Inventory\Model\ResourceModel\SourceItem\SaveMultiple; use Magento\Inventory\Model\SourceItem\Validator\SourceItemsValidator; use Magento\InventoryApi\Api\Data\SourceItemInterface; @@ -36,19 +37,27 @@ class SourceItemsSaveHandler */ private $logger; + /** + * @var DeleteMultiple + */ + private $deleteMultiple; + /** * @param SourceItemsValidator $sourceItemsValidator + * @param DeleteMultiple $deleteMultiple * @param SaveMultiple $saveMultiple * @param LoggerInterface $logger */ public function __construct( SourceItemsValidator $sourceItemsValidator, + DeleteMultiple $deleteMultiple, SaveMultiple $saveMultiple, LoggerInterface $logger ) { $this->sourceItemsValidator = $sourceItemsValidator; $this->saveMultiple = $saveMultiple; $this->logger = $logger; + $this->deleteMultiple = $deleteMultiple; } /** @@ -73,6 +82,7 @@ public function execute(array $sourceItems) } try { + $this->deleteMultiple->execute($sourceItems); $this->saveMultiple->execute($sourceItems); } catch (Exception $e) { $this->logger->error($e->getMessage()); diff --git a/Inventory/Test/Integration/Model/SourceItem/Command/Handler/SourceItemsSaveHandlerTest.php b/Inventory/Test/Integration/Model/SourceItem/Command/Handler/SourceItemsSaveHandlerTest.php new file mode 100644 index 000000000000..517d1ea6994e --- /dev/null +++ b/Inventory/Test/Integration/Model/SourceItem/Command/Handler/SourceItemsSaveHandlerTest.php @@ -0,0 +1,110 @@ +sourceItemsSaveHandler = $objectManager->get(SourceItemsSaveHandler::class); + $this->sourceItemFactory = $objectManager->get(SourceItemInterfaceFactory::class); + $this->defaultSourceProvider = $objectManager->get(DefaultSourceProviderInterface::class); + } + + /** + * Make sure exception is thrown when max auto_increment in inventory_source_item is reached + * + * @magentoDataFixture Magento_InventoryApi::Test/_files/products.php + * @magentoDbIsolation disabled + */ + public function testMaxAutoIncrementIsReached(): void + { + $this->expectException(CouldNotSaveException::class); + /** @var ResourceConnection $resourceConnection */ + $resourceConnection = Bootstrap::getObjectManager()->get(ResourceConnection::class); + + //insert record with maximum increment to inventory_source_item table + $tableName = $resourceConnection->getTableName('inventory_source_item'); + $maxIncrementValue = 4294967295; + + $resourceConnection->getConnection()->insert($tableName, [ + SourceItem::ID_FIELD_NAME => $maxIncrementValue, + SourceItemInterface::SOURCE_CODE => $this->defaultSourceProvider->getCode(), + SourceItemInterface::SKU => 'dummy-sku', + SourceItemInterface::QUANTITY => 100, + SourceItemInterface::STATUS => 1 + ]); + + $sourceItemParams = [ + 'data' => [ + SourceItemInterface::SOURCE_CODE => $this->defaultSourceProvider->getCode(), + SourceItemInterface::SKU => 'SKU-1', + SourceItemInterface::QUANTITY => 100, + SourceItemInterface::STATUS => 1 + ] + ]; + + $sourceItem = $this->sourceItemFactory->create($sourceItemParams); + + $this->sourceItemsSaveHandler->execute([$sourceItem]); + } + + /** + * @inheritdoc + */ + protected function tearDown(): void + { + /** @var ResourceConnection $resourceConnection */ + $resourceConnection = Bootstrap::getObjectManager()->get(ResourceConnection::class); + $sourceItemTableName = $resourceConnection->getTableName('inventory_source_item'); + + //reset auto_increment + $resourceConnection->getConnection() + ->delete($sourceItemTableName, [SourceItemInterface::SKU . ' = (?)' => 'dummy-sku']); + $maxSourceItemIdQuery = sprintf("select max(%s) from %s", SourceItem::ID_FIELD_NAME, $sourceItemTableName); + $maxSourceItemId = $resourceConnection->getConnection()->fetchOne($maxSourceItemIdQuery); + $autoIncrementValue = (int)$maxSourceItemId + 1; + $setIncrementQuery = sprintf("ALTER TABLE %s AUTO_INCREMENT = %s", $sourceItemTableName, $autoIncrementValue); + $resourceConnection->getConnection()->query($setIncrementQuery); + + parent::tearDown(); + } +}