diff --git a/Inventory/Model/SourceItem/Validator/SkuValidator.php b/Inventory/Model/SourceItem/Validator/SkuValidator.php index 20d5b3572a0..31be62b4099 100644 --- a/Inventory/Model/SourceItem/Validator/SkuValidator.php +++ b/Inventory/Model/SourceItem/Validator/SkuValidator.php @@ -7,6 +7,8 @@ namespace Magento\Inventory\Model\SourceItem\Validator; +use Magento\Catalog\Api\ProductRepositoryInterface; +use Magento\Framework\Exception\NoSuchEntityException; use Magento\Framework\Validation\ValidationResult; use Magento\Framework\Validation\ValidationResultFactory; use Magento\Inventory\Model\Validators\NoSpaceBeforeAndAfterString; @@ -34,19 +36,28 @@ class SkuValidator implements SourceItemValidatorInterface */ private $noSpaceBeforeAndAfterString; + /** + * @var ProductRepositoryInterface + */ + private $productRepository; + /** * @param ValidationResultFactory $validationResultFactory * @param NotAnEmptyString $notAnEmptyString * @param NoSpaceBeforeAndAfterString $noSpaceBeforeAndAfterString + * @param ProductRepositoryInterface $productRepository */ public function __construct( ValidationResultFactory $validationResultFactory, NotAnEmptyString $notAnEmptyString, - NoSpaceBeforeAndAfterString $noSpaceBeforeAndAfterString + NoSpaceBeforeAndAfterString $noSpaceBeforeAndAfterString, + ?ProductRepositoryInterface $productRepository = null ) { $this->validationResultFactory = $validationResultFactory; $this->notAnEmptyString = $notAnEmptyString; $this->noSpaceBeforeAndAfterString = $noSpaceBeforeAndAfterString; + $this->productRepository = $productRepository ?: + \Magento\Framework\App\ObjectManager::getInstance()->get(ProductRepositoryInterface::class); } /** @@ -57,9 +68,32 @@ public function validate(SourceItemInterface $source): ValidationResult $value = $source->getSku(); $errors = [ $this->notAnEmptyString->execute(SourceItemInterface::SKU, (string)$value), - $this->noSpaceBeforeAndAfterString->execute(SourceItemInterface::SKU, (string)$value) + $this->noSpaceBeforeAndAfterString->execute(SourceItemInterface::SKU, (string)$value), + $this->validateSkuExists((string)$value) ]; $errors = array_merge(...$errors); return $this->validationResultFactory->create(['errors' => $errors]); } + + /** + * Validate that product with given SKU exists + * + * @param string $sku + * @return array + */ + private function validateSkuExists(string $sku): array + { + $errors = []; + if (empty($sku)) { + return $errors; + } + + try { + $this->productRepository->get($sku); + } catch (NoSuchEntityException $e) { + $errors[] = __('Product with SKU "%1" does not exist.', $sku); + } + + return $errors; + } } diff --git a/Inventory/Test/Unit/Model/SourceItem/Validator/SkuValidatorTest.php b/Inventory/Test/Unit/Model/SourceItem/Validator/SkuValidatorTest.php index 2a152a1ae4a..e55a415da91 100644 --- a/Inventory/Test/Unit/Model/SourceItem/Validator/SkuValidatorTest.php +++ b/Inventory/Test/Unit/Model/SourceItem/Validator/SkuValidatorTest.php @@ -7,6 +7,9 @@ namespace Magento\Inventory\Test\Unit\Model\SourceItem\Validator; +use Magento\Catalog\Api\Data\ProductInterface; +use Magento\Catalog\Api\ProductRepositoryInterface; +use Magento\Framework\Exception\NoSuchEntityException; use Magento\Framework\Phrase; use Magento\Framework\Validation\ValidationResult; use Magento\Framework\Validation\ValidationResultFactory; @@ -35,6 +38,11 @@ class SkuValidatorTest extends TestCase */ private $noSpaceBeforeAndAfterString; + /** + * @var ProductRepositoryInterface|MockObject + */ + private $productRepository; + /** * @var SourceItem|MockObject */ @@ -50,12 +58,14 @@ protected function setUp(): void $this->validationResultFactory = $this->createMock(ValidationResultFactory::class); $this->notAnEmptyString = $this->createMock(NotAnEmptyString::class); $this->noSpaceBeforeAndAfterString = $this->createMock(NoSpaceBeforeAndAfterString::class); + $this->productRepository = $this->createMock(ProductRepositoryInterface::class); $this->sourceItemMock = $this->getMockBuilder(SourceItem::class)->disableOriginalConstructor() ->onlyMethods(['getSku', 'getSourceCode', 'getQuantity', 'getStatus', 'getData', 'setData'])->getMock(); $this->skuValidator = new SkuValidator( $this->validationResultFactory, $this->notAnEmptyString, - $this->noSpaceBeforeAndAfterString + $this->noSpaceBeforeAndAfterString, + $this->productRepository ); } @@ -98,9 +108,14 @@ public function testValidate(array $source): void $errors = [$source['execute']]; $errors = array_merge(...$errors); $this->noSpaceBeforeAndAfterString->method('execute')->willReturn($source['execute']); - $this->validationResultFactory->method('create')->with( - ['errors' => $errors] - )->willReturn(new ValidationResult($errors)); + + // Mock product repository to return existing product + $product = $this->createMock(ProductInterface::class); + $this->productRepository->method('get')->willReturn($product); + + $this->validationResultFactory->method('create')->with( + ['errors' => $errors] + )->willReturn(new ValidationResult($errors)); $result = $this->skuValidator->validate($this->sourceItemMock); if ($source['is_string_whitespace']) { foreach ($result->getErrors() as $error) { @@ -110,4 +125,40 @@ public function testValidate(array $source): void $this->assertEmpty($result->getErrors()); } } + + /** + * Test validation when SKU does not exist + * + * @return void + */ + public function testValidateNonExistentSku(): void + { + $sku = 'non_existent_sku'; + $this->sourceItemMock->expects($this->atLeastOnce())->method('getSku') + ->willReturn($sku); + + $this->notAnEmptyString->method('execute')->willReturn([]); + $this->noSpaceBeforeAndAfterString->method('execute')->willReturn([]); + + // Mock product repository to throw NoSuchEntityException + $this->productRepository->expects($this->once()) + ->method('get') + ->with($sku) + ->willThrowException(new NoSuchEntityException(__('Product not found'))); + + $expectedError = __('Product with SKU "%1" does not exist.', $sku); + $errors = [$expectedError]; + + $this->validationResultFactory->method('create')->with( + ['errors' => $errors] + )->willReturn(new ValidationResult($errors)); + + $result = $this->skuValidator->validate($this->sourceItemMock); + + $this->assertCount(1, $result->getErrors()); + $errorMessage = $result->getErrors()[0]; + $this->assertInstanceOf(Phrase::class, $errorMessage); + $this->assertEquals('Product with SKU "%1" does not exist.', $errorMessage->getText()); + $this->assertEquals(['non_existent_sku'], $errorMessage->getArguments()); + } }