Aide · silicon ioi

Email Template - Jinja

Fiche

Introduction et objectifs #

Ce guide vous révèle comment dynamiser et automatiser vos communications clients grâce à Jinja et Frappe. Que ce soit pour des factures, des relances ou des confirmations, découvrez comment créer des emails intelligents, multilingues et sur mesure, adaptés à chaque destinataire.

Qu’est-ce que Jinja ? #

Jinja est un moteur de templating pour Python, largement utilisé pour générer du contenu dynamique (HTML, emails, fichiers de configuration, etc.). Il permet de séparer la logique de présentation (ce qui est affiché) de la logique métier (le code Python). Jinja est utilisé avec le frameworks Frappe pour créer des pages ou des emails dynamiques.

Site officiel : https://jinja.palletsprojects.com/en/stable/templates

Pourquoi utiliser Jinja ? #

  • Séparation des responsabilités : le code Python et la présentation sont séparés.
  • Réutilisabilité : les templates peuvent être inclus ou étendus.
  • Flexibilité : logique conditionnelle, boucles, filtres, etc.
  • Intégration facile avec Frappe.

Fonctionnement de base: #

  • Syntaxe : Jinja utilise des balises pour insérer des variables, des boucles, des conditions, etc.
  • Variables : {{ variable }}
  • Instructions : {% instruction %}
  • Commentaires : {# commentaire #}

Fonctions et balises les plus utilisées: #

Fonction/Balise Exemple
Affichage de variables {{ variable }}
Récupérer une valeur du DocType {{ master.nom_du_champ }}
Structures conditionnelles {% if condition %} Contenu si condition vraie {% elif autre_condition %} Contenu si autre_condition vraie {% else %} Contenu sinon {% endif %}
Boucles {% for item in liste %} {{ item }} {% endfor %}
Définition de variables {% set ma_variable = “valeur” %}
Filtres {{ variable | filtre }}
Inclusion de templates {% include “autre_template.html” %}
Héritage de templates {% extends “base.html” %}
Macros {% macro ma_macro(arg1, arg2) %} {{ arg1 }} - {{ arg2 }} {% endmacro %}

Cas client : envoi de factures par Email #

Problématique initiale : Besoin d’envoyer des factures directement par email avec personnalisation du texte selon la langue du client.

Solution proposée : Silicon ioi permet de générer et envoyer des emails directement depuis l’interface, avec prévisualisation, pièces jointes automatiques, traduction automatique, et personnalisation du sujet et du corps de l’email.

Pour la personnalisation du mail envoyé, utilisation de l’Email Template.

Interface Email Template #

Il faut cocher la case **Use HTML** si utilisation des balises HTML dans le template.

Exemple de sujet d’Email: #

{{ _("Invoice", master.language) }} Silicon ioi - {{ master.name }} {{ frappe.utils.format_date(frappe.utils.nowdate(), "dd-MM-yyyy") }}

Exemple de corps d’Email (multilingue): #

{%- set doc = frappe.get_doc('ioi Sales Invoice', master.name) -%}
{%- set customerContact = frappe.get_doc('Contact', doc.invoice_customer_contact_id) if doc.invoice_customer_contact_id else None -%}
{# Traduction automatique en fonction de la langue #}

{% if doc.language == 'fr' %}

{% if customerContact and customerContact.gender == 'Male' %}

{% set salutation = 'Cher' %}

{% elif customerContact and customerContact.gender == 'Female' %}

{% set salutation = 'Chère' %}

{% else %}

{% set salutation = 'Cher/Cher(e)' %}

{% endif %}

{{ salutation }} {% if customerContact.last_name %}{{ customerContact.last_name }}{% else %}Client{% endif %},

Nous vous remercions pour votre confiance.

Vous trouverez ci-joint la facture <strong>{{ doc.prefix_id }}{{ doc.identification }}</strong> d'un montant de <strong>{{ "%.2f"|format(doc.total_tvac)|replace('.', ',') }}{{ doc.currency_id }}</strong>.

Date d'échéance : <strong>{{ doc.due_date.strftime('%d-%m-%Y') }}</strong>.

Cordialement, Votre équipe <span style="color: #5A14E6; font-weight: bold;">Silicon ioi</span>

{%- elif doc.language == 'nl' -%}

{# Version néerlandaise #}

{% if customerContact and customerContact.gender == 'Male' %}

{% set salutation = 'Geachte heer' %}

{% elif customerContact and customerContact.gender == 'Female' %}

{% set salutation = 'Geachte mevrouw' %}

{% else %}

{% set salutation = 'Beste' %}

{% endif %}

{{ salutation }} {% if customerContact.last_name %}{{ customerContact.last_name }}{% else %}klant{% endif %},

Hartelijk dank voor uw vertrouwen.

Bijgevoegd vindt u factuur <strong>{{ doc.prefix_id }}{{ doc.identification }}</strong> met een bedrag van <strong>{{ "%.2f"|format(doc.total_tvac)|replace('.', ',') }}{{ doc.currency_id }}</strong>.

Vervaldatum: <strong>{{ doc.due_date.strftime('%d-%m-%Y') }}</strong>.

Met vriendelijke groet, Uw <span style="color: #5A14E6; font-weight: bold;">Silicon ioi</span>-team

Structure d’un template Jinja pour les Emails #

Élément Syntaxe JINJA Exemple
Variable {{ variable }} {{ client.nom }}
Condition {% if condition %}…{% endif %} {% if client.statut == “premium” %}…{% endif %}
Boucle {% for item in list %}…{% endfor %} {% for produit in produits %}{{ produit.nom }}{% endfor %}
Définition variable {% set var = value %} {% set salutation = “Cher” %}
Commentaire {# commentaire #} {# Ce texte n’apparaît pas dans le rendu #}
Traduction {{ _(“text”, lang) }} {{ _(“Invoice”, master.language) }}
Formatage nombre {{ “%.2f”|format(number) }} {{ “%.2f”|format(1234.5678)|replace(‘.’, ‘,’) }}
Formatage date {{ date.strftime(‘%d-%m-%Y’) }} {{ frappe.utils.nowdate()|strftime(‘%d-%m-%Y’) }}

Tutoriel : template Jinja/Frappe pour les Emails de facturation #

Introduction #

Ce tutoriel explique comment utiliser Jinja et Frappe pour générer dynamiquement des emails de facturation multilingues. Le template s’adapte à la langue du client et insère des données dynamiques comme le numéro de facture, le montant, la date d’échéance, etc.

Structure du template #

Ligne de sujet #

{{ _("Invoice", master.language) }} Silicon ioi - {{ master.name }} {{ frappe.utils.format_date(frappe.utils.nowdate(), "dd-MM-yyyy") }}
-	{{ _("Invoice", master.language) }} : Traduit "Invoice" selon la langue du document.
-	{{ master.name }} : Numéro de la facture.
-	{{ frappe.utils.format_date(...) }} : Date du jour formatée.

Exemple de sortie :

Facture Silicon ioi - FCL2026020018 04-03-2026

Corps de l’email #

Le corps du template est divisé en sections selon la langue (doc.language). Voici la structure commune et les sections spécifiques à chaque langue.

Structure commune #
{%- set doc = frappe.get_doc('ioi Sales Invoice', master.name) -%}

{%- set customerContact = frappe.get_doc('Contact', doc.invoice_customer_contact_id) if doc.invoice_customer_contact_id else None -%}

Sections par langue

Le template vérifie la valeur de doc.language et affiche la section correspondante.

Exemple pour le français (fr)

{% if doc.language == 'fr' %}

{% if customerContact and customerContact.gender == 'Male' %}

{% set salutation = 'Cher' %}

{% elif customerContact and customerContact.gender == 'Female' %}

{% set salutation = 'Chère' %}

{% else %}

{% set salutation = 'Cher/Cher(e)' %}

{% endif %}

{{ salutation }} {% if customerContact.last_name %}{{ customerContact.last_name }}{% else %}Client{% endif %},

Nous vous remercions pour votre confiance.

Facture : <strong>{{ doc.prefix_id }}{{ doc.identification }}</strong> ({{ "%.2f"|format(doc.total_tvac)|replace('.', ',') }}{{ doc.currency_id }}).

Échéance : <strong>{{ doc.due_date.strftime('%d-%m-%Y') }}</strong>.

Cordialement, Votre équipe <span style="color: #5A14E6; font-weight: bold;">Silicon ioi</span>

{% endif %}

Exemple pour le néerlandais (nl)

{%- elif doc.language == 'nl' -%}

{# Version néerlandaise #}

{% if customerContact and customerContact.gender == 'Male' %}

{% set salutation = 'Geachte heer' %}

{% else %}

{% set salutation = 'Beste' %}

{% endif %}

{{ salutation }} {% if customerContact.last_name %}{{ customerContact.last_name }}{% else %}klant{% endif %},

Hartelijk dank voor uw vertrouwen.

Factuur : <strong>{{ doc.prefix_id }}{{ doc.identification }}</strong> ({{ "%.2f"|format(doc.total_tvac)|replace('.', ',') }}{{ doc.currency_id }}).

Vervaldatum : <strong>{{ doc.due_date.strftime('%d-%m-%Y') }}</strong>.

Met vriendelijke groet, Uw <span style="color: #5A14E6; font-weight: bold;">Silicon ioi</span>-team

Exemple pour l'anglais (en)

{%- elif doc.language == 'en' -%}

{# Version anglaise #}

{% if customerContact and customerContact.gender == 'Male' %}

{% set salutation = 'Dear Mr.' %}

{% elif customerContact and customerContact.gender == 'Female' %}

{% set salutation = 'Dear Ms.' %}

{% else %}

{% set salutation = 'Dear' %}

{% endif %}

{{ salutation }} {% if customerContact.last_name %}{{ customerContact.last_name }}{% else %}Customer{% endif %},

Thank you for your trust.

Invoice: <strong>{{ doc.prefix_id }}{{ doc.identification }}</strong> ({{ "%.2f"|format(doc.total_tvac)|replace('.', ',') }}{{ doc.currency_id }}).

Due date: <strong>{{ doc.due_date.strftime('%d-%m-%Y') }}</strong>.

Best regards, Your <span style="color: #5A14E6; font-weight: bold;">Silicon ioi</span> team

Exemple pour l'allemand (de)

{%- elif doc.language == 'de' -%}

{# Version allemande #}

{% if customerContact and customerContact.gender == 'Male' %}

{% set salutation = 'Sehr geehrter Herr' %}

{% elif customerContact and customerContact.gender == 'Female' %}

{% set salutation = 'Sehr geehrte Frau' %}

{% else %}

{% set salutation = 'Sehr geehrte(r)' %}

{% endif %}

{{ salutation }} {% if customerContact.last_name %}{{ customerContact.last_name }}{% else %}Kunde{% endif %},

Vielen Dank für Ihr Vertrauen.

Rechnung: <strong>{{ doc.prefix_id }}{{ doc.identification }}</strong> ({{ "%.2f"|format(doc.total_tvac)|replace('.', ',') }}{{ doc.currency_id }}).

Fälligkeitsdatum: <strong>{{ doc.due_date.strftime('%d-%m-%Y') }}</strong>.

Mit freundlichen Grüßen, Ihr <span style="color: #5A14E6; font-weight: bold;">Silicon ioi</span>-Team

{%- endif -%}

Pied de page #

{# Pied de page avec logo et coordonnées #}

<a href="http://www.silicon-ioi.online">

<img src="https://silicon-ioi.online/files/.../logo.png" alt="Logo" width="250">

</a>

<span style="color: #5A14E6; font-weight: bold;">Silicon ioi – Digitalize your business</span>

<a href="http://www.silicon-ioi.online" style="color: #5A14E6;">www.silicon-ioi.online</a>

<span style="color: #999999;">Silicon ioi | xxx, xxx xxx | xxx</span>

**Fonctions clés utilisées :**

{{ _("texte", language) }}

Traduit un texte dans la langue spécifiée.

frappe.get_doc()

Récupère un document Frappe (ex: une facture, un contact).

strftime()

Formate une date (ex: {{ date.strftime('%d-%m-%Y') }}).

{% set var = value %}

Définit une variable dans le template.

{% if/elif/else %}

Structures conditionnelles.

{% for item in list %}

Boucles pour parcourir des listes ou dictionnaires.

Exemple de Sortie Complète

Sujet

Facture Silicon ioi - FCL2026020018 04-03-2026

Corps (pour le français)

Cher Dupont,

Nous vous remercions pour votre confiance.

Facture : FCL2026020018 (1130,00 EUR).

Échéance : 03-02-2026.

Cordialement, Votre équipe Silicon ioi

Exemple complet : template multilingue pour factures #

Sujet: #
{{ _("Invoice", master.language) }} Silicon ioi - {{ master.name }} {{ frappe.utils.format_date(frappe.utils.nowdate(), "dd-MM-yyyy") }}
Corps: #
{%- set doc = frappe.get_doc('ioi Sales Invoice', master.name) -%}

{%- set customerContact = frappe.get_doc('Contact', doc.invoice_customer_contact_id) if doc.invoice_customer_contact_id else None -%}

{# Salutation adaptée à la langue et au genre #}

{% if doc.language == 'fr' %}

{% if customerContact and customerContact.gender == 'Male' %}

{% set salutation = 'Cher' %}

{% elif customerContact and customerContact.gender == 'Female' %}

{% set salutation = 'Chère' %}

{% else %}

{% set salutation = 'Cher/Cher(e)' %}

{% endif %}

{{ salutation }} {% if customerContact.last_name %}{{ customerContact.last_name }}{% else %}Client{% endif %},

Nous vous remercions pour votre confiance.

Facture : <strong>{{ doc.prefix_id }}{{ doc.identification }}</strong> ({{ "%.2f"|format(doc.total_tvac)|replace('.', ',') }}{{ doc.currency_id }}).

Échéance : <strong>{{ doc.due_date.strftime('%d-%m-%Y') }}</strong>.

Cordialement, Votre équipe <span style="color: #5A14E6; font-weight: bold;">Silicon ioi</span>

{%- elif doc.language == 'nl' -%}

{# Version néerlandaise #}

{% if customerContact and customerContact.gender == 'Male' %}

{% set salutation = 'Geachte heer' %}

{% else %}

{% set salutation = 'Beste' %}

{% endif %}

{{ salutation }} {% if customerContact.last_name %}{{ customerContact.last_name }}{% else %}klant{% endif %},

Hartelijk dank voor uw vertrouwen.

Factuur : <strong>{{ doc.prefix_id }}{{ doc.identification }}</strong> ({{ "%.2f"|format(doc.total_tvac)|replace('.', ',') }}{{ doc.currency_id }}).

Vervaldatum : <strong>{{ doc.due_date.strftime('%d-%m-%Y') }}</strong>.

Met vriendelijke groet, Uw <span style="color: #5A14E6; font-weight: bold;">Silicon ioi</span>-team

{%- elif doc.language == 'en' -%}

{# Version anglaise #}

{% if customerContact and customerContact.gender == 'Male' %}

{% set salutation = 'Dear Mr.' %}

{% elif customerContact and customerContact.gender == 'Female' %}

{% set salutation = 'Dear Ms.' %}

{% else %}

{% set salutation = 'Dear' %}

{% endif %}

{{ salutation }} {% if customerContact.last_name %}{{ customerContact.last_name }}{% else %}Customer{% endif %},

Thank you for your trust.

Invoice: <strong>{{ doc.prefix_id }}{{ doc.identification }}</strong> ({{ "%.2f"|format(doc.total_tvac)|replace('.', ',') }}{{ doc.currency_id }}).

Due date: <strong>{{ doc.due_date.strftime('%d-%m-%Y') }}</strong>.

Best regards, Your <span style="color: #5A14E6; font-weight: bold;">Silicon ioi</span> team

{%- elif doc.language == 'de' -%}

{# Version allemande #}

{% if customerContact and customerContact.gender == 'Male' %}

{% set salutation = 'Sehr geehrter Herr' %}

{% elif customerContact and customerContact.gender == 'Female' %}

{% set salutation = 'Sehr geehrte Frau' %}

{% else %}

{% set salutation = 'Sehr geehrte(r)' %}

{% endif %}

{{ salutation }} {% if customerContact.last_name %}{{ customerContact.last_name }}{% else %}Kunde{% endif %},

Vielen Dank für Ihr Vertrauen.

Rechnung: <strong>{{ doc.prefix_id }}{{ doc.identification }}</strong> ({{ "%.2f"|format(doc.total_tvac)|replace('.', ',') }}{{ doc.currency_id }}).

Fälligkeitsdatum: <strong>{{ doc.due_date.strftime('%d-%m-%Y') }}</strong>.

Mit freundlichen Grüßen, Ihr <span style="color: #5A14E6; font-weight: bold;">Silicon ioi</span>-Team

{%- endif -%}

{# Pied de page avec logo et coordonnées #}

<a href="http://www.silicon-ioi.online">

<img src="https://silicon-ioi.online/files/.../logo.png" alt="Logo" width="250">

</a>

<span style="color: #5A14E6; font-weight: bold;">Silicon ioi – Digitalize your business</span>

<a href="http://www.silicon-ioi.online" style="color: #5A14E6;">www.silicon-ioi.online</a>

<span style="color: #999999;">Silicon ioi | xxx, xxx xxx | xxx</span>

Méthode avec utilisation d’une macro #

Dans le contexte de Jinja, une macro est un outil qui permet de définir un bloc de code réutilisable, un peu comme une fonction en programmation. Elle permet d’éviter la répétition et de rendre le template plus modulaire, plus lisible et plus facile à maintenir.

Explication des Macros en Jinja #

Définition d’une Macro #

Une macro se définit avec la syntaxe suivante :

{% macro nom_de_la_macro(param1, param2, ...) %}

{# Contenu de la macro #}

{{ param1 }} fait quelque chose avec {{ param2 }}.

{% endmacro %}

macro : Mot-clé pour déclarer une macro.

nom_de_la_macro : Nom donné à la macro pour l'appeler plus tard.

param1, param2, ... : Paramètres à passer à la macro pour la personnaliser.

Utilisation d’une Macro #

Une fois définie, on peut appeler la macro autant de fois que nécessaire dans le template, en lui passant des valeurs différentes :

{{ nom_de_la_macro("valeur1", "valeur2", ...) }}

Exemple dans notre cas où le code Jinja répétait la même structure pour chaque langue :

{% if doc.language == 'fr' %}

{# Logique pour le français #}

{% elif doc.language == 'nl' %}

{# Logique pour le néerlandais #}

...

{% endif %}

→ Répétition de la logique de salutation et de la structure du corps de l’email.

Solution avec une Macro :

→ Créer une macro email_body pour centraliser la logique commune et éviter la répétition.

{%- macro email_body(lang, male_salutation, female_salutation, default_salutation, thank_you, invoice_label, due_date_label, regards) -%}

{# Logique de salutation et corps de l'email #}

{{ salutation }} {{ customerContact.last_name }},

{{ thank_you }}

{{ invoice_label }}: <strong>...</strong>

{{ regards }}, Votre équipe Silicon ioi

{%- endmacro -%}
Paramètres : #
lang : La langue actuelle (ex: 'fr', 'nl').

male_salutation : Salutation pour un homme (ex: 'Cher', 'Geachte heer').

female_salutation : Salutation pour une femme (ex: 'Chère', 'Geachte mevrouw').

default_salutation : Salutation par défaut (ex: 'Cher/Cher(e)').

thank_you, invoice_label, due_date_label, regards : Textes spécifiques à chaque langue.

Appel de la Macro #

Pour chaque langue, on appelle la macro avec les paramètres adaptés :

{% if doc.language == 'fr' %}

{{ email_body('fr', 'Cher', 'Chère', 'Cher/Cher(e)', 'Nous vous remercions...', 'Facture', 'Échéance', 'Cordialement') }}

{%- elif doc.language == 'nl' -%}

{{ email_body('nl', 'Geachte heer', 'Geachte mevrouw', 'Beste', 'Hartelijk dank...', 'Factuur', 'Vervaldatum', 'Met vriendelijke groet') }}

...

{%- endif -%}

Avantages des Macros #

La logique de salutation et de formatage est écrite une seule fois dans la macro, mais utilisée pour toutes les langues.

Si on veut modifier le format de l’email (ex: ajouter une ligne), on a qu’à le faire dans la macro, et non dans chaque bloc if/elif.

Le code est plus court et plus clair, car la répétition est éliminée.

Ajouter une nouvelle langue ou modifier un texte devient plus simple (il suffit d’ajouter un nouvel appel à la macro).

Code complet en utilisant la macro #

{%- set doc = frappe.get_doc('ioi Sales Invoice', master.name) -%}

{%- set customerContact = frappe.get_doc('Contact', doc.invoice_customer_contact_id) if doc.invoice_customer_contact_id else None -%}

{# Macro pour générer la salutation et le corps de l'email #}

{%- macro email_body(lang, male_salutation, female_salutation, default_salutation, thank_you, invoice_label, due_date_label, regards, team_label) -%}

{%- if customerContact and customerContact.gender == 'Male' -%}

{%- set salutation = male_salutation -%}

{%- elif customerContact and customerContact.gender == 'Female' -%}

{%- set salutation = female_salutation -%}

{%- else -%}

{%- set salutation = default_salutation -%}

{%- endif -%}

{{ salutation }} {% if customerContact.last_name %}{{ customerContact.last_name }}{% else %}{{ _('Client', lang) }}{% endif %},

{{ thank_you }}

{{ invoice_label }}: <strong>{{ doc.prefix_id }}{{ doc.identification }}</strong> ({{ "%.2f"|format(doc.total_tvac)|replace('.', ',') }}{{ doc.currency_id }}).

{{ due_date_label }}: <strong>{{ doc.due_date.strftime('%d-%m-%Y') }}</strong>.

{{ regards }}, {% if lang == 'nl' %}Uw{% elif lang == 'de' %}Ihr{% else %}Votre{% endif %} <span style="color: #5A14E6; font-weight: bold;">Silicon ioi</span>{{ team_label }}

{%- endmacro -%}

{# Appel de la macro selon la langue #}

{% if doc.language == 'fr' %}

{{ email_body('fr', 'Cher', 'Chère', 'Cher/Cher(e)', 'Nous vous remercions pour votre confiance', 'Facture', 'Échéance', 'Cordialement', ' équipe') }}

{%- elif doc.language == 'nl' -%}

{{ email_body('nl', 'Geachte heer', 'Geachte mevrouw', 'Beste', 'Hartelijk dank voor uw vertrouwen', 'Factuur', 'Vervaldatum', 'Met vriendelijke groet', '-team') }}

{%- elif doc.language == 'en' -%}

{{ email_body('en', 'Dear Mr.', 'Dear Ms.', 'Dear', 'Thank you for your trust', 'Invoice', 'Due date', 'Best regards', ' team') }}

{%- elif doc.language == 'de' -%}

{{ email_body('de', 'Sehr geehrter Herr', 'Sehr geehrte Frau', 'Sehr geehrte(r)', 'Vielen Dank für Ihr Vertrauen', 'Rechnung', 'Fälligkeitsdatum', 'Mit freundlichen Grüßen', '-Team') }}

{%- endif -%}

{# Pied de page avec logo et coordonnées #}

<a href="http://www.silicon-ioi.online">

<img src="https://silicon-ioi.online/files/.../logo.png" alt="Logo" width="250">

</a>

<span style="color: #5A14E6; font-weight: bold;">Silicon ioi – Digitalize your business</span>

<a href="http://www.silicon-ioi.online" style="color: #5A14E6;">www.silicon-ioi.online</a>

<span style="color: #999999;">Silicon ioi | xxx, xxx xxx | xxx</span>

Bonnes pratiques et astuces #

Les tests et la prévisualisation #

La prévisualisation est une étape critique pour s’assurer que vos emails ou documents générés dynamiquement s’affichent correctement avant d’être envoyés aux clients. Elle permet de :

  • Vérifier le rendu visuel : S’assurer que les styles (gras, couleurs, alignements) sont appliqués comme prévu.
  • Valider les données dynamiques : Confirmer que les variables (numéro de facture, montant, date d’échéance) sont correctement remplacées par les valeurs réelles.
  • Détecter les erreurs de syntaxe : Identifier les balises Jinja mal fermées ou les variables non définies.
  • Dans Silicon ioi, utilisez l’option “Prévisualiser” disponible dans l’éditeur de templates.
  • Testez avec différents jeux de données (ex : un client masculin, féminin, ou sans genre défini) pour couvrir tous les cas d’usage.
  • Vérifiez l’affichage sur différents clients mail (Gmail, Outlook, Apple Mail) si possible, car certains styles CSS peuvent être interprétés différemment.

Documentation et les commentaires #

Un template bien documenté est plus facile à comprendre, modifier et maintenir, surtout si plusieurs personnes travaillent dessus. Les commentaires aident à :

  • Expliquer la logique : clarifier pourquoi une condition ou une boucle est utilisée.
  • Indiquer les dépendances : préciser d’où viennent les variables (ex : doc vient de frappe.get_doc(‘ioi Sales Invoice’, master.name)).
  • Faciliter les mises à jour : savoir rapidement quelles parties du template doivent être modifiées si un champ change dans la base de données.

Astuce

Utilisez les commentaires Jinja {# … #} pour ajouter des notes invisibles dans le rendu final.

Les images #

Les images dans les emails (logos, signatures) doivent être accessibles publiquement pour s’afficher correctement chez le destinataire. Si l’image est stockée en “privé” dans ioi, elle ne sera pas visible dans l’email reçu.

Dans Silicon ioi, téléchargez les images (ex : logo) en mode publique pour que l’image soit accessible publiquement.

Utilisez l’URL complète dans le template :

<img src="https://votre-domaine.silicon-ioi.online/files/logo.png" alt="Logo Silicon ioi" width="200">

Dans notre exemple : https://silicon-ioi.online/files/1200x630wa.jpg

  • Votre-domaine.silicon-ioi.online => silicon-ioi.online

  • Chemin vers le fichier => /files/1200x630wa.jpg

→ Ouvrez l’URL de l’image dans un navigateur en mode privé pour confirmer qu’elle s’affiche sans authentification.

Astuce

Utilisez des formats légers (Png, Jpeg, Webp, Avif).

Astuce

Redimensionnez les images à la taille affichée (ex : width=“200” dans le HTML) pour éviter des temps de chargement longs.

Ajoutez/modifiez des traductions #

Silicon ioi utilise un système de traduction pour afficher les textes (ex : “Invoice”, “Due date”) dans la langue du client. Si une traduction est manquante ou incorrecte, l’email peut contenir des termes en anglais ou des erreurs.

Mécanisme de recherche: #

Quand on utilise {{ _("Invoice", language) }} dans un template Jinja, Frappe suit cet ordre pour trouver la traduction:

  1. Fichiers JSON de l’application: apps/ioi/translations/fr.json.
  2. Table tabTranslation dans la base de données.
  3. Retour du texte source si aucune traduction n’est trouvée.

Comment gérer les traductions #

Via l’interface Frappe (méthode recommandée pour les non-développeurs) :

  • Allez dans Settings > Translations.
  • Recherchez le terme à traduire (ex : “Invoice”).
  • Ajoutez ou modifiez la traduction pour chaque langue (ex : “Facture” pour le français).
  • Sauvegardez et videz le cache (via bench clear-cache) si nécessaire.

Via les fichiers JSON (pour les développeurs) :

→ Les traductions sont stockées dans des fichiers comme apps/ioi/translations/fr.json.

Exemple de contenu :

{

"Invoice": "Facture",

"Due date": "Date d'échéance",

"Thank you for your trust": "Nous vous remercions pour votre confiance"

}

Après modification, redémarrez Frappe pour appliquer les changements.

Via la base de données (pour les mises à jour en masse) :

Utilisez des requêtes SQL pour ajouter/modifier des traductions dans la table tabTranslation :

INSERT INTO \`tabTranslation\` (source_text, language, translated_text)

VALUES ("Invoice", "fr", "Facture");

→ Testez les traductions en changeant la langue de l’utilisateur ou du document dans Frappe.

Utilisation des variables #

Des noms de variables clairs et cohérents rendent votre template :

  • Plus lisible : Facile à comprendre pour vous et vos collègues.
  • Moins sujet aux erreurs : Réduit les risques de confusion (ex : d_date vs due_date).
  • Plus maintenable : Simplifie les mises à jour futures.

Utilisez des noms descriptifs, parlants :

{# Bonne pratique #}

{% set customer_name = customerContact.last_name %}

{% set invoice_amount = doc.total_tvac %}
{# Mauvaise pratique #}

{% set cn = customerContact.last_name %}

{% set amt = doc.total_tvac %}

Évitez les caractères spéciaux (espace, tirets, accents) :

{# Bonne pratique #}

{% set due_date = doc.due_date %}
{# Mauvaise pratique #}

{% set due-date = doc.due_date %}

{% set date_d'échéance = doc.due_date %}

Soyez cohérent :

  • Si vous utilisez camelCase (ex : customerName), appliquez-le partout.
  • Si vous utilisez snake_case (ex : customer_name), restez cohérent.

Exemple complet :

{%- set invoice_document = frappe.get_doc('ioi Sales Invoice', master.name) -%}

{%- set client_contact = frappe.get_doc('Contact', invoice_document.invoice_customer_contact_id) if invoice_document.invoice_customer_contact_id else None -%}

{# Calcul du montant TTC #}

{%- set total_amount = "%.2f"|format(invoice_document.total_tvac)|replace('.', ',') -%}

{%- set currency = invoice_document.currency_id -%}

Montant total : {{ total_amount }} {{ currency }}

Le « - » et la mise en forme #

Les symboles {{-, -}}, {%-, -%}, {#-, et -#} permettent de supprimer les espaces blancs (espaces, tabulations, sauts de ligne) autour des balises Jinja. Cela évite les problèmes de mise en forme, notamment dans les emails ou les documents HTML où l’alignement est crucial.

Syntaxe et Effet :

{{- variable }}

Supprime les espaces avant la variable.

{{ variable -}}

Supprime les espaces après la variable.

{%- if condition %}

Supprime les espaces avant un bloc (ex : if, for).

{% endif -%}

Supprime les espaces après un bloc.

{#- commentaire -#}

Supprime les espaces avant un commentaire.

{# commentaire -#}

Supprime les espaces après un commentaire.

Quand les utiliser #

Pour les emails : Éviter les espaces indésirables qui perturbent l’alignement.

<p>

Bonjour {{- user.name -}},

{{- message -}}

</p>

Utiliser {{- et -}} pour supprimer les espaces autour des variables.

Utiliser {%- et -%} pour supprimer les espaces autour des blocs (if, for, etc.).

→ Indispensable pour les emails et les documents HTML où la mise en forme compte.

→ Rend le code plus propre et évite les surprises de rendu.

Fonctions clés de Jinja et Frappe #

→ Fonctions pour les nombres:

Fonction/Filtre Rôle Exemple Résultat
+ Addition {{ 5 + 3 }} 8
- Soustraction {{ 10 - 4 }} 6
* Multiplication {{ 3 * 4 }} 12
/ Division {{ 10 / 2 }} 5.0
// Division entière {{ 10 // 3 }} 3
% Modulo {{ 10 % 3 }} 1
** Puissance {{ 2 ** 3 }} 8
abs() Valeur absolue {{ -5 | abs }} 5
round() Arrondir un nombre {{ 3.14159 | round(2) }} 3.14
int() Convertir en entier {{ “5” | int }} 5
float() Convertir en décimal {{ “3.14” | float }} 3.14
sum() Somme d’une liste de nombres {{ [1, 2, 3] | sum }} 6
min() Valeur minimale {{ [1, 2, 3] | min }} 1
max() Valeur maximale {{ [1, 2, 3] | max }} 3
format() Formater un nombre {{ 1234.5678 | format(“%.2f”) | replace(“.”, “,”) }} 1234,57
random() Nombre aléatoire {{ [1, 2, 3] | random }} 2 (aléatoire)

→ Fonctions pour les textes:

Fonction/Filtre Rôle Exemple Résultat
upper() Mettre en majuscules {{ “bonjour” | upper }} BONJOUR
lower() Mettre en minuscules {{ “BONJOUR” | lower }} bonjour
capitalize() Première lettre en majuscule {{ “bonjour” | capitalize }} Bonjour
title() Première lettre de chaque mot en majuscule {{ “bonjour tout le monde” | title }} Bonjour Tout Le Monde
trim() Supprimer les espaces en début/fin {{ " bonjour " | trim }} bonjour
replace() Remplacer une chaîne par une autre {{ “bonjour” | replace(“jour”, “soir”) }} bonsoir
split() Diviser une chaîne en liste {{ “bonjour tout le monde” | split(" ") }} [‘bonjour’, ‘tout’, ‘le’, ‘monde’]
join() Joindre une liste en chaîne {{ [“bonjour”, “monde”] | join(", ") }} bonjour, monde
length() Longueur d’une chaîne {{ “bonjour” | length }} 7
truncate() Tronquer une chaîne {{ “bonjour” | truncate(4) }} bonj…
slice() Extraire une partie de la chaîne {{ “bonjour” | slice(0, 3) }} bon
strip() Supprimer les espaces {{ " bonjour! " | strip }} bonjour!

→ Fonctions pour les dates:

Fonction/Filtre Rôle Exemple Résultat
frappe.utils.nowdate() Date actuelle {{ frappe.utils.nowdate() }} 2026-03-04
frappe.utils.now() Date et heure actuelles {{ frappe.utils.now() }} 2026-03-04 15:30:00
strftime() Formater une date {{ frappe.utils.nowdate() | strftime(“%d-%m-%Y”) }} 04-03-2026
frappe.utils.getdate() Convertir une chaîne en objet date {{ frappe.utils.getdate(“04/03/2026”) }} Objet date
date_diff() Différence en jours entre 2 dates {{ (frappe.utils.getdate(“10-03-2026”) - frappe.utils.getdate(“04-03-2026”)).days }} 6
week_number() Numéro de semaine {{ frappe.utils.getdate(“04-03-2026”).isocalendar()[1] }} 10 (semaine 10 de 2026)
add_days() Ajouter des jours à une date {{ frappe.utils.add_days(frappe.utils.nowdate(), 7) }} 2026-03-11
add_months() Ajouter des mois à une date {{ frappe.utils.add_months(frappe.utils.nowdate(), 1) }} 2026-04-04

→ Fonctions utiles spécifiques à Frappe:

Fonction Description Exemple Résultat (exemple)
frappe.get_doc() Récupérer un document Frappe {{ frappe.get_doc(“User”, “admin”).full_name }} Administrator
frappe.db.get_value() Récupérer une valeur depuis la base de données {{ frappe.db.get_value(“User”, “admin”, “email”) }} admin@example.com
frappe.utils.flt() Convertir en float {{ frappe.utils.flt(“3.14”) }} 3.14
frappe.utils.cint() Convertir en entier {{ frappe.utils.cint(“5”) }} 5
frappe.utils.cstr() Convertir en chaîne {{ frappe.utils.cstr(123) }} “123”
frappe.utils.comma_and() Formater une liste en chaîne {{ frappe.utils.comma_and([“Pommes”, “Poires”, “Bananes”]) }} Pommes, Poires et Bananes

Commentaires et documentation dans les templates #

Commentaires simples (sur une seule ligne):

{# Ce commentaire ne sera pas affiché dans le rendu final #}

Commentaires multi-lignes:

{#
Ce commentaire s'étend sur plusieurs lignes.
Il est utile pour documenter des sections complexes.
Aucun de ce texte n'apparaîtra dans le rendu final.
#}

Différence avec les commentaires HTML:

  • Commentaires Jinja ({# ... #}): Ne sont pas visibles dans le rendu final.
  • Commentaires HTML (<!-- ... -->): Sont visibles dans le code source HTML généré.

Annexes: résumé des fonctions utiles #

→ Fonctions pour les dates et heures:

Fonction Description Exemple
nowdate() Retourne la date actuelle au format YYYY-MM-DD. {{ frappe.utils.nowdate() }}
now() Retourne la date et l’heure actuelles au format YYYY-MM-DD HH:MM:SS. {{ frappe.utils.now() }}
today() Alias de nowdate(). {{ frappe.utils.today() }}
getdate(string) Convertit une chaîne en objet date. {{ frappe.utils.getdate(“04/03/2026”) }}
format_date(date, format) Formate une date selon le format spécifié. {{ frappe.utils.format_date(frappe.utils.nowdate(), “dd-MM-yyyy”) }}
add_days(date, days) Ajoute un nombre de jours à une date. {{ frappe.utils.add_days(frappe.utils.nowdate(), 7) }}
date_diff(end_date, start_date) Retourne la différence en jours entre deux dates. {{ frappe.utils.date_diff(frappe.utils.getdate(“10-03-2026”), frappe.utils.nowdate()) }}

→ Fonctions pour les nombres:

Fonction Description Exemple
flt(value, precision=2) Convertit une valeur en float avec gestion des erreurs. {{ frappe.utils.flt(“3.14159”, 2) }}
fmt_money(amount, precision=2, currency=None) Formate un montant avec symbole monétaire. {{ frappe.utils.fmt_money(1234.5678, 2, “EUR”) }}
cint(value) Convertit une valeur en int avec gestion des erreurs. {{ frappe.utils.cint(“5”) }}
round(number, precision=0) Arrondit un nombre. {{ frappe.utils.round(3.14159, 2) }}

→ Fonctions pour les chaînes de caractères:

Fonction Description Exemple
scrub(string) Remplace les espaces et caractères spéciaux par des underscores (_). {{ frappe.utils.scrub(“Mon Fichier.txt”) }}
comma_and(list) Formate une liste en chaîne avec des virgules et “et” (ex: “A, B et C”). {{ frappe.utils.comma_and([“Pommes”, “Poires”, “Bananes”]) }}
get_link_to_form(doctype, name, label=None) Génère un lien vers un formulaire Frappe. {{ frappe.utils.get_link_to_form(“User”, “admin”) }}