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 :
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 // 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 :
- 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 ?
- Configuration > Modules / Applications : activez le module "MesPdf".
- Ouvrez la configuration du module Propositions commerciales : dans la liste des modèles de documents,
cyan_mesdocsapparaît. Activez-le, et définissez-le par défaut si besoin. - 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 :
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() :
$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.
- Ne jamais modifier les modèles de
htdocs/core: une mise à jour les écrase. - Copier le modèle dans un module de
htdocs/customdé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.