¿Cómo agregar una columna con filtro a la cuadrícula de pedidos de Magento 2?
Publicado: 2020-02-03A menudo, los administradores de las tiendas Magento 2 requieren opciones adicionales cuando se trata de usar y personalizar la cuadrícula de pedidos: el filtrado basado en un parámetro específico listo para usar puede convertirse en un verdadero desafío.
Recientemente, un desarrollador de Magento me contactó con una pregunta. Trató de expandir la cuadrícula de pedidos en Magento 2.3.1. Las publicaciones antiguas disponibles en la web no ayudaron; naturalmente, mucho ha cambiado en Magento desde los últimos dos años.
Basado en su pregunta, le ofrezco que eche un vistazo a la solución para un caso específico:
Necesitamos agregar una columna, con algún código regional de un cliente que completó una compra, a la cuadrícula de pedidos. Además, un administrador de la tienda debe tener la posibilidad de filtrar pedidos por esta columna recién agregada.
Puede parecer fácil, pero hay un par de cosas a las que vale la pena prestar atención. Por ejemplo, un comprador que realizó una compra puede no tener ninguna dirección de entrega, en el caso de un pedido virtual. O, ¿cómo enumeraremos las regiones? Todo esto debe tenerse en cuenta al llegar al desarrollo. Con base en las preguntas mencionadas anteriormente, supongamos:
- los productos virtuales no tendrán una región de entrega ("nula"). Esto le ayudará a elegirlos en función de este parámetro,
- las regiones se enumerarán y tendrán un aspecto de códigos sin su transformación en etiquetas, tal como está en el Magento 2 predeterminado.
*Tenga en cuenta que al final de este artículo habrá un enlace al módulo con acceso abierto en GitHub. Sin embargo, incluyo el enlace en este párrafo si no logra terminar este artículo: https://github.com/mageworx/articles-extended-orders-grid.
Sin embargo, a pesar de la falta de tiempo, te animo a que sigas leyendo.
Por lo tanto, para agregar una nueva columna a la cuadrícula de pedidos, debe:
Tabla de contenido
- 1. Crear un nuevo módulo
- 2. Agrega una columna a la grilla
- Explicaciones
- 3. Agregar datos a la columna
- ¿Cómo agregar una columna adicional?
- [Actualización] ¿Cómo agregar una columna con información de artículos de pedido?
1. Crear un nuevo módulo
Primero, decidamos el módulo y los nombres de los proveedores. Bueno, no es necesario que elija un nombre de proveedor: es MageWorx (como si tuviera otra opción, es broma). Todavía puedo elegir el nombre del módulo. Que sea ExtendedOrdersGrid (por cierto, tenemos una extensión del mismo nombre para Magento 2). De hecho, usar MageWorx como nombre de proveedor en el espacio de nombres no le da derecho a solicitar soporte gratuito. De todos modos, si los miembros de nuestro equipo de soporte tuvieron un buen fin de semana, aún puede intentarlo el lunes.
Vamos a crear el siguiente directorio: `app/code/MageWorx/ExtendedOrdersGrid`. Para registrar un módulo, necesitaremos algunos archivos estándar:
> registration.php php <?php \Magento\Framework\Component\ComponentRegistrar::register( \Magento\Framework\Component\ComponentRegistrar::MODULE, 'MageWorx_ExtendedOrdersGrid', __DIR__ ); > composer.json json { "name": "mageworx/module-extended-orders-grid", "description": "Extended Orders Grid Extension", "require": { "magento/module-ui" : ">=100.1.0 < 102", "magento/module-sales" : ">=100.0.0 <103" }, "type": "magento2-module", "version": "1.0.0", "license": [ "OSL-3.0", "AFL-3.0" ], "autoload": { "files": [ "registration.php" ], "psr-4": { "MageWorx\\ExtendedOrdersGrid\\": "" } } } > etc/module.xml xml <?xml version="1.0"?> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd"> <module name="MageWorx_ExtendedOrdersGrid" setup_version="1.0.0"> <sequence> <module name="Magento_Sales"/> <module name="Magento_Ui"/> </sequence> </module> </config>
Es importante tener en cuenta que eliminé los derechos de autor que se agregan en mi IDE automáticamente. Por lo tanto, puedes usar este código sin problemas. ?
Luego, ejecuta algunos comandos:
> sudo -u www-data php bin/magento module:enable MageWorx_ExtendedOrdersGrid > sudo -u www-data php bin/magento setup:upgrade
¡Y voilá! ¡Ahora, nuestro módulo se puede ver en Magento 2! Ah, si trabaja en un servidor remoto, no olvide transferir los archivos antes de realizar la prueba.
2. Agrega una columna a la grilla
Luego, usando la interfaz de usuario de Magento 2, agreguemos una nueva columna a la cuadrícula estándar. Para eso, crea un archivo:
> view/adminhtml/ui_component/sales_order_grid.xml
con el siguiente contenido (su significado lo discutiremos más adelante):
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="code"> <argument name="data" xsi:type="array"> <item name="config" xsi:type="array"> <item name="component" xsi:type="string">Magento_Ui/js/grid/columns/column</item> <item name="label" xsi:type="string" translate="true">Region Code</item> <item name="sortOrder" xsi:type="number">60</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="filter" xsi:type="string">text</item> </item> </argument> </column> </columns> </listing>
Aquí, debe especificar que el nombre no se toma de ningún lado. Para los desarrolladores experimentados, esto es claro, pero para aquellos que solo conocen Magento 2, agregaré algunas explicaciones al final de este párrafo.
Usamos un nodo de `columnas` estándar para agregar columnas a la cuadrícula, donde también se agregará una nueva columna bajo el nombre de 'código'. A continuación, escribamos los atributos de nuestra columna en la grilla:
1) componente . Esta es una clase JS que es responsable de la creación y procesamiento de esta columna. Se encuentra en el módulo Magento_Ui en la siguiente dirección:
`proveedor/magento/module-ui/view/base/web/js/grid/columns/column.js`
De hecho, si eres un desarrollador curioso, echa un vistazo a otras realizaciones también. Hay un montón de cosas interesantes por ahí.
2) Etiqueta. Esta es una línea con un nombre de columna, que se mostrará a un usuario final. No olvide agregarlo al archivo de localización i18n, si se ha establecido la propiedad `translate`. ?
3) orden de clasificación. Esta es la posición de la columna en la cuadrícula. Si el módulo se ha instalado en Magento 2 que nunca ha sido administrado por un administrador de la tienda, tendrá efecto. De lo contrario, en el Magento 2 que se está utilizando, nuestra columna se agregará al final de la lista sin importar lo que hagamos.
4) Alinear. Esto significa alinear el contenido de la columna. Supongo que eso está claro.
5) Tipo de datos. Este es un tipo de datos que manipularemos. En nuestro caso, eso es simplemente una línea de texto. Sin embargo, puede ser una lista o un valor booleano, así como números si hablamos de cantidad de productos, por ejemplo.
6) visibles. Esto no es más que la visibilidad de la columna, aunque mucho depende de si la cuadrícula se usó previamente o no.
Todos los datos sobre la cuadrícula se almacenan en la base de datos de Magento, en la tabla `ui_bookmark`. Por lo tanto, si no hay registro sobre nuestra columna para la cuadrícula modificada en el momento de la instalación de nuestro módulo, no espere ningún milagro.
7) Filtrar . Este es el tipo de filtro. Aquí, especificamos que el filtrado debe hacerse como con el texto normal. Mientras se ejecuta el código, se transformará en la condición `LIKE %value%` de MySQL.
Explicaciones
Para acortar la historia larga, el nombre del componente de la interfaz de usuario extendida debe corresponder al nombre del original. En nuestro caso, es `vendor/magento/module-sales/view/adminhtml/ui_component/sales_order_grid.xml` y se calcula a partir de la raíz del módulo `view/adminhtml/ui_component/sales_order_grid.xml`.
La cuadrícula de la interfaz de usuario se agrega al controlador requerido usando el diseño `vendor/magento/module-sales/view/adminhtml/layout/sales_order_index.xml` de la siguiente manera:
xml <?xml version="1.0"?> <!-- /** * Copyright Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ --> <page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd"> <update handle="styles"/> <body> <referenceContainer name="content"> <uiComponent name="sales_order_grid"/> </referenceContainer> </body> </page>
Esto significa *agregar este componente de la interfaz de usuario bajo el nombre `sales_order_grid` al contenido de la página*, al igual que en el caso de los bloques. Sin embargo, en lugar de bloques, tenemos `uiComponent` con sus atributos y limitaciones.
Ahora, borre el caché de Magento 2 usando el siguiente comando:
> sudo -u www-data php bin/magento cache:clean config
y verifique los resultados en la grilla de pedidos:
3. Agregar datos a la columna
Es posible que haya notado que apareció la columna, pero su contenido no se ve exactamente como se esperaba... no se muestra ningún dato allí. Bastante justo, no agregamos nada, por lo tanto, no hay contenido allí.
Comencemos a escribir un complemento simple que lo ayudará a completar nuestra columna. Para eso, capturemos la consulta de la colección de la cuadrícula, hagamos una combinación dentro de la tabla y la cuadrícula requeridas. El complemento se verá de la siguiente manera:
> app/code/MageWorx/ExtendedOrdersGrid/Plugin/AddDataToOrdersGrid.php
php <?php namespace MageWorx\ExtendedOrdersGrid\Plugin; /** * Class AddDataToOrdersGrid */ class AddDataToOrdersGrid { /** * @var \Psr\Log\LoggerInterface */ private $logger; /** * AddDataToOrdersGrid constructor. * * @param \Psr\Log\LoggerInterface $customLogger * @param array $data */ public function __construct( \Psr\Log\LoggerInterface $customLogger, array $data = [] ) { $this->logger = $customLogger; } /** * @param \Magento\Framework\View\Element\UiComponent\DataProvider\CollectionFactory $subject * @param \Magento\Sales\Model\ResourceModel\Order\Grid\Collection $collection * @param $requestName * @return mixed */ public function afterGetReport($subject, $collection, $requestName) { if ($requestName !== 'sales_order_grid_data_source') { return $collection; } if ($collection->getMainTable() === $collection->getResource()->getTable('sales_order_grid')) { try { $orderAddressTableName = $collection->getResource()->getTable('sales_order_address'); $directoryCountryRegionTableName = $collection->getResource()->getTable('directory_country_region'); $collection->getSelect()->joinLeft( ['soa' => $orderAddressTableName], 'soa.parent_id = main_table.entity_id AND soa.address_type = \'shipping\'', null ); $collection->getSelect()->joinLeft( ['dcrt' => $directoryCountryRegionTableName], 'soa.region_id = dcrt.region_id', ['code'] ); } catch (\Zend_Db_Select_Exception $selectException) { // Do nothing in that case $this->logger->log(100, $selectException); } } return $collection; } }
Se referirá a la siguiente clase:
`Magento\Framework\View\Element\UiComponent\DataProvider\CollectionFactory`
> etc/adminhtml/di.xml xml <?xml version="1.0"?> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd"> <!-- Plugins --> <!-- Adds additional data to the orders grid collection --> <type name="Magento\Framework\View\Element\UiComponent\DataProvider\CollectionFactory"> <plugin name="mageworx_extended_orders_grid_add_data_to_orders_grid" type="MageWorx\ExtendedOrdersGrid\Plugin\AddDataToOrdersGrid" sortOrder="10" disabled="false"/> </type> </config>
El complemento se ejecuta de la siguiente manera:
Como captará absolutamente todas las colecciones, agreguemos validación a la tabla `sales_order_grid` requerida. Cuando se encuentra y Magento intenta obtener datos sobre esto, unimos la tabla con la dirección `sales_order_address` por `order_id` (`entity_id` en la tabla `sales_order_grid` y `parent_id` en la tabla `sales_order_address` ( `soa` alias)). Ahora, tenemos acceso a los datos de la dirección de entrega del pedido del cliente, que podemos usar para determinar `region_id`. Se encuentra como un número en la tabla `sales_order_address`. Este número corresponde al índice en la tabla `directorio_país_región` (alias `dcrt`). Como necesitamos este código regional de la tabla como se mencionó anteriormente, conectemos la columna 'código'. Esta columna precisa obtendrá una salida (corresponde al valor de `columna` en `sales_order_grid.xml`).
Luego, borre el caché:
> sudo -u www-data php bin/magento cache:clean config
Inicie sesión en el panel de administración de la cuadrícula de pedidos. Si todo se ha hecho correctamente, veremos desplegados nuestros códigos regionales:
El acceso gratuito al módulo está disponible en GitHub: https://github.com/mageworx/articles-extended-orders-grid.
Nota al margen importante!
Para agregar cualquier dato a esta columna, se requiere obtener la columna 'your_column_name' y todos los datos necesarios agregados al crear una colección. Es decir, debe hacer algo diferente: reemplace el nombre de la tabla y escriba su propia unión. Además, no olvide editar el nombre de la columna en el archivo `sales_order_grid.xml` si es necesario.
¿Cómo agregar una columna adicional?
Si decide agregar una columna más, siga las pautas descritas en el siguiente compromiso de Git: https://github.com/mageworx/articles-extended-orders-grid/commit/d31c364a25ce493ab64731c5ca0481e146dbbac3
Allí, agregamos la columna de telephone
a la cuadrícula de la tabla sales_order_address
para la dirección del tipo de shipping
. Como puede ver en el código de confirmación, no se requirieron modificaciones de código significativas.
Además, estas columnas se pueden exportar con éxito desde la interfaz estándar de 'cuadrícula de pedidos'.
Así es como se ve la cuadrícula con la columna 'teléfono':
En la siguiente captura de pantalla, puede ver los mismos pedidos exportados a un archivo .csv:
[Actualización] ¿Cómo agregar una columna con información de artículos de pedido?
Como sabe, todos los pedidos tienen una cantidad de artículos, desde uno hasta más allá del número (sí, el sueño de los comerciantes). Pero, ¿cómo podemos mostrar esa información en la cuadrícula de pedidos para iniciar una búsqueda o ejecutar un análisis más fácilmente?
No podemos simplemente agregar una columna como lo hicimos antes porque, en ese caso, solo obtenemos un nombre de producto o SKU en cada fila. O bien, los registros de pedidos se duplicarán… Tampoco necesitamos ese lío.
Por lo tanto, intentaré explicar cómo podemos hacerlo de la manera correcta (en mi opinión).
Supongamos que necesitamos una columna de datos 'Nombre del producto' en la cuadrícula de pedidos.
Primero, agreguemos una nueva columna en la definición sales_order_grid
, como lo hicimos antes:
<columns> .... <column name="name"> <argument name="data" xsi:type="array"> <item name="config" xsi:type="array"> <item name="component" xsi:type="string">Magento_Ui/js/grid/columns/column</item> <item name="filter" xsi:type="string">text</item> <item name="label" xsi:type="string" translate="true">Product Name</item> <item name="visible" xsi:type="boolean">false</item> <item name="sortOrder" xsi:type="number">70</item> </item> </argument> </column> </columns>
Luego, todo lo que necesitamos es crear la consulta correcta para nuestra nueva columna. Debe contener el nombre de cada producto comprado en ese pedido, separados por una coma, con la posibilidad de buscar por los valores de esa columna, etc. Vamos a crear un nuevo método en el plugin mageworx_extended_orders_grid_add_data_to_orders_grid
:
/** * Adds products name column to the orders grid collection * * @param OrderGridCollection $collection * @return OrderGridCollection */ private function addProductsNameColumn(OrderGridCollection $collection): OrderGridCollection { return $collection; }
y nombre ese método dentro del cuerpo del método original:
if ($collection->getMainTable() === $collection->getResource()->getTable('sales_order_grid')) { try { $orderAddressTableName = $collection->getResource()->getTable('sales_order_address'); ... // Add product's name column $this->addProductsNameColumn($collection); } catch (\Zend_Db_Select_Exception $selectException) { ...
Para obtener los datos deseados en una columna, debemos crear una subselección con dos columnas: order_id
y name
(nombre del producto) en la selección individual, que se puede unir a la colección principal más adelante:
// Get original table name $orderItemsTableName = $collection->getResource()->getTable('sales_order_item'); // Create new select instance $itemsTableSelectGrouped = $collection->getConnection()->select(); // Add table with columns which must be selected (skip useless columns) $itemsTableSelectGrouped->from( $orderItemsTableName, [ 'name' => new \Zend_Db_Expr('GROUP_CONCAT(DISTINCT name SEPARATOR \',\')'), 'order_id' => 'order_id' ] ); // Group our select to make only one column for one order $itemsTableSelectGrouped->group('order_id');
Aclaraciones:
- La línea
$collection->getConnection()->select()
creará una nueva instancia deMagento\Framework\Db\Select
.
Esto es necesario porque no podemos usar la selección original de la colección, ya que tiene sus propios datos dentro, y cualquier modificación generará errores. - La columna de
name
debe tener todos los nombres de productos para el pedido especificado, es decir, debe agruparse usando la\Zend_Db_Expr('GROUP_CONCAT(DISTINCT name SEPARATOR \',\')')
. Para ese propósito, estamos agregandogroup('order_id')
a la selección posterior. Sin agrupar, no podemos usar la funciónGROUP_CONCAT
.
Ahora, podemos agregar nuestra subselección a la colección principal y será el final lógico del método addProductsNameColumn
:
// Add our sub-select to main collection with only one column: name $collection->getSelect() ->joinLeft( ['soi' => $itemsTableSelectGrouped], 'soi.order_id = main_table.entity_id', ['name'] ); return $collection;
Aclaraciones:
-
soi
es un alias para nuestra pseudotabla. -
order_id
es una clave, que usamos para vincular nuestra tabla principal (cuadrícula) a los datos de los artículos del pedido. -
['name']
es la única columna que se agrega al resultado, porque no necesitamos otra información.
El resultado final está disponible en el repositorio oficial de ese ejemplo.
Aquí está el enlace a la confirmación específica: https://github.com/mageworx/articles-extended-orders-grid/commit/0cdffcd4ba66cacb2fd857ba7626fdbcfc0d6fe3
Así es como se ve esa columna en nuestro host de ensayo:
Y aquí está el resultado de la exportación (CSV):
Así es como se ve la consulta cuando se intenta buscar pedidos con productos "negros" (en nuestro host de desarrollo):
SELECCIONE main_table
.*, soat
. telephone
, dcrt
. code
, soi
. name
DESDE sales_order_grid
AS main_table
LEFT JOIN sales_order_address
AS soat
ON soat.parent_id = main_table.entity_id AND soat.address_type = 'shipping'
LEFT JOIN directory_country_region
AS dcrt
ON soat.region_id = dcrt.region_id
LEFT JOIN (SELECT GROUP_CONCAT(DISTINCT name SEPARATOR ',') AS name
, sales_order_item
. order_id
FROM sales_order_item
GROUP BY order_id
) AS soi
ON soi.order_id = main_table.entity_id
DONDE soi
. name
COMO '%Black%'
Evidentemente, esta no es la forma más rápida de generar datos. Sin embargo, esa es probablemente la más fácil. La mejor manera es acumular datos sobre nombres de productos en una columna separada de una tabla separada (order_id, products_name) y agregar esta tabla sin agrupación adicional ni ninguna subselección.
Para ese propósito, agregamos el grupo ('order_id') a nuestra selección (al final del código del método).
La selección significa un elemento.
El grupo significa el método selecto.
Supongo que eso es todo. Si tiene alguna pregunta o solicitud, deje un comentario en el campo de comentarios.