Sylius / PayPalPlugin

Official integration with PayPal Commerce Platform
36 stars 55 forks source link

[Bug] Duplication Payment on Payment Complete #272

Open p-carrillo opened 1 year ago

p-carrillo commented 1 year ago

SyliusPayPalPlugin version affected: 1.4.2

Description
When an order is completed we are getting a payment duplication on Database and in sylius admin. The original payment is set to completed as expected, but the complete action sets a new payment in new state as seen in image:

image

Steps to reproduce

Make a complete payment with paypal plugin

Possible Solution

We found this code in CompletePayPalOrderFromPaymentPageAction.php:

    public function __invoke(Request $request): Response
    {
        $orderId = $request->attributes->getInt('id');

        /** @var OrderInterface $order */
        $order = $this->orderProvider->provideOrderById($orderId);
        /** @var PaymentInterface $payment */
        $payment = $order->getLastPayment(PaymentInterface::STATE_PROCESSING);

        $this->paymentStateManager->complete($payment);

        $orderStateMachine = $this->stateMachine->get($order, OrderCheckoutTransitions::GRAPH);
        $orderStateMachine->apply(OrderCheckoutTransitions::TRANSITION_SELECT_PAYMENT);
        $orderStateMachine->apply(OrderCheckoutTransitions::TRANSITION_COMPLETE);

        $this->orderManager->flush();

        $request->getSession()->set('sylius_order_id', $order->getId());

        return new JsonResponse([
            'return_url' => $this->router->generate('sylius_shop_order_thank_you', [], UrlGeneratorInterface::ABSOLUTE_URL),
        ]);
    }

Where sylius plugin makes an state transition to TRANSITION_SELECT_PAYMENT. Looking in the complete controller from sylius we do not see this transaction:

vendor/sylius/sylius/src/Sylius/Bundle/ApiBundle/CommandHandler/Checkout/CompleteOrderHandler.php

    public function __invoke(CompleteOrder $completeOrder): OrderInterface
    {
        $orderTokenValue = $completeOrder->orderTokenValue;

        /** @var OrderInterface|null $cart */
        $cart = $this->orderRepository->findOneBy(['tokenValue' => $orderTokenValue]);

        Assert::notNull($cart, sprintf('Order with %s token has not been found.', $orderTokenValue));

        if ($completeOrder->notes !== null) {
            $cart->setNotes($completeOrder->notes);
        }

        $stateMachine = $this->stateMachineFactory->get($cart, OrderCheckoutTransitions::GRAPH);

        Assert::true(
            $stateMachine->can(OrderCheckoutTransitions::TRANSITION_COMPLETE),
            sprintf('Order with %s token cannot be completed.', $orderTokenValue)
        );

        $stateMachine->apply(OrderCheckoutTransitions::TRANSITION_COMPLETE);

        $this->eventBus->dispatch(new OrderCompleted($cart->getTokenValue()), [new DispatchAfterCurrentBusStamp()]);

        return $cart;
    }

As seen in the code above, Sylius do not make the TRANSITION_SELECT_PAYMENT step. Overwriting the plugin controller and commenting this line solves the problem for us.

benbd5 commented 1 year ago

Same problem on SyliusPayPalPlugin version 1.5