diff --git a/app/code/Magento/AsynchronousOperations/Model/BulkManagement.php b/app/code/Magento/AsynchronousOperations/Model/BulkManagement.php index 6cf0611eb28ec..4add11a41f515 100644 --- a/app/code/Magento/AsynchronousOperations/Model/BulkManagement.php +++ b/app/code/Magento/AsynchronousOperations/Model/BulkManagement.php @@ -151,28 +151,28 @@ public function retryBulk($bulkUuid, array $errorCodes) // remove corresponding operations from database (i.e. move them to 'open' status) $connection->beginTransaction(); try { - $operationIds = []; + $operationKeys = []; $currentBatchSize = 0; $maxBatchSize = 10000; /** @var OperationInterface $operation */ foreach ($retriablyFailedOperations as $operation) { if ($currentBatchSize === $maxBatchSize) { - $whereCondition = $connection->quoteInto('operation_key IN (?)', $operationIds) + $whereCondition = $connection->quoteInto('operation_key IN (?)', $operationKeys) . " AND " . $connection->quoteInto('bulk_uuid = ?', $bulkUuid); $connection->delete( $this->resourceConnection->getTableName('magento_operation'), $whereCondition ); - $operationIds = []; + $operationKeys = []; $currentBatchSize = 0; } $currentBatchSize++; - $operationIds[] = $operation->getId(); + $operationKeys[] = $operation->getOperationKey(); } // remove operations from the last batch - if (!empty($operationIds)) { - $whereCondition = $connection->quoteInto('operation_key IN (?)', $operationIds) + if (!empty($operationKeys)) { + $whereCondition = $connection->quoteInto('operation_key IN (?)', $operationKeys) . " AND " . $connection->quoteInto('bulk_uuid = ?', $bulkUuid); $connection->delete( diff --git a/app/code/Magento/AsynchronousOperations/Model/Operation.php b/app/code/Magento/AsynchronousOperations/Model/Operation.php index 00f33d10a1e1b..79e7f2e10ff31 100644 --- a/app/code/Magento/AsynchronousOperations/Model/Operation.php +++ b/app/code/Magento/AsynchronousOperations/Model/Operation.php @@ -7,6 +7,7 @@ use Magento\AsynchronousOperations\Api\Data\OperationInterface; use Magento\AsynchronousOperations\Model\OperationStatusValidator; +use Magento\Framework\Bulk\OperationInterface as BulkOperationInterface; use Magento\Framework\DataObject; /** @@ -162,6 +163,23 @@ public function setErrorCode($errorCode) return $this->setData(self::ERROR_CODE, $errorCode); } + /** + * @inheritDoc + */ + public function getOperationKey(): ?int + { + return $this->getData(self::OPERATION_KEY) ? (int) $this->getData(self::OPERATION_KEY) : null; + } + + /** + * @inheritDoc + */ + public function setOperationKey(?int $operationKey): BulkOperationInterface + { + $this->setData(self::OPERATION_KEY, $operationKey); + return $this; + } + /** * Retrieve existing extension attributes object. * diff --git a/app/code/Magento/AsynchronousOperations/Model/ResourceModel/Operation/OperationRepository.php b/app/code/Magento/AsynchronousOperations/Model/ResourceModel/Operation/OperationRepository.php index 6757b0c8f0a5c..4151afa037502 100644 --- a/app/code/Magento/AsynchronousOperations/Model/ResourceModel/Operation/OperationRepository.php +++ b/app/code/Magento/AsynchronousOperations/Model/ResourceModel/Operation/OperationRepository.php @@ -91,7 +91,7 @@ public function createByTopic($topicName, $entityParams, $groupId, $operationId) ]; $data = [ 'data' => [ - OperationInterface::ID => $operationId, + OperationInterface::OPERATION_KEY => $operationId, OperationInterface::BULK_ID => $groupId, OperationInterface::TOPIC_NAME => $topicName, OperationInterface::SERIALIZED_DATA => $this->jsonSerializer->serialize($serializedData), diff --git a/app/code/Magento/AsynchronousOperations/Test/Unit/Model/BulkManagementTest.php b/app/code/Magento/AsynchronousOperations/Test/Unit/Model/BulkManagementTest.php index 14abb41c77fc4..bf0ac9e159b00 100644 --- a/app/code/Magento/AsynchronousOperations/Test/Unit/Model/BulkManagementTest.php +++ b/app/code/Magento/AsynchronousOperations/Test/Unit/Model/BulkManagementTest.php @@ -215,7 +215,7 @@ public function testRetryBulk() $operation = $this->getMockForAbstractClass(OperationInterface::class); $operationCollection->expects($this->once())->method('getItems')->willReturn([$operation]); $connection->expects($this->once())->method('beginTransaction')->willReturnSelf(); - $operation->expects($this->once())->method('getId')->willReturn($operationId); + $operation->expects($this->once())->method('getOperationKey')->willReturn($operationId); $this->resourceConnection->expects($this->once()) ->method('getTableName')->with($operationTable)->willReturn($operationTable); $connection->expects($this->at(1)) @@ -265,7 +265,7 @@ public function testRetryBulkWithException() $operation = $this->getMockForAbstractClass(OperationInterface::class); $operationCollection->expects($this->once())->method('getItems')->willReturn([$operation]); $connection->expects($this->once())->method('beginTransaction')->willReturnSelf(); - $operation->expects($this->once())->method('getId')->willReturn($operationId); + $operation->expects($this->once())->method('getOperationKey')->willReturn($operationId); $this->resourceConnection->expects($this->once()) ->method('getTableName')->with($operationTable)->willReturn($operationTable); $connection->expects($this->at(1)) diff --git a/dev/tests/api-functional/testsuite/Magento/AsynchronousOperations/Api/OperationRepositoryInterfaceTest.php b/dev/tests/api-functional/testsuite/Magento/AsynchronousOperations/Api/OperationRepositoryInterfaceTest.php index 0e8cdb6ef37ef..a0c96c4de4c1b 100644 --- a/dev/tests/api-functional/testsuite/Magento/AsynchronousOperations/Api/OperationRepositoryInterfaceTest.php +++ b/dev/tests/api-functional/testsuite/Magento/AsynchronousOperations/Api/OperationRepositoryInterfaceTest.php @@ -121,4 +121,53 @@ public function testGetList() $this->assertEquals('bulk-uuid-searchable-6', $item['bulk_uuid']); } } + + /** + * @magentoApiDataFixture Magento/AsynchronousOperations/_files/operation_searchable.php + */ + public function testGetMultipleBulkUuids() + { + $searchCriteria = [ + 'searchCriteria' => [ + 'filter_groups' => [ + [ + 'filters' => [ + [ + 'field' => 'status', + 'value' => OperationInterface::STATUS_TYPE_COMPLETE, + 'condition_type' => 'eq', + ], + ], + ], + ], + 'current_page' => 1, + ], + ]; + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '?' . http_build_query($searchCriteria), + 'httpMethod' => Request::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'operation' => self::SERVICE_NAME . 'GetList', + ], + ]; + + $response = $this->_webApiCall($serviceInfo, $searchCriteria); + + $this->assertArrayHasKey('search_criteria', $response); + $this->assertArrayHasKey('total_count', $response); + $this->assertArrayHasKey('items', $response); + + $this->assertEquals($searchCriteria['searchCriteria'], $response['search_criteria']); + $this->assertEquals(2, $response['total_count']); + $this->assertCount(2, $response['items']); + + $this->assertEquals( + ['bulk-uuid-searchable-6', 'bulk-uuid-searchable-8'], + array_column($response['items'], 'bulk_uuid') + ); + } } diff --git a/dev/tests/integration/testsuite/Magento/AsynchronousOperations/Model/OperationManagementTest.php b/dev/tests/integration/testsuite/Magento/AsynchronousOperations/Model/OperationManagementTest.php index 4be795dd654cd..2db16af43c34e 100644 --- a/dev/tests/integration/testsuite/Magento/AsynchronousOperations/Model/OperationManagementTest.php +++ b/dev/tests/integration/testsuite/Magento/AsynchronousOperations/Model/OperationManagementTest.php @@ -61,11 +61,11 @@ public function testGetBulkStatus() } /** @var OperationInterface $operation */ $operation = array_shift($operations); - $operationId = $operation->getId(); + $operationKey = $operation->getOperationKey(); $this->assertTrue($this->model->changeOperationStatus( 'bulk-uuid-5', - $operationId, + $operationKey, OperationInterface::STATUS_TYPE_OPEN )); @@ -74,7 +74,7 @@ public function testGetBulkStatus() $select = $connection->select() ->from($table) ->where("bulk_uuid = ?", 'bulk-uuid-5') - ->where("operation_key = ?", $operationId); + ->where("operation_key = ?", $operationKey); $updatedOperation = $connection->fetchRow($select); $this->assertEquals(OperationInterface::STATUS_TYPE_OPEN, $updatedOperation['status']); diff --git a/dev/tests/integration/testsuite/Magento/AsynchronousOperations/_files/operation_searchable.php b/dev/tests/integration/testsuite/Magento/AsynchronousOperations/_files/operation_searchable.php index 1e27df71d5709..eed6713dd5bcd 100644 --- a/dev/tests/integration/testsuite/Magento/AsynchronousOperations/_files/operation_searchable.php +++ b/dev/tests/integration/testsuite/Magento/AsynchronousOperations/_files/operation_searchable.php @@ -25,6 +25,13 @@ 'operation_count' => 6, 'start_time' => '2009-10-10 00:00:00', ], + 'started_searchable_second' => [ + 'uuid' => 'bulk-uuid-searchable-8', + 'user_id' => 1, + 'description' => 'Bulk Description', + 'operation_count' => 1, + 'start_time' => '2012-10-10 00:00:00', + ], 'not_started' => [ 'uuid' => 'bulk-uuid-searchable-7', 'user_id' => 1, @@ -89,6 +96,15 @@ 'result_message' => '', 'operation_key' => 5 ], + [ + 'bulk_uuid' => 'bulk-uuid-searchable-8', + 'topic_name' => 'topic-5', + 'serialized_data' => json_encode(['entity_id' => 5]), + 'status' => OperationInterface::STATUS_TYPE_COMPLETE, + 'error_code' => null, + 'result_message' => '', + 'operation_key' => 0 + ], ]; $bulkQuery = "INSERT INTO {$bulkTable} (`uuid`, `user_id`, `description`, `operation_count`, `start_time`)" diff --git a/lib/internal/Magento/Framework/Bulk/OperationInterface.php b/lib/internal/Magento/Framework/Bulk/OperationInterface.php index a621106be3806..45f684f1bb3cf 100644 --- a/lib/internal/Magento/Framework/Bulk/OperationInterface.php +++ b/lib/internal/Magento/Framework/Bulk/OperationInterface.php @@ -15,11 +15,12 @@ interface OperationInterface extends \Magento\Framework\Api\ExtensibleDataInterf /**#@+ * Constants for keys of data array. Identical to the name of the getter in snake case */ - const ID = 'operation_key'; + const ID = 'id'; const BULK_ID = 'bulk_uuid'; const TOPIC_NAME = 'topic_name'; const SERIALIZED_DATA = 'serialized_data'; const RESULT_SERIALIZED_DATA = 'result_serialized_data'; + const OPERATION_KEY = 'operation_key'; const STATUS = 'status'; const RESULT_MESSAGE = 'result_message'; const ERROR_CODE = 'error_code'; @@ -172,4 +173,21 @@ public function getErrorCode(); * @since 103.0.0 */ public function setErrorCode($errorCode); + + /** + * Get operation key + * + * @return int|null + * @since 103.0.1 + */ + public function getOperationKey(): ?int; + + /** + * Set operation key + * + * @param int|null $operationKey + * @return $this + * @since 103.0.1 + */ + public function setOperationKey(?int $operationKey): self; }