From b3f1e8faa29afb5fccf4ab85da5f33b7e079be7e Mon Sep 17 00:00:00 2001 From: Frederik Rommel Date: Fri, 13 Sep 2024 13:51:38 +0200 Subject: [PATCH] =?UTF-8?q?PAYOSWXP-156:=20set=20transaction-state=20to=20?= =?UTF-8?q?=E2=80=9Eauthorized=E2=80=9C=20on=20=E2=80=9Eappointed=E2=80=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/DependencyInjection/controllers.xml | 13 -- src/DependencyInjection/webhooks.xml | 4 + .../Webhook/Handler/PaymentStatusHandler.php | 51 +++++ .../order-history/order-item.html.twig | 10 - .../AccountOrderControllerDecorator.php | 96 --------- .../Handler/PaymentStatusHandlerTest.php | 68 ++++++ .../AccountOrderControllerDecoratorTest.php | 200 ------------------ 7 files changed, 123 insertions(+), 319 deletions(-) create mode 100644 src/Payone/Webhook/Handler/PaymentStatusHandler.php delete mode 100644 src/Resources/views/storefront/page/account/order-history/order-item.html.twig delete mode 100644 src/Storefront/Controller/Account/AccountOrderControllerDecorator.php create mode 100644 tests/Payone/Webhook/Handler/PaymentStatusHandlerTest.php delete mode 100644 tests/Storefront/Controller/Account/AccountOrderControllerDecoratorTest.php diff --git a/src/DependencyInjection/controllers.xml b/src/DependencyInjection/controllers.xml index 1d6e0d712..a6f7aa755 100644 --- a/src/DependencyInjection/controllers.xml +++ b/src/DependencyInjection/controllers.xml @@ -61,19 +61,6 @@ - - - - - - - - - - - - diff --git a/src/DependencyInjection/webhooks.xml b/src/DependencyInjection/webhooks.xml index 846bcec4e..b575687d0 100644 --- a/src/DependencyInjection/webhooks.xml +++ b/src/DependencyInjection/webhooks.xml @@ -35,6 +35,10 @@ + + + + diff --git a/src/Payone/Webhook/Handler/PaymentStatusHandler.php b/src/Payone/Webhook/Handler/PaymentStatusHandler.php new file mode 100644 index 000000000..4079f59b8 --- /dev/null +++ b/src/Payone/Webhook/Handler/PaymentStatusHandler.php @@ -0,0 +1,51 @@ +transactionDataHandler->getPaymentTransactionByPayoneTransactionId( + $salesChannelContext->getContext(), + $request->request->getInt('txid') + ); + + if (!$paymentTransaction instanceof PaymentTransaction) { + return; + } + + $this->stateMachineRegistry->transition( + new Transition( + OrderTransactionDefinition::ENTITY_NAME, + $paymentTransaction->getOrderTransaction()->getId(), + StateMachineTransitionActions::ACTION_AUTHORIZE, + 'stateId' + ), + $salesChannelContext->getContext() + ); + } + + public function supports(SalesChannelContext $salesChannelContext, array $data): bool + { + return isset($data['txid']) && ($data['txaction'] ?? null) === TransactionStatusService::ACTION_APPOINTED; + } +} diff --git a/src/Resources/views/storefront/page/account/order-history/order-item.html.twig b/src/Resources/views/storefront/page/account/order-history/order-item.html.twig deleted file mode 100644 index f47334b72..000000000 --- a/src/Resources/views/storefront/page/account/order-history/order-item.html.twig +++ /dev/null @@ -1,10 +0,0 @@ -{% sw_extends '@Storefront/storefront/page/account/order-history/order-item.html.twig' %} - -{% block page_account_order_item_context_menu_content_change_payment_button %} - {% set RATEPAY_PAYMENT_HANDLER = constant('PayonePayment\\PaymentHandler\\PaymentHandlerGroups::RATEPAY') %} - - {# You can't change the payment if it is a ratepay order #} - {% if order.transactions|last.paymentMethod.handlerIdentifier not in RATEPAY_PAYMENT_HANDLER %} - {{ parent() }} - {% endif %} -{% endblock %} \ No newline at end of file diff --git a/src/Storefront/Controller/Account/AccountOrderControllerDecorator.php b/src/Storefront/Controller/Account/AccountOrderControllerDecorator.php deleted file mode 100644 index a8b0ce724..000000000 --- a/src/Storefront/Controller/Account/AccountOrderControllerDecorator.php +++ /dev/null @@ -1,96 +0,0 @@ - ['storefront']])] -class AccountOrderControllerDecorator extends StorefrontController -{ - /** - * @var AccountOrderController - */ - protected $decoratedController; - - public function __construct(StorefrontController $decoratedController, protected EntityRepository $orderRepository) - { - /** @phpstan-ignore-next-line */ - $this->decoratedController = $decoratedController; - } - - public function orderOverview(Request $request, SalesChannelContext $context): Response - { - return $this->decoratedController->orderOverview($request, $context); - } - - public function cancelOrder(Request $request, SalesChannelContext $context): Response - { - return $this->decoratedController->cancelOrder($request, $context); - } - - public function orderSingleOverview(Request $request, SalesChannelContext $context): Response - { - return $this->decoratedController->orderSingleOverview($request, $context); - } - - public function ajaxOrderDetail(Request $request, SalesChannelContext $context): Response - { - return $this->decoratedController->ajaxOrderDetail($request, $context); - } - - public function editOrder(string $orderId, Request $request, SalesChannelContext $context): Response - { - if ($this->isRatepayOrder($orderId, $context->getContext())) { - return $this->redirectToRoute('frontend.account.order.page'); - } - - return $this->decoratedController->editOrder($orderId, $request, $context); - } - - public function orderChangePayment(string $orderId, Request $request, SalesChannelContext $context): Response - { - return $this->decoratedController->orderChangePayment($orderId, $request, $context); - } - - public function updateOrder(string $orderId, Request $request, SalesChannelContext $context): Response - { - if ($this->isRatepayOrder($orderId, $context->getContext())) { - return $this->redirectToRoute('frontend.account.order.page'); - } - - return $this->decoratedController->updateOrder($orderId, $request, $context); - } - - protected function isRatepayOrder(string $orderId, Context $context): bool - { - $criteria = new Criteria([$orderId]); - $criteria->addAssociation('transactions.paymentMethod'); - - /** @var OrderEntity|null $order */ - $order = $this->orderRepository->search($criteria, $context)->first(); - - if ($order && $order->getTransactions()) { - $transaction = $order->getTransactions()->last(); - - if ($transaction - && $transaction->getPaymentMethod() - && \in_array($transaction->getPaymentMethod()->getHandlerIdentifier(), PaymentHandlerGroups::RATEPAY, true)) { - return true; - } - } - - return false; - } -} diff --git a/tests/Payone/Webhook/Handler/PaymentStatusHandlerTest.php b/tests/Payone/Webhook/Handler/PaymentStatusHandlerTest.php new file mode 100644 index 000000000..9dc25ea19 --- /dev/null +++ b/tests/Payone/Webhook/Handler/PaymentStatusHandlerTest.php @@ -0,0 +1,68 @@ +createMock(TransactionDataHandlerInterface::class), + $this->createMock(StateMachineRegistry::class), + ); + + $salesChannelMock = $this->createMock(SalesChannelContext::class); + + static::assertTrue($handler->supports($salesChannelMock, ['txid' => 1, 'txaction' => 'appointed']), 'supports should return true, cause of valid txid nd correct status'); + + static::assertFalse($handler->supports($salesChannelMock, ['txaction' => 'appointed']), 'supports should return false, cause of missing txid'); + static::assertFalse($handler->supports($salesChannelMock, ['txid' => 1]), 'supports should return false, cause of missing status'); + static::assertFalse($handler->supports($salesChannelMock, []), 'supports should return false, cause of missing data'); + static::assertFalse($handler->supports($salesChannelMock, []), 'supports should return false, cause of missing data'); + + static::assertFalse($handler->supports($salesChannelMock, ['txid' => 1, 'txaction' => TransactionStatusService::ACTION_CAPTURE]), 'supports should return false, cause of wrong status'); + static::assertFalse($handler->supports($salesChannelMock, ['txid' => 1, 'txaction' => TransactionStatusService::ACTION_COMPLETED]), 'supports should return false, cause of wrong status'); + static::assertFalse($handler->supports($salesChannelMock, ['txid' => 1, 'txaction' => TransactionStatusService::ACTION_FAILED]), 'supports should return false, cause of wrong status'); + } + + public function testIsCaptureGotExecuted(): void + { + $dataHandler = $this->createMock(TransactionDataHandlerInterface::class); + $dataHandler->method('getPaymentTransactionByPayoneTransactionId')->willReturn($this->createMock(PaymentTransaction::class)); + $stateMachine = $this->createMock(StateMachineRegistry::class); + $stateMachine->expects(static::once())->method('transition'); + + $request = new Request(); + $request->request->set('txid', 123); + + (new PaymentStatusHandler($dataHandler, $stateMachine)) + ->process($this->createMock(SalesChannelContext::class), $request); + } + + public function testIsCaptureGotNotExecutedIfTransactionIsNotFound(): void + { + $dataHandler = $this->createMock(TransactionDataHandlerInterface::class); + $dataHandler->method('getPaymentTransactionByPayoneTransactionId')->willReturn(null); + $stateMachine = $this->createMock(StateMachineRegistry::class); + $stateMachine->expects(static::never())->method('transition'); + + $request = new Request(); + $request->request->set('txid', 123); + + (new PaymentStatusHandler($dataHandler, $stateMachine)) + ->process($this->createMock(SalesChannelContext::class), $request); + } +} diff --git a/tests/Storefront/Controller/Account/AccountOrderControllerDecoratorTest.php b/tests/Storefront/Controller/Account/AccountOrderControllerDecoratorTest.php deleted file mode 100644 index efb284d2b..000000000 --- a/tests/Storefront/Controller/Account/AccountOrderControllerDecoratorTest.php +++ /dev/null @@ -1,200 +0,0 @@ -getContainer()->get(AccountOrderController::class); - - static::assertInstanceOf(AccountOrderControllerDecorator::class, $controller); - } - - public function testItRedirectsFromEditOrderPageToOverviewPageOnRatepayOrder(): void - { - $salesChannelContext = $this->createSalesChannelContextWithLoggedInCustomerAndWithNavigation(); - $order = $this->getRandomOrder($salesChannelContext); - $paymentTransaction = $this->getPaymentTransaction($order, PayoneRatepayDebitPaymentHandler::class); - $order->setTransactions(new OrderTransactionCollection([$paymentTransaction->getOrderTransaction()])); - - $orderRepository = $this->createMock(EntityRepository::class); - $orderRepository->expects(static::once())->method('search')->willReturn( - $this->getEntitySearchResult($order, $salesChannelContext) - ); - - $decoratedController = $this->createMock(AccountOrderController::class); - $decoratedController->expects(static::never())->method('editOrder'); - - $controller = new AccountOrderControllerDecorator( - $decoratedController, - $orderRepository - ); - $controller->setContainer($this->getContainer()); - - $response = $controller->editOrder($order->getId(), new Request(), $salesChannelContext); - - static::assertInstanceOf(RedirectResponse::class, $response); - } - - public function testItNotRedirectsFromEditOrderPageToOverviewPageOnOtherPaymentMethodThanRatepay(): void - { - $salesChannelContext = $this->createSalesChannelContextWithLoggedInCustomerAndWithNavigation(); - $order = $this->getRandomOrder($salesChannelContext); - $paymentTransaction = $this->getPaymentTransaction($order, PayoneDebitPaymentHandler::class); - $order->setTransactions(new OrderTransactionCollection([$paymentTransaction->getOrderTransaction()])); - - $orderRepository = $this->createMock(EntityRepository::class); - $orderRepository->expects(static::once())->method('search')->willReturn( - $this->getEntitySearchResult($order, $salesChannelContext) - ); - - $request = new Request(); - $decoratedController = $this->createMock(AccountOrderController::class); - $decoratedController->expects(static::once())->method('editOrder')->with( - static::equalTo($order->getId()), - static::equalTo($request), - static::equalTo($salesChannelContext) - ); - - $controller = new AccountOrderControllerDecorator( - $decoratedController, - $orderRepository - ); - $controller->setContainer($this->getContainer()); - - $response = $controller->editOrder($order->getId(), $request, $salesChannelContext); - - static::assertNotInstanceOf(RedirectResponse::class, $response); - } - - public function testItRedirectsFromUpdateOrderRequestToOverviewPageOnRatepayOrder(): void - { - $salesChannelContext = $this->createSalesChannelContextWithLoggedInCustomerAndWithNavigation(); - $order = $this->getRandomOrder($salesChannelContext); - $paymentTransaction = $this->getPaymentTransaction($order, PayoneRatepayDebitPaymentHandler::class); - $order->setTransactions(new OrderTransactionCollection([$paymentTransaction->getOrderTransaction()])); - - $orderRepository = $this->createMock(EntityRepository::class); - $orderRepository->expects(static::once())->method('search')->willReturn( - $this->getEntitySearchResult($order, $salesChannelContext) - ); - - $decoratedController = $this->createMock(AccountOrderController::class); - $decoratedController->expects(static::never())->method('updateOrder'); - - $controller = new AccountOrderControllerDecorator( - $decoratedController, - $orderRepository - ); - $controller->setContainer($this->getContainer()); - - $response = $controller->updateOrder($order->getId(), new Request(), $salesChannelContext); - - static::assertInstanceOf(RedirectResponse::class, $response); - } - - public function testItNotRedirectsFromUpdateOrderRequestToOverviewPageOnOtherPaymentMethodThanRatepay(): void - { - $salesChannelContext = $this->createSalesChannelContextWithLoggedInCustomerAndWithNavigation(); - $order = $this->getRandomOrder($salesChannelContext); - $paymentTransaction = $this->getPaymentTransaction($order, PayoneDebitPaymentHandler::class); - $order->setTransactions(new OrderTransactionCollection([$paymentTransaction->getOrderTransaction()])); - - $orderRepository = $this->createMock(EntityRepository::class); - $orderRepository->expects(static::once())->method('search')->willReturn( - $this->getEntitySearchResult($order, $salesChannelContext) - ); - - $request = new Request(); - $decoratedController = $this->createMock(AccountOrderController::class); - $decoratedController->expects(static::once())->method('updateOrder')->with( - static::equalTo($order->getId()), - static::equalTo($request), - static::equalTo($salesChannelContext) - ); - - $controller = new AccountOrderControllerDecorator( - $decoratedController, - $orderRepository - ); - $controller->setContainer($this->getContainer()); - - $response = $controller->updateOrder($order->getId(), $request, $salesChannelContext); - - static::assertNotInstanceOf(RedirectResponse::class, $response); - } - - public function testItCallsParentFunctions(): void - { - $salesChannelContext = $this->createSalesChannelContextWithLoggedInCustomerAndWithNavigation(); - $request = new Request(); - $orderId = Uuid::randomHex(); - - $decoratedController = $this->createMock(AccountOrderController::class); - $decoratedController->expects(static::once())->method('orderOverview')->with( - static::equalTo($request), - static::equalTo($salesChannelContext) - ); - $decoratedController->expects(static::once())->method('cancelOrder')->with( - static::equalTo($request), - static::equalTo($salesChannelContext) - ); - $decoratedController->expects(static::once())->method('orderSingleOverview')->with( - static::equalTo($request), - static::equalTo($salesChannelContext) - ); - $decoratedController->expects(static::once())->method('ajaxOrderDetail')->with( - static::equalTo($request), - static::equalTo($salesChannelContext) - ); - $decoratedController->expects(static::once())->method('orderChangePayment')->with( - static::equalTo($orderId), - static::equalTo($request), - static::equalTo($salesChannelContext) - ); - - $controller = new AccountOrderControllerDecorator( - $decoratedController, - $this->createMock(EntityRepository::class) - ); - - $controller->orderOverview($request, $salesChannelContext); - $controller->cancelOrder($request, $salesChannelContext); - $controller->orderSingleOverview($request, $salesChannelContext); - $controller->ajaxOrderDetail($request, $salesChannelContext); - $controller->orderChangePayment($orderId, $request, $salesChannelContext); - } - - protected function getEntitySearchResult(OrderEntity $order, SalesChannelContext $salesChannelContext): EntitySearchResult - { - return new EntitySearchResult( - 'order', - 1, - new EntityCollection([$order]), - null, - new Criteria(), - $salesChannelContext->getContext() - ); - } -}