From 696eb7a36023c5fb8b93d21f05ee8313cc29bbd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Chru=C5=9Bciel?= Date: Tue, 23 Jul 2019 15:26:01 +0200 Subject: [PATCH] [Checkout] Extract cart assignment from order complete --- .../Command/Cart/AssignCustomerToCartSpec.php | 25 ++++++++++ spec/Command/Cart/CompleteOrderSpec.php | 9 +--- .../Cart/AssignCustomerToCartHandlerSpec.php | 46 +++++++++++++++++++ .../Handler/Cart/CompleteOrderHandlerSpec.php | 29 +++--------- src/Command/Cart/AssignCustomerToCart.php | 30 ++++++++++++ src/Command/Cart/CompleteOrder.php | 11 +---- .../Checkout/CompleteOrderAction.php | 9 +++- .../Cart/AssignCustomerToCartHandler.php | 38 +++++++++++++++ src/Handler/Cart/CompleteOrderHandler.php | 14 +----- .../config/services/handler/cart.xml | 8 +++- tests/Controller/Cart/CartDropCartApiTest.php | 4 +- .../Cart/CartPutItemToCartApiTest.php | 4 +- tests/Controller/Utils/OrderPlacerTrait.php | 4 +- 13 files changed, 175 insertions(+), 56 deletions(-) create mode 100644 spec/Command/Cart/AssignCustomerToCartSpec.php create mode 100644 spec/Handler/Cart/AssignCustomerToCartHandlerSpec.php create mode 100644 src/Command/Cart/AssignCustomerToCart.php create mode 100644 src/Handler/Cart/AssignCustomerToCartHandler.php diff --git a/spec/Command/Cart/AssignCustomerToCartSpec.php b/spec/Command/Cart/AssignCustomerToCartSpec.php new file mode 100644 index 000000000..88cb36794 --- /dev/null +++ b/spec/Command/Cart/AssignCustomerToCartSpec.php @@ -0,0 +1,25 @@ +beConstructedWith('ORDERTOKEN', 'example@customer.com'); + } + + function it_has_order_token(): void + { + $this->orderToken()->shouldReturn('ORDERTOKEN'); + } + + function it_has_email(): void + { + $this->email()->shouldReturn('example@customer.com'); + } +} diff --git a/spec/Command/Cart/CompleteOrderSpec.php b/spec/Command/Cart/CompleteOrderSpec.php index e215ca7c0..4138eaee5 100644 --- a/spec/Command/Cart/CompleteOrderSpec.php +++ b/spec/Command/Cart/CompleteOrderSpec.php @@ -10,7 +10,7 @@ final class CompleteOrderSpec extends ObjectBehavior { function let(): void { - $this->beConstructedWith('ORDERTOKEN', 'example@customer.com'); + $this->beConstructedWith('ORDERTOKEN'); } function it_has_order_token(): void @@ -18,14 +18,9 @@ function it_has_order_token(): void $this->orderToken()->shouldReturn('ORDERTOKEN'); } - function it_has_email(): void - { - $this->email()->shouldReturn('example@customer.com'); - } - function it_can_have_a_note(): void { - $this->beConstructedWith('ORDERTOKEN', 'example@customer.com', 'Some order notes'); + $this->beConstructedWith('ORDERTOKEN', 'Some order notes'); $this->notes()->shouldReturn('Some order notes'); } diff --git a/spec/Handler/Cart/AssignCustomerToCartHandlerSpec.php b/spec/Handler/Cart/AssignCustomerToCartHandlerSpec.php new file mode 100644 index 000000000..8ff41b3f9 --- /dev/null +++ b/spec/Handler/Cart/AssignCustomerToCartHandlerSpec.php @@ -0,0 +1,46 @@ +beConstructedWith($orderRepository, $customerProvider); + } + + function it_handles_assigning_customer_to_cart( + CustomerInterface $customer, + CustomerProviderInterface $customerProvider, + OrderInterface $order, + OrderRepositoryInterface $orderRepository + ): void { + $orderRepository->findOneBy(['tokenValue' => 'ORDERTOKEN'])->willReturn($order); + + $customerProvider->provide('example@customer.com')->willReturn($customer); + + $order->setCustomer($customer)->shouldBeCalled(); + + $this(new AssignCustomerToCart('ORDERTOKEN', 'example@customer.com')); + } + + function it_throws_an_exception_if_order_does_not_exist( + OrderRepositoryInterface $orderRepository + ): void { + $orderRepository->findOneBy(['tokenValue' => 'ORDERTOKEN'])->willReturn(null); + + $this + ->shouldThrow(\InvalidArgumentException::class) + ->during('__invoke', [new AssignCustomerToCart('ORDERTOKEN', 'example@customer.com')]) + ; + } +} diff --git a/spec/Handler/Cart/CompleteOrderHandlerSpec.php b/spec/Handler/Cart/CompleteOrderHandlerSpec.php index db32b4165..5ac97648e 100644 --- a/spec/Handler/Cart/CompleteOrderHandlerSpec.php +++ b/spec/Handler/Cart/CompleteOrderHandlerSpec.php @@ -7,26 +7,19 @@ use PhpSpec\ObjectBehavior; use SM\Factory\FactoryInterface as StateMachineFactoryInterface; use SM\StateMachine\StateMachineInterface; -use Sylius\Component\Core\Model\CustomerInterface; use Sylius\Component\Core\Model\OrderInterface; use Sylius\Component\Core\OrderCheckoutTransitions; use Sylius\Component\Core\Repository\OrderRepositoryInterface; use Sylius\ShopApiPlugin\Command\Cart\CompleteOrder; -use Sylius\ShopApiPlugin\Provider\CustomerProviderInterface; final class CompleteOrderHandlerSpec extends ObjectBehavior { - function let( - OrderRepositoryInterface $orderRepository, - CustomerProviderInterface $customerProvider, - StateMachineFactoryInterface $stateMachineFactory - ): void { - $this->beConstructedWith($orderRepository, $customerProvider, $stateMachineFactory); + function let(OrderRepositoryInterface $orderRepository, StateMachineFactoryInterface $stateMachineFactory): void + { + $this->beConstructedWith($orderRepository, $stateMachineFactory); } function it_handles_order_completion( - CustomerInterface $customer, - CustomerProviderInterface $customerProvider, OrderInterface $order, OrderRepositoryInterface $orderRepository, StateMachineFactoryInterface $stateMachineFactory, @@ -34,21 +27,16 @@ function it_handles_order_completion( ): void { $orderRepository->findOneBy(['tokenValue' => 'ORDERTOKEN'])->willReturn($order); - $customerProvider->provide('example@customer.com')->willReturn($customer); - $stateMachineFactory->get($order, OrderCheckoutTransitions::GRAPH)->willReturn($stateMachine); $stateMachine->can('complete')->willReturn(true); $order->setNotes(null)->shouldBeCalled(); - $order->setCustomer($customer)->shouldBeCalled(); $stateMachine->apply('complete')->shouldBeCalled(); - $this(new CompleteOrder('ORDERTOKEN', 'example@customer.com')); + $this(new CompleteOrder('ORDERTOKEN')); } function it_handles_order_completion_with_notes( - CustomerInterface $customer, - CustomerProviderInterface $customerProvider, OrderInterface $order, OrderRepositoryInterface $orderRepository, StateMachineFactoryInterface $stateMachineFactory, @@ -56,16 +44,13 @@ function it_handles_order_completion_with_notes( ): void { $orderRepository->findOneBy(['tokenValue' => 'ORDERTOKEN'])->willReturn($order); - $customerProvider->provide('example@customer.com')->willReturn($customer); - $stateMachineFactory->get($order, OrderCheckoutTransitions::GRAPH)->willReturn($stateMachine); $stateMachine->can('complete')->willReturn(true); $order->setNotes('Some notes')->shouldBeCalled(); - $order->setCustomer($customer)->shouldBeCalled(); $stateMachine->apply('complete')->shouldBeCalled(); - $this(new CompleteOrder('ORDERTOKEN', 'example@customer.com', 'Some notes')); + $this(new CompleteOrder('ORDERTOKEN', 'Some notes')); } function it_throws_an_exception_if_order_does_not_exist( @@ -75,7 +60,7 @@ function it_throws_an_exception_if_order_does_not_exist( $this ->shouldThrow(\InvalidArgumentException::class) - ->during('__invoke', [new CompleteOrder('ORDERTOKEN', 'example@customer.com')]) + ->during('__invoke', [new CompleteOrder('ORDERTOKEN')]) ; } @@ -92,7 +77,7 @@ function it_throws_an_exception_if_order_cannot_be_completed( $this ->shouldThrow(\InvalidArgumentException::class) - ->during('__invoke', [new CompleteOrder('ORDERTOKEN', 'example@customer.com')]) + ->during('__invoke', [new CompleteOrder('ORDERTOKEN')]) ; } } diff --git a/src/Command/Cart/AssignCustomerToCart.php b/src/Command/Cart/AssignCustomerToCart.php new file mode 100644 index 000000000..e588f42df --- /dev/null +++ b/src/Command/Cart/AssignCustomerToCart.php @@ -0,0 +1,30 @@ +orderToken = $orderToken; + $this->email = $email; + } + + public function orderToken(): string + { + return $this->orderToken; + } + + public function email(): string + { + return $this->email; + } +} diff --git a/src/Command/Cart/CompleteOrder.php b/src/Command/Cart/CompleteOrder.php index 62edb615c..dda566d2e 100644 --- a/src/Command/Cart/CompleteOrder.php +++ b/src/Command/Cart/CompleteOrder.php @@ -9,16 +9,12 @@ class CompleteOrder /** @var string */ protected $orderToken; - /** @var string */ - protected $email; - /** @var string|null */ protected $notes; - public function __construct(string $orderToken, string $email, ?string $notes = null) + public function __construct(string $orderToken, ?string $notes = null) { $this->orderToken = $orderToken; - $this->email = $email; $this->notes = $notes; } @@ -27,11 +23,6 @@ public function orderToken(): string return $this->orderToken; } - public function email(): string - { - return $this->email; - } - public function notes(): ?string { return $this->notes; diff --git a/src/Controller/Checkout/CompleteOrderAction.php b/src/Controller/Checkout/CompleteOrderAction.php index 767d7d93d..54db6946e 100644 --- a/src/Controller/Checkout/CompleteOrderAction.php +++ b/src/Controller/Checkout/CompleteOrderAction.php @@ -6,6 +6,7 @@ use FOS\RestBundle\View\View; use FOS\RestBundle\View\ViewHandlerInterface; +use Sylius\ShopApiPlugin\Command\Cart\AssignCustomerToCart; use Sylius\ShopApiPlugin\Command\Cart\CompleteOrder; use Sylius\ShopApiPlugin\Exception\WrongUserException; use Sylius\ShopApiPlugin\Provider\LoggedInShopUserProviderInterface; @@ -42,10 +43,16 @@ public function __invoke(Request $request): Response } try { + $this->bus->dispatch( + new AssignCustomerToCart( + $request->attributes->get('token'), + $request->request->get('email', $defaultEmail ?? null) + ) + ); + $this->bus->dispatch( new CompleteOrder( $request->attributes->get('token'), - $request->request->get('email', $defaultEmail ?? null), $request->request->get('notes') ) ); diff --git a/src/Handler/Cart/AssignCustomerToCartHandler.php b/src/Handler/Cart/AssignCustomerToCartHandler.php new file mode 100644 index 000000000..d5ce5f6f5 --- /dev/null +++ b/src/Handler/Cart/AssignCustomerToCartHandler.php @@ -0,0 +1,38 @@ +orderRepository = $orderRepository; + $this->customerProvider = $customerProvider; + } + + public function __invoke(AssignCustomerToCart $assignOrderToCustomer): void + { + /** @var OrderInterface $order */ + $order = $this->orderRepository->findOneBy(['tokenValue' => $assignOrderToCustomer->orderToken()]); + + Assert::notNull($order, sprintf('Order with %s token has not been found.', $assignOrderToCustomer->orderToken())); + + $customer = $this->customerProvider->provide($assignOrderToCustomer->email()); + + $order->setCustomer($customer); + } +} diff --git a/src/Handler/Cart/CompleteOrderHandler.php b/src/Handler/Cart/CompleteOrderHandler.php index 2d7508319..89235d0aa 100644 --- a/src/Handler/Cart/CompleteOrderHandler.php +++ b/src/Handler/Cart/CompleteOrderHandler.php @@ -9,7 +9,6 @@ use Sylius\Component\Core\OrderCheckoutTransitions; use Sylius\Component\Core\Repository\OrderRepositoryInterface; use Sylius\ShopApiPlugin\Command\Cart\CompleteOrder; -use Sylius\ShopApiPlugin\Provider\CustomerProviderInterface; use Webmozart\Assert\Assert; final class CompleteOrderHandler @@ -17,19 +16,12 @@ final class CompleteOrderHandler /** @var OrderRepositoryInterface */ private $orderRepository; - /** @var CustomerProviderInterface */ - private $customerProvider; - /** @var StateMachineFactory */ private $stateMachineFactory; - public function __construct( - OrderRepositoryInterface $orderRepository, - CustomerProviderInterface $customerProvider, - StateMachineFactory $stateMachineFactory - ) { + public function __construct(OrderRepositoryInterface $orderRepository, StateMachineFactory $stateMachineFactory) + { $this->orderRepository = $orderRepository; - $this->customerProvider = $customerProvider; $this->stateMachineFactory = $stateMachineFactory; } @@ -44,9 +36,7 @@ public function __invoke(CompleteOrder $completeOrder): void Assert::true($stateMachine->can(OrderCheckoutTransitions::TRANSITION_COMPLETE), sprintf('Order with %s token cannot be completed.', $completeOrder->orderToken())); - $customer = $this->customerProvider->provide($completeOrder->email()); $order->setNotes($completeOrder->notes()); - $order->setCustomer($customer); $stateMachine->apply(OrderCheckoutTransitions::TRANSITION_COMPLETE); } diff --git a/src/Resources/config/services/handler/cart.xml b/src/Resources/config/services/handler/cart.xml index 4dd9afd22..51296e239 100644 --- a/src/Resources/config/services/handler/cart.xml +++ b/src/Resources/config/services/handler/cart.xml @@ -98,10 +98,16 @@ + + + + + + - diff --git a/tests/Controller/Cart/CartDropCartApiTest.php b/tests/Controller/Cart/CartDropCartApiTest.php index d0d0aa556..33e778bad 100644 --- a/tests/Controller/Cart/CartDropCartApiTest.php +++ b/tests/Controller/Cart/CartDropCartApiTest.php @@ -6,6 +6,7 @@ use Sylius\Component\Core\Model\OrderInterface; use Sylius\ShopApiPlugin\Command\Cart\AddressOrder; +use Sylius\ShopApiPlugin\Command\Cart\AssignCustomerToCart; use Sylius\ShopApiPlugin\Command\Cart\ChoosePaymentMethod; use Sylius\ShopApiPlugin\Command\Cart\ChooseShippingMethod; use Sylius\ShopApiPlugin\Command\Cart\CompleteOrder; @@ -68,6 +69,7 @@ public function it_returns_not_found_exception_if_order_is_in_different_state_th /** @var MessageBusInterface $bus */ $bus = $this->get('sylius_shop_api_plugin.command_bus'); $bus->dispatch(new PickupCart($token, 'WEB_GB')); + $bus->dispatch(new AssignCustomerToCart($token, 'sylius@example.com')); $bus->dispatch(new PutSimpleItemToCart($token, 'LOGAN_MUG_CODE', 5)); $bus->dispatch(new AddressOrder( $token, @@ -95,7 +97,7 @@ public function it_returns_not_found_exception_if_order_is_in_different_state_th /** @var OrderInterface $order */ $order = $this->get('sylius.repository.order')->findOneBy(['tokenValue' => $token]); - $bus->dispatch(new CompleteOrder($token, 'sylius@example.com')); + $bus->dispatch(new CompleteOrder($token)); $this->client->request('DELETE', '/shop-api/carts/' . $order->getTokenValue(), [], [], self::CONTENT_TYPE_HEADER); $response = $this->client->getResponse(); diff --git a/tests/Controller/Cart/CartPutItemToCartApiTest.php b/tests/Controller/Cart/CartPutItemToCartApiTest.php index a3c6ce4df..6a9e9bec0 100644 --- a/tests/Controller/Cart/CartPutItemToCartApiTest.php +++ b/tests/Controller/Cart/CartPutItemToCartApiTest.php @@ -6,6 +6,7 @@ use Sylius\Component\Core\Model\OrderInterface; use Sylius\ShopApiPlugin\Command\Cart\AddressOrder; +use Sylius\ShopApiPlugin\Command\Cart\AssignCustomerToCart; use Sylius\ShopApiPlugin\Command\Cart\ChoosePaymentMethod; use Sylius\ShopApiPlugin\Command\Cart\ChooseShippingMethod; use Sylius\ShopApiPlugin\Command\Cart\CompleteOrder; @@ -234,6 +235,7 @@ public function it_does_not_allow_to_add_product_if_order_has_been_placed(): voi /** @var MessageBusInterface $bus */ $bus = $this->get('sylius_shop_api_plugin.command_bus'); $bus->dispatch(new PickupCart($token, 'WEB_GB')); + $bus->dispatch(new AssignCustomerToCart($token, 'sylius@example.com')); $bus->dispatch(new PutSimpleItemToCart($token, 'LOGAN_MUG_CODE', 5)); $bus->dispatch(new AddressOrder( $token, @@ -261,7 +263,7 @@ public function it_does_not_allow_to_add_product_if_order_has_been_placed(): voi /** @var OrderInterface $order */ $order = $this->get('sylius.repository.order')->findOneBy(['tokenValue' => $token]); - $bus->dispatch(new CompleteOrder($token, 'sylius@example.com')); + $bus->dispatch(new CompleteOrder($token)); $data = <<get('sylius_shop_api_plugin.command_bus'); $bus->dispatch(new PickupCart($token, 'WEB_GB')); + $bus->dispatch(new AssignCustomerToCart($token, $email)); $bus->dispatch(new PutSimpleItemToCart($token, 'LOGAN_MUG_CODE', 5)); $bus->dispatch(new AddressOrder( $token, @@ -43,7 +45,7 @@ protected function placeOrderForCustomerWithEmail(string $email, string $token): )); $bus->dispatch(new ChooseShippingMethod($token, 0, 'DHL')); $bus->dispatch(new ChoosePaymentMethod($token, 0, 'PBC')); - $bus->dispatch(new CompleteOrder($token, $email)); + $bus->dispatch(new CompleteOrder($token)); } /** Function is not typehinted because has to be compatible with \ApiTestCase\ApiTestCase::get($id) */