Search code examples
payment-gatewaymagento2paymentordersemail-confirmation

How to handle conflict in overriding Magento\Sales\Model\Order\Email\Sender\OrderSender in Magento 2


I have had an issue for some time in overriding the OrderSender Model in Magento 2 as a result of creating a custom payment module.

First of all i was not able to prevent email from being sent out once an order is made (wether successful or not successful), which was a problem so I decided to create a flow which would override the OrderSender using the advised process by specifying the preference file in the module i.e.

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

/**
 * Sends order email to the customer.
 *
 * Email will be sent immediately in two cases:
 *
 * - if asynchronous email sending is disabled in global settings
 * - if $forceSyncMode parameter is set to TRUE
 *
 * Otherwise, email will be sent later during running of
 * corresponding cron job.
 *
 * @param Order $order
 * @param bool $forceSyncMode
 * @return bool
 */
public function send(Order $order, $forceSyncMode = false)
{
    $payment = $order->getPayment()->getMethodInstance()->getCode();

    //allow other module or payment to proceed should in case it is not my payment module is calling for order sender.
    if($payment == 'afronijapay' && !$forceSyncMode){
        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;
}}

as shown above so therefore everything worked fine and i was to send the email upon completing my flow of process then called the following when the payment is successful.

//send new order email
            $this->_checkout_session->setForceOrderMailSentOnSuccess(true);
            $this->_orderSender->send($order, true);

Again, I found this as some proposed solution from several sources including stackoverflow/stackexchange and all.

However, in as much as this works another problem comes to mind i.e. what if someone already is overriding this class from another module and Magento 2 uses that overriden class without mine then the problem may re-occur.

I built another payment module (just a copy of the original) using different namespace and vendor name and my fear came to light as Magento 2 is ignoring one of the classes overriding the OrderSender class and using the other thereby making the problem to start re-occuring.

I will appreciate any suggestions on how to tackle this issue. Thanks.


Solution

  • After so many trials i finally come up with this plan

    create an event in your

    <Vendor>/<ModuleName>/etc.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="sales_order_place_after"> <observer name="<vendor>_<modulename>_event_email_stopper" instance="<Vendor>\<ModuleName>\Event\EmailStopper\Order\Email" /> </event> </config>

    Then create a class named Email.php in the directory \\Event\EmailStopper\Order\ with the following content

     namespace <Vendor>\<ModuleName>\Event\EmailStopper\Order;
    class Email implements \Magento\Framework\Event\ObserverInterface
    {
        public function execute(\Magento\Framework\Event\Observer $observer)
        {
            $this->objectManager = \Magento\Framework\App\ObjectManager::getInstance();
        try{
            $order = $observer->getEvent()->getOrder();
            $this->_current_order = $order;
    
            $payment = $order->getPayment()->getMethodInstance()->getCode();
    
            if($payment == 'chukplcspredirect' || $payment == 'chukplcspdirect'){
                $this->stopNewOrderEmail($order);
            }
        }
        catch (\ErrorException $ee){
    
        }
        catch (\Exception $ex)
        {
    
        }
        catch (\Error $error){
    
        }
    
    }
    
    public function stopNewOrderEmail(\Magento\Sales\Model\Order $order){
        $order->setCanSendNewEmailFlag(false);
        $order->setSendEmail(false);
        try{
            $order->save();
        }
        catch (\ErrorException $ee){
    
        }
        catch (\Exception $ex)
        {
    
        }
        catch (\Error $error){
    
        }
    }
    } 
    

    and when you are done you can easily send email for the order using the code below

    $order->setCanSendNewEmailFlag(true);
    $order->save();
    $this->_checkout_session->setForceOrderMailSentOnSuccess(true);
    $this->_orderSender->send($order, true);