Question

I want to a column in sales_order_grid I successfully did that but I also want to get my custom attribute from sales_order collection because I want to set value on some action, my problem is a can't get that attribute...

Thanks.

Was it helpful?

Solution

I found a way to do that:

Step 1

First of all it's better to make you own custom module make app/code/[Vendor]/[Module]/registration.php also app/code/[Vendor]/[Module]/etc/module.xml.

Step 2

Add your custom column in DB mine is custom_print_status, also I made an UPDATE script to set default value in my custom attribute in all existing orders, so create app/code/[Vendor]/[Module]/Setup/InstallData.php

<?php
namespace [Vendor]\[Module]\Setup;

use Magento\Framework\Setup\InstallDataInterface;
use Magento\Framework\Setup\ModuleContextInterface;
use Magento\Framework\Setup\ModuleDataSetupInterface;
use Magento\Sales\Model\Order;

class InstallData implements InstallDataInterface
{
    /**
     * @var \Magento\Sales\Setup\SalesSetupFactory
     */
    protected $salesSetupFactory;
    protected $_resourceConnection;
    /**
     * @param \Magento\Sales\Setup\SalesSetupFactory $salesSetupFactory
     */
    public function __construct(
        \Magento\Sales\Setup\SalesSetupFactory $salesSetupFactory,
        \Magento\Framework\App\ResourceConnection  $resourceConnection

    ) {
        $this->salesSetupFactory = $salesSetupFactory;
        $this->_resourceConnection = $resourceConnection;
    }

    /**
     * {@inheritDoc}
     */
    public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context) 
    {
        $installer = $setup;

        $installer->startSetup();

        $salesSetup = $this->salesSetupFactory->create(['resourceName' => 'sales_setup', 'setup' => $installer]);

        $salesSetup->addAttribute(Order::ENTITY, 'custom_print_status', [
            'type' => \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER,
            'length'=> 11,
            'visible' => false,
            'nullable' => false
        ]);

        /* UPDATE CUSTOM PRINT STATUS TO 'No' By PartbSaif */
        $updateData = array('custom_print_status' => 0);
        $connection = $this->_resourceConnection->getConnection();
        $connection->update(
            $connection->getTableName('sales_order'),
            $updateData
        );
        /* ========================================= */

        $installer->endSetup();
    }
}

Step 3

Add your custom column in sales_order_grid, create app/code/[Vendor]/[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="custom_print_status" class="[Vendor]\[Module]\Ui\Component\Listing\Column\CustomPrintStatus" component="Magento_Ui/js/grid/columns/select">
            <settings>
                <filter>select</filter>
                <options class="[Vendor]\[Module]\Ui\Component\Listing\Column\CustomPrintStatus\Options"/>
                <dataType>select</dataType>
                <label translate="true">Print Status</label>
            </settings>
        </column>
    </columns>
</listing>

Step 4

For render your custom column from sales_order table. e.g 0/1 in sales_order_grid, create app/code/[Vendor]/[Module]/Ui/Component/Listing/Column/CustomPrintStatus.php

<?php 

namespace [Vendor]\[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\Framework\App\ResourceConnection;

class CustomPrintStatus extends Column
{
    protected $_orderRepository;
    protected $_searchCriteria;
    protected $_resourceConnection;

    public function __construct(
        ContextInterface $context, 
        UiComponentFactory $uiComponentFactory, 
        OrderRepositoryInterface $orderRepository, 
        SearchCriteriaBuilder $criteria,
        ResourceConnection  $resourceConnection,
        array $components = [], 
        array $data = [])
    {
        $this->_orderRepository = $orderRepository;
        $this->_searchCriteria  = $criteria;
        $this->_resourceConnection = $resourceConnection;
        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']);
                $customPrintStatus = $order->getCustomPrintStatus();
                $item['custom_print_status'] = $customPrintStatus;
            }
        }

        return $dataSource;
    }
}

Step 5

In DB value will store as 0 and 1 e.g 0 => 'No' & 1 => 'Yes', so to show value as Yes/No, create file. app/code/[Vendor]/[Module]/Ui/Component/Listing/Column/CustomPrintStatus/Options.php

<?php

namespace [Vendor]\[Module]\Ui\Component\Listing\Column\CustomPrintStatus;

class Options implements \Magento\Framework\Option\ArrayInterface
{
    /**
     * @return array
     */
    public function toOptionArray()
    {
        $options = [
            [
                'value' => 1,
                'label' => __('Yes')
            ],
            [
                'value' => 0,
                'label' => __('No')
            ]
        ];

        return $options;
    }
}

Step 6

BTW when you try to filter value in sales_order_grid, you'll get an error, to do that you have to map your value in Order Grid Collection, to do that you have to override Collection file of Order Grid, create file app/code/[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">
     <type name="Magento\Framework\View\Element\UiComponent\DataProvider\CollectionFactory">
         <arguments>
             <argument name="collections" xsi:type="array">
                <item name="sales_order_grid_data_source" xsi:type="string">[Vendor]\[Module]\Model\ResourceModel\Order\Grid\Collection</item>
             </argument>
         </arguments>
     </type>
</config>

app/code/[Vendor]/[Module]/Model/ResourceModel/Order/Grid/Collection.php

<?php

namespace [Vendor]\[Module]\Model\ResourceModel\Order\Grid;

use Magento\Sales\Model\ResourceModel\Order\Grid\Collection as OriginalCollection;

/**
 * Order grid extended collection
 */
class Collection extends OriginalCollection
{
    protected function _initSelect()
    {
        $this->addFilterToMap('created_at', 'main_table.created_at');
        $this->addFilterToMap('increment_id', 'main_table.increment_id');
        $this->addFilterToMap('base_grand_total', 'main_table.base_grand_total');
        $this->addFilterToMap('grand_total', 'main_table.grand_total');
        $this->addFilterToMap('store_id', 'main_table.store_id');
        $this->addFilterToMap('billing_name', 'main_table.billing_name');
        $this->addFilterToMap('shipping_name', 'main_table.shipping_name');
        $this->addFilterToMap('status', 'main_table.status');
        parent::_initSelect();
    }
     protected function _renderFiltersBefore()
     {
         $joinTable = $this->getTable('sales_order');
         $this->getSelect()->joinLeft($joinTable, 'main_table.entity_id = sales_order.entity_id', ['custom_print_status']);
         parent::_renderFiltersBefore();
     }
}

Step 7

Now to set value as No when new order created you have to make event called sales_order_save_before, so create app/code/[Vendor]/[Module]/etc/event.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
    <event name="sales_order_place_after">
        <observer name="set_order_attribute" instance="[Vendor]\[Module]\Observer\SetOrderAttribute"/>
    </event>
</config>

app/code/[Vendor]/[Module]/Observer/SetOrderAttribute.php

<?php
namespace [Vendor]\[Module]\Observer;

class SetOrderAttribute implements \Magento\Framework\Event\ObserverInterface
{
    /**
     * @param \Magento\Framework\Event\Observer $observer
     * @return $this
     */
    public function execute(\Magento\Framework\Event\Observer $observer)
    {
        /** @var \Magento\Sales\Model\Order $order */
        $order = $observer->getEvent()->getOrder();
        $order->setCustomPrintStatus(0);
        return $this;
    }
}

Step 8

For set value on in DB for your custom column, add below code in Model, this code set 1 value on action.

            /* CHANGE PRINT STATUS TO 'Yes' By PartbSaif */
            $yes = 1;
            $order->setCustomPrintStatus($yes)->save();
            /* ========================================= */

Explanation What this module does ?

I want to create column in sales_order_grid column name is custom_print_status, when user select order and click on Print Invoices Or Print All under Action drop-down, the custom_print_status changed to Yes, otherwise it's value is by default set to No, for set value to Yes on above 2 action you need to override /[root]/vendor/magento/module-sales/Model/Order/Pdf/Invoice.php, I hope you know how to override Model file from vendor, if not refer to this link => How to override Model file

In this file you'll find getPdf() function, put above code at the end of foreach loop like this:

        foreach ($invoices as $invoice) {
             /* Code to set value */
        }

Thank You.

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