Initial Post:
I use a sylius version 1.0dev. I need some help about the checkout/complete and email confirmation, the issue seems to be known (https://github.com/Sylius/Sylius/issues/2915), but fixes are not working for me. At this step, the payment status seems to be paid whereas it should be awaiting_payment. In addition, the order confirmation email should not be sent, but only after payment on payum gateway. Is there any existing configuration which triggers this event, and how to implement it please ? Thanks!
Issue partially solved: I implemented a workaround.
First thing to know: I override shopbundle extending it into my own bundle:
<?php
namespace My\ShopBundle;
use Symfony\Component\HttpKernel\Bundle\Bundle;
class MyShopBundle extends Bundle
{
public function getParent()
{
return 'SyliusShopBundle';
}
}
I overrided the sylius.email_manager.order service:
# 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
Classes look like that:
<?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';
}
Template is located as expected: Resources/views/Email/orderPaid.html.twig and is configured as below:
sylius_mailer:
emails:
order_paid:
subject: "The email subject"
template: "MyShopBundle:Email:orderPaid.html.twig"
To disable default confirmation mailing, configure the state machine:
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
To trigger confirmation mailing on thankYou action (use case gateway payment is successfully done), in my bundle (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]
Finally we override the thankYouAction using a standard symfony controller, as below:
<?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 ) ;
}
}
This is a workaround, issue here is not fully solved, and is about doing same thing using state machine. Default configuration mail seems to be sent on checkout complete whereas it shoud take care about payment status instead.
Thanks !