7

I am trying to trigger the customer invoice mail after an order has been paid and the invoice has been created. The payment gateways are PayPal Plus (iways) and Amazon Pay. If I understood correctly, these gateways automatically create the invoice as soon as the order has been processed successfully.

This is the module I wrote, but nothing happens after activating it and clearing cache:

app/code/Vendor/AutoSendInvoice/etc/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="sales_order_invoice_register">
        <observer name="VendorAutoSendInvoice" instance="Vendor\AutoSendInvoice\Observer\AutoSendInvoice" />
    </event>
</config>

This is the Observer app/code/Vendor/AutoSendInvoice/Observer/AutoSendInvoice.php

<?php
namespace Vendor\AutoSendInvoice\Observer;

use Magento\Framework\Event\ObserverInterface;
use Magento\Sales\Model\Order;
use Magento\Sales\Model\Order\Email\Sender\InvoiceSender;
use \Magento\Framework\Exception\LocalizedException;
use \Psr\Log\LoggerInterface;

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

    /**
     * @var \Magento\Sales\Model\Order\Email\Sender\InvoiceSender
     */
    protected $invoiceSender;

    /**
     * Logger
     * @var LoggerInterface
     */
    protected $logger;


    /**
     * @param \Magento\Sales\Model\OrderFactory $orderModel
     * @param InvoiceSender $invoiceSender
     * @param LoggerInterface $logger
     */
    public function __construct(
        \Magento\Sales\Model\OrderFactory $orderModel,
        \Magento\Sales\Model\Order\Email\Sender\InvoiceSender $invoiceSender,
        LoggerInterface $logger
    )
    {
        $this->orderModel = $orderModel;
        $this->invoiceSender = $invoiceSender;
        $this->logger = $logger;
    }

    public function execute(\Magento\Framework\Event\Observer $observer)
    {
        // get the corresponding order & invoice
        $invoice = $observer->getEvent()->getInvoice(); 
$order = $invoice->getOrder();


        if (!$order->getId()) {
            throw new LocalizedException(__('The order no longer exists.'));
        }

        // send invoice email only for PayPal Plus and Amazon Pay AND if order status is "new" or "processing"
        if ( $this->checkPaymentMethod($order ) && $this->checkStateOrder($order )
            ) {
                try {
                    // check if order is allowed to create invoice
                    $this->checkOrder($order);

                    // send invoice email
                    try {
                        $this->invoiceSender->send($invoice);
                    } catch (\Exception $e) {
                        $this->logger->error($e->getMessage());
                    }

                    // add order comment
                    $order->addStatusHistoryComment(
                        'Automatically Invoiced by Vendor',
                        true
                    )->save();


                } catch (\Exception $e) {
                    $this->logger->error($e->getMessage());
                }
            }
        }


    /**
     * @param $order
     * @throws LocalizedException
     */
    protected function checkOrder($order)
    {
        if (!$order->canInvoice()
        ) {
            throw new LocalizedException(
                __('The order does not allow an invoice to be created.')
            );
        }
    }

    protected function checkPaymentMethod($order) {
        // get the payment method for corresponding order
        $payment = $order->getPayment()->getMethodInstance()->getCode();

        if ( $payment == 'iways_paypalplus_payment' || $payment == 'amazon_payment' ) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * Check State Order
     *
     * @param $order
     * @return bool
     */
    protected function checkStateOrder($order)
    {
        if ($order->getState() == Order::STATE_NEW || $order->getState() == Order::STATE_PROCESSING) {
            return true;
        } else {
            return false;
        }
    }
}

I am not getting any error.

  • I don't really see the problem, why your observer's execute method() is not reached. Try to add a simple log in the first line of the method to see if the code is reached. But you have a logical error: the event sales_order_invoice_registeris called at the end of the method register() after the invoice has been created and even paid. At this moment $order->canInvoice() is always false and your mail will never be sent. But anyway if the code would run you should see the exception in the logfile. – HelgeB Feb 25 '19 at 19:57
  • @HelgeB Thanks for the hint. There was also another mistake with how I got the order object. I had to get the invoice first from the event: $invoice = $observer->getEvent()->getInvoice(); and after that the order from the invoice with $invoice->getOrder(); The invoice mail is sent now, but it seems like the event is not the right one, as the invoice number in missing in the email. My guess is that the invoice creating process is not yet finished? – benlau Feb 26 '19 at 2:28
2

If you need the entity_id of the new created invoice you have to choose a later event. For example sales_order_invoice_save_after. Here you will always have the entity_id. Downside of this approach: An invoice is usually saved more than once in the lifecycle.

But you can check for $invoice->getEmailSent() in your code and send the email only if it not has been send earlier.

So changing the event in your xml file to sales_order_invoice_save_after and the condition in your code as follows should give you what you need:

if ( $this->checkPaymentMethod($order) 
     && $this->checkStateOrder($order)
     && !$invoice->getEmailSent()
     ){

    //your other code here...
}
| improve this answer | |
  • Helge, thank you for your help on this. At the moment I am experiencing a strange problem with this solution though: With PayPal everything is working fine, but orders paid with Amazon Pay now don't send out the order confirmation mail. The invoice mail is sent though...I don't see how this code is interfering with Amazon at all? – benlau Mar 4 '19 at 8:47
  • 1
    That's strange indeed. I can't see any reason how this code can interfere with order confirmation mail. But to get sure you can try to disable your oberver and see if then Amazon Pay will send mails. If that would be the case you need to debug inside the Amazon Pay module to see what could be the problem. – HelgeB Mar 4 '19 at 9:07
  • When the module is disabled the mail is sent the way it should be. Currently, my best guess is that it has to do with this line: $order->addStatusHistoryComment( 'Automatically Invoiced by Vendor', true )->save();..but I will try debugging the Amazon Pay module next. – benlau Mar 4 '19 at 9:18
  • Ah, ok. I have overseen the save(). Try to remove only the save() call from your code, I guess the order will be saved anyway later in the code. And also set the second parameter of addStatusHistoryComment() method to false and let the status change be done by the default process. That might indeed be a problem. – HelgeB Mar 4 '19 at 9:20
  • I tried both removing save() and setting the second parameter to false, but same result. Furthermore, without save() the order history comment is not saved at all. – benlau Mar 4 '19 at 18:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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