Question

I'm trying to execute cron job after customer click place order button and redirect to success page. So the purpose of my job, if admin did not respond the order in 3 days, the order status will automatically canceled.

I have override the \Magento\Checkout\Controller\Onepage\Success in my module and use execute function to run my job via terminal.

<?php namespace Mymodule\Checkout\Controller\Onepage;

class Success extends \Magento\Checkout\Controller\Onepage\Success
{
    /**
     * Order success action
     *
     * @return \Magento\Framework\Controller\ResultInterface
     */
    public function execute()
    {
        exec('php bin/magento cron:run --group="custom"');
        return parent::execute();
    }
}

Here is crontab.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Cron:etc/crontab.xsd">
    <group id="custom_group">
        <job name="test_cronjob" instance="Mymodule\Checkout\Cron\CancelOrder" method="execute">
            <schedule>* * */3 * *</schedule>
        </job>
    </group>
</config>

Here is CancelOrder.php

<?php namespace Mymodule\Checkout\Cron;

class CancelOrder {
    protected $orderFactory;

    protected $checkoutSession;

    public function __construct(
        \Magento\Sales\Model\OrderFactory $orderFactory,
        \Magento\Checkout\Model\Session $checkoutSession
    ){
        $this->orderFactory = $orderFactory;
        $this->checkoutSession = $checkoutSession;
    }

    public function execute() {
        $orderId = $this->checkoutSession->getLastOrderId();
        if (!empty($orderId)) {
            $order = $this->orderFactory->create();
            $order->load($orderId);

            if ($order->getStatus() == 'pending') {
                $order->setState('canceled');
                $order->setStatus('canceled');

                $order->save();

                // send email to customer
            } else {
                return 0;
            }
        }
    }
}

When i try place order, the job is not executed. Is there something wrong with my code?

Was it helpful?

Solution

From my understanding, you want to cancel the orders which are older than 3 days. In this case, we need to create the Cron job. So, we will compare the current date with the created date (take a look table sales_order, find the column created_at).

We should use Service Contracts Layer:

  • \Magento\Sales\Api\OrderRepositoryInterface $orderRepository and \Magento\Framework\Api\SearchCriteriaBuilder $searchCriteriaBuilder are used for getting the order items.

  • \Magento\Sales\Api\OrderManagementInterface is used for canceling order.

Our Cron:

namespace Mymodule\Checkout\Cron;

class CancelOrder
{
    /**
     * @var \Magento\Sales\Api\OrderRepositoryInterface
     */
    protected $orderRepository;
    /**
     * @var \Magento\Framework\Api\SearchCriteriaBuilder
     */
    protected $searchCriteriaBuilder;

    /**
     * @var \Magento\Sales\Api\OrderManagementInterface
     */
    protected $orderManagement;

    /**
     * CancelOrder constructor.
     * @param \Magento\Sales\Api\OrderRepositoryInterface $orderRepository
     * @param \Magento\Framework\Api\SearchCriteriaBuilder $searchCriteriaBuilder
     * @param \Magento\Sales\Api\OrderManagementInterface $orderManagement
     */
    public function __construct(
        \Magento\Sales\Api\OrderRepositoryInterface $orderRepository,
        \Magento\Framework\Api\SearchCriteriaBuilder $searchCriteriaBuilder,
        \Magento\Sales\Api\OrderManagementInterface $orderManagement
    )
    {
        $this->orderRepository = $orderRepository;
        $this->searchCriteriaBuilder = $searchCriteriaBuilder;
        $this->orderManagement = $orderManagement;
    }

    public function execute()
    {
        $agoDate = '2016-11-07'; // For example date, your logic to calculate the date here
        $searchCriteria = $this->searchCriteriaBuilder
        ->addFilter(
            'created_at',
            $agoDate,
            'gt'
        )->addFilter(
           'status'
           'pending'
           'eq'
        )->create();

        $orders = $this->orderRepository->getList($searchCriteria);
        foreach ($orders->getItems() as $order) {
                $this->orderManagement->cancel($order->getEntityId()); // Cancel Order
        };

    }
}

You should set your Cron runs every minute: https://crontab.guru/

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Cron:etc/crontab.xsd">
    <group id="custom_group">
        <job name="test_cronjob" instance="Mymodule\Checkout\Cron\CancelOrder" method="execute">
            <schedule>* * * * *</schedule>
        </job>
    </group>
</config>

NOTE: You can test your custom Cron directly: https://magento.stackexchange.com/a/152812/33057

OTHER TIPS

Create your own cron job that will automatically cancel orders older than 3 days filtered by order status.

Licensed under: CC-BY-SA with attribution
Not affiliated with magento.stackexchange
scroll top