From 1365c5d378d9d110391b88d4b0dc2dd1de59a85b Mon Sep 17 00:00:00 2001 From: mamazu <14860264+mamazu@users.noreply.github.com> Date: Wed, 4 Sep 2019 18:53:42 +0200 Subject: [PATCH] Addding validation for product in current channel --- doc/swagger.yml | 2 + .../ProductInCartChannelCheckerSpec.php | 49 +++++++++++ ...BasedConfigurableItemToCartHandlerSpec.php | 28 ++++++- .../Cart/PutSimpleItemToCartHandlerSpec.php | 37 ++++++++- ...BasedConfigurableItemToCartHandlerSpec.php | 32 ++++++- src/Checker/ProductInCartChannelChecker.php | 15 ++++ .../ProductInCartChannelCheckerInterface.php | 12 +++ ...tionBasedConfigurableItemToCartHandler.php | 12 ++- .../Cart/PutSimpleItemToCartHandler.php | 12 ++- ...iantBasedConfigurableItemToCartHandler.php | 11 ++- src/Resources/config/services.xml | 12 +-- src/Resources/config/services/checker.xml | 13 +++ .../config/services/checker/channel.xml | 11 +++ .../config/services/handler/cart.xml | 3 + .../Controller/Cart/PutItemToCartApiTest.php | 83 +++++++++++++++++++ tests/DataFixtures/ORM/channel.yml | 11 +++ tests/DataFixtures/ORM/shop.yml | 4 +- .../cart/product_not_in_cart_channel.json | 4 + 18 files changed, 322 insertions(+), 29 deletions(-) create mode 100644 spec/Checker/ProductInCartChannelCheckerSpec.php create mode 100644 src/Checker/ProductInCartChannelChecker.php create mode 100644 src/Checker/ProductInCartChannelCheckerInterface.php create mode 100644 src/Resources/config/services/checker.xml create mode 100644 src/Resources/config/services/checker/channel.xml create mode 100644 tests/Responses/Expected/cart/product_not_in_cart_channel.json diff --git a/doc/swagger.yml b/doc/swagger.yml index 764bd242d..94927b904 100644 --- a/doc/swagger.yml +++ b/doc/swagger.yml @@ -141,6 +141,8 @@ paths: description: "Invalid input, validation failed." schema: $ref: "#/definitions/GeneralError" + 500: + description: "An error occurred - maybe the product is not in the channel of the cart" /carts/{token}/multiple-items: parameters: diff --git a/spec/Checker/ProductInCartChannelCheckerSpec.php b/spec/Checker/ProductInCartChannelCheckerSpec.php new file mode 100644 index 000000000..6ad29375e --- /dev/null +++ b/spec/Checker/ProductInCartChannelCheckerSpec.php @@ -0,0 +1,49 @@ +shouldImplement(ProductInCartChannelCheckerInterface::class); + } + + function it_returns_true_if_the_channels_match( + ProductInterface $product, + OrderInterface $order, + ChannelInterface $channel + ): void + { + $product->getChannels()->willReturn(new ArrayCollection([$channel->getWrappedObject()])); + + $order->getChannel()->willReturn($channel); + + $this->isProductInCartChannel($product, $order)->shouldReturn(true); + } + + function it_returns_false_if_the_channels_do_not_match( + ProductInterface $product, + OrderInterface $order, + ChannelInterface $orderChannel, + ChannelInterface $productChannel1, + ChannelInterface $productChannel2 + ): void { + $product->getChannels()->willReturn(new ArrayCollection([ + $productChannel1->getWrappedObject(), + $productChannel2->getWrappedObject() + ])); + + $order->getChannel()->willReturn($orderChannel); + + $this->isProductInCartChannel($product, $order)->shouldReturn(false); + } +} diff --git a/spec/Handler/Cart/PutOptionBasedConfigurableItemToCartHandlerSpec.php b/spec/Handler/Cart/PutOptionBasedConfigurableItemToCartHandlerSpec.php index 113ca542a..9ce4957d6 100644 --- a/spec/Handler/Cart/PutOptionBasedConfigurableItemToCartHandlerSpec.php +++ b/spec/Handler/Cart/PutOptionBasedConfigurableItemToCartHandlerSpec.php @@ -13,6 +13,7 @@ use Sylius\Component\Core\Repository\OrderRepositoryInterface; use Sylius\Component\Core\Repository\ProductRepositoryInterface; use Sylius\Component\Product\Model\ProductOptionValueInterface; +use Sylius\ShopApiPlugin\Checker\ProductInCartChannelCheckerInterface; use Sylius\ShopApiPlugin\Command\Cart\PutOptionBasedConfigurableItemToCart; use Sylius\ShopApiPlugin\Modifier\OrderModifierInterface; @@ -21,15 +22,17 @@ final class PutOptionBasedConfigurableItemToCartHandlerSpec extends ObjectBehavi function let( OrderRepositoryInterface $orderRepository, ProductRepositoryInterface $productRepository, - OrderModifierInterface $orderModifier + OrderModifierInterface $orderModifier, + ProductInCartChannelCheckerInterface $channelChecker ): void { - $this->beConstructedWith($orderRepository, $productRepository, $orderModifier); + $this->beConstructedWith($orderRepository, $productRepository, $orderModifier, $channelChecker); } function it_handles_putting_new_item_to_cart( OrderInterface $cart, OrderRepositoryInterface $orderRepository, OrderModifierInterface $orderModifier, + ProductInCartChannelCheckerInterface $channelChecker, ProductInterface $tShirt, ProductOptionValueInterface $blueOptionValue, ProductOptionValueInterface $redOptionValue, @@ -47,6 +50,7 @@ function it_handles_putting_new_item_to_cart( $blueTShirt->getOptionValues()->willReturn(new ArrayCollection([$blueOptionValue->getWrappedObject()])); $blueOptionValue->getCode()->willReturn('BLUE_OPTION_VALUE_CODE'); $blueOptionValue->getOptionCode()->willReturn('COLOR_OPTION_CODE'); + $channelChecker->isProductInCartChannel($tShirt, $cart)->willReturn(true); $redTShirt->getOptionValues()->willReturn(new ArrayCollection([$redOptionValue->getWrappedObject()])); $redOptionValue->getCode()->willReturn('RED_OPTION_VALUE_CODE'); @@ -85,6 +89,7 @@ function it_throws_an_exception_if_product_variant_cannot_be_resolved( OrderInterface $cart, CartItemFactoryInterface $cartItemFactory, OrderRepositoryInterface $orderRepository, + ProductInCartChannelCheckerInterface $channelChecker, ProductInterface $tShirt, ProductVariantInterface $blueTShirt, ProductVariantInterface $redTShirt, @@ -102,6 +107,7 @@ function it_throws_an_exception_if_product_variant_cannot_be_resolved( $blueTShirt->getOptionValues()->willReturn(new ArrayCollection([$blueOptionValue->getWrappedObject()])); $blueOptionValue->getCode()->willReturn('BLUE_OPTION_VALUE_CODE'); $blueOptionValue->getOptionCode()->willReturn('COLOR_OPTION_CODE'); + $channelChecker->isProductInCartChannel($tShirt, $cart); $redTShirt->getOptionValues()->willReturn(new ArrayCollection([$redOptionValue->getWrappedObject()])); $redOptionValue->getCode()->willReturn('GREEN_OPTION_VALUE_CODE'); @@ -114,4 +120,22 @@ function it_throws_an_exception_if_product_variant_cannot_be_resolved( new PutOptionBasedConfigurableItemToCart('ORDERTOKEN', 'T_SHIRT_CODE', ['COLOR_OPTION_CODE' => 'RED_OPTION_VALUE_CODE'], 5), ]); } + + function it_throws_an_exception_if_product_is_not_in_same_channel_as_cart( + OrderInterface $cart, + OrderRepositoryInterface $orderRepository, + ProductInCartChannelCheckerInterface $channelChecker, + ProductInterface $tShirt, + ProductRepositoryInterface $productRepository + ): void { + $productRepository->findOneByCode('T_SHIRT_CODE')->willReturn($tShirt); + + $orderRepository->findOneBy(['tokenValue' => 'ORDERTOKEN'])->willReturn($cart); + + $channelChecker->isProductInCartChannel($tShirt, $cart)->willReturn(false); + + $this->shouldThrow(\InvalidArgumentException::class)->during('__invoke', [ + new PutOptionBasedConfigurableItemToCart('ORDERTOKEN', 'T_SHIRT_CODE', ['COLOR_OPTION_CODE' => 'RED_OPTION_VALUE_CODE'], 5), + ]); + } } diff --git a/spec/Handler/Cart/PutSimpleItemToCartHandlerSpec.php b/spec/Handler/Cart/PutSimpleItemToCartHandlerSpec.php index 98aa371d7..1ab4a2d90 100644 --- a/spec/Handler/Cart/PutSimpleItemToCartHandlerSpec.php +++ b/spec/Handler/Cart/PutSimpleItemToCartHandlerSpec.php @@ -11,6 +11,7 @@ use Sylius\Component\Core\Model\ProductVariantInterface; use Sylius\Component\Core\Repository\OrderRepositoryInterface; use Sylius\Component\Core\Repository\ProductRepositoryInterface; +use Sylius\ShopApiPlugin\Checker\ProductInCartChannelCheckerInterface; use Sylius\ShopApiPlugin\Command\Cart\PutSimpleItemToCart; use Sylius\ShopApiPlugin\Modifier\OrderModifierInterface; @@ -19,9 +20,10 @@ final class PutSimpleItemToCartHandlerSpec extends ObjectBehavior function let( OrderRepositoryInterface $cartRepository, ProductRepositoryInterface $productRepository, - OrderModifierInterface $orderModifier + OrderModifierInterface $orderModifier, + ProductInCartChannelCheckerInterface $channelChecker ): void { - $this->beConstructedWith($cartRepository, $productRepository, $orderModifier); + $this->beConstructedWith($cartRepository, $productRepository, $orderModifier, $channelChecker); } function it_handles_putting_new_item_to_cart( @@ -30,7 +32,8 @@ function it_handles_putting_new_item_to_cart( ProductInterface $product, ProductRepositoryInterface $productRepository, ProductVariantInterface $productVariant, - OrderModifierInterface $orderModifier + OrderModifierInterface $orderModifier, + ProductInCartChannelCheckerInterface $channelChecker ): void { $productRepository->findOneBy(['code' => 'T_SHIRT_CODE'])->willReturn($product); $product->getVariants()->willReturn(new ArrayCollection([$productVariant->getWrappedObject()])); @@ -38,6 +41,8 @@ function it_handles_putting_new_item_to_cart( $cartRepository->findOneBy(['tokenValue' => 'ORDERTOKEN'])->willReturn($cart); + $channelChecker->isProductInCartChannel($product, $cart)->willReturn(true); + $orderModifier->modify($cart, $productVariant, 5)->shouldBeCalled(); $this(new PutSimpleItemToCart('ORDERTOKEN', 'T_SHIRT_CODE', 5)); @@ -68,6 +73,7 @@ function it_throws_an_exception_if_product_has_not_been_found( function it_throws_an_exception_if_product_is_configurable( OrderInterface $cart, OrderRepositoryInterface $cartRepository, + ProductInCartChannelCheckerInterface $channelChecker, ProductInterface $product, ProductRepositoryInterface $productRepository, ProductVariantInterface $productVariant @@ -75,10 +81,35 @@ function it_throws_an_exception_if_product_is_configurable( $cartRepository->findOneBy(['tokenValue' => 'ORDERTOKEN'])->willReturn($cart); $productRepository->findOneBy(['code' => 'T_SHIRT_CODE'])->willReturn($product); $product->getVariants()->willReturn(new ArrayCollection([$productVariant->getWrappedObject()])); + + $channelChecker->isProductInCartChannel($product, $cart)->willReturn(true); + $product->isSimple()->willReturn(false); $this->shouldThrow(\InvalidArgumentException::class)->during('__invoke', [ new PutSimpleItemToCart('ORDERTOKEN', 'T_SHIRT_CODE', 5), ]); } + + function it_throws_an_exception_if_product_is_not_in_same_channel_as_cart( + OrderInterface $cart, + OrderRepositoryInterface $cartRepository, + ProductInCartChannelCheckerInterface $channelChecker, + ProductInterface $product, + ProductRepositoryInterface $productRepository, + ProductVariantInterface $productVariant + ): void { + $cartRepository->findOneBy(['tokenValue' => 'ORDERTOKEN'])->willReturn($cart); + $productRepository->findOneBy(['code' => 'T_SHIRT_CODE'])->willReturn($product); + $product->getVariants()->willReturn(new ArrayCollection([$productVariant->getWrappedObject()])); + $product->isSimple()->willReturn(false); + + $channelChecker->isProductInCartChannel($product, $cart)->willReturn(false); + + $this->shouldThrow(\InvalidArgumentException::class)->during( + '__invoke', [ + new PutSimpleItemToCart('ORDERTOKEN', 'T_SHIRT_CODE', 5), + ] + ); + } } diff --git a/spec/Handler/Cart/PutVariantBasedConfigurableItemToCartHandlerSpec.php b/spec/Handler/Cart/PutVariantBasedConfigurableItemToCartHandlerSpec.php index 93b59423a..519ba8130 100644 --- a/spec/Handler/Cart/PutVariantBasedConfigurableItemToCartHandlerSpec.php +++ b/spec/Handler/Cart/PutVariantBasedConfigurableItemToCartHandlerSpec.php @@ -6,9 +6,11 @@ use PhpSpec\ObjectBehavior; use Sylius\Component\Core\Model\OrderInterface; +use Sylius\Component\Core\Model\ProductInterface; use Sylius\Component\Core\Model\ProductVariantInterface; use Sylius\Component\Core\Repository\OrderRepositoryInterface; use Sylius\Component\Core\Repository\ProductVariantRepositoryInterface; +use Sylius\ShopApiPlugin\Checker\ProductInCartChannelCheckerInterface; use Sylius\ShopApiPlugin\Command\Cart\PutVariantBasedConfigurableItemToCart; use Sylius\ShopApiPlugin\Modifier\OrderModifierInterface; @@ -17,19 +19,25 @@ final class PutVariantBasedConfigurableItemToCartHandlerSpec extends ObjectBehav function let( OrderRepositoryInterface $cartRepository, ProductVariantRepositoryInterface $productVariantRepository, - OrderModifierInterface $orderModifier + OrderModifierInterface $orderModifier, + ProductInCartChannelCheckerInterface $channelChecker ): void { - $this->beConstructedWith($cartRepository, $productVariantRepository, $orderModifier); + $this->beConstructedWith($cartRepository, $productVariantRepository, $orderModifier, $channelChecker); } function it_handles_putting_new_item_to_cart( OrderInterface $cart, OrderModifierInterface $orderModifier, OrderRepositoryInterface $cartRepository, + ProductInCartChannelCheckerInterface $channelChecker, ProductVariantInterface $productVariant, + ProductInterface $product, ProductVariantRepositoryInterface $productVariantRepository ): void { $productVariantRepository->findOneByCodeAndProductCode('RED_SMALL_T_SHIRT_CODE', 'T_SHIRT_CODE')->willReturn($productVariant); + $productVariant->getProduct()->willReturn($product); + + $channelChecker->isProductInCartChannel($product, $cart)->willReturn(true); $cartRepository->findOneBy(['tokenValue' => 'ORDERTOKEN'])->willReturn($cart); @@ -59,4 +67,24 @@ function it_throws_an_exception_if_product_has_not_been_found( new PutVariantBasedConfigurableItemToCart('ORDERTOKEN', 'T_SHIRT_CODE', 'RED_SMALL_T_SHIRT_CODE', 5), ]); } + + function it_throws_an_exception_if_product_has_different_channel_than_cart( + OrderInterface $cart, + OrderRepositoryInterface $cartRepository, + ProductInCartChannelCheckerInterface $channelChecker, + ProductVariantRepositoryInterface $productVariantRepository, + ProductVariantInterface $productVariant, + ProductInterface $product + ): void { + $productVariantRepository->findOneByCodeAndProductCode('RED_SMALL_T_SHIRT_CODE', 'T_SHIRT_CODE')->willReturn($productVariant); + $productVariant->getProduct()->willReturn($product); + + $cartRepository->findOneBy(['tokenValue' => 'ORDERTOKEN'])->willReturn($cart); + + $channelChecker->isProductInCartChannel($product, $cart)->willReturn(false); + + $this->shouldThrow(\InvalidArgumentException::class)->during('__invoke', [ + new PutVariantBasedConfigurableItemToCart('ORDERTOKEN', 'T_SHIRT_CODE', 'RED_SMALL_T_SHIRT_CODE', 5), + ]); + } } diff --git a/src/Checker/ProductInCartChannelChecker.php b/src/Checker/ProductInCartChannelChecker.php new file mode 100644 index 000000000..2ba8ad9f6 --- /dev/null +++ b/src/Checker/ProductInCartChannelChecker.php @@ -0,0 +1,15 @@ +getChannel(), $product->getChannels()->toArray(), true); + } +} diff --git a/src/Checker/ProductInCartChannelCheckerInterface.php b/src/Checker/ProductInCartChannelCheckerInterface.php new file mode 100644 index 000000000..c50d0f1c6 --- /dev/null +++ b/src/Checker/ProductInCartChannelCheckerInterface.php @@ -0,0 +1,12 @@ +cartRepository = $cartRepository; $this->productRepository = $productRepository; $this->orderModifier = $orderModifier; + $this->channelChecker = $channelChecker; } public function __invoke(PutOptionBasedConfigurableItemToCart $putConfigurableItemToCart): void @@ -43,8 +49,8 @@ public function __invoke(PutOptionBasedConfigurableItemToCart $putConfigurableIt /** @var ProductInterface $product */ $product = $this->productRepository->findOneByCode($putConfigurableItemToCart->product()); - Assert::notNull($product, 'Product has not been found'); + Assert::true($this->channelChecker->isProductInCartChannel($product, $cart), 'Product is not in same channel as cart'); $productVariant = $this->getVariant($putConfigurableItemToCart->options(), $product); diff --git a/src/Handler/Cart/PutSimpleItemToCartHandler.php b/src/Handler/Cart/PutSimpleItemToCartHandler.php index b48f25a99..f1d37074a 100644 --- a/src/Handler/Cart/PutSimpleItemToCartHandler.php +++ b/src/Handler/Cart/PutSimpleItemToCartHandler.php @@ -8,6 +8,7 @@ use Sylius\Component\Core\Model\ProductInterface; use Sylius\Component\Core\Repository\OrderRepositoryInterface; use Sylius\Component\Core\Repository\ProductRepositoryInterface; +use Sylius\ShopApiPlugin\Checker\ProductInCartChannelCheckerInterface; use Sylius\ShopApiPlugin\Command\Cart\PutSimpleItemToCart; use Sylius\ShopApiPlugin\Modifier\OrderModifierInterface; use Webmozart\Assert\Assert; @@ -23,27 +24,32 @@ final class PutSimpleItemToCartHandler /** @var OrderModifierInterface */ private $orderModifier; + /** @var ProductInCartChannelCheckerInterface */ + private $channelChecker; + public function __construct( OrderRepositoryInterface $cartRepository, ProductRepositoryInterface $productRepository, - OrderModifierInterface $orderModifier + OrderModifierInterface $orderModifier, + ProductInCartChannelCheckerInterface $channelChecker ) { $this->cartRepository = $cartRepository; $this->productRepository = $productRepository; $this->orderModifier = $orderModifier; + $this->channelChecker = $channelChecker; } public function __invoke(PutSimpleItemToCart $putSimpleItemToCart): void { /** @var OrderInterface $cart */ $cart = $this->cartRepository->findOneBy(['tokenValue' => $putSimpleItemToCart->orderToken()]); - Assert::notNull($cart, 'Cart has not been found'); /** @var ProductInterface $product */ $product = $this->productRepository->findOneBy(['code' => $putSimpleItemToCart->product()]); - Assert::notNull($product, 'Product has not been found'); + + Assert::true($this->channelChecker->isProductInCartChannel($product, $cart), 'Product is not in same channel as cart'); Assert::true($product->isSimple(), 'Product has to be simple'); $productVariant = $product->getVariants()[0]; diff --git a/src/Handler/Cart/PutVariantBasedConfigurableItemToCartHandler.php b/src/Handler/Cart/PutVariantBasedConfigurableItemToCartHandler.php index ac71c881d..0dfae4db6 100644 --- a/src/Handler/Cart/PutVariantBasedConfigurableItemToCartHandler.php +++ b/src/Handler/Cart/PutVariantBasedConfigurableItemToCartHandler.php @@ -8,6 +8,7 @@ use Sylius\Component\Core\Model\ProductVariantInterface; use Sylius\Component\Core\Repository\OrderRepositoryInterface; use Sylius\Component\Core\Repository\ProductVariantRepositoryInterface; +use Sylius\ShopApiPlugin\Checker\ProductInCartChannelCheckerInterface; use Sylius\ShopApiPlugin\Command\Cart\PutVariantBasedConfigurableItemToCart; use Sylius\ShopApiPlugin\Modifier\OrderModifierInterface; use Webmozart\Assert\Assert; @@ -23,27 +24,31 @@ final class PutVariantBasedConfigurableItemToCartHandler /** @var OrderModifierInterface */ private $orderModifier; + /** @var ProductInCartChannelCheckerInterface */ + private $channelChecker; + public function __construct( OrderRepositoryInterface $cartRepository, ProductVariantRepositoryInterface $productVariantRepository, - OrderModifierInterface $orderModifier + OrderModifierInterface $orderModifier, + ProductInCartChannelCheckerInterface $channelChecker ) { $this->cartRepository = $cartRepository; $this->productVariantRepository = $productVariantRepository; $this->orderModifier = $orderModifier; + $this->channelChecker = $channelChecker; } public function __invoke(PutVariantBasedConfigurableItemToCart $putConfigurableItemToCart): void { /** @var OrderInterface $cart */ $cart = $this->cartRepository->findOneBy(['tokenValue' => $putConfigurableItemToCart->orderToken()]); - Assert::notNull($cart, 'Cart has not been found'); /** @var ProductVariantInterface $productVariant */ $productVariant = $this->productVariantRepository->findOneByCodeAndProductCode($putConfigurableItemToCart->productVariant(), $putConfigurableItemToCart->product()); - Assert::notNull($productVariant, 'Product variant has not been found'); + Assert::true($this->channelChecker->isProductInCartChannel($productVariant->getProduct(), $cart), 'Product is not in same channel as cart'); $this->orderModifier->modify($cart, $productVariant, $putConfigurableItemToCart->quantity()); } diff --git a/src/Resources/config/services.xml b/src/Resources/config/services.xml index 01d5bca41..10d50c4ff 100644 --- a/src/Resources/config/services.xml +++ b/src/Resources/config/services.xml @@ -15,6 +15,7 @@ + @@ -27,17 +28,6 @@ - - - - - - - - - diff --git a/src/Resources/config/services/checker.xml b/src/Resources/config/services/checker.xml new file mode 100644 index 000000000..bbe0a07e8 --- /dev/null +++ b/src/Resources/config/services/checker.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + diff --git a/src/Resources/config/services/checker/channel.xml b/src/Resources/config/services/checker/channel.xml new file mode 100644 index 000000000..8d5941015 --- /dev/null +++ b/src/Resources/config/services/checker/channel.xml @@ -0,0 +1,11 @@ + + + + + + + + + diff --git a/src/Resources/config/services/handler/cart.xml b/src/Resources/config/services/handler/cart.xml index 6fdbc448d..14666a7c9 100644 --- a/src/Resources/config/services/handler/cart.xml +++ b/src/Resources/config/services/handler/cart.xml @@ -30,6 +30,7 @@ + @@ -38,6 +39,7 @@ + @@ -46,6 +48,7 @@ + diff --git a/tests/Controller/Cart/PutItemToCartApiTest.php b/tests/Controller/Cart/PutItemToCartApiTest.php index d0446b6a5..90ae30105 100644 --- a/tests/Controller/Cart/PutItemToCartApiTest.php +++ b/tests/Controller/Cart/PutItemToCartApiTest.php @@ -226,6 +226,32 @@ public function it_validates_if_product_exists_during_add_simple_product(): void $this->assertResponse($response, 'cart/validation_product_not_exists_response', Response::HTTP_BAD_REQUEST); } + /** + * @test + */ + public function it_validates_if_simple_product_is_in_same_channel_as_cart(): void + { + $this->loadFixturesFromFiles(['shop.yml', 'channel.yml']); + + $token = 'SDAOSLEFNWU35H3QLI5325'; + + /** @var MessageBusInterface $bus */ + $bus = $this->get('sylius_shop_api_plugin.command_bus'); + $bus->dispatch(new PickupCart($token, 'unused_channel')); + + $data = + <<client->request('POST', sprintf('/shop-api/carts/%s/items', $token), [], [], self::CONTENT_TYPE_HEADER, $data); + $response = $this->client->getResponse(); + + $this->assertResponse($response, 'cart/product_not_in_cart_channel', Response::HTTP_INTERNAL_SERVER_ERROR); + } + /** * @test */ @@ -465,6 +491,33 @@ public function it_validates_if_product_exists_during_add_variant_based_configur $this->assertResponse($response, 'cart/validation_product_not_exists_response', Response::HTTP_BAD_REQUEST); } + /** + * @test + */ + public function it_validates_if_variant_based_product_is_in_cart_channel(): void + { + $this->loadFixturesFromFiles(['shop.yml', 'channel.yml']); + + $token = 'SDAOSLEFNWU35H3QLI5325'; + + /** @var MessageBusInterface $bus */ + $bus = $this->get('sylius_shop_api_plugin.command_bus'); + $bus->dispatch(new PickupCart($token, 'unused_channel')); + + $data = + <<client->request('POST', sprintf('/shop-api/carts/%s/items', $token), [], [], self::CONTENT_TYPE_HEADER, $data); + $response = $this->client->getResponse(); + + $this->assertResponse($response, 'cart/product_not_in_cart_channel', Response::HTTP_INTERNAL_SERVER_ERROR); + } + /** * @test */ @@ -606,6 +659,36 @@ public function it_increases_quantity_of_existing_item_while_adding_the_same_pro $this->assertResponse($response, 'cart/add_product_variant_based_on_options_multiple_times_to_cart_response', Response::HTTP_CREATED); } + /** + * @test + */ + public function it_validates_product_channel_when_adding_a_product_variant_based_on_option_to_the_cart(): void + { + $this->loadFixturesFromFiles(['shop.yml', 'channel.yml']); + + $token = 'SDAOSLEFNWU35H3QLI5325'; + + /** @var MessageBusInterface $bus */ + $bus = $this->get('sylius_shop_api_plugin.command_bus'); + $bus->dispatch(new PickupCart($token, 'unused_channel')); + + $data = + <<client->request('POST', sprintf('/shop-api/carts/%s/items', $token), [], [], self::CONTENT_TYPE_HEADER, $data); + $response = $this->client->getResponse(); + + $this->assertResponse($response, 'cart/product_not_in_cart_channel', Response::HTTP_INTERNAL_SERVER_ERROR); + } + /** * @test */ diff --git a/tests/DataFixtures/ORM/channel.yml b/tests/DataFixtures/ORM/channel.yml index 656dcdfa1..8647c42ee 100644 --- a/tests/DataFixtures/ORM/channel.yml +++ b/tests/DataFixtures/ORM/channel.yml @@ -23,6 +23,17 @@ Sylius\Component\Core\Model\Channel: enabled: true taxCalculationStrategy: "order_items_based" accountVerificationRequired: false + unused_channel: + code: "unused_channel" + name: "Channel that is not used in a product" + hostname: "localhost" + description: "Lorem ipsum" + baseCurrency: "@euro" + defaultLocale: "@locale_de_de" + locales: ["@locale_de_de"] + color: "red" + enabled: true + taxCalculationStrategy: "order_items_based" Sylius\Component\Currency\Model\Currency: pound: diff --git a/tests/DataFixtures/ORM/shop.yml b/tests/DataFixtures/ORM/shop.yml index 30a3777a1..402a0011a 100644 --- a/tests/DataFixtures/ORM/shop.yml +++ b/tests/DataFixtures/ORM/shop.yml @@ -38,7 +38,7 @@ Sylius\Component\Core\Model\Product: mug: code: "LOGAN_MUG_CODE" createdAt: "" - channels: ["@gb_web_channel"] + channels: ["@gb_web_channel", "@de_web_channel"] currentLocale: "en_GB" translations: ["@en_gb_mug_product_translation", "@de_de_mug_product_translation"] images: ["@mug_thumbnail"] @@ -60,7 +60,7 @@ Sylius\Component\Core\Model\Product: hat: code: "LOGAN_HAT_CODE" createdAt: "" - channels: ["@gb_web_channel"] + channels: ["@gb_web_channel", "@de_web_channel"] options: ["@hat_size"] currentLocale: "en_GB" translations: ["@en_gb_hat_product_translation", "@de_de_hat_product_translation"] diff --git a/tests/Responses/Expected/cart/product_not_in_cart_channel.json b/tests/Responses/Expected/cart/product_not_in_cart_channel.json new file mode 100644 index 000000000..7b287f5cf --- /dev/null +++ b/tests/Responses/Expected/cart/product_not_in_cart_channel.json @@ -0,0 +1,4 @@ +{ + "code": 500, + "message": "Product is not in same channel as cart" +}