diff --git a/src/Checker/OrderPaymentEditionChecker.php b/src/Checker/OrderPaymentEditionChecker.php new file mode 100644 index 0000000..dc64ecc --- /dev/null +++ b/src/Checker/OrderPaymentEditionChecker.php @@ -0,0 +1,28 @@ +requestStack->getCurrentRequest(); + if (null === $request) { + return true; + } + + return 'setono_sylius_order_edit_admin_update' !== $request->attributes->get('_route'); + } +} 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(); + 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/OrderProcessing/OrderPaymentProcessor.php b/src/OrderProcessing/OrderPaymentProcessor.php index 5a7aec4..2a6df74 100644 --- a/src/OrderProcessing/OrderPaymentProcessor.php +++ b/src/OrderProcessing/OrderPaymentProcessor.php @@ -4,26 +4,21 @@ namespace Setono\SyliusOrderEditPlugin\OrderProcessing; +use Setono\SyliusOrderEditPlugin\Checker\OrderPaymentEditionCheckerInterface; use Sylius\Component\Order\Model\OrderInterface; use Sylius\Component\Order\Processor\OrderProcessorInterface; -use Symfony\Component\HttpFoundation\RequestStack; final class OrderPaymentProcessor implements OrderProcessorInterface { public function __construct( private readonly OrderProcessorInterface $decorated, - private readonly RequestStack $requestStack, + private readonly OrderPaymentEditionCheckerInterface $orderPaymentEditionChecker, ) { } public function process(OrderInterface $order): void { - /** @var mixed $route */ - $route = $this->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..a2ef9ef 100644 --- a/src/Resources/config/services/order_processing.xml +++ b/src/Resources/config/services/order_processing.xml @@ -2,11 +2,36 @@ - + - + + + + + + + + + + + + + + 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..8932e79 --- /dev/null +++ b/tests/Unit/Checker/OrderPaymentEditionCheckerTest.php @@ -0,0 +1,52 @@ +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(); + + self::assertFalse($checker->shouldOrderPaymentBeEdited($order)); + } + + 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(); + + self::assertTrue($checker->shouldOrderPaymentBeEdited($order)); + } + + public function testItSaysOrderPaymentCanBeEditedIfThereIsNoCurrentRequest(): void + { + $requestStack = $this->prophesize(RequestStack::class); + $requestStack->getCurrentRequest()->willReturn(null); + + $checker = new OrderPaymentEditionChecker($requestStack->reveal()); + $order = new Order(); + + 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())); + } +} 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); } }