Every order has a status associated with a stage in the order processing workflow.
The state describes the position of an order in the workflow. By default, Magento store has a set of predefined order statuses and order state settings. All the available order statuses can be found in admin panel under Stores -> Settings -> Order Status
. Sometimes we need to create a new order status and state. Let’s explore how to programmatically create a new order state and status in Magento 2.
The order statuses are stored in sales_order_status
database table while the order states and their bindings to statuses are defined in sales_order_status_state
table. We will need to create a simple setup script in order to add a new order state and status.
First of all we need to create a new custom extension, for example Atwix_OrderFlow
. Create a registration.php
file in the app/code/Atwix/OrderFlow
:
<?php /* File: app/code/Atwix/OrderFlow/registration.php */ use \Magento\Framework\Component\ComponentRegistrar; ComponentRegistrar::register( ComponentRegistrar::MODULE, 'Atwix_OrderFlow', __DIR__ );
And create the module.xml
configuration file in app/code/Atwix/OrderFlow/etc
folder with the following code:
<?xml version="1.0"?> <!-- File: app/code/Atwix/OrderFlow/etc/module.xml --> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd"> <module name="Atwix_OrderFlow" setup_version="1.0.0"> <sequence> <module name="Magento_Sales"/> </sequence> </module> </config>
The installation data class is as follows. For instance, two similar methods have been created:
- addNewOrderProcessingStatus
- addNewOrderStateAndStatus
The first method will add a new order status to the existent order state. The second one will create a new order status and new order state.
<?php /* File: app/code/Atwix/OrderFlow/Setup/InstallData.php */ namespace Atwix\OrderFlow\Setup; use Exception; use Magento\Framework\Exception\AlreadyExistsException; use Magento\Framework\Setup\InstallDataInterface; use Magento\Framework\Setup\ModuleContextInterface; use Magento\Framework\Setup\ModuleDataSetupInterface; use Magento\Sales\Model\Order; use Magento\Sales\Model\Order\Status; use Magento\Sales\Model\Order\StatusFactory; use Magento\Sales\Model\ResourceModel\Order\Status as StatusResource; use Magento\Sales\Model\ResourceModel\Order\StatusFactory as StatusResourceFactory; /** * Class InstallData */ class InstallData implements InstallDataInterface { /** * Custom Processing Order-Status code */ const ORDER_STATUS_PROCESSING_FULFILLMENT_CODE = 'processing_custom'; /** * Custom Processing Order-Status label */ const ORDER_STATUS_PROCESSING_FULFILLMENT_LABEL = 'Processing Custom'; /** * Custom Order-State code */ const ORDER_STATE_CUSTOM_CODE = 'some_custom_state'; /** * Custom Order-Status code */ const ORDER_STATUS_CUSTOM_CODE = 'some_custom_status'; /** * Custom Order-Status label */ const ORDER_STATUS_CUSTOM_LABEL = 'Some Custom Status'; /** * Status Factory * * @var StatusFactory */ protected $statusFactory; /** * Status Resource Factory * * @var StatusResourceFactory */ protected $statusResourceFactory; /** * InstallData constructor * * @param StatusFactory $statusFactory * @param StatusResourceFactory $statusResourceFactory */ public function __construct( StatusFactory $statusFactory, StatusResourceFactory $statusResourceFactory ) { $this->statusFactory = $statusFactory; $this->statusResourceFactory = $statusResourceFactory; } /** * Installs data for a module * * @param ModuleDataSetupInterface $setup * @param ModuleContextInterface $context * * @return void * * @throws Exception */ public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context) { $this->addNewOrderProcessingStatus(); $this->addNewOrderStateAndStatus(); } /** * Create new order processing status and assign it to the existent state * * @return void * * @throws Exception */ protected function addNewOrderProcessingStatus() { /** @var StatusResource $statusResource */ $statusResource = $this->statusResourceFactory->create(); /** @var Status $status */ $status = $this->statusFactory->create(); $status->setData([ 'status' => self::ORDER_STATUS_PROCESSING_FULFILLMENT_CODE, 'label' => self::ORDER_STATUS_PROCESSING_FULFILLMENT_LABEL, ]); try { $statusResource->save($status); } catch (AlreadyExistsException $exception) { return; } $status->assignState(Order::STATE_PROCESSING, false, true); } /** * Create new custom order status and assign it to the new custom order state * * @return void * * @throws Exception */ protected function addNewOrderStateAndStatus() { /** @var StatusResource $statusResource */ $statusResource = $this->statusResourceFactory->create(); /** @var Status $status */ $status = $this->statusFactory->create(); $status->setData([ 'status' => self::ORDER_STATUS_CUSTOM_CODE, 'label' => self::ORDER_STATUS_CUSTOM_LABEL, ]); try { $statusResource->save($status); } catch (AlreadyExistsException $exception) { return; } $status->assignState(self::ORDER_STATE_CUSTOM_CODE, true, true); } }
As you may have noticed, each method performs two steps. First of all, it creates a new order status and saves it, so it will appear in sales_order_status
database table. Then it links the created status to an order state by adding a new record to the sales_order_status_state
database table.
There are no separate table for order states, so each unique value in state
column of sales_order_status_state
table is considered as a separate order state.
Run the Setup Upgrade command in order to activate the module and execute the setup script:
php bin/magento setup:upgrade
Now you can check the results in Stores -> Settings -> Order Status
.
Thanks for reading!