Question

I'm trying to add some extra columns into Magento's customer grid. I've got an order count working successfully (Total amount of orders a customer has placed)

I'm trying to get the Last Order date in, but I'm unable to get it working. Has anyone done this before or can someone point me in the right direction as to how to do this?

This is my current code, but it errors and just displays a SQL query.

    $orderTableName = Mage::getSingleton('core/resource')
        ->getTableName('sales/order');
    $collection->getSelect()
        ->joinLeft(
            array('orders' => $orderTableName),
            'orders.customer_id=e.entity_id',
            array(
                'order_count' => 'COUNT(customer_id)',
                'last_order' => 'MAX(created_at)'
            )
        );
    $collection->groupByAttribute('entity_id');
Was it helpful?

Solution

Here is working example for CE 1.8.1:

protected function _prepareCollection()
{
    $collection = Mage::getResourceModel('customer/customer_collection')
        ->addNameToSelect()
        ->addAttributeToSelect('email')
        ->addAttributeToSelect('created_at')
        ->addAttributeToSelect('group_id')
        ->joinAttribute('billing_postcode', 'customer_address/postcode', 'default_billing', null, 'left')
        ->joinAttribute('billing_city', 'customer_address/city', 'default_billing', null, 'left')
        ->joinAttribute('billing_telephone', 'customer_address/telephone', 'default_billing', null, 'left')
        ->joinAttribute('billing_region', 'customer_address/region', 'default_billing', null, 'left')
        ->joinAttribute('billing_country_id', 'customer_address/country_id', 'default_billing', null, 'left');



    // add 2 new fields as sub queries      
    $sql ='SELECT MAX(o.created_at)'
        . ' FROM ' . Mage::getSingleton('core/resource')->getTableName('sales/order') . ' AS o'
        . ' WHERE o.customer_id = e.entity_id ';
    $expr = new Zend_Db_Expr('(' . $sql . ')'); 

    $collection->getSelect()->from(null, array('last_order_date'=>$expr));

    $sql ='SELECT COUNT(*)'
        . ' FROM ' . Mage::getSingleton('core/resource')->getTableName('sales/order') . ' AS o'
        . ' WHERE o.customer_id = e.entity_id ';
    $expr = new Zend_Db_Expr('(' . $sql . ')'); 

    $collection->getSelect()->from(null, array('orders_count'=>$expr));

    //echo $collection->getSelect(); exit;      

    $this->setCollection($collection);

    return parent::_prepareCollection();
}

and

protected function _prepareColumns()
{
    $this->addColumn('entity_id', array(
        'header'    => Mage::helper('customer')->__('ID'),
        'width'     => '50px',
        'index'     => 'entity_id',
        'type'  => 'number',
    ));

    $this->addColumn('last_order_date', array(
        'header'    => Mage::helper('customer')->__('Last Order Date'),
        'type'      => 'datetime',
        'align'     => 'center',
        'index'     => 'last_order_date',
        'gmtoffset' => true,        
    ));

    $this->addColumn('orders_count', array(
        'header'    => Mage::helper('customer')->__('Orders Count'),
        'index'     => 'orders_count',
    ));

    ........
    ........

The output is

orders

OTHER TIPS

Here is how I would do this.
I would create 2 attributes called last_order_date and orders_count on the customer entity that are only visible in the backend. Or not visible at all. Here is one possible way to add them.

The I would create an observer on the checkout_submit_all_after event that would change the values of these attributes.
Something like this:

public function checkoutSubmitAllAfter($observer) {
    $order = $observer->getEvent()->getOrder();
    if ($order) { //if on onepage checkout;
        $customer = $order->getCustomer();
        $lastOrderDate = $order->getCreatedAt();
        $increment = 1;
    }
    else { //if on multishipping checkout
       $orders = $observer->getEvent()->getOrders();
       //get last order that's the important one;
       $order = $orders[count($orders) - 1];
       $customer = $order->getCustomer();
       $lastOrderDate = $order->getCreatedAt();
       $increment = count($orders);
    }
    if ($customer && $customer->getId()) { //check if the customer is logged in
       //make sure you have a clean instance of the customer
       //this line may not be needed. Test with it and without it.
       $customer = Mage::getModel('customer/customer')->load($customer->getId());
       //set the new values on the customer entity
       $customer->setLastOrderDate($lastOrderDate);
       $customer->setOrdersCount((int)$customer->getOrdersCount() + $increment);
       $customer->save();
    }
}

I haven't tested the code, so I may have missed something.

Now you have the values you need on the customer object and you don't need any crazy join or sort order and specially no group by.
You can add your 2 new columns in the customer grid and you can even make them sortable and filterable easily.

If you already have customers in your db, then you will need a one time only script that sets the values for the existing customers.
But you can identify these values easily.

If you need only "complete" status like me, then just add . ' AND o.status LIKE "complete" ' after . ' WHERE o.customer_id = e.entity_id ';

I've also added the total Money spent by the customer (so the total of all of it's complete orders)

    $total_pricesql ='SELECT sum(o.base_grand_total)'
        . ' FROM ' . Mage::getSingleton('core/resource')->getTableName('sales/order') . ' AS o'
        . ' WHERE o.customer_id = e.entity_id ' . ' AND o.status LIKE  "complete" ';
    $expr = new Zend_Db_Expr('(' . $total_pricesql . ')'); 

    $collection->getSelect()->from(null, array('total_price'=>$expr));

and later in the same file

    $this->addColumn('total_price', array(
        'header' => Mage::helper('sales')->__('Total'),
        'index' => 'total_price',
        'type'  => 'number',
        'filter'    => false,
    ));

so change @Amasty's first codes:

protected function _prepareCollection() {
$collection = Mage::getResourceModel('customer/customer_collection')
    ->addNameToSelect()
    ->addAttributeToSelect('email')
    ->addAttributeToSelect('created_at')
    ->addAttributeToSelect('group_id')
    ->joinAttribute('billing_postcode', 'customer_address/postcode', 'default_billing', null, 'left')
    ->joinAttribute('billing_city', 'customer_address/city', 'default_billing', null, 'left')
    ->joinAttribute('billing_telephone', 'customer_address/telephone', 'default_billing', null, 'left')
    ->joinAttribute('billing_region', 'customer_address/region', 'default_billing', null, 'left')
    ->joinAttribute('billing_country_id', 'customer_address/country_id', 'default_billing', null, 'left');



// add 3 new fields as sub queries      
$sql ='SELECT MAX(o.created_at)'
    . ' FROM ' . Mage::getSingleton('core/resource')->getTableName('sales/order') . ' AS o'
    . ' WHERE o.customer_id = e.entity_id ' . ' AND o.status LIKE  "complete" ';
$expr = new Zend_Db_Expr('(' . $sql . ')'); 

$collection->getSelect()->from(null, array('last_order_date'=>$expr));

$sql ='SELECT COUNT(*)'
    . ' FROM ' . Mage::getSingleton('core/resource')->getTableName('sales/order') . ' AS o'
    . ' WHERE o.customer_id = e.entity_id ' . ' AND o.status LIKE  "complete" ';
$expr = new Zend_Db_Expr('(' . $sql . ')'); 

$collection->getSelect()->from(null, array('orders_count'=>$expr));

$total_pricesql ='SELECT sum(o.base_grand_total)'
    . ' FROM ' . Mage::getSingleton('core/resource')->getTableName('sales/order') . ' AS o'
    . ' WHERE o.customer_id = e.entity_id ' . ' AND o.status LIKE  "complete" ';
$expr = new Zend_Db_Expr('(' . $total_pricesql . ')'); 

$collection->getSelect()->from(null, array('total_price'=>$expr));

//echo $collection->getSelect(); exit;      

$this->setCollection($collection); return parent::_prepareCollection();}

and the second code:

protected function _prepareColumns() {
$this->addColumn('entity_id', array(
    'header'    => Mage::helper('customer')->__('ID'),
    'width'     => '50px',
    'index'     => 'entity_id',
    'type'  => 'number',
));

$this->addColumn('last_order_date', array(
    'header'    => Mage::helper('customer')->__('Last Order Date'),
    'type'      => 'datetime',
    'align'     => 'center',
    'index'     => 'last_order_date',
    'gmtoffset' => true,        
));

$this->addColumn('orders_count', array(
    'header'    => Mage::helper('customer')->__('Orders Count'),
    'index'     => 'orders_count',
));

$this->addColumn('total_price', array(
    'header' => Mage::helper('sales')->__('Total'),
    'index' => 'total_price',
    'type'  => 'number',
    'filter'    => false,
));

........
........

Here is how I solved the problem with filter and ordering working, _prepareCollection:

$collection = Mage::getResourceModel('customer/customer_collection')
    ->addNameToSelect()
    ->joinAttribute('billing_street', 'customer_address/street', 'default_billing', null, 'left')
    ->joinAttribute('billing_city', 'customer_address/city', 'default_billing', null, 'left')
    ->joinAttribute('billing_region', 'customer_address/region', 'default_billing', null, 'left')
    ->joinAttribute('billing_postcode', 'customer_address/postcode', 'default_billing', null, 'left')
;

$sql = sprintf('SELECT MAX(o.created_at) AS created_at FROM %s AS o GROUP BY o.customer_id', Mage::getSingleton('core/resource')->getTableName('sales/order_grid'));
$expr = new Zend_Db_Expr('(' . $sql . ')');

$collection->joinTable(array('order' => 'sales/order_grid'), 'customer_id=entity_id', array('order_created_at' => 'created_at'), "order.created_at IN ($expr)", 'left');

Then on _prepareColumns:

$this->addColumn('order_created_at', array(
    'header'    => Mage::helper('sales')->__('Purchased On'),
    'type'      => 'datetime',
    'index'     => 'order_created_at',
    'gmtoffset' => true,
));
Licensed under: CC-BY-SA with attribution
Not affiliated with magento.stackexchange
scroll top