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 ) ;
}
}
Это обходной путь, проблема здесь не полностью решена, и это примерно то же самое с использованием конечного автомата. Конфигурационное письмо по умолчанию, похоже, отправляется после завершения оформления заказа, тогда как вместо этого оно должно позаботиться о статусе оплаты.
Спасибо!