Duplicate orders with same Quote Id

This problem is so hard to detect a cause. This one #25222 is one of a cause to make multiple duplicated orders. And Amazon Pay as well, I can’t recall exactly.
But generally, for somewhat reason is that the function Magento\Quote\Model\QuoteManagement::submitQuote is called on twice or even more.

  • So my solution is to make a hook/plugin on the function “submitQuote” to manage a problem when it will happen – also we do a trace to log to know what happens. [ See code below]

So then we usually check a folder /var/order_duplicated_log. If there is a file with the prefix is “duplicated_”, then a duplicated order issue would happen. Base on a trace on a duplicated log file and logs from system.log of Magento, We can catch what code lines/3rd-party extension causes the issue.

I’m available if someone would like to hire me to fix it. Drop me an email to luuvantrung@gmail.com

I make a plugin :

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <type name="Magento\Quote\Model\QuoteManagement">
        <plugin name="prevent-placeorder-exception" type="FixBugs\DuplicatedOrder\Plugin\QuoteManagement\SubmitQuote" sortOrder="1" />
    </type>

</config>
<?php
namespace FixBugs\DuplicatedOrder\Plugin\QuoteManagement;
use Magento\Framework\Event\Observer;
use Magento\Framework\Event\ObserverInterface;
use Magento\Framework\Message\ManagerInterface;
use Magento\Framework\App\RequestInterface;

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


class SubmitQuote {
    
    public function __construct(
        \Magento\Framework\App\ResponseFactory $responseFactory,
        \Magento\Framework\UrlInterface $url,
        \Magento\Sales\Model\ResourceModel\Order\CollectionFactory $orderCollectionFactory,
        RequestInterface $request    
    ) {
        $this->responseFactory = $responseFactory;
        $this->url = $url;
        $this->orderCollectionFactory = $orderCollectionFactory;
        $this->request = $request;
    }

    public function beforeSubmit($subject,  $quote, $orderData = [] ) {
                
        $objectManager = \Magento\Framework\App\ObjectManager::getInstance();
        /** @var  $session \Magento\Framework\Session\Generic */
        $session   = $objectManager->get('Magento\Framework\Session\Generic');
        $response  = $objectManager->get('Magento\Framework\App\Response\Http');

        /** @var  $messageManager \Magento\Framework\Message\ManagerInterface */
        $messageManager = $objectManager->get('Magento\Framework\Message\ManagerInterface');

        /** @var  $chekcoutSession \Magento\Checkout\Model\Session */
        $chekcoutSession = $objectManager->get('Magento\Checkout\Model\Session');
        
        $orderSender = $objectManager->get('Magento\Sales\Model\Order\Email\Sender\OrderSender');
        
        if ( $quote &&
            $quote->getId() > 0 &&
            $quote->hasItems() &&
            $quote->getHasError() === null &&
            ($payment = $quote->getPayment()) &&            
            ($order = $chekcoutSession->getLastRealOrder()) &&
            $order->getStatus() === "processing"
            ) 
                {
                    //log information here - /var/order_duplicated_log - so we can check later - maybe find some useful information to fix this bug.
                    $relativeFileName = "duplicated_".$order->getIncrementId().'_'.time().'.log';
                    
                    $contents = array(
                        'time' => date("Y-m-d H:i:s"),                        
                        'request_info' => $_SERVER,
                        'params' => $this->request->getParams(),
                        'debugs' => $this->getBackTraces()
                            
                    );
                    $this->writeLogFile($relativeFileName, json_encode($contents, JSON_PRETTY_PRINT) );
                    
                    /*Send email if it has not been sent*/
                    if($order->getCanSendNewEmailFlag() && $order->getEmailSent()){
                        $orderSender->send($order);
                    }

                    /*Redirect to cart page -  Maybe here we can set void is inactive */

                    $session->destroy(['send_expire_cookie' => true]);
                    $messageManager->addNoticeMessage(
                        __('Message to a customer')
                    );
                    $response->setRedirect( "checkout/cart" )->sendResponse();
                    
                    die();
                    
        } else {
                  
                $relativeFileName = 'not_duplicated'.$quote->getId().'_'.time().'.log';    
                $contents = array(
                    'time' => date("Y-m-d H:i:s"),                        
                    'request_info' => $_SERVER,
                    'params' => $this->request->getParams(),
                    'debugs' => $this->getBackTraces()

                );
                $this->writeLogFile($relativeFileName, json_encode($contents, JSON_PRETTY_PRINT) );  
        }
        return [$quote, $orderData];
    }
    
    protected  function writeLogFile( $relativeFileName, $content ) {
        
        $om = \Magento\Framework\App\ObjectManager::getInstance();        
        $directory = $om->get('Magento\Framework\Filesystem\DirectoryList');
        $rootPath  =  $directory->getRoot();        
        $logFolder = $rootPath . DIRECTORY_SEPARATOR . 'var' . DIRECTORY_SEPARATOR . 'order_duplicated_log_plugin';
        
        if( !file_exists($logFolder) )  mkdir( $logFolder, 0777 );
        $relativeFileName = DIRECTORY_SEPARATOR . 'order_duplicated_log' . DIRECTORY_SEPARATOR . $relativeFileName;
        
        /** @var \Magento\Framework\Filesystem $filesystem */
        $filesystem = $om->get('Magento\Framework\Filesystem');
        
        /** @var \Magento\Framework\Filesystem\Directory\WriteInterface|\Magento\Framework\Filesystem\Directory\Write $writer */
        $writer = $filesystem->getDirectoryWrite('var');
        /** @var \Magento\Framework\Filesystem\File\WriteInterface|\Magento\Framework\Filesystem\File\Write $file */
        $file = $writer->openFile($relativeFileName, 'w');
        try {
            $file->lock();
            try {                
                $file->write($content);                
            } finally {                
                $file->unlock();                
            }
        } finally {
            $file->close();
        }
    }
    
    protected function getBackTraces(){
        
        $debugs = debug_backtrace();
        $debugClasses = array();
        foreach ($debugs as $debug) {
            $debugLines = array();

            $debugLines['file'] = isset($debug['file']) ? $debug['file'] : '';
            $debugLines['class'] = isset($debug['class']) ? $debug['class'] : '';
            $debugLines['method'] = isset($debug['function']) ? $debug['function'] : '';
            $debugLines['line'] = isset($debug['line']) ? $debug['line'] : '';

            //$debugClasses[] = implode("||", $debugLines);
            $debugClasses[] = $debugLines;
        }
        return $debugClasses;
    }
    
}

Leave a Reply

Your email address will not be published. Required fields are marked *