Como adicionar coluna com filtro à grade de pedidos do Magento 2?

Publicados: 2020-02-03

Muitas vezes, os administradores de lojas Magento 2 exigem opções extras quando se trata de usar e personalizar a grade de pedidos - a filtragem com base em um parâmetro específico pronto para uso pode se tornar um verdadeiro desafio.

Recentemente, um desenvolvedor Magento me procurou com uma pergunta. Ele tentou expandir a grade de pedidos no Magento 2.3.1. Os posts antigos disponíveis na web não ajudaram – naturalmente, muita coisa mudou no Magento nos últimos dois anos.

Com base na pergunta dele, ofereço a você que dê uma olhada na solução para um caso específico:

Precisamos adicionar uma coluna ― com algum código regional de um cliente que concluiu uma compra ― à grade de pedidos. Além disso, um administrador de loja deve ter a possibilidade de filtrar pedidos por esta coluna recém-adicionada.

Pode parecer fácil, mas há algumas coisas que vale a pena prestar atenção. Por exemplo, um comprador que fez uma compra pode não ter nenhum endereço de entrega – no caso de um pedido virtual. Ou, como vamos listar as regiões? Tudo isso deve ser levado em consideração ao se chegar ao desenvolvimento. Com base nas perguntas mencionadas anteriormente, vamos supor:

  • os produtos virtuais não terão uma região de entrega ('null'). Isso ajudará você a escolhê-los com base nesse parâmetro,
  • as regiões serão listadas e terão uma aparência de códigos sem sua transformação em rótulos, assim como no Magento 2 padrão.

*Observe que no final deste artigo haverá um link para o módulo com acesso aberto no GitHub. No entanto, incluo o link neste parágrafo se você não conseguir terminar este artigo: https://github.com/mageworx/articles-extended-orders-grid.

No entanto, apesar da falta de tempo, encorajo-vos a continuar a ler.?

Assim, para adicionar uma nova coluna à grade de pedidos, você precisa:

Índice

  • 1. Crie um novo módulo
  • 2. Adicione uma coluna à grade
    • Explicações
  • 3. Adicione dados à coluna
  • Como adicionar uma coluna extra?
  • [Atualização] Como adicionar uma coluna com informações de itens do pedido?

1. Crie um novo módulo

Primeiro, vamos decidir sobre os nomes do módulo e do fornecedor. Bem, não há necessidade de eu escolher um nome de fornecedor – é MageWorx (como se eu tivesse escolha, estou brincando). Eu ainda posso escolher o nome do módulo. Que seja ExtendedOrdersGrid (aliás temos uma extensão de mesmo nome para Magento 2). Na verdade, usar MageWorx como um nome de fornecedor no namespace não lhe dá o direito de solicitar suporte gratuito. De qualquer forma, se os membros da nossa equipe de suporte tiveram um bom fim de semana, você ainda pode tentar na segunda-feira.?

Vamos criar o seguinte diretório: `app/code/MageWorx/ExtendedOrdersGrid`. Para registrar um módulo, precisaremos de alguns arquivos padrão:

 > 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>

É importante notar que eu cortei os direitos autorais que são adicionados ao meu IDE automaticamente. Assim, você pode usar este código sem problemas. ?

Em seguida, execute alguns comandos:

 > sudo -u www-data php bin/magento module:enable MageWorx_ExtendedOrdersGrid > sudo -u www-data php bin/magento setup:upgrade

E voilá! Agora, nosso módulo pode ser visto no Magento 2! Ah, se você trabalha em um servidor remoto, não esqueça de transferir os arquivos antes de testar.

2. Adicione uma coluna à grade

Em seguida, usando a interface do usuário do Magento 2, vamos adicionar uma nova coluna à grade padrão. Para isso, crie um arquivo:

 > view/adminhtml/ui_component/sales_order_grid.xml

com o seguinte conteúdo (seu significado discutiremos mais adiante):

 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>

Aqui, você precisa especificar que o nome não é retirado de nenhum lugar. Para desenvolvedores experientes, isso é claro, mas para quem conhece apenas o Magento 2, adicionarei algumas explicações no final deste parágrafo.

Usamos um nó padrão `columns` para adicionar colunas à grade, onde uma nova coluna sob o nome 'código' deve ser adicionada também. Em seguida, vamos escrever os atributos da nossa coluna na grade:

1) Componente . Esta é uma classe JS que é responsável pela criação e processamento desta coluna. Ele está localizado no módulo Magento_Ui no seguinte endereço:

`vendor/magento/module-ui/view/base/web/js/grid/columns/column.js`

Na verdade, se você é um desenvolvedor curioso, dê uma olhada em outras realizações também. Há muitas coisas interessantes por aí.

2) Etiqueta. Esta é uma linha com um nome de coluna, que será exibida para um usuário final. Não se esqueça de adicioná-lo ao arquivo de localização i18n, se a propriedade `translate` tiver sido estabelecida. ?

3) Ordem de classificação. Esta é a posição da coluna na grade. Se o módulo foi instalado no Magento 2 que nunca foi gerenciado por um administrador da loja, ele terá efeito. Caso contrário, no Magento 2 que está sendo usado, nossa coluna será adicionada ao final da lista, não importa o que façamos.

4) Alinhar. Isso significa alinhar o conteúdo da coluna. Acho que está claro.

5) Tipo de dados. Este é um tipo de dados que iremos manipular. No nosso caso, isso é simplesmente uma linha de texto. No entanto, pode ser uma lista ou um valor booleano, assim como números se falarmos de quantidade de produtos, por exemplo.

6) Visível. Isso nada mais é do que a visibilidade da coluna, embora muito dependa se a grade foi usada anteriormente ou não.

Todos os dados sobre a grade são armazenados no banco de dados Magento, na tabela `ui_bookmark`. Assim, se não houver registro da nossa coluna para a grade modificada no momento da instalação do nosso módulo, não espere nenhum milagre.

7) Filtro . Este é o tipo de filtro. Aqui, especificamos que a filtragem deve ser feita como no texto normal. Durante a execução do código, ele se transformará na condição `LIKE %value%` do MySQL.


Extensões MageWorx Magento 2

Explicações

Para encurtar a história, o nome do componente de IU estendido deve corresponder ao nome do original. No nosso caso, é `vendor/magento/module-sales/view/adminhtml/ui_component/sales_order_grid.xml`, e é calculado a partir da raiz do módulo `view/adminhtml/ui_component/sales_order_grid.xml`.

A própria grade da interface do usuário é adicionada ao controlador necessário usando o layout `vendor/magento/module-sales/view/adminhtml/layout/sales_order_index.xml` da seguinte forma:

 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>

Isso significa *adicionar este componente de interface do usuário sob o nome `sales_order_grid` ao conteúdo da página* ― assim como no caso de blocos. No entanto, em vez de blocos, temos `uiComponent` com seus atributos e limitações.


Agora, limpe o cache do Magento 2 usando o seguinte comando:

 > sudo -u www-data php bin/magento cache:clean config

e confira os resultados na grade de pedidos:

Como adicionar coluna com filtro à grade de pedidos do Magento 2? | Blog Magento Magento

3. Adicione dados à coluna

Você deve ter notado que a coluna apareceu, mas seu conteúdo não parece exatamente como esperado... não há dados exibidos lá. Justo, não adicionamos nada, portanto, não há conteúdo.

Vamos começar a escrever um plugin simples que o ajudará a preencher nossa coluna. Para isso, vamos pegar a consulta da coleção de grades, fazer uma junção dentro da tabela e grade necessárias. O plugin terá a seguinte aparência:

 > 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; } }

Ele se referirá à seguinte classe:

`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>

O plugin funciona da seguinte forma:

Como ele pegará absolutamente todas as coleções, vamos adicionar validação à tabela `sales_order_grid` necessária. Quando ele é encontrado e o Magento tenta obter dados sobre isso, fazemos uma junção da tabela com o endereço `sales_order_address` por `order_id` (`entity_id` na tabela `sales_order_grid` e `parent_id` na tabela `sales_order_address` ( alias `soa`)). Agora, temos acesso aos dados do endereço de entrega do pedido do cliente, que podemos usar para determinar o `region_id`. Ele está localizado como um número na tabela `sales_order_address`. Este número corresponde ao índice na tabela `directory_country_region` (alias `dcrt`). Como precisamos deste código regional da tabela como mencionado acima, vamos conectar a coluna 'código'. Esta coluna precisa obterá a saída (corresponde ao valor `column` em `sales_order_grid.xml`).

Em seguida, limpe o cache:

 > sudo -u www-data php bin/magento cache:clean config

Faça login no painel de administração na grade de pedidos. Se tudo foi feito corretamente, veremos nossos códigos regionais exibidos:

Como adicionar coluna com filtro à grade de pedidos do Magento 2? | Blog Magento Magento

O acesso gratuito ao módulo está disponível no GitHub: https://github.com/mageworx/articles-extended-orders-grid.

Nota importante!

Para adicionar quaisquer dados a esta coluna, é necessário obter a coluna 'your_column_name' e todos os dados necessários adicionados ao criar uma coleção. Ou seja, você precisa fazer algo diferente – substituir o nome da tabela e escrever sua própria junção. Além disso, não se esqueça de editar o nome da coluna no arquivo `sales_order_grid.xml` se necessário.

Como adicionar uma coluna extra?

Se você decidir adicionar mais uma coluna, por favor, siga as diretrizes descritas no seguinte Git commit: https://github.com/mageworx/articles-extended-orders-grid/commit/d31c364a25ce493ab64731c5ca0481e146dbbac3

Lá, adicionamos a coluna de telephone à grade da tabela sales_order_address para o endereço do tipo de shipping . Como você pode ver no código do commit, nenhuma modificação significativa no código foi necessária.

Além disso, essas colunas podem ser exportadas com sucesso da interface padrão 'grade de pedidos'.

Aqui está como a grade com a coluna 'telefone' se parece:

Como adicionar coluna com filtro à grade de pedidos do Magento 2? | Blog Magento Magento

Na captura de tela abaixo, você pode ver os mesmos pedidos exportados para um arquivo .csv:

Como adicionar coluna com filtro à grade de pedidos do Magento 2? | Blog Magento Magento

[Atualização] Como adicionar uma coluna com informações de itens do pedido?

Como você sabe, todos os pedidos têm quantidade de itens, começando de um até além do número (sim, o sonho dos comerciantes). Mas como podemos exibir essas informações na grade de pedidos para iniciar uma pesquisa ou executar uma análise com mais facilidade?

Não podemos simplesmente adicionar uma coluna como fizemos anteriormente porque obtemos apenas um nome de produto ou SKU em cada linha nesse caso. Ou os registros de pedidos serão duplicados... Também não precisamos dessa bagunça.

Assim, vou tentar explicar como podemos fazer isso da maneira certa (na minha opinião).

Suponha que precisamos de uma coluna de dados 'Nome do produto' na grade de pedidos.

Primeiro, vamos adicionar uma nova coluna na definição sales_order_grid , como fizemos anteriormente:

 <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>

Então, tudo o que precisamos é construir a consulta certa para nossa nova coluna. Ele deve conter o nome de cada produto comprado nesse pedido, separado por vírgula, com possibilidade de pesquisar pelos valores dessa coluna, etc. Vamos criar um novo método no 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; }

e nomeie esse método dentro do corpo do 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 obter os dados desejados em uma coluna, devemos criar uma sub-seleção com duas colunas: order_id e name (nome do produto) na seleção individual, que pode ser agregada à coleção principal posteriormente:

 // 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');

Esclarecimentos:

  • A linha $collection->getConnection()->select() criará uma nova instância Magento\Framework\Db\Select .
    Isso é necessário porque não podemos usar a seleção original da coleção, pois ela contém seus próprios dados e quaisquer modificações levarão a erros.
  • A coluna name deve ter todos os nomes de produtos para a ordem especificada, ou seja, deve ser agrupada usando a \Zend_Db_Expr('GROUP_CONCAT(DISTINCT name SEPARATOR \',\')') . Para isso, estamos adicionando group('order_id') ao select posteriormente. Sem agrupamento, não podemos usar a função GROUP_CONCAT .

Agora, podemos adicionar nossa sub-seleção à coleção principal e será o fim lógico do 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;

Esclarecimentos:

  • soi é um alias para nossa pseudo-tabela.
  • order_id é uma chave, que usamos para vincular nossa tabela principal (grade) aos dados dos itens do pedido.
  • ['name'] é a única coluna que é adicionada ao resultado, pois não precisamos de outras informações.

O resultado final está disponível no repositório oficial desse exemplo.
Aqui está o link para o commit específico: https://github.com/mageworx/articles-extended-orders-grid/commit/0cdffcd4ba66cacb2fd857ba7626fdbcfc0d6fe3

Veja como essa coluna fica em nosso host de teste:

?‍? Como adicionar coluna com filtro à grade de pedidos do Magento 2? | Blog Magento Magento

E aqui está o resultado da exportação (CSV):

E aqui está o resultado da exportação (CSV):

Veja como fica a consulta ao tentar pesquisar pedidos com produtos "Pretos" (em nosso host de desenvolvimento):
SELECT main_table .*, soat . telephone , dcrt . code , soi . name FROM 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
ONDE soi . name LIKE '%Black%'

Evidentemente, essa não é a maneira mais rápida de gerar dados. No entanto, esse é provavelmente o mais fácil. A melhor maneira é acumular dados sobre nomes de produtos em uma coluna separada de uma tabela separada (order_id, products_name) e adicionar essa tabela sem agrupamento extra e qualquer subseleção.

Para isso, adicionamos o grupo ('order_id') ao nosso select (no final do código do método).
O select significa um elemento.
O grupo significa o método de seleção.


Acho que é isso. Se você tiver alguma dúvida ou solicitação, deixe um comentário no campo de comentários.