7

I am new to magento2 and developing a custom payment module for ccavenue.I am facing a problem regarding order confirmation email.

The order confirmation email is sending once the customer redirecting to payment gateway page and order is creating with pending status.I want to send this email after a successful transaction.

Here is my payment js code

define(
[
    'jquery',
    'Magento_Checkout/js/view/payment/default',
    'Magento_Checkout/js/action/place-order',
    'Magento_Checkout/js/action/select-payment-method',
    'Magento_Customer/js/model/customer',
    'Magento_Checkout/js/checkout-data',
    'Magento_Checkout/js/model/payment/additional-validators',
    'mage/url',
],
function (
    $,
    Component,
    placeOrderAction,
    selectPaymentMethodAction,
    customer,
    checkoutData,
    additionalValidators,
    url) {


        return Component.extend({
            defaults: {
                template: 'Magekmf_Ccavenue/payment/ccavenue'
            },
            placeOrder: function (data, event) {
                if (event) {
                    event.preventDefault();
                }
                var self = this,
                    placeOrder,
                    emailValidationResult = customer.isLoggedIn(),
                    loginFormSelector = 'form[data-role=email-with-possible-login]';
                if (!customer.isLoggedIn()) {
                    $(loginFormSelector).validation();
                    emailValidationResult = Boolean($(loginFormSelector + ' input[name=username]').valid());
                }
                if (emailValidationResult && this.validate() && additionalValidators.validate()) {
                    this.isPlaceOrderActionAllowed(false);
                    placeOrder = placeOrderAction(this.getData(), true, this.messageContainer);

                    $.when(placeOrder).fail(function () {
                        self.isPlaceOrderActionAllowed(true);
                    }).done(this.afterPlaceOrder.bind(this));
                    return true;
                }
                return false;
            },

            selectPaymentMethod: function() {
                selectPaymentMethodAction(this.getData());
                checkoutData.setSelectedPaymentMethod(this.item.method);
                return true;
            },

            afterPlaceOrder: function () {
                window.location.replace(url.build('ccavenue/request'));
            },
            /** Returns send check to info */
            getMailingAddress: function() {
                return window.checkoutConfig.payment.checkmo.mailingAddress;
            }


        });
    }
);
11
  • 1
    Show more detail with code.
    – Sohel Rana
    Commented Jan 13, 2017 at 7:50
  • What type of integration do you use? It seems you call wrong Web API entry point from your payment js component. Seems you need to call set-payment-information, but you calls payment-information (this is default action), but anyway you need to provide more details.
    – joni jones
    Commented Jan 13, 2017 at 14:51
  • @joni i have edited my question.Please check
    – Renjith R
    Commented Jan 16, 2017 at 13:00
  • @renjith, as I assumed in the previous comment, you need to call set-payment-information instead payment-information (placeOrder method) after that, redirect customer to external payment provider and when customer comes back to Magento store - call payment-information action (placeOrder method)
    – joni jones
    Commented Jan 16, 2017 at 14:44
  • @joni Can you provide any reference link.Thanks.
    – Renjith R
    Commented Jan 17, 2017 at 7:54

3 Answers 3

12

I was facing same issue but I found alternative solution like I turned off Magento default Order Confirmation email and Send Order Confirmation Email When Order is being placed Successfully.

Here are the step to follow :

Create Observer Event which being called after order placed : events.xml

<?xml version="1.0"?>

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
    <event name="checkout_onepage_controller_success_action">
        <observer name="checkout_onepage_controller_success_action_sendmail" instance="<vendor_name>\OrderSuccessMail\Observer\SendMailOnOrderSuccess" />
    </event>
</config>

Observer: SendMailOnOrderSuccess.php

<?php

namespace <vendor_name>\OrderSuccessMail\Observer;

use Magento\Framework\Event\ObserverInterface;

class SendMailOnOrderSuccess implements ObserverInterface
{
    /**
     * @var \Magento\Sales\Model\OrderFactory
     */
    protected $orderModel;

    /**
     * @var \Magento\Sales\Model\Order\Email\Sender\OrderSender
     */
    protected $orderSender;

    /**
     * @var \Magento\Checkout\Model\Session $checkoutSession
     */
    protected $checkoutSession;

    /**
     * @param \Magento\Sales\Model\OrderFactory $orderModel
     * @param \Magento\Sales\Model\Order\Email\Sender\OrderSender $orderSender
     * @param \Magento\Checkout\Model\Session $checkoutSession
     *
     * @codeCoverageIgnore
     */
    public function __construct(
        \Magento\Sales\Model\OrderFactory $orderModel,
        \Magento\Sales\Model\Order\Email\Sender\OrderSender $orderSender,
        \Magento\Checkout\Model\Session $checkoutSession
    )
    {
        $this->orderModel = $orderModel;
        $this->orderSender = $orderSender;
        $this->checkoutSession = $checkoutSession;
    }

    /**
     * @param \Magento\Framework\Event\Observer $observer
     * @return void
     */
    public function execute(\Magento\Framework\Event\Observer $observer)
    {
        $orderIds = $observer->getEvent()->getOrderIds();
        if(count($orderIds))
        {
            $this->checkoutSession->setForceOrderMailSentOnSuccess(true);
            $order = $this->orderModel->create()->load($orderIds[0]);
            $this->orderSender->send($order, true);
        }
    }
}

Here $this->orderSender->send($order, true); called which extends abstract class method() which check if Order confirmation email is enabled from backend or not so we need create plugin for that

di.xml

<?xml version="1.0"?>

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <type name="Magento\Sales\Model\Order\Email\Container\OrderIdentity">
        <plugin name="change_is_enable_method" type="\<vendor_name>\OrderSuccessMail\Plugin\Sales\Order\Email\Container\OrderIdentityPlugin"/>
    </type>
</config>

OrderIdentityPlugin.php

<?php

namespace <vendor_name>\OrderSuccessMail\Plugin\Sales\Order\Email\Container;

class OrderIdentityPlugin
{
    /**
     * @var \Magento\Checkout\Model\Session $checkoutSession
     */
    protected $checkoutSession;

    /**
     * @param \Magento\Checkout\Model\Session $checkoutSession
     *
     * @codeCoverageIgnore
     */
    public function __construct(
        \Magento\Checkout\Model\Session $checkoutSession
    )
    {
        $this->checkoutSession = $checkoutSession;
    }

    /**
     * @param \Magento\Sales\Model\Order\Email\Container\OrderIdentity $subject
     * @param callable $proceed
     * @return bool
     */
    public function aroundIsEnabled(\Magento\Sales\Model\Order\Email\Container\OrderIdentity $subject, callable $proceed)
    {
        $returnValue = $proceed();

        $forceOrderMailSentOnSuccess = $this->checkoutSession->getForceOrderMailSentOnSuccess();
        if(isset($forceOrderMailSentOnSuccess) && $forceOrderMailSentOnSuccess)
        {
            if($returnValue)
                $returnValue = false;
            else
                $returnValue = true;

            $this->checkoutSession->unsForceOrderMailSentOnSuccess();
        }

        return $returnValue;
    }
}

Here in above plugin we have checked if confirmation is enabled from backend config or not, If yes then It works as default but if No then our custom email Confirmation order will be sent.

Hope it helps.

7
  • 1
    Hi. How did you turn off this default email? If i turn off stores -> configuration -> sales -> sales email -> order then no emails will be sent. Thank you for your help! Commented Sep 5, 2017 at 11:18
  • I did same setting as you did but I wrote the script when Backend email is off then my custom code will work. @TanelTammik Commented Sep 5, 2017 at 11:20
  • @ Ronak Chauhan can you please share full code when Backend email is off
    – Mahesh
    Commented Aug 14, 2018 at 13:38
  • @RonakChauhan can you please share full code when Backend email is off
    – Mahesh
    Commented Aug 14, 2018 at 13:39
  • 3
    Thanks for the solution. It didn't work for me with Magento 2.3.1. It seems that the isEnabled method is called more than once, which ends up with never sending an email. Moving the $this->checkoutSession->unsForceOrderMailSentOnSuccess(); line from OrderIdentityPlugin.php to SendMailOnOrderSuccess.php right after $this->orderSender->send($order, true); solved the problem.
    – Zsolti
    Commented Jun 24, 2019 at 13:43
6

This can be achieved by rewriting

Magento\Sales\Model\Order\Email\Sender\OrderSender::send

function, For that first add the following in your di.xml

<preference for="Magento\Sales\Model\Order\Email\Sender\OrderSender" type="Company\Module\Model\Order\Email\Sender\OrderSender"/>

and Create class OrderSender with as below

namespace Company\Module\Model\Order\Email\Sender;

use Magento\Sales\Model\Order;

class OrderSender extends \Magento\Sales\Model\Order\Email\Sender\OrderSender {

    public function send(Order $order, $forceSyncMode = false)
    {
        $payment = $order->getPayment()->getMethodInstance()->getCode();

        if($payment == 'your-payment-method-code'){
            return false;
        }

        $order->setSendEmail(true);

        if (!$this->globalConfig->getValue('sales_email/general/async_sending') || $forceSyncMode) {
            if ($this->checkAndSend($order)) {
                $order->setEmailSent(true);
                $this->orderResource->saveAttribute($order, ['send_email', 'email_sent']);
                return true;
            }
        }

        $this->orderResource->saveAttribute($order, 'send_email');

        return false;
    }
}

Once you return back to site from payment gateway send confirmation mail manually from your success controller.

5
  • I tried this but its not taking my OrderSender its taking core modules OrderSender Commented Dec 13, 2017 at 12:23
  • found it was overriten already by other module Commented Dec 13, 2017 at 13:03
  • Hello, this solution is already implemented by ccavenue plugin, using the di code, it will manage the not send mail to the user but the Model file not working fine for ccavenue orders, I checked multiple time there is only override file in my code, please help me out of this stuck? and i am using magento 2.3.2 version Commented Oct 9, 2019 at 12:14
  • @PMB........... Commented Oct 9, 2019 at 12:27
  • Used this and worked for my project. Used by other module though.
    – Duke
    Commented Oct 30, 2023 at 12:03
0

thank you so much @Zsolti it fixed my problem, also if someone has code style check on pipelines, here is styled code
OrderIndentityPlugin

<?php

namespace Devall\OrderSuccess\Plugin\Sales\Order\Email\Container;

class OrderIdentityPlugin
{
    /**
     * @var \Magento\Checkout\Model\Session $checkoutSession
     */
    protected $checkoutSession;

    /**
     * @param \Magento\Checkout\Model\Session $checkoutSession
     *
     * @codeCoverageIgnore
     */
    public function __construct(
        \Magento\Checkout\Model\Session $checkoutSession
    ) {
        $this->checkoutSession = $checkoutSession;
    }

    /**
     * @param \Magento\Sales\Model\Order\Email\Container\OrderIdentity $subject
     * @param callable $proceed
     * @return bool
     */
    public function aroundIsEnabled(
        \Magento\Sales\Model\Order\Email\Container\OrderIdentity $subject,
        callable $proceed
    ) {
        $returnValue = $proceed();

        $forceOrderMailSentOnSuccess = $this->checkoutSession->getForceOrderMailSentOnSuccess();
        if (isset($forceOrderMailSentOnSuccess) && $forceOrderMailSentOnSuccess) {
            if ($returnValue) {
                $returnValue = false;
            } else {
                $returnValue = true;
            }
        }

        return $returnValue;
    }
}

SendMailOnOrderSuccess

<?php

namespace Devall\OrderSuccess\Observer;

use Magento\Framework\Event\ObserverInterface;

class SendMailOnOrderSuccess implements ObserverInterface
{
    /**
     * @var \Magento\Sales\Model\OrderFactory
     */
    protected $orderModel;

    /**
     * @var \Magento\Sales\Model\Order\Email\Sender\OrderSender
     */
    protected $orderSender;

    /**
     * @var \Magento\Checkout\Model\Session $checkoutSession
     */
    protected $checkoutSession;

    /**
     * @param \Magento\Sales\Model\OrderFactory $orderModel
     * @param \Magento\Sales\Model\Order\Email\Sender\OrderSender $orderSender
     * @param \Magento\Checkout\Model\Session $checkoutSession
     *
     * @codeCoverageIgnore
     */
    public function __construct(
        \Magento\Sales\Model\OrderFactory $orderModel,
        \Magento\Sales\Model\Order\Email\Sender\OrderSender $orderSender,
        \Magento\Checkout\Model\Session $checkoutSession
    ) {
        $this->orderModel = $orderModel;
        $this->orderSender = $orderSender;
        $this->checkoutSession = $checkoutSession;
    }

    /**
     * @param \Magento\Framework\Event\Observer $observer
     * @return void
     */
    public function execute(\Magento\Framework\Event\Observer $observer)
    {
        $orderIds = $observer->getEvent()->getOrderIds();
        if (count($orderIds)) {
            $this->checkoutSession->setForceOrderMailSentOnSuccess(true);
            $order = $this->orderModel->create()->load($orderIds[0]);
            $this->orderSender->send($order, true);
            $this->checkoutSession->unsForceOrderMailSentOnSuccess();
        }
    }
}

This answer is for 2.3.*

Not the answer you're looking for? Browse other questions tagged or ask your own question.