Personnalisations

Modèles Jinja

Utiliser les variables et les fonctions Jinja dans les modèles d'email, les notifications et les formats d'impression.

Modèles Jinja

Jinja est le langage de modèle de Dokos. Il mélange du HTML et des expressions entre accolades. Vous l'utilisez dans les modèles d'email, les notifications et les formats d'impression personnalisés.

La documentation du langage est sur le site de Jinja.

Syntaxe de base

SyntaxeRôleExemple
{{ … }}Affiche une valeur{{ doc.customer_name }}
{% … %}Exécute une instruction (if, for, set){% if doc.due_date %}…{% endif %}
{# … #}Commentaire, non affiché{# à revoir #}

Un filtre transforme une valeur. Il s'écrit après une barre verticale :

{{ doc.posting_date | global_date_format }}

Variables disponibles

Les variables dépendent de l'endroit où le modèle est utilisé :

ContexteAccès au documentAutres variables
Format d'impressiondocmeta, letter_head, footer, no_letterhead, print_settings, print_heading_template
Notificationdocnowdate, frappe
Modèle d'emailLes champs directement, sans préfixe doc. : {{ customer_name }}email_signature et email_footer si Utiliser le HTML est coché

Pour trouver le nom d'un champ, ouvrez le document puis Personnaliser dans le menu. Le nom figure dans la colonne Nom du champ.

Fonctions disponibles

Par défaut, un modèle Jinja tourne dans un environnement restreint. Il lit les données, mais ne les modifie pas.

DomaineFonctions
Documentsfrappe.get_doc, frappe.get_cached_doc, frappe.get_last_doc : renvoient une copie en lecture seule du document. get_formatted() reste disponible. save(), insert() et submit() ne le sont pas.
Listesfrappe.get_list (avec permissions), frappe.get_all (sans permissions)
Base de donnéesfrappe.db.get_value, frappe.db.get_single_value, frappe.db.get_list, frappe.db.get_all, frappe.db.exists, frappe.db.count, frappe.db.get_default, frappe.db.escape, frappe.db.sql (lecture seule : SELECT et EXPLAIN), frappe.qb
Métadonnéesfrappe.get_meta (copie en lecture seule, avec get_field, has_field, get_label, get_options)
Formatagefrappe.format_value, frappe.format_date, frappe.date_format, frappe.time_format, frappe.bold, _() (traduction)
Utilitairesfrappe.utils (sélection : formatdate, getdate, get_time, add_days, flt, fmt_money, money_in_words, get_url_to_form…), frappe.get_url, frappe.render_template, frappe.get_system_settings, frappe.get_hooks, frappe.sanitize_html, html2text, json.loads, json.dumps
Sessionfrappe.session.user, frappe.user, frappe.get_fullname, frappe.form_dict, frappe.request.path, frappe.lang
Requêtesfrappe.make_get_request (HTTP et HTTPS uniquement, adresses internes bloquées)
Filtresglobal_date_format, markdown, abs_url

Ces fonctions ne sont pas disponibles dans un modèle Jinja : frappe.new_doc, frappe.db.set_value, frappe.db.commit, frappe.sendmail, frappe.enqueue, frappe.make_post_request et les autres fonctions d'écriture. Utilisez un script Python pour modifier des données.

Exception : dans une notification, la variable frappe est celle des scripts Python. frappe.get_doc y renvoie le document complet. Évitez d'y appeler des fonctions d'écriture : une notification doit seulement afficher des données.

L'administrateur du serveur peut lever la restriction pour tous les sites avec la clé disable_render_safe_exec: 1 dans common_site_config.json. Les modèles ont alors accès aux mêmes fonctions que les scripts Python. Ce réglage réduit la sécurité : un utilisateur qui modifie un modèle peut alors écrire en base.

Exemple de modèle d'email

Ce modèle s'utilise depuis une facture de vente. Il lit la fiche du contact indiqué dans le champ contact_person, puis affiche son prénom.

{% if contact_person %}
{% set contact = frappe.get_doc("Contact", contact_person) %}
Bonjour {{ contact.first_name }},
{% else %}
Bonjour,
{% endif %}

Veuillez trouver ci-joint votre facture {{ name }}.

Le total à régler est de {{ frappe.format_value(grand_total, {"fieldtype": "Currency"}) }}.

Bien cordialement,

Dans un modèle d'email, les champs s'écrivent sans le préfixe doc. : contact_person, name, grand_total.

Exemple de notification

Cette notification part à la validation d'une facture de vente. Elle liste les articles dans un tableau HTML.

<p>Bonjour {{ doc.contact_display or "" }},</p>

<p>Votre facture {{ doc.name }} du {{ frappe.utils.formatdate(doc.posting_date) }} est disponible.</p>

<table class="table table-bordered">
  <thead>
    <tr><th>Article</th><th>Quantité</th><th>Montant</th></tr>
  </thead>
  <tbody>
    {% for item in doc.items %}
    <tr>
      <td>{{ item.item_name }}</td>
      <td>{{ item.get_formatted("qty") }}</td>
      <td>{{ item.get_formatted("amount", doc) }}</td>
    </tr>
    {% endfor %}
  </tbody>
</table>

<p>Total : {{ doc.get_formatted("grand_total") }}</p>

get_formatted("amount", doc) formate le montant dans la devise du document parent.

Exemple de format d'impression

Cet extrait affiche l'en-tête, l'adresse du client et le numéro de TVA dans un format d'impression de facture de vente.

{% if letter_head and not no_letterhead %}
<div class="letter-head">{{ letter_head }}</div>
{% endif %}

<h2>{{ _("Invoice") }} {{ doc.name }}</h2>

{%- if doc.docstatus == 0 and (print_settings == None or print_settings.add_draft_heading) -%}
<h4 class="text-center">{{ _("DRAFT") }}</h4>
{%- endif -%}

<p><strong>{{ doc.customer_name }}</strong></p>
{% if doc.customer_address %}
  {% set address = frappe.get_doc("Address", doc.customer_address) %}
  <p>
    {{ address.address_line1 }}<br>
    {% if address.address_line2 %}{{ address.address_line2 }}<br>{% endif %}
    {{ address.pincode }} {{ address.city }}<br>
    {{ address.country }}
  </p>
{% endif %}

{% set tax_id = frappe.db.get_value("Customer", doc.customer, "tax_id") %}
{% if tax_id %}
<p>{{ _("Tax Id") }} : {{ tax_id }}</p>
{% endif %}

<p>{{ _("Date") }} : {{ doc.get_formatted("posting_date") }}</p>
<p>{{ _("Due Date") }} : {{ doc.get_formatted("due_date") }}</p>
<p><strong>{{ _("Grand Total") }} : {{ doc.get_formatted("grand_total") }}</strong></p>

{% if not no_letterhead and footer %}
<div class="letter-head-footer">{{ footer }}</div>
{% endif %}

Pour créer le format et le tester, voir Formats d'impression.