Skip to content

[Bug] Duplication Payment on Payment Complete #272

@p-carrillo

Description

@p-carrillo

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions