How to Show Shipping Country Column on The Sales Order Grid?

0

Sometimes we got the requirement from the many clients about to show “Shipping Country” column on the sales order grid but to do that you need to do customization and by default, only several main columns are only visible in the grid and there are extra columns are also available which you can be enabled from “Columns” dropdown on the top-right side.

Today, In this blog, we learn about “How to show Shipping Country column on the sales order grid in Magento 2”. I assume you already have a module to add an extra column on the grid.

Let’s check the simple 4 steps:

Step 1: First, create the sales_order_grid.xml in the following location

app/code/[Namespace]/[Module]/view/adminhtml/ui_component/

<?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">
    <listingToolbar name="listing_top"/>
    <columns name="sales_order_columns">
        <column name="country_name" class="[Namespace]\[Module]\Ui\Component\Listing\Column\Country">
            <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">Shipping Country</item>
               	    <item name="sortOrder" xsi:type="number">50</item>
               	    <item name="align" xsi:type="string">left</item>
               	    <item name="dataType" xsi:type="string">text</item>
               	    <item name="visible" xsi:type="boolean">true</item>
               	    <item name="bodyTmpl" xsi:type="string">ui/grid/cells/html</item>
                </item>
            </argument>
        </column>
    </columns>
</listing>

As you can see in the above code, we have used the class “[Namespace][Module]\Ui\Component\Listing\Column\Country” in the column field so we need to create the Country file in the next step.

Quick Tip: Learn about getting system configuration value

Step 2: Now, Create the Country.php in the following location

app/code/[Namespace]/[Module]/Ui/Component/Listing/Column

<?php
namespace [Namespace]\[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;
use \Magento\Directory\Model\CountryFactory;

class Country extends Column
{
    protected $_orderRepository;
    protected $_searchCriteria;
    protected $_countryFactory;

    public function __construct(ContextInterface $context, UiComponentFactory $uiComponentFactory, OrderRepositoryInterface $orderRepository, SearchCriteriaBuilder $criteria, CountryFactory $countryFactory, array $components = [], array $data = [])
    {
        $this->_orderRepository = $orderRepository;
        $this->_searchCriteria  = $criteria;
        $this->_countryFactory = $countryFactory;
        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"]);
                $getShippingCountryId = $order->getShippingAddress()->getCountryId();
                $country = $this->_countryFactory->create()->loadByCode($getShippingCountryId);
                $item[$this->getData('name')] = $country->getName();
            }
        }
        return $dataSource;
    }
}

In the above code, you can see we have got the order collection and fetch the shipping country id and to get the name of the country from country id we use the country collection and set that name in the $item array.

Now, we need to use join the collection and that can be done via a plugin.

Step 3: Now, Create the di.xml in the following location

app/code/[Namespace]/[Module]/etc/

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
	<type name="Magento\Framework\View\Element\UiComponent\DataProvider\CollectionFactory">
		<plugin
			name="sales_order_additional_columns"
			type="[Namespace]\[Module]\Plugin\AdditionalFields\CollectionFactory"
			sortOrder="1"
			disabled="false"
		/>
	</type>
</config>

As per the above code now time to create the CollectionFactory class in the plugin folder.

Step 4: Create the CollectionFactory.php file in the following location

app/code/[Namespace]/[Module]/Plugin/AdditionalFields/

<?php
namespace [Namespace]\[Module]\Plugin\AdditionalFields;
class CollectionFactory
{
    private $collection;
    public function aroundGetReport(
        \Magento\Framework\View\Element\UiComponent\DataProvider\CollectionFactory $subject,
        \Closure $proceed,
        $requestName
    ){
        $result = $proceed($requestName);
        if ($requestName == 'sales_order_grid_data_source') { // To check is that sales order grid
            if ($result instanceof \Magento\Sales\Model\ResourceModel\Order\Grid\Collection) { // Check that is the object of order grid
                $select = $result->getSelect();
                // Here, join the new field country_id which contain the country code
                $select->join(
                    ["soa" => "sales_order_address"],
                    'main_table.entity_id = soa.parent_id AND soa.address_type="shipping"',
                    array('country_id')
                )->distinct();
                // I have imported country table which contain county code & Name 
                // I join the new field country_name in the grid 
                // this country_name field name you can see on the sales_order_grid both are need to same to workable your filter perfectly
                $select->join(
                    array('cn' => "country"),
                    'soa.country_id = cn.code',
                    array('country_name')
                );
            }
        }
        return $result;
    }
}

We have used the around plugin method to join the collection and it’s a very important function because using this function your all filters will work.

As you can see in the above code we have used the if condition to check is that sales order grid or not because we don’t want that function will affect any other grid.

After that, we used the join method which gets the country_id to get the country name.

Also, the name column “country_name” should be the same as we have defined in the ui_component file so your filters will work perfectly as expected.

 <column name="country_name" ... 
  .......
 />

Please check all steps carefully and let me know if you have any doughts.

Thanks for reading this post!

About the author

I’m Magento Certified Developer having quite 5 years of commercial development expertise in Magento as well as in Shopify. I’ve worked primarily with the Magento and Shopify e-commerce platform, managing the complexities concerned in building e-commerce solutions tailored to a client’s specific desires.

Related Posts

Leave a Reply