Question

I've added a new column to the table sales_order called export_status, now I want to add new order grid column with the data from the new sales_order column.

I've managed to add column to the sales_order_grid table.

$installer->getConnection()->addColumn($installer->getTable("sales_order_grid"), "xml_exported", [
     'type' => \Magento\Framework\DB\Ddl\Table::TYPE_TEXT,
     'comment' => 'XML Exported'
]);

How can I now make it actually show in the orders grid with the value from the sales_order export_status column?

Was it helpful?

Solution

After lots of digging into Magento's core code, I found a solution to my question. Instead of adding a column to the grid via the database, I created a UI component sales_order_grid.xml under [COMPANY]/[MODULE]/view/adminhtml/ui_component/sales_order_grid.xml

<?xml version="1.0" encoding="UTF-8"?>
<listing xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd">
    <columns name="sales_order_columns">
        <column name="export_status" class="[COMPANY]\[MODULE]\Ui\Component\Listing\Column\Status">
            <argument name="data" xsi:type="array">
                <item name="config" xsi:type="array">
                    <item name="visible" xsi:type="boolean">true</item>
                    <item name="label" xsi:type="string" translate="true">XML Exported</item>
                </item>
            </argument>
        </column>
    </columns>
</listing>

Then created the UI class under [COMPANY]/[MODULE]/Ui/Component/Listing/Column/Status.php

namespace [COMPANY]\[MODULE]\Ui\Component\Listing\Column;

use \Magento\Sales\Api\OrderRepositoryInterface;
use \Magento\Framework\View\Element\UiComponent\ContextInterface;
use \Magento\Framework\View\Element\UiComponentFactory;
use \Magento\Ui\Component\Listing\Columns\Column;
use \Magento\Framework\Api\SearchCriteriaBuilder;

class Status extends Column
{
    protected $_orderRepository;
    protected $_searchCriteria;

    public function __construct(ContextInterface $context, UiComponentFactory $uiComponentFactory, OrderRepositoryInterface $orderRepository, SearchCriteriaBuilder $criteria, array $components = [], array $data = [])
    {
        $this->_orderRepository = $orderRepository;
        $this->_searchCriteria  = $criteria;
        parent::__construct($context, $uiComponentFactory, $components, $data);
    }

    public function prepareDataSource(array $dataSource)
    {
        if (isset($dataSource['data']['items'])) {
            foreach ($dataSource['data']['items'] as & $item) {

                $order  = $this->_orderRepository->get($item["entity_id"]);
                $status = $order->getData("export_status");

                switch ($status) {
                    case "0":
                        $export_status = "No";
                        break;
                    case "1";
                        $export_status = "Yes";
                        break;
                    default:
                        $export_status = "Failed";
                        break;

                }

                // $this->getData('name') returns the name of the column so in this case it would return export_status
                $item[$this->getData('name')] = $export_status;
            }
        }

        return $dataSource;
    }
}

OTHER TIPS

My solution may be a bit more efficient since it follows the native way of adding a column to the grid, and you won't have to load every order displayed on the page to obtain the column data (utilizing the sales_order_grid table instead). The above is a great example of how to create a customized renderer though.

vendor/[vendor]/[package]/view/adminhtml/ui_component/sales_order_grid.xml

<!-- Add the column "my_column" (My Column) to the sales order grid. -->
<listing xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd">
<columns name="sales_order_columns">
    <column name="my_column">
        <argument name="data" xsi:type="array">
            <item name="config" xsi:type="array">
                <item name="filter" xsi:type="string">text</item>
                <item name="label" xsi:type="string" translate="true">My Column</item>
            </item>
        </argument>
    </column>
</columns>

Please note that you must enable the column using the drop-down widget above the order grid before it appears.

vendor/[vendor]/[package]/etc/di.xml

<!-- Sync the column "my_column" between the sales_order and sales_order_grid tables -->
<virtualType name="Magento\Sales\Model\ResourceModel\Order\Grid" type="Magento\Sales\Model\ResourceModel\Grid">
    <arguments>
        <argument name="columns">
            <item name="my_column" xsi:type="string">sales_order.my_column</item>
        </argument>
    </arguments>
</virtualType>

Sample setup code to add a column to sales_order_grid table (use this in your install/upgrade script). The same code works for the sales_order table by the way.

$setup->getConnection()->addColumn(
        $setup->getTable('sales_order_grid'),
        'my_column',
        [
            'type' => \Magento\Framework\DB\Ddl\Table::TYPE_TEXT,
            'length' => 255,
            'nullable' => true,
            'comment' => 'My Column'
        ]
    );

Hope it helps! :-)

For creating a new column in order grid , I have referred Magento Default Module vendor/magento/module-customer-balance

In my case,'custom_column' column already exists in the sales_order table.

I have to show 'custom_column' column in order grid

Step 1: Add a new Column in sales_order_grid table

        $connection = $installer->getConnection();
        if ($connection->isTableExists('sales_order_grid')) {
            $connection->addColumn(
                $connection->getTableName('sales_order_grid'),
                'custom_column',
                [
                    "type"      =>  Table::TYPE_TEXT,
                    'default'   =>  null,
                    "comment"   =>  'Custom Column'
                ]
            );
    }

Step 2 : di.xml file in app\code[Vendor][NameSpace]\etc\di.xml

 <!-- Adding Columns in sales_order_grid-->
    <virtualType name="Magento\Sales\Model\ResourceModel\Order\Grid">
        <arguments>
            <argument name="columns" xsi:type="array">
                <item name="custom_column" xsi:type="string">sales_order.custom_column</item>
            </argument>
        </arguments>
    </virtualType>
    <virtualType name="Magento\SalesArchive\Model\ResourceModel\Order\Grid">
        <arguments>
            <argument name="columns" xsi:type="array">
                <item name="custom_column" xsi:type="string">sales_order.custom_column</item>
            </argument>
        </arguments>
    </virtualType>

Step 3 : Create sales_order_grid.xml layout file under app\code[Vendor][NameSpace]\view\adminhtml\ui_component

<listing xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd">
    <columns name="sales_order_columns">
        <column name="custom_column">
            <argument name="data" xsi:type="array">
                <item name="config" xsi:type="array">
                    <item name="filter" xsi:type="string">text</item>
                    <item name="label" xsi:type="string" translate="true">Custom Column</item>
                </item>
            </argument>
        </column>
    </columns>
</listing>

Note: This has been tested in Magento version 2.2.6

The answers here were very helpful, thank you! Here's an answer with some updated material (usage of db_schema.xml vs setup scripts, how to populate column data & clear UI bookmarks).


1. Create Database Columns

I didn't see any answers here using db_schema.xml. I'm not sure this feature was implemented when the question was first asked, but it is a much easier method for creating the necessary database columns in the grid tables.

Here's an example db_schema.xml for adding the coupon_code column to both of the order grid tables:

Vendor/Module/etc/db_schema.xml

<?xml version="1.0"?>
<schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd">
    <!-- Add column to "sales_order_grid" -->
    <table name="sales_order_grid">
        <column xsi:type="varchar" name="coupon_code" nullable="true" length="255" comment="Coupon Code"/>
    </table>
    <!-- Enterprise Edition: Add column to "magento_sales_order_grid_archive" -->
    <table name="magento_sales_order_grid_archive">
        <column xsi:type="varchar" name="coupon_code" nullable="true" length="255" comment="Coupon Code"/>
    </table>
</schema>

2. Configure Grid Columns in Virtual Classes

The grid columns are defined in a virtual Magento\Sales\Model\ResourceModel\Order\Grid class in the Magento_Sales dependency injection (di.xml) file. You can study the file to see how to select columns and join data from other tables.

Vendor/Module/etc/di.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <virtualType name="Magento\Sales\Model\ResourceModel\Order\Grid">
        <arguments>
            <argument name="columns" xsi:type="array">
                <item name="coupon_code" xsi:type="string">sales_order.coupon_code</item>
            </argument>
        </arguments>
    </virtualType>
    <virtualType name="Magento\SalesArchive\Model\ResourceModel\Order\Grid">
        <arguments>
            <argument name="columns" xsi:type="array">
                <item name="coupon_code" xsi:type="string">sales_order.coupon_code</item>
            </argument>
        </arguments>
    </virtualType>
</config>

Enterprise edition users will also have the Magento_SalesArchive module. The module's di.xml file defines a similar Magento\SalesArchive\Model\ResourceModel\Order\Grid virtual class.


3. Add Columns to UI Components

Now we need to add the column to the UI component definition file.

Vender/Module/view/adminhtml/ui_component/sales_order_grid.xml

<?xml version="1.0" encoding="UTF-8"?>
<listing xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd">
    <columns name="sales_order_columns">
        <column name="coupon_code">
            <settings>
                <filter>text</filter>
                <label translate="true">Coupon Code</label>
                <visible>false</visible>
            </settings>
        </column>
    </columns>
</listing>

Enterprise users: update the archive grid component as well.

Vender/Module/view/adminhtml/ui_component/sales_archive_order_grid.xml

<?xml version="1.0" encoding="UTF-8"?>
<listing xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd">
    <columns name="sales_order_columns">
        <column name="coupon_code">
            <settings>
                <filter>text</filter>
                <label translate="true">Coupon Code</label>
                <visible>false</visible>
            </settings>
        </column>
    </columns>
</listing>

4. Populate Data

The columns should be created in the database, configured to show on the order grids, and new orders should populate the data as expected. Existing orders will need another solution to populate missing data.

The best solution I found was from this article. The solution simply runs a SQL UPDATE / SET query (example in patch file below).


5. Optional: Delete UI Bookmarks

If you find that the column settings are not reflecting on the grid, you may want to delete the sales_order_grid entries in the ui_bookmark database table (Refer to example in patch file below).

Enterprise users: refresh the magento_sales_order_grid_archive entries as well.




I addressed steps 4 and 5 together with a patch file.

Vendor/Module/Setup/Patch/Data/PopulateGridData.php

<?php

namespace Vendor\Module\Setup\Patch\Data;

use Magento\Framework\Setup\Patch\DataPatchInterface;
use Magento\Ui\Model\ResourceModel\Bookmark\Collection as BookmarkCollection;

class PopulateGridData implements DataPatchInterface
{
    /**
     * @var BookmarkCollection
     */
    private $bookmarkCollection;

    /**
     * @param BookmarkCollection $bookmarkCollection
     */
    public function __construct(
        BookmarkCollection $bookmarkCollection
    ) {
        $this->bookmarkCollection = $bookmarkCollection;
    }

    /**
     * Populate sales order grid tables
     */
    private function populateSalesOrderGridColumns()
    {
        // Get connection
        $connection = $this->bookmarkCollection->getConnection();

        // Get grid table names
        $gridTables = [
            $connection->getTableName('sales_order_grid'),
            $connection->getTableName('magento_sales_order_grid_archive'),
        ];

        // Loop through grid tables
        foreach ($gridTables as $table) {
            // Build update select
            $select = $connection->select()->join(
                $connection->getTableName('sales_order'),
                sprintf("sales_order.entity_id = %s.entity_id", $table),
                ['netsuite_internal_id', 'coupon_code']
            );

            // Execute SQL query
            $connection->query(
                $connection->updateFromSelect(
                    $select,
                    $table
                )
            );
        }
    }

    /**
     * Refresh UI bookmarks table
     */
    private function deleteOrderGridBookmarks()
    {
        // Get collection and connection
        $connection = $this->bookmarkCollection->getConnection();

        // Get ID's to delete
        $ids = $this->bookmarkCollection->addFieldToFilter('namespace', [
            'in' => ['sales_order_grid', 'sales_archive_order_grid']
        ])->getColumnValues('bookmark_id');

        // Delete
        $connection->delete(
            $this->bookmarkCollection->getMainTable(),
            $connection->quoteInto('bookmark_id IN(?)', $ids)
        );
    }

    /**
     * Delete order grid UI bookmarks
     */
    public function apply()
    {
        $this->populateSalesOrderGridColumns();
        $this->deleteOrderGridBookmarks();
    }

    /**
     * Get aliases (previous names) for the patch.
     *
     * @return string[]
     */
    public function getAliases()
    {
        return [];
    }

    /**
     * Get array of patches that have to be executed prior to this.
     *
     * @return string[]
     */
    public static function getDependencies()
    {
        return [];
    }
}

Demo/ExtendedGrid/view/adminhtml/ui_component/sales_order_grid.xml

<?xml version="1.0" encoding="UTF-8"?>
<!--
/**
 * Copyright © Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */
-->
<listing xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd">
    <columns name="sales_order_columns">
        <column name="new_column_name" class="Demo\ExtendedGrid\Ui\Component\Listing\Column\NewColumnStatus">
            <argument name="data" xsi:type="array">
                <item name="config" xsi:type="array">
                    <item name="sortable" xsi:type="boolean">false</item>
                    <item name="has_preview" xsi:type="string">1</item>
                    <item name="label" xsi:type="string" translate="true">New Column Name</item>
              </item>
            </argument>
        </column>
    </columns>
</listing>

Then Created the UI Class to render it.

Demo/ExtendedGrid/Ui/Component/Listing/Column/NewColumnStatus.php

<?php
/**
 * Copyright © Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */
namespace Demo\ExtendedGrid\Ui\Component\Listing\Column;

/**
 * Class  NewColumnStatus
 */
class NewColumnStatus extends \Magento\Ui\Component\Listing\Columns\Column
{

    /**
     * @var string[]
     */
    protected $statuses;

   /**
     * Constructor
     *
     * @param ContextInterface $context
     * @param UiComponentFactory $uiComponentFactory
     * @param CollectionFactory $collectionFactory
     * @param array $components
     * @param array $data
     */
       public function __construct(
        \Magento\Framework\View\Element\UiComponent\ContextInterface $context,
        \Magento\Framework\View\Element\UiComponentFactory $uiComponentFactory,
        \Magento\Framework\UrlInterface $urlBuilder,
        array $components = [],
        array $data = []
    ) {
        $this->urlBuilder = $urlBuilder;
         parent::__construct($context, $uiComponentFactory, $components, $data);
    }


    /**
     * Prepare Data Source
     *
     * @param array $dataSource
     * @return void
     */
    public function prepareDataSource(array $dataSource)
    {
        if (isset($dataSource['data']['items'])) {
            foreach ($dataSource['data']['items'] as &$item) {

           //put  the logic here


            }
        }

        return $dataSource;
   }
}

Dont forget to clear cache.

I have created custom module which will add custom attribute in Sales Order entity and then show in admin Sales Order grid.

module.xml file to define the module. app\code\COMPANY\MODULE\etc\module.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../lib/internal/Magento/Framework/Module/etc/module.xsd">
    <module name="COMPANY_MODULE" setup_version="1.0.0">
        <sequence>
            <module name="Magento_Sales"/>
            <module name="Magento_Quote"/>
            <module name="Magento_Checkout"/>
        </sequence>
    </module>
</config>

di.xml file in app\code\COMPANY\MODULE\etc\di.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <virtualType name="Magento\Sales\Model\ResourceModel\Order\Grid" type="Magento\Sales\Model\ResourceModel\Grid">
        <arguments>
            <argument name="columns" xsi:type="array">
                <item name="export_status" xsi:type="string">sales_order.export_status</item>
            </argument>
        </arguments>
    </virtualType>
</config>

InstallData.php to add custom attribute export_status in database table

app\code\COMPANY\MODULE\Setup\InstallData.php

<?php

namespace COMPANY\MODULE\Setup;

use Magento\Eav\Setup\EavSetup;
use Magento\Eav\Setup\EavSetupFactory;
use Magento\Framework\Setup\InstallDataInterface;
use Magento\Framework\Setup\ModuleContextInterface;
use Magento\Framework\Setup\ModuleDataSetupInterface;

/**
 * @codeCoverageIgnore
 */
class InstallData implements InstallDataInterface
{
    /**
     * EAV setup factory
     *
     * @var EavSetupFactory
     */
    private $eavSetupFactory;

    /**
     * Init
     *
     * @param EavSetupFactory $eavSetupFactory
     */
    public function __construct(EavSetupFactory $eavSetupFactory)
    {
        $this->eavSetupFactory = $eavSetupFactory;
    }

    /**
     * {@inheritdoc}
     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
     */
    public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context)
    {
        /** @var EavSetup $eavSetup */
        $eavSetup = $this->eavSetupFactory->create(['setup' => $setup]);
        if (version_compare($context->getVersion(), '1.0.0') < 0){      
            $objectManager = \Magento\Framework\App\ObjectManager::getInstance();
            $salesSetup = $objectManager->create('Magento\Sales\Setup\SalesSetup');
            $salesSetup->addAttribute('order', 'export_status', ['type' =>'varchar']);
            $quoteSetup = $objectManager->create('Magento\Quote\Setup\QuoteSetup'); 
        }
    }
}

sales_order_grid.xml to add custom column in Sales Order admin grid.

<?xml version="1.0" encoding="UTF-8"?>
<listing xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd">
    <columns name="sales_order_columns">
        <column name="export_status">
            <argument name="data" xsi:type="array">
                <item name="config" xsi:type="array">
                    <item name="filter" xsi:type="string">text</item>
                    <item name="label" xsi:type="string" translate="true">XML Exported</item>
                </item>
            </argument>
        </column>
    </columns>
</listing>

You can download the full module by clicking on below link http://vdcstaging.co.in/download/add-custom-culumn-to-admin-grid.zip

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