Agregar columna a una cuadrícula (observador): columna 'store_id' en donde la cláusula es un problema ambiguo

16

Estoy agregando una columna a la cuadrícula de pedidos usando el enfoque de observador:

  1. En el evento -> sales_order_grid_collection_load_before Estoy agregando una unión a la colección
  2. En el evento -> core_block_abstract_prepare_layout_beforeEstoy agregando una columna a la cuadrícula

EDITAR más información:

En el evento (1):

   public function salesOrderGridCollectionLoadBefore($observer)
{
    $collection = $observer->getOrderGridCollection();
    $collection->addFilterToMap('store_id', 'main_table.store_id');
    $select = $collection->getSelect();
    $select->joinLeft(array('oe' => $collection->getTable('sales/order')), 'oe.entity_id=main_table.entity_id', array('oe.customer_group_id'));

}

En evento (2):

public function appendCustomColumn(Varien_Event_Observer $observer)
{
    $block = $observer->getBlock();
    if (!isset($block)) {
        return $this;
    }

    if ($block->getType() == 'adminhtml/sales_order_grid') {
        /* @var $block Mage_Adminhtml_Block_Customer_Grid */
        $this->_addColumnToGrid($block);
    }
}

protected function _addColumnToGrid($grid)
{

    $groups = Mage::getResourceModel('customer/group_collection')
        ->addFieldToFilter('customer_group_id', array('gt' => 0))
        ->load()
        ->toOptionHash();
    $groups[0] = 'Guest';


    /* @var $block Mage_Adminhtml_Block_Customer_Grid */
    $grid->addColumnAfter('customer_group_id', array(
        'header' => Mage::helper('customer')->__('Customer Group'),
        'index' => 'customer_group_id',
        'filter_index' => 'oe.customer_group_id',
        'type' => 'options',
        'options' => $groups,
    ), 'shipping_name');
}

Todo funciona bien hasta que filtre la cuadrícula con el filtro de vista de tienda: Columna 'store_id' en donde la cláusula es un problema ambiguo

He impreso la consulta:

SELECT `main_table`.*, `oe`.`customer_group_id` 
FROM `sales_flat_order_grid` AS `main_table`
LEFT JOIN `sales_flat_order` AS `oe` ON oe.entity_id=main_table.entity_id 
WHERE (store_id = '5') AND (oe.customer_group_id = '6')

Como tu veas store_idseñoritamain_table alias.

Para lograr esto, solo necesito configurar la filter_indexcolumna de identificación de la tienda, pero a través del observador. Entonces, la pregunta es ¿cómo puedo hacerlo sobre la marcha ?
Sin anular la clase de bloque ? (de lo contrario, el enfoque del observador es inútil)

Fra
fuente

Respuestas:

32

Intentemos esto nuevamente con otra solución que les mencioné antes :-), he creado la extensión completa para mostrarle cómo agregar el campo a la tabla de cuadrícula. Después de eso, solo necesita un archivo de actualización de diseño para agregar la columna a la página de la cuadrícula de pedidos.

Llamé a la extensión Example_SalesGrid, pero puede cambiarla según sus propias necesidades.

Comencemos creando el módulo init xml en /app/etc/modules/Example_SalesGrid.xml :

<?xml version="1.0" encoding="UTF-8"?>
<!--
 Module bootstrap file
-->
<config>
    <modules>
        <Example_SalesGrid>
            <active>true</active>
            <codePool>community</codePool>
            <depends>
                <Mage_Sales />
            </depends>
        </Example_SalesGrid>
    </modules>
</config>

A continuación, creamos nuestro módulo config xml en /app/code/community/Example/SalesGrid/etc/config.xml :

<?xml version="1.0" encoding="UTF-8"?>
<config>
    <modules>
        <Example_SalesGrid>
            <version>0.1.0</version> <!-- define version for sql upgrade -->
        </Example_SalesGrid>
    </modules>
    <global>
        <models>
            <example_salesgrid>
                <class>Example_SalesGrid_Model</class>
            </example_salesgrid>
        </models>
        <blocks>
            <example_salesgrid>
                <class>Example_SalesGrid_Block</class>
            </example_salesgrid>
        </blocks>
        <events>
            <!-- Add observer configuration -->
            <sales_order_resource_init_virtual_grid_columns>
                <observers>
                    <example_salesgrid>
                        <model>example_salesgrid/observer</model>
                        <method>addColumnToResource</method>
                    </example_salesgrid>
                </observers>
            </sales_order_resource_init_virtual_grid_columns>
        </events>
        <resources>
            <!-- initialize sql upgrade setup -->
            <example_salesgrid_setup>
                <setup>
                    <module>Example_SalesGrid</module>
                    <class>Mage_Sales_Model_Mysql4_Setup</class>
                </setup>
            </example_salesgrid_setup>
        </resources>
    </global>
    <adminhtml>
        <layout>
            <!-- layout upgrade configuration -->
            <updates>
                <example_salesgrid>
                    <file>example/salesgrid.xml</file>
                </example_salesgrid>
            </updates>
        </layout>
    </adminhtml>
</config>

Ahora creamos el script de actualización de SQL en /app/code/community/Example/SalesGrid/sql/example_salesgrid_setup/install-0.1.0.php :

<?php
/**
 * Setup scripts, add new column and fulfills
 * its values to existing rows
 *
 */
$this->startSetup();
// Add column to grid table

$this->getConnection()->addColumn(
    $this->getTable('sales/order_grid'),
    'customer_group_id',
    'smallint(6) DEFAULT NULL'
);

// Add key to table for this field,
// it will improve the speed of searching & sorting by the field
$this->getConnection()->addKey(
    $this->getTable('sales/order_grid'),
    'customer_group_id',
    'customer_group_id'
);

// Now you need to fullfill existing rows with data from address table

$select = $this->getConnection()->select();
$select->join(
    array('order'=>$this->getTable('sales/order')),
    $this->getConnection()->quoteInto(
        'order.entity_id = order_grid.entity_id'
    ),
    array('customer_group_id' => 'customer_group_id')
);
$this->getConnection()->query(
    $select->crossUpdateFromSelect(
        array('order_grid' => $this->getTable('sales/order_grid'))
    )
);

$this->endSetup();

A continuación, creamos el archivo de actualización de diseño en /app/design/adminhtml/default/default/layout/example/salesgrid.xml:

<?xml version="1.0"?>
<layout>
    <!-- main layout definition that adds the column -->
    <add_order_grid_column_handle>
        <reference name="sales_order.grid">
            <action method="addColumnAfter">
                <columnId>customer_group_id</columnId>
                <arguments module="sales" translate="header">
                    <header>Customer Group</header>
                    <index>customer_group_id</index>
                    <type>options</type>
                    <filter>Example_SalesGrid_Block_Widget_Grid_Column_Customer_Group</filter>
                    <renderer>Example_SalesGrid_Block_Widget_Grid_Column_Renderer_Customer_Group</renderer>
                    <width>200</width>
                </arguments>
                <after>grand_total</after>
            </action>
        </reference>
    </add_order_grid_column_handle>
    <!-- order grid action -->
    <adminhtml_sales_order_grid>
        <!-- apply the layout handle defined above -->
        <update handle="add_order_grid_column_handle" />
    </adminhtml_sales_order_grid>
    <!-- order grid view action -->
    <adminhtml_sales_order_index>
        <!-- apply the layout handle defined above -->
        <update handle="add_order_grid_column_handle" />
    </adminhtml_sales_order_index>
</layout>

Ahora necesitamos dos archivos de bloque, uno para crear las opciones de filtro, /app/code/community/Example/SalesGrid/Block/Widget/Grid/Column/Customer/Group.php:

<?php

class Example_SalesGrid_Block_Widget_Grid_Column_Customer_Group extends Mage_Adminhtml_Block_Widget_Grid_Column_Filter_Select  {

    protected $_options = false;

    protected function _getOptions(){

        if(!$this->_options) {
            $methods = array();
            $methods[] = array(
                'value' =>  '',
                'label' =>  ''
            );
            $methods[] = array(
                'value' =>  '0',
                'label' =>  'Guest'
            );

            $groups = Mage::getResourceModel('customer/group_collection')
                ->addFieldToFilter('customer_group_id', array('gt' => 0))
                ->load()
                ->toOptionArray();

            $this->_options = array_merge($methods,$groups);
        }
        return $this->_options;
    }
}

Y el segundo para traducir los valores de fila al texto correcto que se mostrará, /app/code/community/Example/SalesGrid/Block/Widget/Grid/Column/Renderer/Customer/Group.php :

<?php

class Example_SalesGrid_Block_Widget_Grid_Column_Renderer_Customer_Group extends Mage_Adminhtml_Block_Widget_Grid_Column_Renderer_Abstract   {

    protected $_options = false;

    protected function _getOptions(){

        if(!$this->_options) {
            $methods = array();
            $methods[0] = 'Guest';

            $groups = Mage::getResourceModel('customer/group_collection')
                ->addFieldToFilter('customer_group_id', array('gt' => 0))
                ->load()
                ->toOptionHash();
            $this->_options = array_merge($methods,$groups);
        }
        return $this->_options;
    }

    public function render(Varien_Object $row){
        $value = $this->_getValue($row);
        $options = $this->_getOptions();
        return isset($options[$value]) ? $options[$value] : $value;
    }
}

El último archivo necesario solo es necesario si crea una columna adicional a partir de una tabla distinta de ventas / pedido (sales_flat_order). Todos los campos en sales / order_grid que coinciden con el nombre de la columna de sales / order se actualizan automáticamente en la tabla sales / order_grid. Si necesita agregar la opción de pago, por ejemplo, necesitará este observador para agregar el campo a la consulta para que los datos se puedan copiar en la tabla correcta. El observador utilizado para esto está en /app/code/community/Example/SalesGrid/Model/Observer.php :

<?php
/**
 * Event observer model
 *
 *
 */
class Example_SalesGrid_Model_Observer {

    public function addColumnToResource(Varien_Event_Observer $observer) {
        // Only needed if you use a table other than sales/order (sales_flat_order)

        //$resource = $observer->getEvent()->getResource();
        //$resource->addVirtualGridColumn(
        //  'payment_method',
        //  'sales/order_payment',
        //  array('entity_id' => 'parent_id'),
        //  'method'
        //);
    }
}

Este código se basa en el ejemplo de http://www.ecomdev.org/2010/07/27/adding-order-attribute-to-orders-grid-in-magento-1-4-1.html

Espero que el ejemplo anterior resuelva su problema.

Vladimir Kerkhoff
fuente
Lo siento, no pude probarlo mientras viajaba ... Suena un poco más complicado que mi enfoque (¿funciona también para un nuevo pedido?)
Fra
El observador de la cuadrícula maneja los cambios de datos en cada cambio, ya que este es un uso nativo de Magento que no necesita crear uniones a otras tablas, esto acelera la consulta en grandes cantidades de pedidos (todos los datos se almacenan en sales_flat_order_grid).
Vladimir Kerkhoff
Cuando intento usar esto, aparece
Vaishal Patel el
4

Intenta usar estos:

public function salesOrderGridCollectionLoadBefore($observer)
{
    /**
     * @var $select Varien_DB_Select
     */
    $collection = $observer->getOrderGridCollection();
    $collection->addFilterToMap('store_id', 'main_table.store_id');
    $select     = $collection->getSelect();
    $select->joinLeft(array('oe' => $collection->getTable('sales/order')), 'oe.entity_id=main_table.entity_id', array('oe.customer_group_id'));
    if ($where = $select->getPart('where')) {
        foreach ($where as $key=> $condition) {
            if (strpos($condition, 'store_id')) {
                $value       = explode('=', trim($condition, ')'));
                $value       = trim($value[1], "' ");
                $where[$key] = "(main_table.store_id = '$value')";
            }
        }
        $select->setPart('where', $where);
    }
}
mageUz
fuente
1
Esto debería haber sido realmente aceptado como la respuesta para el enfoque de observador del PO.
musicliftsme
2

¿Realmente necesitas en tu método salesOrderGridCollectionLoadBeforeel siguiente código $collection->addFilterToMap('store_id', 'main_table.store_id');? Si no, elimínelo e intente lo siguiente:

protected function _addColumnToGrid($grid)
{
....... // here you code from your post above

    $storeIdColumn = $grid->getColumn('store_id');

    if($storeIdColumn) {
        $storeIdColumn->addData(array('filter_index' => 'main_table.store_id'));
    }
}
Sylvain Rayé
fuente
Ya probé ambos :( Column('store_id');no está disponible en core_block_abstract_prepare_layout_before (_prepareColumn () se llama después, por lo que la columna no existe en ese momento) addFilterToMapno está haciendo su trabajo
Fra
alguna idea de por qué addFilterToMap no funciona?
Fra
Soory, no tuve mucho tiempo para echar un vistazo estos últimos días. Quizas mañana. Solo una idea, porque recuerdo un poco de la razón por la que dije que no usaba addFilterToMap, es cómo se usa, quizás incorrecto, los parámetros son incorrectos o no se usan en el momento adecuado. Son solo ideas de recuerdos.
Sylvain Rayé
2

En lugar de usar el nombre de la columna estática, puede usar el siguiente método para todas las columnas. Puedo entender si usa la respuesta de mageUz que funcionará para una columna y si elige otra columna, entonces podría estar recibiendo el mismo error. Entonces, el siguiente código le brinda una solución para todas las columnas simultáneamente.

public function salesOrderGridCollectionLoadBefore(Varien_Event_Observer $observer)
{
    $collection = $observer->getOrderGridCollection();
    $select = $collection->getSelect();
    $select->joinLeft(array('order' => $collection->getTable('sales/order')), 'order.entity_id=main_table.entity_id',array('shipping_arrival_date' => 'shipping_arrival_date'));

    if ($where = $select->getPart('where')) {
        foreach ($where as $key=> $condition) {
            $parsedString = $this->get_string_between($condition, '`', '`');
    $yes = $this->checkFiledExistInTable('order_grid',$parsedString);
    if($yes){
        $condition = str_replace('`','',$condition);
        $where[$key] = str_replace($parsedString,"main_table.".$parsedString,$condition);
    }
        }
        $select->setPart('where', $where);
    }
}

 public function checkFiledExistInTable($entity=null,$parsedString=null){
   $resource = Mage::getSingleton('core/resource');
   $readConnection = $resource->getConnection('core_read');

    if($entity == 'order'){
       $table = 'sales/order';
    }elseif($entity == 'order_grid'){
        $table = 'sales/order_grid';
    }else{
        return false;
    }

     $tableName = $resource->getTableName($table);
    $saleField = $readConnection->describeTable($tableName);

    if (array_key_exists($parsedString,$saleField)){
       return true;
   }else{
      return false;
   }
 }

function get_string_between($string, $start, $end){
    $string = ' ' . $string;
    $ini = strpos($string, $start);
    if ($ini == 0) return '';
    $ini += strlen($start);
    $len = strpos($string, $end, $ini) - $ini;
    return substr($string, $ini, $len);
}
jyotiranjan.in
fuente