Sylius / Отправить подтверждение по электронной почте против конечного автомата

Начальное сообщение:

Я использую sylius версии 1.0dev. Мне нужна помощь по поводу оформления заказа / завершения и подтверждения по электронной почте, проблема, кажется, известна ( https://github.com/Sylius/Sylius/issues/2915), но исправления не работают для меня. На этом шаге статус оплаты, кажется, оплачен, тогда как он должен быть в ожидании_платы. Кроме того, электронное письмо с подтверждением заказа не должно отправляться, а только после оплаты на Payum Gateway. Есть ли какая-либо существующая конфигурация, которая вызывает это событие, и как это реализовать, пожалуйста? Спасибо!

Проблема частично решена: я реализовал обходной путь.

Первое, что нужно знать: я переопределяю shopbundle, расширяя его в свой собственный пакет:

<?php

namespace My\ShopBundle;

use Symfony\Component\HttpKernel\Bundle\Bundle;

class MyShopBundle extends Bundle
{
    public function getParent()
    {
        return 'SyliusShopBundle';
    }
}

Я переопределил службу sylius.email_manager.order:

# sylius service configuration
parameters:
    # override email manager for order
    sylius.myproject.order.email.manager.class:MyBundle\ShopBundle\EmailManager\OrderEmailManager
#################################################
# override service sylius.email_manager.order   #
#                                               #
# - use configurable class                      #
# - send service container in arguments         #
#                                               #
#################################################
services:
    sylius.email_manager.order:
        class: %sylius.myproject.order.email.manager.class%
        arguments:
            - @sylius.email_sender
            - @service_container

Классы выглядят так:

<?php

namespace My\ShopBundle\EmailManager;

use Sylius\Bundle\CoreBundle\Mailer\Emails;
use Sylius\Component\Core\Model\OrderInterface;
use Sylius\Component\Mailer\Sender\SenderInterface;
use My\ShopBundle\Mailer\Emails as MyEmails;

/**
 * @author I
 */
class OrderEmailManager
{
    /**
     * @var SenderInterface
     */
    protected $emailSender;
    /**
     *
     */
    protected $container ;

    /**
     * @param SenderInterface $emailSender
     */
    public function __construct( SenderInterface $emailSender, $container )
    {
        $this->emailSender = $emailSender;
        $this->container = $container ;
    }

    /**
     * @param OrderInterface $order
     * Issue : sent on checkout/complete (payment is not yet done on gateway)
     */
    public function sendConfirmationEmail(OrderInterface $order)
    {
        // sylius.shop.email.bcc is array parameter: expected bcc as array variable
        if( $this->container->hasParameter( 'sylius.shop.email.bcc' ) ){
            $this->emailSender->send( Emails::ORDER_CONFIRMATION, [$order->getCustomer()->getEmail()], ['order' => $order], $this->container->getParameter( 'sylius.shop.email.bcc' ) ) ;
        }else{
            // no bcc defined
            $this->emailSender->send( Emails::ORDER_CONFIRMATION, [$order->getCustomer()->getEmail()], ['order' => $order] ) ;
        }
    }

    /**
     * function used on gateway payment
     * here we use MyEmails to define the template (as it is done for the default confimration mail)
     */
    public function sendPaymentConfirmationEmail(OrderInterface $order)
    {
        // sylius.shop.email.bcc is array parameter: expected bcc as array variable
        if( $this->container->hasParameter( 'sylius.shop.email.bcc' ) ){
            $this->emailSender->send( MyEmails::ORDER_PAID, [$order->getCustomer()->getEmail()], ['order' => $order], $this->container->getParameter( 'sylius.shop.email.bcc' ) ) ;
        }else{
            // no bcc defined
            $this->emailSender->send( MyEmails::ORDER_PAID, [$order->getCustomer()->getEmail()], ['order' => $order] ) ;
        }
    }
}

/**
 *
 * (c) I
 *
 */

namespace My\ShopBundle\Mailer;

/**
 * @author I
 */
class Emails
{
    const ORDER_PAID = 'order_paid';
}

Шаблон расположен должным образом: Resources/views/Email/orderPaid.html.twig и настроен следующим образом:

sylius_mailer:
    emails:
        order_paid:
            subject: "The email subject"
            template: "MyShopBundle:Email:orderPaid.html.twig"

Чтобы отключить рассылку подтверждений по умолчанию, настройте конечный автомат:

winzou_state_machine:
    # disable order confirmation email on checkout/complete (we prefer on thank you action, see order.yml configuration in MyShopBundle to override the thankYouAction)
    sylius_order:
        callbacks:
            after:
                sylius_order_confirmation_email:
                    disabled: true

Чтобы инициировать рассылку подтверждений в ответ на действие спасибо (в случае использования платежа через шлюз успешно), в моем комплекте (Resources/config/routing/order.yml):

sylius_shop_order_pay:
    path: /{lastNewPaymentId}/pay
    methods: [GET]
    defaults:
        _controller: sylius.controller.payum:prepareCaptureAction
        _sylius:
            redirect:
                route: sylius_shop_order_after_pay

sylius_shop_order_after_pay:
    path: /after-pay
    methods: [GET]
    defaults:
        _controller: sylius.controller.payum:afterCaptureAction

sylius_shop_order_thank_you:
    path: /thank-you
    methods: [GET]
    defaults:
        # OVERRIDE (add: send mail success confirmation + standard controller because this one is not a service and must not be)
        _controller: MyShopBundle:Payment:thankYou
        _sylius:
            template: MyShopBundle:Checkout:thankYou.html.twig

sylius_shop_order_show_details:
    path: /{tokenValue}
    methods: [GET]
    defaults:
        _controller: sylius.controller.order:showAction
        _sylius:
            template: SyliusShopBundle:Checkout:orderDetails.html.twig
            grid: sylius_shop_account_order
            section: shop_account
            repository:
                method: findOneBy
                arguments:
                    [tokenValue: $tokenValue]

Наконец, мы перезаписываем ThankYouAction, используя стандартный контроллер Symfony, как показано ниже:

<?php

namespace My\ShopBundle\Controller ;

// use Doctrine\ORM\EntityManager;
// use FOS\RestBundle\View\View;
// use Payum\Core\Registry\RegistryInterface;
// use Sylius\Bundle\ResourceBundle\Controller\RequestConfiguration;
// use Sylius\Bundle\ResourceBundle\Controller\ResourceController;
// use Sylius\Component\Order\Context\CartContextInterface;
// use Sylius\Component\Order\Model\OrderInterface;
// use Sylius\Component\Order\SyliusCartEvents;
// use Sylius\Component\Resource\ResourceActions;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\EventDispatcher\GenericEvent;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Webmozart\Assert\Assert;

// Carefull using ResourceController extending, cause this is a service and not a controller (different constructor)
class PaymentController extends Controller
{

    /**
     * @param Request $request
     *
     * @return Response
     */
    public function thankYouAction(Request $request = null)
    {
        // old implementation (get parameters from custom configuration, more heavy and difficult to maintain)
        //$configuration = $this->requestConfigurationFactory->create($this->metadata, $request);

        // default value for order
        $order = null ;
        // if session variable sylius_order_id exist : deal with order
        if( $request->getSession()->has( 'sylius_order_id' ) ){
            $orderId = $request->getSession()->get( 'sylius_order_id', null ) ;
            // old behaviour based on custom configuration in case session variable does not exist anymore: does a homepage redirect
            // if (null === $orderId) {
            //     return $this->redirectHandler->redirectToRoute(
            //         $configuration,
            //         $configuration->getParameters()->get('after_failure[route]', 'sylius_shop_homepage', true),
            //         $configuration->getParameters()->get('after_failure[parameters]', [], true)
            //     );
            // }

            $request->getSession()->remove( 'sylius_order_id' ) ;
            // prefer call repository service in controller (previously repository came from custom configuration)
            $orderRepository = $this->get( 'sylius.repository.order' ) ;
            $order = $orderRepository->find( $orderId ) ;


            Assert::notNull($order);
            // send email confirmation via sylius.email_manager.order service
            $this->sendEmailConfirmation( $order ) ;
            // old rendering from tankyouAction in Sylius\Bundle\CoreBundle\Controller\OrderController
            // $view = View::create()
            //     ->setData([
            //         'order' => $order
            //     ])
            //     ->setTemplate($configuration->getParameters()->get('template'))
            // ;
            // return $this->viewHandler->handle($configuration, $view);

            // prefer symfony rendering (controller knows its view, execute a controller creation with command line, your template will be defined inside)
            $response = $this->render( 'MyShopBundle:Checkout:thankYou.html.twig', array( 'order' => $order ) ) ;
            // deal with http cache expiration duration
            $response->setSharedMaxAge( 3600 ) ;
        }else{
            // redirect to home page
            $response = $this->redirect( $this->generateUrl( 'sylius_shop_homepage' ) ) ;
        }
        return $response ;
    }

    /**
     *
     */
    private function sendEmailConfirmation( $order ){
        $emailService = $this->container->get( 'sylius.email_manager.order' ) ;
        $emailService->sendPaymentConfirmationEmail( $order ) ;
    }
}

Это обходной путь, проблема здесь не полностью решена, и это примерно то же самое с использованием конечного автомата. Конфигурационное письмо по умолчанию, похоже, отправляется после завершения оформления заказа, тогда как вместо этого оно должно позаботиться о статусе оплаты.

Спасибо!

0 ответов

Другие вопросы по тегам