Aller au contenu principal
Making DigitalMaking Digital
Note technique

Personnaliser les modèles PDF de Dolibarr sans toucher au cœur

En bref

Pour personnaliser un devis, une facture ou un bon de livraison Dolibarr, on copie un modèle existant (par exemple pdf_cyan) dans un petit module de htdocs/custom déclaré avec 'models' => 1, on renomme ensemble le fichier, la classe et $this->name, puis on active le modèle dans la configuration du module. Les modèles du cœur ne doivent jamais être modifiés. Les PDF sont dessinés avec TCPDF.

Vous voulez vos devis aux couleurs de l'entreprise, une mention en plus sur les factures ou un bloc déplacé sur le bon de livraison. La tentation est d'ouvrir htdocs/core/modules/.../pdf_xxx.modules.php et de le modifier : c'est la seule chose à ne pas faire, la mise à jour suivante de Dolibarr écrasera le fichier. La méthode propre, celle de la documentation officielle : copier un modèle existant dans un petit module placé dans htdocs/custom, renommer le fichier, la classe et le nom du modèle, puis l'activer dans la configuration du module concerné. Les PDF sont produits avec la bibliothèque TCPDF (et non FPDF), livrée dans htdocs/includes/tecnickcom/tcpdf.

Faut-il vraiment coder ?

Pas toujours. Avant de copier un modèle, regardez Configuration > PDF (options communes à tous les documents) et la page de configuration de chaque module, qui propose un texte libre imprimé en bas des documents (par exemple PROPOSAL_FREE_TEXT pour les devis). Le logo et les coordonnées viennent de la fiche de votre société. Un modèle personnalisé se justifie quand la mise en page elle-même change.

Quel modèle copier pour quel document ?

Les modèles livrés sont dans htdocs/core/modules/<dossier>/doc/. Relevé dans le code de Dolibarr 24.0.2 :

Document Dossier Modèles livrés
Devis (proposition commerciale) propale/doc pdf_azur, pdf_cyan
Commande client commande/doc pdf_einstein, pdf_eratosthene, pdf_proforma
Facture facture/doc pdf_sponge, pdf_octopus
Expédition expedition/doc pdf_espadon, pdf_merou, pdf_rouget
Bon de livraison delivery/doc pdf_storm, pdf_typhon
Réception reception/doc pdf_squille
Commande fournisseur supplier_order/doc pdf_cornas, pdf_muscadet
Facture fournisseur supplier_invoice/doc pdf_canelle
Demande de prix fournisseur supplier_proposal/doc pdf_aurore, pdf_zenith
Intervention fichinter/doc pdf_soleil
Contrat contract/doc pdf_strato

Deux erreurs fréquentes dans les anciens tutoriels : les modèles de devis sont dans propale/doc et non dans expedition/doc, et pdf_crabe n'existe plus dans les versions actuelles (les factures utilisent pdf_sponge ou pdf_octopus).

Comment créer le module qui accueille le modèle ?

Un module minimal suffit. Depuis le dossier htdocs de Dolibarr, créez l'arborescence et copiez le modèle de départ, ici pdf_cyan pour les devis :

Terminal
mkdir -p custom/mespdf/core/modules/propale/doc
cp core/modules/propale/doc/pdf_cyan.modules.php custom/mespdf/core/modules/propale/doc/pdf_cyan_mesdocs.modules.php

Puis le descripteur du module :

PHP
<?php
// htdocs/custom/mespdf/core/modules/modMesPdf.class.php
include_once DOL_DOCUMENT_ROOT.'/core/modules/DolibarrModules.class.php';

class modMesPdf extends DolibarrModules
{
	public function __construct($db)
	{
		$this->db = $db;
		$this->numero = 500100; // > 500000 : pas de réservation si le module n'est pas diffusé
		$this->rights_class = 'mespdf';
		$this->family = 'other';
		$this->name = preg_replace('/^mod/i', '', get_class($this));
		$this->description = 'Nos modèles PDF personnalisés';
		$this->version = '1.0';
		$this->const_name = 'MAIN_MODULE_'.strtoupper($this->name);
		$this->picto = 'generic';
		$this->module_parts = array('models' => 1); // le module a son dossier core/modules/xxx/doc
		$this->config_page_url = array();
		$this->depends = array('modPropale');
		$this->langfiles = array();
		$this->const = array();
		$this->rights = array();
		$this->menu = array();
	}
}

La ligne qui compte est 'models' => 1 : elle ajoute le dossier du module à la liste des dossiers où Dolibarr cherche des modèles. Sans module, un fichier placé dans htdocs/custom/core/modules/propale/doc/ n'apparaît pas dans la liste : nous l'avons vérifié. Le numéro est libre au-delà de 500000 pour un module non diffusé (page "List of modules id" du wiki). Pour un module plus complet (droits, menus, pages de réglage), le Module Builder intégré à Dolibarr génère un squelette de départ.

Que faut-il renommer dans la copie ?

Trois choses, qui doivent concorder :

Diff
- class pdf_cyan extends ModelePDFPropales
+ class pdf_cyan_mesdocs extends ModelePDFPropales
...
- 		$this->name = "cyan";
+ 		$this->name = "cyan_mesdocs";

Le nom du fichier (pdf_cyan_mesdocs.modules.php) est le troisième élément : Dolibarr en déduit le nom du modèle (ce qui suit pdf_) et charge la classe pdf_ + nom au moment de générer le document. Les require_once DOL_DOCUMENT_ROOT.'/core/...' du début de fichier restent tels quels : ils pointent vers le cœur, qui ne bouge pas.

Comment activer le modèle ?

  1. Configuration > Modules / Applications : activez le module "MesPdf".
  2. Ouvrez la configuration du module Propositions commerciales : dans la liste des modèles de documents, cyan_mesdocs apparaît. Activez-le, et définissez-le par défaut si besoin.
  3. Sur un devis, choisissez le modèle et cliquez sur Générer.

L'activation écrit elle-même la ligne dans llx_document_model (et la constante PROPALE_ADDON_PDF pour le modèle par défaut) : l'INSERT manuel des anciens tutoriels est inutile. Pour générer un document depuis un script, l'API REST le permet :

Terminal
curl -X PUT "https://votre-dolibarr/api/index.php/documents/builddoc" \
  -H "DOLAPIKEY: votre_cle_api" -H "Content-Type: application/json" \
  -d '{"modulepart":"propal","original_file":"PR1007-0001/PR1007-0001.pdf","doctemplate":"cyan_mesdocs","langcode":"fr_FR"}'

Que modifier dans le code du modèle ?

Un modèle fait plus de 2 000 lignes (2 318 pour pdf_cyan), mais il est découpé en méthodes faciles à repérer : write_file() (assemblage du document, page par page), _pagehead() (logo, titre, adresses), _tableau() (cadre du tableau des lignes), defineColumnField() (colonnes : description, TVA, quantité...), drawInfoTable() (conditions et mode de règlement, délai de livraison), drawTotalTable() (totaux), drawSignatureArea() et _pagefoot() (pied de page). Le dessin se fait avec les méthodes TCPDF : SetFont(), SetTextColor(), SetXY() pour se placer en millimètres, MultiCell() ou writeHTMLCell() pour écrire.

Exemple : le titre du devis en bleu au lieu du bleu nuit d'origine, dans _pagehead() :

Diff
 		$pdf->SetFont('', 'B', $default_font_size + 3);
 		$pdf->SetXY($posx, $posy);
- 		$pdf->SetTextColor(0, 0, 60);
+ 		$pdf->SetTextColor(10, 132, 255); // titre en bleu
 		$title = $outputlangs->transnoentities("PdfCommercialProposalTitle");

Dans notre test, le PDF produit par la copie contenait bien la nouvelle couleur, absente du PDF généré avec cyan, et indiquait "TCPDF 6.7.5" comme producteur.

Et les modèles ODT ?

Dolibarr sait aussi remplir des modèles ODT (doc_generic_proposal_odt pour les devis), modifiables dans LibreOffice sans PHP. Leur limite : ils produisent un fichier ODT. La conversion en PDF passe par la constante MAIN_ODT_AS_PDF réglée sur libreoffice, qui lance soffice en ligne de commande : LibreOffice doit donc être installé sur le serveur. Pour un rendu PDF précis et sans dépendance, nous restons sur un modèle PHP copié.

À chaque mise à jour de Dolibarr, comparez votre copie avec la nouvelle version du modèle d'origine : les corrections du cœur n'arrivent pas toutes seules dans votre fichier. Nous développons ce type de modèle, et plus largement des applications sur mesure autour des ERP, que nous hébergeons et maintenons. Des documents à refaire ? Parlons-en.

À retenir
  • Ne jamais modifier les modèles de htdocs/core : une mise à jour les écrase.
  • Copier le modèle dans un module de htdocs/custom déclaré avec 'models' => 1.
  • Renommer ensemble le fichier, la classe et $this->name, puis activer le modèle dans la configuration du module.
  • La bibliothèque est TCPDF : SetFont, SetTextColor, SetXY, MultiCell.

Testé avec Dolibarr 24.0.2 (TCPDF 6.7.5) et MariaDB 11.4.13.

Questions fréquentes

Mon modèle n'apparaît pas dans la liste, pourquoi ?

Vérifiez trois points : le module qui le contient est activé et déclare 'models' => 1, le fichier est dans le bon dossier (core/modules/propale/doc pour un devis), et le nom du fichier, la classe et $this->name concordent.

Peut-on garder le modèle d'origine en parallèle ?

Oui. Plusieurs modèles peuvent être actifs pour un même type de document : dans notre test, cyan et cyan_mesdocs étaient actifs ensemble, l'un des deux étant proposé par défaut.

La copie est-elle écrasée par une mise à jour de Dolibarr ?

Non, une mise à jour remplace les fichiers du cœur, pas ceux de htdocs/custom. Comparez toutefois votre copie avec la nouvelle version du modèle d'origine pour reprendre les corrections utiles.

Où sont enregistrés les PDF générés ?

Dans le dossier des documents de Dolibarr, un sous-dossier par document : par exemple documents/propale/PR1007-0001/PR1007-0001.pdf pour un devis.

Making Digital

Nous connectons les logiciels des PME, automatisons leurs tâches répétitives et créons des assistants IA, depuis 2010. Nos articles partent de nos projets réels.

Notre parcours
Une question sur ce sujet ?

Parlons-en 30 minutes.

Vous saurez si votre problème se règle, comment, et en combien de temps. Sans engagement.

Un échange de 30 minutes, en visio ou par téléphone

Gratuit, sans engagement. On parle de votre problème, pas de technique.