Comment ajouter une colonne avec filtre à la grille de commandes Magento 2 ?
Publié: 2020-02-03Souvent, les administrateurs de magasins Magento 2 ont besoin d'options supplémentaires lorsqu'il s'agit d'utiliser et de personnaliser la grille des commandes - le filtrage basé sur un paramètre spécifique prêt à l'emploi peut devenir un véritable défi.
Récemment, un développeur Magento m'a contacté avec une question. Il a essayé d'étendre la grille des commandes sur Magento 2.3.1. Les anciens messages disponibles sur le Web n'ont pas aidé ― naturellement, beaucoup de choses ont changé dans Magento depuis les deux dernières années.
Sur la base de sa question, je vous propose de jeter un œil à la solution pour un cas précis :
Nous devons ajouter une colonne ― avec un code régional d'un client qui a effectué un achat ― à la grille des commandes. De plus, un administrateur de magasin doit avoir la possibilité de filtrer les commandes par cette colonne nouvellement ajoutée.
Cela peut sembler facile, mais il y a quelques points auxquels il convient de prêter attention. Par exemple, un acheteur qui a effectué un achat peut ne pas avoir d'adresse de livraison ― dans le cas d'une commande virtuelle. Ou, comment allons-nous lister les régions ? Tout cela doit être pris en considération lors du développement. Sur la base des questions mentionnées précédemment, supposons :
- les produits virtuels n'auront pas de région de livraison ("null"). Cela vous aidera à les choisir en fonction de ce paramètre,
- les régions seront listées et auront un aperçu des codes sans leur transformation en étiquettes, comme c'est le cas dans le Magento 2 par défaut.
*Veuillez noter qu'à la fin de cet article, il y aura un lien vers le module en libre accès sur GitHub. Cependant, j'inclus le lien dans ce paragraphe si vous ne parvenez pas à terminer cet article : https://github.com/mageworx/articles-extended-orders-grid.
Cependant, malgré le manque de temps, je vous encourage à continuer à lire.?
Ainsi, pour ajouter une nouvelle colonne à la grille des commandes, il faut :
Table des matières
- 1. Créer un nouveau module
- 2. Ajouter une colonne à la grille
- Explications
- 3. Ajouter des données à la colonne
- Comment ajouter une colonne supplémentaire ?
- [Mise à jour] Comment ajouter une colonne avec les informations sur les articles de commande ?
1. Créer un nouveau module
Tout d'abord, décidons des noms de module et de fournisseur. Eh bien, pas besoin que je choisisse un nom de fournisseur - c'est MageWorx (comme si j'avais le choix, je plaisante). Il me reste à choisir le nom du module. Soit ExtendedOrdersGrid (nous avons une extension du même nom pour Magento 2). En fait, l'utilisation de MageWorx comme nom de fournisseur dans l'espace de noms ne vous donne pas le droit de demander une assistance gratuite. Quoi qu'il en soit, si les membres de notre équipe d'assistance ont passé un bon week-end, vous pouvez toujours essayer lundi. ?
Créons le répertoire suivant : `app/code/MageWorx/ExtendedOrdersGrid`. Pour enregistrer un module, nous aurons besoin de quelques fichiers standards :
> 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>
Il est important de noter que j'ai coupé le droit d'auteur qui est ajouté automatiquement dans mon IDE. Ainsi, vous pouvez utiliser ce code sans problème. ?
Ensuite, exécutez quelques commandes :
> sudo -u www-data php bin/magento module:enable MageWorx_ExtendedOrdersGrid > sudo -u www-data php bin/magento setup:upgrade
Et voila ! Maintenant, notre module est visible dans Magento 2 ! Oh, si vous travaillez sur un serveur distant, n'oubliez pas de transférer les fichiers avant de tester.
2. Ajouter une colonne à la grille
Ensuite, en utilisant l'interface utilisateur de Magento 2, ajoutons une nouvelle colonne à la grille standard. Pour cela, créez un fichier :
> view/adminhtml/ui_component/sales_order_grid.xml
avec le contenu suivant (sa signification, nous en discuterons plus loin):
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>
Ici, vous devez spécifier que le nom n'est pas sorti de nulle part. Pour les développeurs expérimentés, c'est clair, mais pour ceux qui ne connaissent que Magento 2, j'ajouterai quelques explications à la fin de ce paragraphe.
Nous avons utilisé un nœud standard "columns" pour ajouter des colonnes à la grille, où une nouvelle colonne sous le nom de "code" doit également être ajoutée. Ensuite, écrivons les attributs de notre colonne dans la grille :
1) Composant . Il s'agit d'une classe JS responsable de la création et du traitement de cette colonne. Il se situe dans le module Magento_Ui à l'adresse suivante :
`vendor/magento/module-ui/view/base/web/js/grid/columns/column.js`
En fait, si vous êtes un développeur curieux, jetez également un œil à d'autres réalisations. Il y a beaucoup de choses passionnantes là-bas.
2) Étiquette. Il s'agit d'une ligne avec un nom de colonne, qui sera affiché à un utilisateur final. N'oubliez pas de l'ajouter au fichier de localisation i18n, si la propriété `translate` a été établie. ?
3) TrierOrdre. Il s'agit de la position de la colonne dans la grille. Si le module a été installé sur Magento 2 qui n'a jamais été géré par un administrateur de boutique, cela aura un effet. Sinon, sur Magento 2 qui est utilisé, notre colonne sera ajoutée à la fin de la liste quoi que nous fassions.
4) Alignez. Cela signifie aligner le contenu de la colonne. Je suppose que c'est clair.
5) Type de données. C'est un type de données que nous allons manipuler. Dans notre cas, il s'agit simplement d'une ligne de texte. Cependant, il peut s'agir d'une liste ou d'une valeur booléenne, ainsi que de nombres si l'on parle de quantité de produits, par exemple.
6) visibles. Ce n'est rien d'autre que la visibilité de la colonne, bien que cela dépende en grande partie de l'utilisation ou non de la grille.
Toutes les données concernant la grille sont stockées dans la base de données Magento, dans la table `ui_bookmark`. Ainsi, s'il n'y a aucune trace de notre colonne pour la grille modifiée au moment de l'installation de notre module, ne vous attendez pas à un miracle.
7) Filtre . C'est le type de filtre. Ici, nous avons spécifié que le filtrage doit être effectué comme avec du texte normal. Lors de l'exécution du code, il se transformera en condition MySQL `LIKE %value%`.
Explications
Pour faire court, le nom du composant d'interface utilisateur étendu doit correspondre au nom de l'original. Dans notre cas, il s'agit de `vendor/magento/module-sales/view/adminhtml/ui_component/sales_order_grid.xml`, et il est calculé à partir de la racine du module `view/adminhtml/ui_component/sales_order_grid.xml`.
La grille de l'interface utilisateur elle-même est ajoutée au contrôleur requis à l'aide de la disposition `vendor/magento/module-sales/view/adminhtml/layout/sales_order_index.xml` comme suit :
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>
Cela signifie *ajouter ce composant d'interface utilisateur sous le nom `sales_order_grid` au contenu de la page* ― comme dans le cas des blocs. Cependant, au lieu de blocs, nous avons `uiComponent` avec ses attributs et ses limitations.
Maintenant, effacez le cache de Magento 2 à l'aide de la commande suivante :
> sudo -u www-data php bin/magento cache:clean config
et vérifiez les résultats dans la grille des commandes :
3. Ajouter des données à la colonne
Vous avez peut-être remarqué que la colonne est apparue, mais son contenu ne ressemble pas à ce que vous attendiez… aucune donnée n'y est affichée. Assez juste, nous n'avons rien ajouté, donc pas de contenu là-bas.
Passons à l'écriture d'un plugin simple qui vous aidera à remplir notre colonne. Pour cela, attrapons la requête de collection de grille, faisons une jointure dans la table et la grille requises. Le plugin ressemblera à ceci :
> 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; } }
Il fera référence à la classe suivante :
`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>
Le plugin fonctionne de la manière suivante :
Comme il interceptera absolument toutes les collections, ajoutons une validation à la table `sales_order_grid` requise. Lorsqu'il est trouvé et que Magento tente d'obtenir des données à ce sujet, nous effectuons une jointure de la table avec l'adresse `sales_order_address` par`order_id` (`entity_id` dans la table `sales_order_grid` et `parent_id` dans la table `sales_order_address` ( alias "soa")). Maintenant, nous avons accès aux données de l'adresse de livraison de la commande du client, que nous pouvons utiliser pour déterminer `region_id`. Il se trouve sous la forme d'un nombre dans la table `sales_order_address`. Ce numéro correspond à l'index dans la table `directory_country_region` (alias `dcrt`). Comme nous avons besoin de ce code régional du tableau mentionné ci-dessus, connectons la colonne 'code'. Cette colonne précise obtiendra la sortie (correspond à la valeur `column` dans `sales_order_grid.xml`).
Ensuite, videz le cache :
> sudo -u www-data php bin/magento cache:clean config
Connectez-vous au panneau d'administration de la grille des commandes. Si tout a été fait correctement, nous verrons nos codes régionaux affichés :
Un accès gratuit au module est disponible sur GitHub : https://github.com/mageworx/articles-extended-orders-grid.
Remarque importante !
Pour ajouter des données à cette colonne, il est nécessaire d'obtenir la colonne 'your_column_name' et toutes les données nécessaires ajoutées lors de la création d'une collection. Autrement dit, vous devez faire quelque chose de différent : remplacer le nom de la table et écrire votre propre jointure. N'oubliez pas non plus de modifier le nom de la colonne dans le fichier `sales_order_grid.xml` si nécessaire.
Comment ajouter une colonne supplémentaire ?
Si vous décidez d'ajouter une colonne supplémentaire, veuillez suivre les directives décrites dans le commit Git suivant : https://github.com/mageworx/articles-extended-orders-grid/commit/d31c364a25ce493ab64731c5ca0481e146dbbac3
Là, nous avons ajouté la colonne telephone
à la grille à partir de la table sales_order_address
pour l'adresse du type d' shipping
. Comme vous pouvez le voir dans le code de validation, aucune modification significative du code n'a été requise.
De plus, ces colonnes peuvent être exportées avec succès à partir de l'interface standard de « grille de commande ».
Voici à quoi ressemble la grille avec la colonne 'téléphone' :
Dans la capture d'écran ci-dessous, vous pouvez voir les mêmes commandes exportées vers un fichier .csv :
[Mise à jour] Comment ajouter une colonne avec les informations sur les articles de commande ?
Comme vous le savez, toutes les commandes ont une quantité d'articles, de un à un nombre supérieur (ouais, le rêve des marchands). Mais comment pouvons-nous afficher ces informations dans la grille des commandes pour lancer une recherche ou exécuter une analyse plus facilement ?
Nous ne pouvons pas simplement ajouter une colonne comme nous l'avons fait précédemment, car nous n'obtenons qu'un seul nom de produit ou SKU sur chaque ligne dans ce cas. Ou bien, les enregistrements de commande seront dupliqués… Nous n'avons pas non plus besoin de ce gâchis.
Ainsi, je vais essayer d'expliquer comment nous pouvons faire cela de la bonne manière (à mon avis).
Supposons que nous ayons besoin d'une colonne de données "Nom du produit" dans la grille des commandes.
Commençons par ajouter une nouvelle colonne dans la définition sales_order_grid
, comme nous l'avons fait précédemment :
<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>
Ensuite, tout ce dont nous avons besoin est de construire la bonne requête pour notre nouvelle colonne. Il doit contenir le nom de chaque produit acheté dans cette commande, séparé par une virgule, avec la possibilité de rechercher par les valeurs de cette colonne, etc. Créons une nouvelle méthode dans le 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; }
et nommez cette méthode dans le corps de la méthode d'origine :
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) { ...
Pour obtenir les données souhaitées dans une colonne, nous devons créer une sous-sélection à deux colonnes : order_id
et name
(nom du produit) dans la sélection individuelle, qui peut être jointe à la collection principale ultérieurement :
// 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');
Précisions :
-
$collection->getConnection()->select()
créera une nouvelle instanceMagento\Framework\Db\Select
.
Ceci est nécessaire car nous ne pouvons pas utiliser la sélection d'origine de la collection car elle contient ses propres données, et toute modification entraînera des erreurs. -
name
doit contenir tous les noms de produits pour la commande spécifiée, c'est-à-dire qu'elle doit être regroupée à l'aide de l'\Zend_Db_Expr('GROUP_CONCAT(DISTINCT name SEPARATOR \',\')')
. À cette fin, nous ajoutonsgroup('order_id')
à la sélection plus tard. Sans regroupement, nous ne pouvons pas utiliser la fonctionGROUP_CONCAT
.
Maintenant, nous pouvons ajouter notre sous-sélection à la collection principale et ce sera la fin logique de la méthode 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;
Précisions :
-
soi
est un alias pour notre pseudo-table. -
order_id
est une clé que nous utilisons pour lier notre table principale (grille) aux données des articles de la commande. -
['name']
est la seule colonne qui est ajoutée au résultat, car nous n'avons pas besoin d'autres informations.
Le résultat final est disponible dans le référentiel officiel de cet exemple.
Voici le lien vers le commit spécifique : https://github.com/mageworx/articles-extended-orders-grid/commit/0cdffcd4ba66cacb2fd857ba7626fdbcfc0d6fe3
Voici à quoi ressemble cette colonne sur notre hôte intermédiaire :
Et voici le résultat de l'export (CSV):
Voici à quoi ressemble la requête lorsque vous essayez de rechercher des commandes avec des produits "noirs" (sur notre hôte de développement) :
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
OÙ soi
. name
COMME '%Black%'
Évidemment, ce n'est pas le moyen le plus rapide de sortir des données. Cependant, c'est probablement le plus simple. La meilleure façon est d'accumuler des données sur les noms de produits dans une colonne distincte d'une table distincte (order_id, products_name) et d'ajouter cette table sans regroupement supplémentaire ni sous-sélection.
Pour cela, nous ajoutons le groupe ('order_id') à notre select (à la fin du code de la méthode).
Le select signifie un élément.
Le groupe désigne la méthode de sélection.
Je suppose que c'est ça. Si vous avez des questions ou des demandes, veuillez laisser un commentaire dans le champ de commentaire.