Ajouter un export de données personnalisés dans Dolibarr

Un logiciel de gestion d’entreprise permet de centraliser un maximum d’informations utiles en un seul endroit. Ces données, il faut aussi pouvoir les exploiter et il est parfois nécessaire de les extraire pour les analyser dans un outil dédié à cet usage. L’export se fait en général dans des formats compatibles avec les tableurs comme le CSV, le format OpenDocument et évidemment l’incontournable format d’Excel.

Dolibarr dispose en standard d’un certain nombre d’exports prêt à l’emploi. Il est possible lors de leur génération de les personnaliser en choisissant les colonnes que l’on souhaite voir apparaître et les filtres à appliquer aux données.

Cependant ces exports couvrent des besoins génériques et parfois il est nécessaire de les compléter par des exports répondant à un besoin précis du client. Pour ajouter un export spécifique à Dolibarr, il n’existe malheureusement pas encore dans le logiciel d’interface permettant de réaliser cet ajout simplement.

Il faut donc ouvrir le coffre du moteur et mettre les doigts dans le cambouis. La suite de cet article s’adresse donc à des personnes ayant déjà eu l’occasion de mettre le nez dans du code.

Il existe cependant un module permettant de simplifier l’opération, mais qui ne sera pas adapté dans le cas de l’export d’importants volumes de données : MyList  disponible gratuitement sur le Dolistore ou avec une liste personnalisée selon vos besoins. Il faut cependant une connaissance de la base de données de Dolibarr et savoir écrire des requêtes SQL pour utiliser ce module.

L’autre solution est d’utiliser des outils open source d’analyse statistique directement connecté à la base de données ou à une copie de celle-ci (pour éviter de pénaliser les utilisateurs du logiciel durant l’exécution de grosses requêtes).

Dans mon cas, le volume de données retourné dépassant le millier d’enregistrements, je choisis donc l’option consistant à ajouter un export à Dolibarr.

Où sont définis les exports ?

Les extractions standards de Dolibarr sont définies dans les modules décrivant les classes des entités manipulées par le logiciel (propositions, commandes, facture, etc.). Ces définitions sont stockées dans le répertoire htdocs/core/modules et les fichiers modxxxxx.class.php.

Exemple : modFournisseur.class.php

Dans ce fichier vous pourrez retrouver la définition de l’extraction à partir de la ligne 273 (Dolibarr 3.8.2).

// Exports
//--------
$r=0;

$r++;
$this->export_code[$r]=$this->rights_class.'_'.$r;
$this->export_label[$r]='Factures fournisseurs et lignes de facture';
$this->export_icon[$r]='bill';
$this->export_permission[$r]=array(array("fournisseur","facture","export"));

Ces premières lignes permettent de configurer les informations qui apparaissent au niveau de la liste des exports ainsi que le droit nécessaire pour y avoir accès.

$this->export_fields_array[$r]=array('s.rowid'=>"IdCompany",'s.nom'=>'CompanyName', ...

Cette ligne permet d’indiquer la liste des colonnes qui seront disponibles dans l’export. Il s’agit là d’indiquer le nom du champ issu de la requête SQL et de lui associer le nom qui apparaît dans la liste des champs. Les mécanismes de traduction de Dolibarr sont ici mis en œuvre. IdCompany sera traduit en français ou dans la langue choisie par l’utilisateur en fonction des traductions disponibles. Ces dernières sont dans le dossier htdocs/langs/xx_XX (fr_FR pour le français).

Cette ligne reproduite ici de façon incomplète peut être assez longue.

$this->export_TypeFields_array[$r]=array('s.nom'=>'Text','s.address'=>'Text','s.zip'=>'Text','s.town'=>'Text',...

Ce tableau reprend dans le même ordre que le précédent la liste des champs et permet de spécifier le type de la donnée contenue dans la colonne : Text, date, numeric, Boolean, Status, etc. Certains types de colonnes contenant des identifiants liés à une entité Dolibarr peuvent être lié à la table correspondant. Exemple : List:product:label qui permet dans la phase de définition des filtres de choisir un produit dans la liste de ceux qui existent.

$this->export_entities_array[$r]=array('s.rowid'=>"company",'s.nom'=>'company','s.address'=>'company', ...

Ce tableau a un objectif « cosmétique », celui de définir l’icône qui sera associé au champ dans la liste. Cela permet visuellement de savoir à quel type d’entité appartient un champ de l’export.

Suit ensuite pas mal de code lié à la gestion des champs complémentaires ajoutés aux entités. On finit par la requête correspondant à l’export.

$this->export_sql_start[$r]='SELECT DISTINCT ';
$this->export_sql_end[$r]  =' FROM '.MAIN_DB_PREFIX.'societe as s';
$this->export_sql_end[$r] .=' LEFT JOIN '.MAIN_DB_PREFIX.'c_country as c ON s.fk_pays = c.rowid,';
$this->export_sql_end[$r] .=' '.MAIN_DB_PREFIX.'facture_fourn as f';
$this->export_sql_end[$r] .=' LEFT JOIN '.MAIN_DB_PREFIX.'projet as project on (f.fk_projet = project.rowid)';
$this->export_sql_end[$r] .=' LEFT JOIN '.MAIN_DB_PREFIX.'facture_fourn_extrafields as extra ON f.rowid = extra.fk_object';
$this->export_sql_end[$r] .=' , '.MAIN_DB_PREFIX.'facture_fourn_det as fd';
$this->export_sql_end[$r] .=' LEFT JOIN '.MAIN_DB_PREFIX.'facture_fourn_det_extrafields as extraline ON fd.rowid = extraline.fk_object';
$this->export_sql_end[$r] .=' LEFT JOIN '.MAIN_DB_PREFIX.'product as p on (fd.fk_product = p.rowid)';
$this->export_sql_end[$r] .=' WHERE f.fk_soc = s.rowid AND f.rowid = fd.fk_facture_fourn';
$this->export_sql_end[$r] .=' AND f.entity IN ('.getEntity('supplier_invoice',1).')';

Jolie requête, non  ?

Où faut-il ajouter un export ?

Le premier réflexe serait d’ajouter son export dans une des classes existantes. C’est en effet la solution de facilité. Sauf qu’à la première mise à jour de Dolibarr, cet export sera effacé. Il vous faudra alors l’ajouter à nouveau. Peut-être rien d’insurmontable s’il ne s’agit que d’un seul export, mais si leur nombre augmente cela peut devenir pénible et risque d’oubli. Sans compter que si demain quelqu’un reprend votre travail, il se laissera peut-être piéger.

La solution qui me semble la plus propre et pérenne consiste à créer un module spécifique à mon client. L’avantage d’un module est qu’il permet de bien isoler le code que vous ajoutez à Dolibarr sans toucher au « cœur » du logiciel.

Alors comment crée-t-on un module ?

Sa création est documentée sur le Wiki de Dolibarr. Un module permet d’ajouter au cœur de Dolibarr de nouvelles fonctionnalités, de nouvelles tables de données, écrans, menus, etc., et de nouveaux exports.
À ce stade, il faut savoir que chaque module complémentaire à un descripteur et un identifiant unique qui est géré via cette page. Si votre module n’a pas vocation a être distribué, car spécifique à votre client, inutile de vous déclarer et de bloquer une plage d’identifiant. Utilisez un identifiant au-dessus de 500 000.

Un modèle complet de module est disponible sur Github.

Dans notre cas nous allons nous contenter de créer le strict minimum.

La structure de répertoire minimale de votre module doit contenir un répertoire core contenant lui-même un répertoire modules. L’ensemble est contenu dans un répertoire qui porte le nom de votre module. Pour l’exemple, il s’appellera par la suite « client ».

Il faut créer dans le répertoire modules un fichier dont le nom commence par mod suivi du nom de la classe qui définira votre module. Dans le cas de cet exemple, je l’appelle modClient.class.php.

J’utilise le fichier modMyModule.class.php fourni dans le modèle pour initialiser ce nouveau fichier en le renommant.

Éditons le contenu de ce fichier. À ce stade, il faut suivre scrupuleusement les instructions du wiki et les commentaires contenus dans le fichier. Voici un exemple. Les commentaires dans le fichier modèle et quelques tests vous permettront de trouver les bons réglages.

public function __construct($db)
{
  global $langs, $conf;
  $this->db = $db;
  $this->numero = 500100;
  $this->rights_class = 'client';
  $this->family = "other";
  $this->name = preg_replace('/^mod/i', '', get_class($this));
  $this->description = "Module spécifique Client";
  $this->version = 'dolibarr';
  $this->const_name = 'MAIN_MODULE_' . strtoupper($this->name);
  $this->special = 2;
  $this->picto = 'client@client'; // mypicto@mymodule
  $this->phpmin = array(5, 3);
  $this->need_dolibarr_version = array(3, 7);

À ce niveau vous devez voir apparaître votre module dans la liste. Une première victoire 

Ajoutons enfin notre export

Là encore il suffit d’adapter l’exemple fourni dans le modèle à son besoin et surtout à sa requête SQL. Voici un exemple

// Exports
$r = 0;
$r++;
$this->export_code[$r]=$this->rights_class.'_'.$r;
$this->export_label[$r]='Export';
$this->export_icon[$r]='bill';
$this->export_permission[$r]=array(array("fournisseur","facture","export"));
$this->export_fields_array[$r]=array('e.ref'=>'Reference','e.periode'=>'Periode','e.niveau1'=>'Niveau1','e.niveau2'=>'Niveau2','e.item'=>'Item','e.montantht'=>'Montant HT');
$this->export_entities_array[$r]=array('e.ref'=>'bill','e.periode'=>'bill','e.niveau1'=>'bill','e.niveau2'=>'bill','e.item'=>'bill','e.montantht'=>'bill');
$this->export_sql_start[$r]='SELECT DISTINCT ';
$this->export_sql_end[$r] =' FROM '.MAIN_DB_PREFIX.'extract_export as e';

Dans le cas présent, je m’appuie sur une vue qui fait tout le boulot d’agrégation des données. Vous n’êtes donc pas obligé d’utiliser uniquement des requêtes portant sur des tables.

Voilà le résultat dans Dolibarr.

Cet article ne se veut nullement exhaustif et reste approximatif sur pas mal de choses. Il s’agit avant tout de vous mettre le pied à l’étrier et je ne suis encore qu’un jeune Padawan Dolibarr  . Il y a d’autres façons de faire des exports comme je l’indiquais et peut-être certaines que je n’ai pas présentées ici. N’hésitez pas à compléter/corriger.