4

I'm using the following code to place an order programmatically in Magento 2:

    // Configure the quote
    $quote = $this->cart->getQuote();
    $quote->setInventoryProcessed(false);
    $quote->setPaymentMethod('custom_gateway');
    $quote->save();

    // Set the payment method
    $payment = $quote->getPayment();
    $payment->importData(['method' => 'custom_gateway']);

    // Update the quote
    $quote->collectTotals()->save();

    // Place the order
    $this->cartManagement->placeOrder($quote->getId());

This code is creating the order as expected, but is also sending an email to the shopper.

I would like to send the confirmation email at a later stage in the process, only when the payment has been confirmed.

How can I place an order without notifying the customer?

2
  • Seem that you're implementing the online payment? Commented Apr 13, 2017 at 13:33
  • Did you find a solution at last? :(
    – ermannob
    Commented Jun 22, 2017 at 15:13

6 Answers 6

1

We can set the flag for order: $order->setCanSendNewEmailFlag(false)

We can see some good examples for online payments:

vendor/magento/module-quote/Observer/Webapi/SubmitObserver.php

vendor/magento/module-paypal/Model/Payflowlink.php
10
  • If the placeOrder() function sends an email, I don't see how I can set the flag after the order has been created. I have just tried the following and the email is still sent: $order = $this->quoteManagement->submit($quote); $order->setCanSendNewEmailFlag(false); Commented Apr 13, 2017 at 13:51
  • It seems that once the order has been placed, it's too late to set the flag. Could you please suggest a way to create an order where your suggestion would be usable? Commented Apr 13, 2017 at 13:54
  • I think we can try with plugin: Magento\Sales\Api\OrderManagementInterface::place(). Should use afterPlace() plugin. We can set $order->setCanSendNewEmailFlag(false). Commented Apr 13, 2017 at 13:54
  • I am not sure about how to implement this. Would you please have a short example? Commented Apr 13, 2017 at 14:01
  • in the Payflow extension you mention, this is what happens: $order = $payment->getOrder(); $order->setCanSendNewEmailFlag(false); So basically the order already exists, that's why you can set a flag. In my case, the order is created from a quote so you can't set the flag before the order is created. Is there any way to disable email notification at the quote level for example? Commented Apr 13, 2017 at 14:09
1

The solution is to use this:

use Magento\Quote\Model\QuoteManagement;
...
// Create order from quote
$order = $this->quoteManagement->submit($quote);

QuoteManagement will not send an order until you call

use Magento\Sales\Model\Order\Email\Sender\OrderSender;
...

// Send the email when desired
$this->orderSender->send($order);
1

I was looking for this and I have came up with this:

  1. Most solutions out there is doing something like this:
$cartId = $this->cartManagementInterface->createEmptyCart();
...
...
$orderId = $this->cartManagementInterface->placeOrder($quote->getId());

Which is the easiest solution in my opinion.

But this method triggers an observer:

sales_model_service_quote_submit_success

Which is responsible for sending the emails.

vendor/magento/module-quote/Observer/SubmitObserver.php

This means you can't do $order->setCanSendNewEmailFlag(false) before the emails is sent at least once.

For this what I did was :

  1. When creating the cart do:

$cart->setCanSendNewEmailFlag(false);

  1. Make a new observer that will be executed before Quote module:
    <sequence>
    <module name="Magento_Sales"/>
    <module name="Magento_Quote"/>
    </sequence>
  1. On the observer do:
    if($quote->getCanSendNewEmailFlag() == false){
    $order->setCanSendNewEmailFlag(false);

With this now you can set the setCanSendNewEmailFlag before sending an email.

0

i checked your code you are using

$this->cartManagement->placeOrder($quote->getId());

the simple workaround for your placeOrder function is. Magento is sending the email by observing this sales_model_service_quote_submit_success dispatch event and vendor/magento/module-quote/Observer/SubmitObserver.php this file is observing that event and will trigger mail based on the condition.

You can observe sales_model_service_quote_submit_before this dispatch event to change the order can send new email flag to false like this $order->setCanSendNewEmailFlag(false);

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_model_service_quote_submit_before">
        <observer instance="Vendor\Module\Observer\Order\ChangeEmailFlag" name="events_change_flag"/>
    </event>
</config>

In ChangeEmailFlag.php


<?php

namespace Vendor\Module\Observer\Order;
  
use Magento\Quote\Model\QuoteRepository;
use Psr\Log\LoggerInterface;

class ChangeEmailFlag implements \Magento\Framework\Event\ObserverInterface
{

    protected $quoteRepository;

    protected $logger;

    public function __construct(
        QuoteRepository $quoteRepository,
        LoggerInterface $logger
    ) {
        $this->logger = $logger;
        $this->quoteRepository = $quoteRepository;
    }

    public function execute(\Magento\Framework\Event\Observer $observer)
    {
        try {
            $order= $observer->getData('order');
            
            if(//your condition)
            {
                $order->setCanSendNewEmailFlag(false);
            }
           
        } catch (\Exception $e) {
            $this->logger->error($e->getMessage());
        }
        return $this;
    }
}

Tested in Magento2.4.6 working perfect.

Please upvote if it is useful.

0

You can stop sending emails using below code . Tested and working fine for Magento 2.4.7.

Create file events.xml

Vendor\Module\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_model_service_quote_submit_before">
        <observer name="disable_methodcode_order_email" instance="Vendor\Module\Observer\DisableOrderEmail" />
    </event>
</config>

Create new file DisableOrderEmail.php

Vendor\Module\Observer\DisableOrderEmail.php

<?php
namespace Vendor\Module\Observer;

use Magento\Framework\Event\ObserverInterface;

class DisableOrderEmail implements ObserverInterface
{
    /**
     * Execute function
     *
     * @param \Magento\Framework\Event\Observer $observer
     * @return void
     */
    public function execute(\Magento\Framework\Event\Observer $observer)
    {
        $order = $observer->getEvent()->getOrder();
        
        if ($order && $order->getPayment() && $order->getPayment()->getMethod() === 'methodcode') {
            $order->setCanSendNewEmailFlag(false);
        }
    }
}
-1

have you checked this: admin->Stores->Configuration->Sales->Sales Emails->Order and set Enabled as no

now check !!

2
  • Thank you for the info. Is there no way to do that for a single order without impacting the global configuration? Commented Apr 13, 2017 at 13:31
  • Basically I am working on a custom payment gateway. If I do what you suggest from a global config, what happens to other payment gateways that need this on? Commented Apr 13, 2017 at 13:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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