diff --git a/UPGRADE-14.0.md b/UPGRADE-14.0.md index 21bf06c7c2c..4b9d958f5d1 100644 --- a/UPGRADE-14.0.md +++ b/UPGRADE-14.0.md @@ -1501,6 +1501,11 @@ Follow the instructions in relevant sections, e.g. `shopsys/coding-standards` or - see #project-base-diff to update your project - take promo code into account in priceByTransportQuery and priceByPaymentQuery ([#3118](https://github.com/shopsys/shopsys/pull/3118)) + + - see #project-base-diff to update your project + +- addProductToListMutation: ensure new product list is created with non-conflicting uuid ([#3126](https://github.com/shopsys/shopsys/pull/3126)) + - add new tests to `ProductListLoggedCustomerTest` and `ProductListNotLoggedCustomerTest` classes - see #project-base-diff to update your project ### Storefront diff --git a/packages/framework/src/Model/Product/List/ProductListFacade.php b/packages/framework/src/Model/Product/List/ProductListFacade.php index cb2e8108b5a..f3ab98d3f00 100644 --- a/packages/framework/src/Model/Product/List/ProductListFacade.php +++ b/packages/framework/src/Model/Product/List/ProductListFacade.php @@ -108,6 +108,15 @@ public function findAnonymousProductList( return $this->productListRepository->findAnonymousProductList($uuid, $productListType); } + /** + * @param string $uuid + * @return bool + */ + public function existsProductListWithUuid(string $uuid): bool + { + return $this->productListRepository->existsProductListWithUuid($uuid); + } + /** * @param \Shopsys\FrameworkBundle\Model\Product\List\ProductList $productList * @param \Shopsys\FrameworkBundle\Model\Product\Product $product diff --git a/packages/framework/src/Model/Product/List/ProductListRepository.php b/packages/framework/src/Model/Product/List/ProductListRepository.php index bc9553396a2..0afaa035752 100644 --- a/packages/framework/src/Model/Product/List/ProductListRepository.php +++ b/packages/framework/src/Model/Product/List/ProductListRepository.php @@ -119,4 +119,13 @@ protected function getRepository(): EntityRepository { return $this->entityManager->getRepository(ProductList::class); } + + /** + * @param string $uuid + * @return bool + */ + public function existsProductListWithUuid(string $uuid): bool + { + return $this->getRepository()->count(['uuid' => $uuid]) > 0; + } } diff --git a/packages/frontend-api/src/Model/Mutation/ProductList/ProductListMutation.php b/packages/frontend-api/src/Model/Mutation/ProductList/ProductListMutation.php index b718a16fdfe..f516ad4f629 100644 --- a/packages/frontend-api/src/Model/Mutation/ProductList/ProductListMutation.php +++ b/packages/frontend-api/src/Model/Mutation/ProductList/ProductListMutation.php @@ -5,6 +5,7 @@ namespace Shopsys\FrontendApiBundle\Model\Mutation\ProductList; use Overblog\GraphQLBundle\Definition\Argument; +use Ramsey\Uuid\Uuid; use Shopsys\FrameworkBundle\Model\Customer\User\CurrentCustomerUser; use Shopsys\FrameworkBundle\Model\Product\Exception\ProductNotFoundException; use Shopsys\FrameworkBundle\Model\Product\List\Exception\ProductAlreadyInListException; @@ -60,6 +61,10 @@ public function addProductToListMutation(Argument $argument): ProductList } if ($productList === null) { + if ($productListUuid !== null && $this->productListFacade->existsProductListWithUuid($productListUuid)) { + $productListUuid = Uuid::uuid4()->toString(); + } + $productListData = $this->productListDataFactory->create($productListType, $customerUser, $productListUuid); $productList = $this->productListFacade->create($productListData); } diff --git a/project-base/app/tests/FrontendApiBundle/Functional/Product/ProductList/ProductListLoggedCustomerTest.php b/project-base/app/tests/FrontendApiBundle/Functional/Product/ProductList/ProductListLoggedCustomerTest.php index 8f60b355de6..2121d451b0d 100644 --- a/project-base/app/tests/FrontendApiBundle/Functional/Product/ProductList/ProductListLoggedCustomerTest.php +++ b/project-base/app/tests/FrontendApiBundle/Functional/Product/ProductList/ProductListLoggedCustomerTest.php @@ -150,6 +150,28 @@ public function testAddProductCreatesNewListWhenNewUuidIsProvided(string $produc $this->assertSame([$productToAddId], array_column($data['products'], 'id')); } + /** + * @dataProvider \Tests\FrontendApiBundle\Functional\Product\ProductList\ProductListTypesDataProvider::getProductListTypes + * @param string $productListType + */ + public function testAddProductCreatesNewListWithNewUuidWhenUuidOfAnonymousListIsProvided( + string $productListType, + ): void { + $anonymousProductListUuid = $this->getAnonymousProductListUuid($productListType); + $productToAddId = 69; + $productToAdd = $this->getReference(ProductDataFixture::PRODUCT_PREFIX . $productToAddId); + $response = $this->getResponseContentForGql(__DIR__ . '/graphql/AddProductToListMutation.graphql', [ + 'productListUuid' => $anonymousProductListUuid, + 'productUuid' => $productToAdd->getUuid(), + 'type' => $productListType, + ]); + $data = $this->getResponseDataForGraphQlType($response, 'AddProductToList'); + + $this->assertNotSame($anonymousProductListUuid, $data['uuid']); + $this->assertSame($productListType, $data['type']); + $this->assertSame([$productToAddId], array_column($data['products'], 'id')); + } + /** * @dataProvider productListDataProvider * @param string $productListType @@ -242,4 +264,17 @@ public function productListDataProvider(): Iterator 'expectedProductIds' => [1], ]; } + + /** + * @param string $productListType + * @return string + */ + private function getAnonymousProductListUuid(string $productListType): string + { + return match ($productListType) { + ProductListTypeEnum::COMPARISON => ProductListDataFixture::PRODUCT_LIST_COMPARISON_NOT_LOGGED_CUSTOMER_UUID, + ProductListTypeEnum::WISHLIST => ProductListDataFixture::PRODUCT_LIST_WISHLIST_NOT_LOGGED_CUSTOMER_UUID, + default => throw new UnknownProductListTypeException($productListType), + }; + } } diff --git a/project-base/app/tests/FrontendApiBundle/Functional/Product/ProductList/ProductListNotLoggedCustomerTest.php b/project-base/app/tests/FrontendApiBundle/Functional/Product/ProductList/ProductListNotLoggedCustomerTest.php index fc262aafab4..be3f81d1564 100644 --- a/project-base/app/tests/FrontendApiBundle/Functional/Product/ProductList/ProductListNotLoggedCustomerTest.php +++ b/project-base/app/tests/FrontendApiBundle/Functional/Product/ProductList/ProductListNotLoggedCustomerTest.php @@ -166,6 +166,28 @@ public function testAddProductCreatesNewListWhenNewUuidIsProvided(string $produc $this->assertSame([$productToAddId], array_column($data['products'], 'id')); } + /** + * @dataProvider \Tests\FrontendApiBundle\Functional\Product\ProductList\ProductListTypesDataProvider::getProductListTypes + * @param string $productListType + */ + public function testAddProductCreatesNewListWithNewUuidWhenUuidOfCustomerUserListIsProvided( + string $productListType, + ): void { + $customerUserProductListUuid = $this->getCustomerUserProductListUuid($productListType); + $productToAddId = 69; + $productToAdd = $this->getReference(ProductDataFixture::PRODUCT_PREFIX . $productToAddId); + $response = $this->getResponseContentForGql(__DIR__ . '/graphql/AddProductToListMutation.graphql', [ + 'productListUuid' => $customerUserProductListUuid, + 'productUuid' => $productToAdd->getUuid(), + 'type' => $productListType, + ]); + $data = $this->getResponseDataForGraphQlType($response, 'AddProductToList'); + + $this->assertNotSame($customerUserProductListUuid, $data['uuid']); + $this->assertSame($productListType, $data['type']); + $this->assertSame([$productToAddId], array_column($data['products'], 'id')); + } + /** * @dataProvider \Tests\FrontendApiBundle\Functional\Product\ProductList\ProductListTypesDataProvider::getProductListTypes * @param string $productListType @@ -471,4 +493,17 @@ private function assertOriginalAnonymousListsDoNotExist(): void $this->assertTrue($originalAnonymousWishlist === null, 'Original anonymous wishlist should not exist anymore'); $this->assertTrue($originalAnonymousComparison === null, 'Original anonymous comparison should not exist anymore'); } + + /** + * @param string $productListType + * @return string + */ + private function getCustomerUserProductListUuid(string $productListType): string + { + return match ($productListType) { + ProductListTypeEnum::COMPARISON => ProductListDataFixture::PRODUCT_LIST_COMPARISON_LOGGED_CUSTOMER_UUID, + ProductListTypeEnum::WISHLIST => ProductListDataFixture::PRODUCT_LIST_WISHLIST_LOGGED_CUSTOMER_UUID, + default => throw new UnknownProductListTypeException($productListType), + }; + } }