How to add Custom Column in sales/order grid in Magento?

Jay Desai picture Jay Desai · Sep 12, 2014 · Viewed 15.1k times · Source

I am trying to add custom columns to my sales/order grid. My columns will be the tracking number and the tile. The title is basically the courier code which shows you through which courier you have send you product. So i have done some following things for this.

  1. I have copied the file from magento/app/code/core/Mage/Adminhtml/Block/Sales/Order/Grid.php to

magento/app/code/local/Mage/Adminhtml/Block/Sales/Order/Grid.php

so that i can add columns and customize my sales/order grid.

  1. In the file Grid.php, There is _prepareCollections() functions.

Here the code goes into it.

protected function _prepareCollection()
    {
        $collection = Mage::getResourceModel($this->_getCollectionClass());
        $this->setCollection($collection);
        $collection->getSelect();
        $collection->getSelect()->join('sales_flat_shipment_track', 'main_table.entity_id =sales_flat_shipment_track.order_id',array('track_number'=> new Zend_Db_Expr('group_concat(sales_flat_shipment_track.track_number SEPARATOR ",")'),'title' => new Zend_Db_Expr('group_concat(sales_flat_shipment_track.title SEPARATOR ",")')));
        return parent::_prepareCollection();    
    }

And Now i will add my columns here in my _prepareColumns() function. Code for that is

protected function _prepareColumns()
    {
        $this->addColumn('track_number', array(
            'header'=> Mage::helper('sales')->__(' Track Number'),
            'width' => '80px',
            'type'  => 'text',
            'index' => 'track_number',
            ));
        $this->addColumn('title', array(

            'header'=> Mage::helper('sales')->__('Title'),
            'width' => '80px',
            'index' => 'title',
            ));

The file Grid.php is here.

<?php
/**
 * Magento
 *
 * NOTICE OF LICENSE
 *
 * This source file is subject to the Open Software License (OSL 3.0)
 * that is bundled with this package in the file LICENSE.txt.
 * It is also available through the world-wide-web at this URL:
 * http://opensource.org/licenses/osl-3.0.php
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 * to [email protected] so we can send you a copy immediately.
 *
 * DISCLAIMER
 *
 * Do not edit or add to this file if you wish to upgrade Magento to newer
 * versions in the future. If you wish to customize Magento for your
 * needs please refer to http://www.magentocommerce.com for more information.
 *
 * @category    Mage
 * @package     Mage_Adminhtml
 * @copyright   Copyright (c) 2014 Magento Inc. (http://www.magentocommerce.com)
 * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
 */

/**
 * Adminhtml sales orders grid
 *
 * @category   Mage
 * @package    Mage_Adminhtml
 * @author      Magento Core Team <[email protected]>
 */
class Mage_Adminhtml_Block_Sales_Order_Grid extends Mage_Adminhtml_Block_Widget_Grid
{

    public function __construct()
    {
        parent::__construct();
        $this->setId('sales_order_grid');
        $this->setUseAjax(true);
        $this->setDefaultSort('created_at');
        $this->setDefaultDir('DESC');
        $this->setSaveParametersInSession(true);
    }

    /**
     * Retrieve collection class
     *
     * @return string
     */
    protected function _getCollectionClass()
    {
        return 'sales/order_grid_collection';
    }

    protected function _prepareCollection()
    {
        $collection = Mage::getResourceModel($this->_getCollectionClass());
        $this->setCollection($collection);
        $collection->getSelect();
        $collection->getSelect()->join('sales_flat_shipment_track', 'main_table.entity_id =sales_flat_shipment_track.order_id',array('track_number'=> new Zend_Db_Expr('group_concat(sales_flat_shipment_track.track_number SEPARATOR ",")'),'title' => new Zend_Db_Expr('group_concat(sales_flat_shipment_track.title SEPARATOR ",")')));
        return parent::_prepareCollection();    
    }

    protected function _prepareColumns()
    {
        $this->addColumn('track_number', array(
            'header'=> Mage::helper('sales')->__(' Track Number'),
            'width' => '80px',
            'type'  => 'text',
            'index' => 'track_number',
            ));
        $this->addColumn('title', array(

            'header'=> Mage::helper('sales')->__('Title'),
            'width' => '80px',
            'index' => 'title',
            ));

        $this->addColumn('real_order_id', array(
            'header'=> Mage::helper('sales')->__('Order #'),
            'width' => '80px',
            'type'  => 'text',
            'index' => 'increment_id',
        ));

        if (!Mage::app()->isSingleStoreMode()) {
            $this->addColumn('store_id', array(
                'header'    => Mage::helper('sales')->__('Purchased From (Store)'),
                'index'     => 'store_id',
                'type'      => 'store',
                'store_view'=> true,
                'display_deleted' => true,
            ));
        }

        $this->addColumn('created_at', array(
            'header' => Mage::helper('sales')->__('Purchased On'),
            'index' => 'created_at',
            'type' => 'datetime',
            'width' => '100px',
        ));

        $this->addColumn('billing_name', array(
            'header' => Mage::helper('sales')->__('Bill to Name'),
            'index' => 'billing_name',
        ));

        $this->addColumn('shipping_name', array(
            'header' => Mage::helper('sales')->__('Ship to Name'),
            'index' => 'shipping_name',
        ));

        $this->addColumn('base_grand_total', array(
            'header' => Mage::helper('sales')->__('G.T. (Base)'),
            'index' => 'base_grand_total',
            'type'  => 'currency',
            'currency' => 'base_currency_code',
        ));

        $this->addColumn('grand_total', array(
            'header' => Mage::helper('sales')->__('G.T. (Purchased)'),
            'index' => 'grand_total',
            'type'  => 'currency',
            'currency' => 'order_currency_code',
        ));

        $this->addColumn('status', array(
            'header' => Mage::helper('sales')->__('Status'),
            'index' => 'status',
            'type'  => 'options',
            'width' => '70px',
            'options' => Mage::getSingleton('sales/order_config')->getStatuses(),
        ));

        if (Mage::getSingleton('admin/session')->isAllowed('sales/order/actions/view')) {
            $this->addColumn('action',
                array(
                    'header'    => Mage::helper('sales')->__('Action'),
                    'width'     => '50px',
                    'type'      => 'action',
                    'getter'     => 'getId',
                    'actions'   => array(
                        array(
                            'caption' => Mage::helper('sales')->__('View'),
                            'url'     => array('base'=>'*/sales_order/view'),
                            'field'   => 'order_id',
                            'data-column' => 'action',
                        )
                    ),
                    'filter'    => false,
                    'sortable'  => false,
                    'index'     => 'stores',
                    'is_system' => true,
            ));
        }
        $this->addRssList('rss/order/new', Mage::helper('sales')->__('New Order RSS'));

        $this->addExportType('*/*/exportCsv', Mage::helper('sales')->__('CSV'));
        $this->addExportType('*/*/exportExcel', Mage::helper('sales')->__('Excel XML'));

        return parent::_prepareColumns();
    }

    protected function _prepareMassaction()
    {
        $this->setMassactionIdField('entity_id');
        $this->getMassactionBlock()->setFormFieldName('order_ids');
        $this->getMassactionBlock()->setUseSelectAll(false);

        if (Mage::getSingleton('admin/session')->isAllowed('sales/order/actions/cancel')) {
            $this->getMassactionBlock()->addItem('cancel_order', array(
                 'label'=> Mage::helper('sales')->__('Cancel'),
                 'url'  => $this->getUrl('*/sales_order/massCancel'),
            ));
        }

        if (Mage::getSingleton('admin/session')->isAllowed('sales/order/actions/hold')) {
            $this->getMassactionBlock()->addItem('hold_order', array(
                 'label'=> Mage::helper('sales')->__('Hold'),
                 'url'  => $this->getUrl('*/sales_order/massHold'),
            ));
        }

        if (Mage::getSingleton('admin/session')->isAllowed('sales/order/actions/unhold')) {
            $this->getMassactionBlock()->addItem('unhold_order', array(
                 'label'=> Mage::helper('sales')->__('Unhold'),
                 'url'  => $this->getUrl('*/sales_order/massUnhold'),
            ));
        }

        $this->getMassactionBlock()->addItem('pdfinvoices_order', array(
             'label'=> Mage::helper('sales')->__('Print Invoices'),
             'url'  => $this->getUrl('*/sales_order/pdfinvoices'),
        ));

        $this->getMassactionBlock()->addItem('pdfshipments_order', array(
             'label'=> Mage::helper('sales')->__('Print Packingslips'),
             'url'  => $this->getUrl('*/sales_order/pdfshipments'),
        ));

        $this->getMassactionBlock()->addItem('pdfcreditmemos_order', array(
             'label'=> Mage::helper('sales')->__('Print Credit Memos'),
             'url'  => $this->getUrl('*/sales_order/pdfcreditmemos'),
        ));

        $this->getMassactionBlock()->addItem('pdfdocs_order', array(
             'label'=> Mage::helper('sales')->__('Print All'),
             'url'  => $this->getUrl('*/sales_order/pdfdocs'),
        ));

        $this->getMassactionBlock()->addItem('print_shipping_label', array(
             'label'=> Mage::helper('sales')->__('Print Shipping Labels'),
             'url'  => $this->getUrl('*/sales_order_shipment/massPrintShippingLabel'),
        ));

        return $this;
    }

    public function getRowUrl($row)
    {
        if (Mage::getSingleton('admin/session')->isAllowed('sales/order/actions/view')) {
            return $this->getUrl('*/sales_order/view', array('order_id' => $row->getId()));
        }
        return false;
    }

    public function getGridUrl()
    {
        return $this->getUrl('*/*/grid', array('_current'=>true));
    }

}

Now I am getting the columns Tracking Number and Title on my Grid. But in my tracking number ,its showing me the duplicate entries. For example, If my tracking number is 12345678, It shows me two values which are same, Like this. 12345678,12345678.

Also in my title, It shows Federal Express,Federal express for two times.

What i want is two things,

a. First There can be 2 tracking nos, or more than that. But it should be shown like this. ex. 12345678,12345678900. It should be distinct.

For some of my order no it shows distinct. But most of them have duplicate entries.

b. Secondly if the courier is send by federal express and then if the product returns and we send by bluedart then it should show federal express, bluedart . But what i am getting is federal express,federal express, blue dart,blue dart.

It is showing me 4 times.

I don't know what exactly problem i am facing. Is der any database problem or the query i have written.

Please let me know whether

protected function _prepareCollection()
        {
            $collection = Mage::getResourceModel($this->_getCollectionClass());
            $this->setCollection($collection);
            $collection->getSelect();
            $collection->getSelect()->join('sales_flat_shipment_track', 'main_table.entity_id =sales_flat_shipment_track.order_id',array('track_number'=> new Zend_Db_Expr('group_concat(sales_flat_shipment_track.track_number SEPARATOR ",")'),'title' => new Zend_Db_Expr('group_concat(sales_flat_shipment_track.title SEPARATOR ",")')));
            return parent::_prepareCollection();    
        }

This function is correct and also the query written in it.

Edited PArt

I also want to filter the track_number and title in my grid.php. I have tried some of the things.

This code goes in grid.php,

protected function spaceSeparatedFilter($collection, $column)
{
    $value = $column->getFilter()->getValue();
    if (!$value) {

        return $this;
    }
    //if there was a space input
        else if(preg_match('/s+/', $value))
    {
        //explode by space, getting array of IDs
        $val = explode(" ", $value);
        //filter the collection, where collection index (order_id) is present in $val array
        $this->getCollection()->addAttributeToFilter($column->getData('index'), array('in'=>$val));
    }
    else
    {
    //else use default grid filter functionality (like $value input)
    $this->getCollection()->addAttributeToFilter($column->getData('index'), array('like' => '%'.$value.'%'));
    }
    return $this;
}

Now i have added filter condition to my addcolumn,

$this->addColumn('track_number', array(
            'header'=> Mage::helper('sales')->__(' Track Number'),
            'width' => '80px',
            'type'  => 'text',
            'index' => 'track_number',
            'filter_condition_callback' => array($this, 'spaceSeparatedFilter'),
            ));

        $this->addColumn('title', array(
            'header'=> Mage::helper('sales')->__('Title'),
            'width' => '80px',
            'index' => 'title',
            'filter_condition_callback' => array($this, 'spaceSeparatedFilter'),
            ));

But i am not able to filter in my sales/order grid. Please let me know the solution for this.

Thanks and Regards.

Answer

Rick Buczynski picture Rick Buczynski · Sep 12, 2014

If in your _prepareCollection method I print the query via:

echo $collection->getSelect()->assemble();

I get this:

SELECT 
    `main_table`.*, 
    group_concat(sales_flat_shipment_track.track_number SEPARATOR ",") AS `track_number`, 
    group_concat(sales_flat_shipment_track.title SEPARATOR ",") AS `title` 

FROM `sales_flat_order_grid` AS `main_table` 

INNER JOIN `sales_flat_shipment_track` 
    ON main_table.entity_id = sales_flat_shipment_track.order_id

By this query I will always get a result, even an "empty" row when there are no orders on the table. Rather, I think what you are trying to achieve can be done using subqueries:

SELECT 
    `main_table`.*, 
    (
        SELECT 
            group_concat(`t`.`track_number` SEPARATOR ",") AS `track_number`

        FROM `sales_flat_shipment_track` AS `t`

        WHERE `main_table`.`entity_id` = `t`.`order_id`
    ),
    (
        SELECT 
            group_concat(`t`.`title` SEPARATOR ",") AS `title`

        FROM `sales_flat_shipment_track` as `t`

        WHERE `main_table`.`entity_id` = `t`.`order_id`
    )

FROM `sales_flat_order_grid` AS `main_table`;

So to translate that for Magento, it would look something like this:

protected function _prepareCollection()
{
    $collection = Mage::getResourceModel('sales/order_grid_collection');

    $collection->getSelect()
        ->from(
            array(),
            array(
                'track_number' => new Zend_Db_Expr('(
                    SELECT GROUP_CONCAT(`t`.`track_number` SEPARATOR ",")
                    FROM `sales_flat_shipment_track` as `t`
                    WHERE `main_table`.`entity_id` = `t`.`order_id`
                )'),
                'title' => new Zend_Db_Expr('(
                    SELECT GROUP_CONCAT(`t`.`title` SEPARATOR ",")
                    FROM `sales_flat_shipment_track` as `t`
                    WHERE `main_table`.`entity_id` = `t`.`order_id`
                )'),
            )
        );

    $this->setCollection($this);

    return parent::_prepareCollection();
}

To your point about the duplicate carrier titles, that is to be expected in a case like this. The only way around it is to add a DISTINCT word in the sub-query for the title, like this:

SELECT GROUP_CONCAT(DISTINCT `t`.`title` SEPARATOR ",")

But I'm not sure what you plan to do with this data in the grid. Hope that helps.