Sylius / AdminOrderCreationPlugin

Create orders in Sylius as an Administrator
MIT License
55 stars 50 forks source link

Fix state machine exception on order creation #176

Closed maciekpaprocki closed 2 years ago

maciekpaprocki commented 3 years ago

This is similar to already existing PR, but i think original poster stopped responding so I can try to get that working.

Issue: https://github.com/Sylius/AdminOrderCreationPlugin/pull/134

However, the issue also appears when product is not virtual, but skipping_shipping_step_allowed in channel

PR: https://github.com/Sylius/AdminOrderCreationPlugin/issues/132

maciekpaprocki commented 3 years ago

For all people coming in and looking for quick patch until this is fixed:

create class :

src/EventListener/Patch

<?php

declare(strict_types=1);

namespace App\EventListener\Patch;

use SM\Factory\FactoryInterface;
use Sylius\Component\Core\Model\OrderInterface;
use Sylius\Component\Core\OrderCheckoutTransitions;
use Sylius\Component\Order\Processor\OrderProcessorInterface;
use Symfony\Component\EventDispatcher\GenericEvent;
use Webmozart\Assert\Assert;

final class AdminOrderCreationListener
{
    /** @var OrderProcessorInterface */
    private $orderProcessor;

    /** @var FactoryInterface */
    private $stateMachineFactory;

    public function __construct(OrderProcessorInterface $orderProcessor, FactoryInterface $stateMachineFactory)
    {
        $this->orderProcessor      = $orderProcessor;
        $this->stateMachineFactory = $stateMachineFactory;
    }

    public function processOrderBeforeCreation(GenericEvent $event): void
    {
        $order = $event->getSubject();
        Assert::isInstanceOf($order, OrderInterface::class);

        $order->recalculateAdjustmentsTotal();
        $this->orderProcessor->process($order);
    }

    public function completeOrderBeforeCreation(GenericEvent $event): void
    {
        $order = $event->getSubject();
        Assert::isInstanceOf($order, OrderInterface::class);

        $stateMachine = $this->stateMachineFactory->get($order, 'sylius_order_checkout');
        $stateMachine->apply(OrderCheckoutTransitions::TRANSITION_ADDRESS);

        if ($stateMachine->can(OrderCheckoutTransitions::TRANSITION_SELECT_SHIPPING)) {
            $stateMachine->apply(OrderCheckoutTransitions::TRANSITION_SELECT_SHIPPING);
        }

        if ($stateMachine->can(OrderCheckoutTransitions::TRANSITION_SELECT_PAYMENT)) {
            $stateMachine->apply(OrderCheckoutTransitions::TRANSITION_SELECT_PAYMENT);
        }
        $stateMachine->apply(OrderCheckoutTransitions::TRANSITION_COMPLETE);
    }
}

add this to services.yaml:

services:
    ...

    Sylius\AdminOrderCreationPlugin\EventListener\OrderCreationListener:
        class: App\EventListener\Patch\AdminOrderCreationListener
        public: yes
        arguments:
            - "@sylius.order_processing.order_processor"
            - "@sm.factory"
        tags:
            - { name: "kernel.event_listener", event: "sylius.order.pre_admin_create", method: processOrderBeforeCreation }
            - { name: "kernel.event_listener", event: "sylius.order.pre_admin_create", method: completeOrderBeforeCreation }
lchrusciel commented 3 years ago

Hey Maciek,

thanks a lot for your contribution. Can you fix the failing test? In the best scenario, we should also cover this behaviour with behat. Would you like to give it a try?

Best regards

maciekpaprocki commented 3 years ago

Hi,

I fixed the phpspec tests failing and added additional test for when shipping should be skipped. Hope this helps.

Best

jdubuisson commented 2 years ago

The proposed fix looks good and the tests make sense. Could this PR be merged ?

GSadee commented 2 years ago

Thank you, @maciekpaprocki! :tada: