myFAB Rapport docx
myFAB · Rapport DOCX — Référence rapide
Prérequis:pip install docxtpl docxcompose htmldocx· LibreOffice requis pour le mode PDF
Créer un paramétrage
Technique → Rapport DOCX → Configurations → Nouveau
| Champ | Valeur attendue | Obligatoire |
|---|---|---|
| Nom du rapport | Libellé affiché dans l'interface | ✓ |
| Code rapport | Identifiant technique unique, sans espaces — ex : `declaration_conformite_ce` |
✓ |
| Modèle | Modèle Odoo cible (ex : `sale.order`, `mrp.production`) |
✓ |
| Champ nom fichier | Champ `Char` du modèle utilisé pour nommer le fichier |
✓ |
| Template DOCX | Fichier `.docx` avec balises Jinja2 |
✓ |
| Préfixe | Texte ajouté au début du nom de fichier généré | |
| Mode de fusion | `composer` (DOCX unique) · `zip` (un fichier/enregistrement) · `pdf` (via LibreOffice) |
✓ |
| Nom fichier impression | Formule Jinja — ex : `{{ docs.name }}` |
|
| Autoescape | Activer si le template contient `<`, `>` ou `&` |
Publier via le bouton Publier — tous les champs passent en lecture seule.
Pour modifier : Dépublier d'abord.
Syntaxe du template
Champs
{{docs.nom_du_champ}}
{{docs.relation_id.champ}}
Fonctions utilitaires
| Fonction | Description |
|---|---|
`{{spelled_out(docs.champ)}}` |
Nombre en toutes lettres |
`{{formatdate(docs.champ)}}` |
Date formatée (Babel, `fr_FR` par défaut) |
`{{fdate(docs.champ, "%d/%m/%Y")}}` |
Date avec format personnalisé |
`{{fnum(docs.champ, " ", ",", 2)}}` |
Numérique — `fnum(val, sep_milliers, sep_décimal, décimales)` |
`{{parsehtml(docs.champ)}}` |
HTML → texte brut |
`{{p html2docx(docs.champ)}}` |
HTML → sous-document Word |
`{{convert_currency(docs.champ, docs.currency_id)}}` |
Montant avec devise |
`{{render_image(docs.champ, width=30, height=30)}}` |
Image binaire (mm) |
`{{r rich_text(docs.champ)}}` |
Texte enrichi |
`{{p add_subdoc(docs.champ)}}` |
Sous-document DOCX binaire |
`{{replace_image('nom', docs.champ)}}` |
Remplacement d'image dans le template |
Langue surchargeable par fonction :
{{formatdate(docs.champ, lang='en_US')}}
Boucles dans un tableau
Chaque directive {%tr %} doit occuper une ligne entière du tableau, avec une cellule fusionnée sur toute la largeur.
{%tr for line in docs.order_line_ids %}
{{line.product_id.display_name}} | {{line.qty}} | {{line.price_unit}}
{%tr endfor %}
- Les lignes
foretendforsont supprimées du rendu final. - Les champs s'accèdent via la variable de boucle (
line).
Conditions dans un tableau
Utiliser impérativement if / else / endif — deux blocs if séparés provoquent une TemplateSyntaxError.
{%tr for line in docs.order_line_ids %}
{%tr if not line.uom_qty %}
[cellule fusionnée] {{line.product_id.display_name}} ← ligne de section
{%tr else %}
{{line.product_id.display_name}} | {{line.uom_qty}} | {{line.price_unit}}
{%tr endif %}
{%tr endfor %}
Ordre obligatoire : for → if → else → endif → endfor
Préférer
not line.champàline.champ == 0pour couvrir0,0.0,FalseetNone.
La directive
{%tr if %}et le contenu{{champ}}doivent être dans deux<w:r>séparés dans le XML Word — sinon le contenu ne s'affiche pas.
Mode PDF
Configurer le chemin LibreOffice dans Paramètres → Technique → Paramètres système :
| OS | Valeur |
|---|---|
| Linux | `/usr/bin/libreoffice` |
| Windows | `C:\Program Files\LibreOffice\program\soffice.exe` |
Clé : default_libreoffice_path
Erreurs courantes
| Erreur | Cause | Solution |
|---|---|---|
`TemplateSyntaxError: unknown tag 'endif'` |
Deux blocs `if` séparés dans un `for` |
Remplacer par `if / else / endif` |
| Ligne fusionnée vide | `{%tr if %}` et `{{champ}}` dans le même `` |
Les séparer en deux runs distincts |
Condition `== 0` ignorée |
Le champ est un `float` (`0.0 != 0`) |
Utiliser `not line.champ` |
| Erreur 500 générique | Erreur Python non affichée | `journalctl -u odoo -n 100` ou `tail -f /var/log/odoo/odoo.log` |
| PDF non généré | LibreOffice absent ou mal configuré | Installer + configurer `default_libreoffice_path` |
Exemple action serveur pour générer une rapport et le mettre en pièce jointe directement d'un OF
report_name = 'DOCX-OF'
report = env['ir.actions.report']._get_report_from_name(report_name)
if not report:
raise UserError("Le rapport DOCX '%s' est introuvable." % report_name)
file_content, file_extension = report._render_docx(report_name,[object.id],data={}
)
if file_extension != 'docx':raise UserError("Le rapport retourne '%s' au lieu de 'docx'."% file_extension)
document = env['document.openprod'].create({'name': 'Rapport DOCX - %s' % object.name,'extension': 'docx','document_type': 'document','attachment': b64encode(file_content),'directory_id': env.ref('base_openprod.default_document_directory').id,'user_id': env.user.id,'company_id': object.company_id.id or env.company.id,'date': datetime.date.today(),
#Liaison avec l'OF
'internal_plan_ids': [(4, object.id)],
})
Note 1 : En cas d'erreur à l'installation du module : installer les modules python docxtpl, docxcompose, htmldocx sur serveur openprod : récupérer l'environnement openprod en faisant un openprod-status :
Exécuter la commande suivante sur l'environnement python (adapter le début le cas échéant) :
/etc/openprod_home/openprod10/venv3/bin/python3.10 -m pip install docxtpl docxcompose htmldocx
Note 2 : Pour faire fonctionner le mode génération en PDF, il est nécessaire d'installer libre office sur votre serveur openprod. Pour cela excecutez la commande suivante depuis votre serveur openprod :
sudo apt-get install libreoffice