From e3835bc068835890177da7d9c128f0c7e0b1679d Mon Sep 17 00:00:00 2001 From: Mateusz Zalewski Date: Tue, 20 Aug 2024 11:54:16 +0200 Subject: [PATCH 1/2] Refactor checking for payments edition --- src/Checker/OrderPaymentEditionChecker.php | 33 +++++++++ .../OrderPaymentEditionCheckerInterface.php | 12 ++++ src/OrderProcessing/OrderPaymentProcessor.php | 11 +-- .../config/services/order_processing.xml | 26 +++++-- tests/Functional/OrderUpdateTest.php | 33 +++++++++ .../OrderPaymentEditionCheckerTest.php | 71 +++++++++++++++++++ .../OrderPaymentProcessorTest.php | 31 ++++---- 7 files changed, 188 insertions(+), 29 deletions(-) create mode 100644 src/Checker/OrderPaymentEditionChecker.php create mode 100644 src/Checker/OrderPaymentEditionCheckerInterface.php create mode 100644 tests/Unit/Checker/OrderPaymentEditionCheckerTest.php diff --git a/src/Checker/OrderPaymentEditionChecker.php b/src/Checker/OrderPaymentEditionChecker.php new file mode 100644 index 0000000..e964ece --- /dev/null +++ b/src/Checker/OrderPaymentEditionChecker.php @@ -0,0 +1,33 @@ +requestStack->getCurrentRequest(); + if (null === $request) { + return true; + } + + if ('setono_sylius_order_edit_admin_update' !== $request->attributes->get('_route')) { + return true; + } + + return $order->getPaymentState() === OrderPaymentStates::STATE_AWAITING_PAYMENT; + } +} diff --git a/src/Checker/OrderPaymentEditionCheckerInterface.php b/src/Checker/OrderPaymentEditionCheckerInterface.php new file mode 100644 index 0000000..3d881aa --- /dev/null +++ b/src/Checker/OrderPaymentEditionCheckerInterface.php @@ -0,0 +1,12 @@ +requestStack->getCurrentRequest()?->attributes->get('_route'); - - // This disables the \Sylius\Component\Core\OrderProcessing\OrderPaymentProcessor if the route is 'setono_sylius_order_edit_admin_update' - // which means we are editing the order in the admin panel - if ('setono_sylius_order_edit_admin_update' === $route) { + if (!$this->orderPaymentEditionChecker->shouldOrderPaymentBeEdited($order)) { return; } diff --git a/src/Resources/config/services/order_processing.xml b/src/Resources/config/services/order_processing.xml index 9c8a21d..05bc6eb 100644 --- a/src/Resources/config/services/order_processing.xml +++ b/src/Resources/config/services/order_processing.xml @@ -2,11 +2,29 @@ - + - + + + + + + + + + + getOrderRepository()->findOneBy(['tokenValue' => 'TOKEN']); + self::assertSame($initialOrderTotalWithoutTaxes - 100, $this->getResultTotal($order)); + self::assertCount(1, $order->getPayments()->toArray()); + } + + public function testItDoesNotChangePaymentsForAlreadyPaidOrders(): void + { + $order = $this->placeOrderProgrammatically(quantity: 5, paid: true); + $initialOrderTotalWithoutTaxes = $this->getInitialTotal($order); + $initialPaymentTotal = $order->getPayments()->first()->getAmount(); + + $this->loginAsAdmin(); + $this->addDiscountsToOrder($order->getId(), [1]); + + self::assertResponseStatusCodeSame(302); + + /** @var OrderInterface $order */ $order = $this->getOrderRepository()->findOneBy(['tokenValue' => 'TOKEN']); self::assertSame($initialOrderTotalWithoutTaxes - 100, $this->getResultTotal($order)); + self::assertCount(1, $order->getPayments()->toArray()); + self::assertSame($initialPaymentTotal, $order->getPayments()->first()->getAmount()); } public function testItAllowsToAddAndRemoveDiscountsForTheWholeOrderMultipleTimes(): void @@ -209,6 +232,7 @@ public function testItAllowsToAddStoreNotes(): void private function placeOrderProgrammatically( string $variantCode = '000F_office_grey_jeans-variant-0', int $quantity = 1, + bool $paid = false, ): EditableOrderInterface { /** @var MessageBusInterface $commandBus */ $commandBus = self::getContainer()->get('sylius.command_bus'); @@ -252,6 +276,15 @@ private function placeOrderProgrammatically( $completeOrder->setOrderTokenValue('TOKEN'); $commandBus->dispatch($completeOrder); + if ($paid) { + /** @var FactoryInterface $stateMachineFactory */ + $stateMachineFactory = self::getContainer()->get('sm.factory'); + /** @var PaymentInterface $payment */ + $payment = $order->getPayments()->first(); + $stateMachineFactory->get($payment, PaymentTransitions::GRAPH)->apply(PaymentTransitions::TRANSITION_COMPLETE); + self::getEntityManager()->flush(); + } + return $this->getOrderRepository()->findOneBy(['tokenValue' => 'TOKEN']); } diff --git a/tests/Unit/Checker/OrderPaymentEditionCheckerTest.php b/tests/Unit/Checker/OrderPaymentEditionCheckerTest.php new file mode 100644 index 0000000..6264be9 --- /dev/null +++ b/tests/Unit/Checker/OrderPaymentEditionCheckerTest.php @@ -0,0 +1,71 @@ +prophesize(RequestStack::class); + $request = new Request([], [], ['_route' => 'setono_sylius_order_edit_admin_update']); + $requestStack->getCurrentRequest()->willReturn($request); + + $checker = new OrderPaymentEditionChecker($requestStack->reveal()); + + $order = $this->prophesize(OrderInterface::class); + $order->getPaymentState()->willReturn(OrderPaymentStates::STATE_AUTHORIZED); + + self::assertFalse($checker->shouldOrderPaymentBeEdited($order->reveal())); + } + + public function testItSaysOrderPaymentShouldBeEditedItTheRouteIsOrderEditButOrderIsAwaitingPayment(): void + { + $requestStack = $this->prophesize(RequestStack::class); + $request = new Request([], [], ['_route' => 'setono_sylius_order_edit_admin_update']); + $requestStack->getCurrentRequest()->willReturn($request); + + $checker = new OrderPaymentEditionChecker($requestStack->reveal()); + + $order = $this->prophesize(OrderInterface::class); + $order->getPaymentState()->willReturn(OrderPaymentStates::STATE_AWAITING_PAYMENT); + + self::assertTrue($checker->shouldOrderPaymentBeEdited($order->reveal())); + } + + public function testItSaysOrderPaymentShouldBeEditedIfItsNotOrderEditRoute(): void + { + $requestStack = $this->prophesize(RequestStack::class); + $request = new Request([], [], ['_route' => 'sylius_admin_order_any_other_route']); + $requestStack->getCurrentRequest()->willReturn($request); + + $checker = new OrderPaymentEditionChecker($requestStack->reveal()); + + $order = $this->prophesize(OrderInterface::class); + + self::assertTrue($checker->shouldOrderPaymentBeEdited($order->reveal())); + } + + public function testItSaysOrderPaymentShouldBeEditedIfThereIsNoCurrentRequest(): void + { + $requestStack = $this->prophesize(RequestStack::class); + $requestStack->getCurrentRequest()->willReturn(null); + + $checker = new OrderPaymentEditionChecker($requestStack->reveal()); + + $order = $this->prophesize(OrderInterface::class); + + self::assertTrue($checker->shouldOrderPaymentBeEdited($order->reveal())); + } +} diff --git a/tests/Unit/OrderProcessing/OrderPaymentProcessorTest.php b/tests/Unit/OrderProcessing/OrderPaymentProcessorTest.php index fd74b88..ee73c4d 100644 --- a/tests/Unit/OrderProcessing/OrderPaymentProcessorTest.php +++ b/tests/Unit/OrderProcessing/OrderPaymentProcessorTest.php @@ -6,45 +6,42 @@ use PHPUnit\Framework\TestCase; use Prophecy\PhpUnit\ProphecyTrait; +use Setono\SyliusOrderEditPlugin\Checker\OrderPaymentEditionCheckerInterface; use Setono\SyliusOrderEditPlugin\OrderProcessing\OrderPaymentProcessor; -use Sylius\Component\Core\Model\OrderInterface; +use Sylius\Component\Core\Model\Order; use Sylius\Component\Order\Processor\OrderProcessorInterface; -use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpFoundation\RequestStack; final class OrderPaymentProcessorTest extends TestCase { use ProphecyTrait; - public function testItDoesNotAllowToProcessOrderIfItsEdited(): void + public function testItDoesNotAllowToProcessOrderIfItShouldNotBeEdited(): void { $orderProcessor = $this->prophesize(OrderProcessorInterface::class); - $requestStack = $this->prophesize(RequestStack::class); - $request = new Request([], [], ['_route' => 'setono_sylius_order_edit_admin_update']); - $requestStack->getCurrentRequest()->willReturn($request); + $orderPaymentEditionChecker = $this->prophesize(OrderPaymentEditionCheckerInterface::class); - $processor = new OrderPaymentProcessor($orderProcessor->reveal(), $requestStack->reveal()); + $processor = new OrderPaymentProcessor($orderProcessor->reveal(), $orderPaymentEditionChecker->reveal()); - $order = $this->prophesize(OrderInterface::class); + $order = new Order(); + $orderPaymentEditionChecker->shouldOrderPaymentBeEdited($order)->willReturn(false); $orderProcessor->process($order)->shouldNotBeCalled(); - $processor->process($order->reveal()); + $processor->process($order); } - public function testItDoesNothingIfItsDifferentRoute(): void + public function testItDoesNothingIfItShouldBeEdited(): void { $orderProcessor = $this->prophesize(OrderProcessorInterface::class); - $requestStack = $this->prophesize(RequestStack::class); - $request = new Request([], [], ['_route' => 'some_other_route']); - $requestStack->getCurrentRequest()->willReturn($request); + $orderPaymentEditionChecker = $this->prophesize(OrderPaymentEditionCheckerInterface::class); - $processor = new OrderPaymentProcessor($orderProcessor->reveal(), $requestStack->reveal()); + $processor = new OrderPaymentProcessor($orderProcessor->reveal(), $orderPaymentEditionChecker->reveal()); - $order = $this->prophesize(OrderInterface::class); + $order = new Order(); + $orderPaymentEditionChecker->shouldOrderPaymentBeEdited($order)->willReturn(true); $orderProcessor->process($order)->shouldBeCalled(); - $processor->process($order->reveal()); + $processor->process($order); } } From 8004c4fa0d6f24c4c9aa999cb53f0cdf286f4ffe Mon Sep 17 00:00:00 2001 From: Mateusz Zalewski Date: Tue, 20 Aug 2024 11:59:33 +0200 Subject: [PATCH 2/2] Apply different checkers for order pre and post completion --- src/Checker/OrderPaymentEditionChecker.php | 7 +- ...PostCheckoutOrderPaymentEditionChecker.php | 33 +++++++++ .../config/services/order_processing.xml | 9 ++- .../OrderPaymentEditionCheckerTest.php | 39 +++------- ...CheckoutOrderPaymentEditionCheckerTest.php | 71 +++++++++++++++++++ 5 files changed, 123 insertions(+), 36 deletions(-) create mode 100644 src/Checker/PostCheckoutOrderPaymentEditionChecker.php create mode 100644 tests/Unit/Checker/PostCheckoutOrderPaymentEditionCheckerTest.php diff --git a/src/Checker/OrderPaymentEditionChecker.php b/src/Checker/OrderPaymentEditionChecker.php index e964ece..dc64ecc 100644 --- a/src/Checker/OrderPaymentEditionChecker.php +++ b/src/Checker/OrderPaymentEditionChecker.php @@ -4,7 +4,6 @@ namespace Setono\SyliusOrderEditPlugin\Checker; -use Sylius\Component\Core\OrderPaymentStates; use Sylius\Component\Order\Model\OrderInterface; use Symfony\Component\HttpFoundation\RequestStack; use Webmozart\Assert\Assert; @@ -24,10 +23,6 @@ public function shouldOrderPaymentBeEdited(OrderInterface $order): bool return true; } - if ('setono_sylius_order_edit_admin_update' !== $request->attributes->get('_route')) { - return true; - } - - return $order->getPaymentState() === OrderPaymentStates::STATE_AWAITING_PAYMENT; + return 'setono_sylius_order_edit_admin_update' !== $request->attributes->get('_route'); } } diff --git a/src/Checker/PostCheckoutOrderPaymentEditionChecker.php b/src/Checker/PostCheckoutOrderPaymentEditionChecker.php new file mode 100644 index 0000000..8d02bcb --- /dev/null +++ b/src/Checker/PostCheckoutOrderPaymentEditionChecker.php @@ -0,0 +1,33 @@ +requestStack->getCurrentRequest(); + if (null === $request) { + return true; + } + + if ('setono_sylius_order_edit_admin_update' !== $request->attributes->get('_route')) { + return true; + } + + return $order->getPaymentState() === OrderPaymentStates::STATE_AWAITING_PAYMENT; + } +} diff --git a/src/Resources/config/services/order_processing.xml b/src/Resources/config/services/order_processing.xml index 05bc6eb..a2ef9ef 100644 --- a/src/Resources/config/services/order_processing.xml +++ b/src/Resources/config/services/order_processing.xml @@ -17,7 +17,7 @@ decorates="sylius.order_processing.order_payment_processor.after_checkout" decoration-priority="64" > - + + + + + prophesize(RequestStack::class); $request = new Request([], [], ['_route' => 'setono_sylius_order_edit_admin_update']); $requestStack->getCurrentRequest()->willReturn($request); $checker = new OrderPaymentEditionChecker($requestStack->reveal()); + $order = new Order(); - $order = $this->prophesize(OrderInterface::class); - $order->getPaymentState()->willReturn(OrderPaymentStates::STATE_AUTHORIZED); - - self::assertFalse($checker->shouldOrderPaymentBeEdited($order->reveal())); + self::assertFalse($checker->shouldOrderPaymentBeEdited($order)); } - public function testItSaysOrderPaymentShouldBeEditedItTheRouteIsOrderEditButOrderIsAwaitingPayment(): void - { - $requestStack = $this->prophesize(RequestStack::class); - $request = new Request([], [], ['_route' => 'setono_sylius_order_edit_admin_update']); - $requestStack->getCurrentRequest()->willReturn($request); - - $checker = new OrderPaymentEditionChecker($requestStack->reveal()); - - $order = $this->prophesize(OrderInterface::class); - $order->getPaymentState()->willReturn(OrderPaymentStates::STATE_AWAITING_PAYMENT); - - self::assertTrue($checker->shouldOrderPaymentBeEdited($order->reveal())); - } - - public function testItSaysOrderPaymentShouldBeEditedIfItsNotOrderEditRoute(): void + public function testItSaysOrderPaymentCanBeEditedIfItsNotOrderEditRoute(): void { $requestStack = $this->prophesize(RequestStack::class); $request = new Request([], [], ['_route' => 'sylius_admin_order_any_other_route']); $requestStack->getCurrentRequest()->willReturn($request); $checker = new OrderPaymentEditionChecker($requestStack->reveal()); + $order = new Order(); - $order = $this->prophesize(OrderInterface::class); - - self::assertTrue($checker->shouldOrderPaymentBeEdited($order->reveal())); + self::assertTrue($checker->shouldOrderPaymentBeEdited($order)); } - public function testItSaysOrderPaymentShouldBeEditedIfThereIsNoCurrentRequest(): void + public function testItSaysOrderPaymentCanBeEditedIfThereIsNoCurrentRequest(): void { $requestStack = $this->prophesize(RequestStack::class); $requestStack->getCurrentRequest()->willReturn(null); $checker = new OrderPaymentEditionChecker($requestStack->reveal()); + $order = new Order(); - $order = $this->prophesize(OrderInterface::class); - - self::assertTrue($checker->shouldOrderPaymentBeEdited($order->reveal())); + self::assertTrue($checker->shouldOrderPaymentBeEdited($order)); } } diff --git a/tests/Unit/Checker/PostCheckoutOrderPaymentEditionCheckerTest.php b/tests/Unit/Checker/PostCheckoutOrderPaymentEditionCheckerTest.php new file mode 100644 index 0000000..edf7f00 --- /dev/null +++ b/tests/Unit/Checker/PostCheckoutOrderPaymentEditionCheckerTest.php @@ -0,0 +1,71 @@ +prophesize(RequestStack::class); + $request = new Request([], [], ['_route' => 'setono_sylius_order_edit_admin_update']); + $requestStack->getCurrentRequest()->willReturn($request); + + $checker = new PostCheckoutOrderPaymentEditionChecker($requestStack->reveal()); + + $order = $this->prophesize(OrderInterface::class); + $order->getPaymentState()->willReturn(OrderPaymentStates::STATE_AUTHORIZED); + + self::assertFalse($checker->shouldOrderPaymentBeEdited($order->reveal())); + } + + public function testItSaysOrderPaymentShouldBeEditedItTheRouteIsOrderEditButOrderIsAwaitingPayment(): void + { + $requestStack = $this->prophesize(RequestStack::class); + $request = new Request([], [], ['_route' => 'setono_sylius_order_edit_admin_update']); + $requestStack->getCurrentRequest()->willReturn($request); + + $checker = new PostCheckoutOrderPaymentEditionChecker($requestStack->reveal()); + + $order = $this->prophesize(OrderInterface::class); + $order->getPaymentState()->willReturn(OrderPaymentStates::STATE_AWAITING_PAYMENT); + + self::assertTrue($checker->shouldOrderPaymentBeEdited($order->reveal())); + } + + public function testItSaysOrderPaymentShouldBeEditedIfItsNotOrderEditRoute(): void + { + $requestStack = $this->prophesize(RequestStack::class); + $request = new Request([], [], ['_route' => 'sylius_admin_order_any_other_route']); + $requestStack->getCurrentRequest()->willReturn($request); + + $checker = new PostCheckoutOrderPaymentEditionChecker($requestStack->reveal()); + + $order = $this->prophesize(OrderInterface::class); + + self::assertTrue($checker->shouldOrderPaymentBeEdited($order->reveal())); + } + + public function testItSaysOrderPaymentShouldBeEditedIfThereIsNoCurrentRequest(): void + { + $requestStack = $this->prophesize(RequestStack::class); + $requestStack->getCurrentRequest()->willReturn(null); + + $checker = new PostCheckoutOrderPaymentEditionChecker($requestStack->reveal()); + + $order = $this->prophesize(OrderInterface::class); + + self::assertTrue($checker->shouldOrderPaymentBeEdited($order->reveal())); + } +}