🧮 Marqueurs avancé - Formules et conditions dans les modèles
Ce guide avancé s'adresse à celles et ceux qui veulent aller plus loin que la simple insertion de variables : mettre en forme une date ou un montant, afficher un texte selon une condition, gérer plusieurs cas ou répéter un bloc.
Tout ce qui est décrit ici fonctionne avec le moteur de modèles téo (téo edit), donc dans :
- les modèles d'emails et leur objet ;
- les modèles de SMS ;
- les modèles de documents ;
- les automatisations (envois automatiques).
Si vous débutez avec les variables, lisez d'abord Modèles de messages et documents. Cette page suppose que vous savez déjà insérer une variable comme {d.benef.prenom}.
1. Rappel : les variables (marqueurs)
Une variable, ou marqueur, est un emplacement que téo remplace automatiquement par la vraie donnée.
Syntaxe : {d.categorie.champ}
Le préfixe d. signifie « données de téo », suivi du chemin vers l'information.
| Variable | Résultat |
|---|---|
{d.benef.prenom} | Prénom du bénéficiaire |
{d.benef.nom} | Nom du bénéficiaire |
{d.dossier.numero} | Numéro du dossier |
{d.seance.date} | Date de la séance |
{d.conseiller.nom} | Nom du conseiller |
{d.centre.nom} | Nom de votre structure |
{d.global.date} | Date du jour de génération |
Dans l'éditeur de modèle, le bouton Variables ouvre la liste complète des marqueurs et les insère en un clic. La référence exhaustive est aussi sur edit.teoapp.fr.
Les données dépendent du contexte
Un modèle est toujours utilisé dans un contexte (un dossier, une facture, une séance, une personne…). Seules les variables de ce contexte sont remplies.
| Contexte du modèle | Familles de variables disponibles |
|---|---|
| Dossier | dossier, benef, conseiller, prestation, financeur, convention, seances, global |
| Séance | seance, dossier, benef, conseiller, global |
| Facture / Devis | facture (ou devis), banque, dossier ou groupe, global |
| Groupe | groupe, benefs, conseiller, prestation, seances, global |
| Personne / Société | personne ou societe, global |
Une variable de séance ({d.seance.date}) ne fonctionne pas dans un modèle utilisé depuis une personne : la donnée n'existe pas dans ce contexte et la variable reste vide.
2. Le principe des formules
Une formule enchaîne une variable avec une ou plusieurs instructions, séparées par le caractère deux-points :.
{d.maVariable:instruction1:instruction2}
Chaque instruction transforme le résultat de la précédente. On lit la formule de gauche à droite.
{d.benef.nom:upperCase}
→ prend le nom du bénéficiaire, puis le passe en majuscules.
téo supprime les espaces situés à l'intérieur d'un marqueur {…}. Conséquences, à retenir dès maintenant :
- un texte à afficher doit être placé entre guillemets simples :
show('Sur place')(et nonshow(Sur place), qui donneraitSurplace) ; - une date avec des espaces ne s'écrit pas en un seul format : utilisez
formatD(LL)ou plusieurs marqueurs séparés par des espaces (voir §3.1).
Les espaces de votre phrase, en dehors des accolades, sont évidemment conservés.
Les sections suivantes couvrent les trois familles de formules : mettre en forme, afficher selon une condition, répéter.
3. Mettre en forme une valeur
3.1 Dates et heures — formatD
Par défaut, une date s'affiche dans un format technique (2025-03-15). formatD(...) la présente proprement, en indiquant le format de sortie.
{d.seance.date:formatD(DD/MM/YYYY)}
→ 15/03/2025
Codes de format les plus utiles :
| Code | Signification | Exemple |
|---|---|---|
DD | Jour sur 2 chiffres | 15 |
dddd | Jour de la semaine en toutes lettres | samedi |
MM | Mois sur 2 chiffres | 03 |
MMMM | Mois en toutes lettres | mars |
YYYY | Année sur 4 chiffres | 2025 |
LL | Date longue localisée | 15 mars 2025 |
Dates « longues » : LL ou plusieurs marqueurs
Comme les espaces sont supprimés à l'intérieur d'un marqueur, on n'écrit pas formatD(dddd DD MMMM YYYY) (cela donnerait samedi15mars2025). Deux solutions correctes :
Le {d.seance.date:formatD(LL)}
→ Le 15 mars 2025
Le {d.seance.date:formatD(dddd)} {d.seance.date:formatD(LL)}
→ Le samedi 15 mars 2025
(ici l'espace est placé entre les deux marqueurs, donc conservé.)
Heures : préciser le format d'entrée
Les heures sont stockées sous la forme 09:00:00. Pour les afficher en 9h00, ajoutez un second paramètre : le format dans lequel l'heure est stockée.
{d.seance.debut:formatD(H[h]mm, hh:mm:ss)}
→ 9h00
H[h]mm= format de sortie (les crochets[h]affichent le « h » littéral) ;hh:mm:ss= format d'entrée (placé après la virgule).
3.2 Montants — formatC
formatC() met en forme un montant (séparateurs, symbole monétaire).
Total à régler : {d.facture.totalTTC:formatC()}
→ Total à régler : 1 800,00 €
Utilisez-le pour tous les montants : {d.facture.totalHT:formatC()}, {d.dossier.montant.previ:formatC()}…
Les montants négatifs (avoirs) sont gérés (-250,50 €). Pour des euros entiers sans décimales, indiquez la précision 0 :
{d.facture.totalHT:formatC(0)}
→ 1 500 €
3.3 Nombres — formatN
{d.dossier.dureePrevi:formatN()} heures prévues
3.4 Texte
| Formule | Effet | Exemple |
|---|---|---|
:upperCase | TOUT EN MAJUSCULES | Dupont → DUPONT |
:lowerCase | tout en minuscules | DUPONT → dupont |
:ucFirst | Première lettre en majuscule | marie → Marie |
:ucWords | Première Lettre De Chaque Mot | marie curie → Marie Curie |
:unaccent | Supprime les accents | Téléphone → Telephone |
Exemple :
{d.benef.civilite} {d.benef.nom:upperCase} {d.benef.prenom:ucFirst}
→ Madame EXEMPLE Marie
3.5 Valeur par défaut (champ vide)
Si une donnée peut être absente, prévoyez un texte de remplacement avec ifEM (« si vide »).
{d.benef.tel.mobile:ifEM:show('Non renseigné')}
→ affiche Non renseigné quand le mobile est vide, sinon le numéro.
Sans valeur par défaut, un champ vide laisse un trou dans la phrase (« Votre conseiller vous contactera »).
3.6 Petits calculs — add sub mul div
Vous pouvez calculer une valeur à partir d'un nombre : addition (add), soustraction (sub), multiplication (mul), division (div).
Montant TTC estimé : {d.facture.totalHT:mul(1.2):formatC()}
→ multiplie le HT par 1,2 puis met en forme le montant.
4. Conditions : afficher un texte selon les données
C'est le cœur de cette page : afficher un contenu différent selon la valeur d'une donnée.
4.1 Si / Sinon — ifEQ + show + elseShow
La formule de base se lit : « si la donnée est égale à une valeur, afficher un texte, sinon afficher un autre texte ».
{d.seance.typeContact:ifEQ('Présentiel'):show('Merci de venir sur place'):elseShow('Un lien de connexion vous sera transmis')}
| Élément | Rôle |
|---|---|
ifEQ('Présentiel') | Si la valeur est égale à Présentiel |
show('…') | …afficher ce texte |
elseShow('…') | Sinon, afficher cet autre texte |
elseShow est facultatif. Le texte est toujours entre guillemets simples.
show / elseShowL'apostrophe ' délimite le texte : show('l'entretien') casse la formule. Reformulez sans apostrophe (« la séance » plutôt que « l'entretien »), ou utilisez ’ (apostrophe typographique).
4.2 Tous les tests disponibles
ifEQ n'est qu'un test parmi d'autres. Chaque test est suivi d'un show (et éventuellement elseShow).
| Test | Signification |
|---|---|
ifEQ(valeur) | égal à la valeur |
ifNE(valeur) | différent de la valeur |
ifGT(valeur) | strictement supérieur à |
ifGTE(valeur) | supérieur ou égal à |
ifLT(valeur) | strictement inférieur à |
ifLTE(valeur) | inférieur ou égal à |
ifEM | la donnée est vide |
ifNEM | la donnée n'est pas vide |
ifIN(valeur) | la donnée contient la valeur |
ifNIN(valeur) | la donnée ne contient pas la valeur |
ifIN : repérer un mot dans un texteifIN teste si un champ contient la valeur indiquée — pratique pour réagir à un mot présent dans un texte libre :
{d.dossier.objectif:ifIN('reconversion'):show('Parcours de reconversion'):elseShow('Autre parcours')}
Pour afficher un texte selon la valeur exacte d'un champ (une modalité parmi plusieurs, par exemple), voir §4.4.
Exemple avec un nombre :
{d.dossier.nbJours:ifGT(90):show('Accompagnement longue durée'):elseShow('Accompagnement court')}
Champ « oui / non » (booléen)
Pour un champ vrai/faux (par exemple « ce document est-il un avoir ? »), testez true ou false :
{d.facture.avoir:ifEQ(true):show('AVOIR'):elseShow('FACTURE')}
ifGT / ifLTLes comparaisons ifGT, ifLT… ne fonctionnent que sur des nombres. Sur une date (2025-03-15), elles ne donnent pas le bon résultat. Pour réagir à une date, comparez plutôt un nombre déjà calculé par téo (ex. {d.dossier.nbJours:ifGT(90)…}) ou un champ texte d'état.
4.3 Choix multiple (« switch »)
Pour afficher un texte différent par valeur, enchaînez plusieurs ifEQ:show. Dès qu'une condition est vraie, le reste est ignoré ; elseShow couvre tous les autres cas.
{d.benef.sexe:ifEQ('H'):show('Cher Monsieur'):ifEQ('F'):show('Chère Madame'):elseShow('Bonjour')}
4.4 Comparer à plusieurs valeurs
Besoin le plus courant : « plusieurs modalités donnent le même texte » (ex. 3 types de contact sur 4 mènent au même message).
Méthode recommandée — enchaîner ifEQ avec le même show
On réutilise le principe du switch, en répétant le même show pour chaque valeur qui doit donner le même résultat :
{d.seance.typeContact:ifEQ('Téléphone'):show('Votre rendez-vous se fera à distance.'):ifEQ('Visio'):show('Votre rendez-vous se fera à distance.'):ifEQ('Distanciel'):show('Votre rendez-vous se fera à distance.'):elseShow('Votre rendez-vous se fera en présentiel.')}
Simple et fiable : aucune notion avancée, on lit la formule de gauche à droite.
Méthode compacte — or (OU) et and (ET)
On peut aussi combiner des tests :
or= OU (il suffit qu'un test soit vrai) ;and= ET (il faut que tous les tests soient vrais).
Pour rappeler une donnée après or / and, on indique le nom du champ précédé d'un point (.champ). ⚠️ Ce chemin est relatif à l'objet de votre première variable : pour {d.seance.typeContact…}, on réécrit simplement .typeContact (le champ frère), pas .seance.typeContact.
OU sur la même donnée :
{d.seance.typeContact:ifEQ('Téléphone'):or(.typeContact):ifEQ('Visio'):show('À distance'):elseShow('Sur place')}
ET entre deux champs du même objet (ici deux champs de dossier) :
{d.dossier.nbJours:ifGT(90):and(.montant.previ):ifGT(2000):show('Dossier majeur'):elseShow('Dossier standard')}
- Pour « une seule donnée, plusieurs valeurs possibles » (votre cas le plus fréquent), la méthode recommandée (enchaîner les
ifEQ:show) est la plus lisible. or/anddeviennent utiles pour combiner deux champs (ET / OU), mais demandent d'écrire le bon chemin relatif (.champFrère).
4.5 Afficher ou masquer un bloc entier
Pour conditionner un paragraphe, une ligne ou un tableau — et notamment n'afficher la valeur d'un marqueur que si une condition est vraie — utilisez les bornes de bloc :
| Formule | Effet si la condition est vraie |
|---|---|
showBegin … showEnd | Affiche la zone entre les deux bornes |
hideBegin … hideEnd | Masque la zone entre les deux bornes |
Exemple — n'afficher l'adresse que pour un rendez-vous en présentiel :
{d.seance.typeContact:ifEQ('Présentiel'):showBegin}
Lieu : {d.seance.lieu.nom}, {d.seance.lieu.adresse} {d.seance.lieu.cp} {d.seance.lieu.ville}
{d.seance.typeContact:showEnd}
Tout ce qui est compris entre showBegin et showEnd (texte et marqueurs) n'apparaît que si la condition est vraie. Les deux bornes utilisent le même chemin de variable.
Pour insérer la valeur d'un marqueur quand une condition est remplie, passez toujours par un bloc showBegin/showEnd (comme ci-dessus). show() ne sert qu'à afficher un texte fixe entre guillemets.
5. Répéter un bloc (listes)
Certaines données sont des listes : les séances d'un dossier, les lignes d'une facture, les bénéficiaires d'un groupe… On les reconnaît à leur nom au pluriel : seances, lignes, benefs.
5.1 La boucle avec [i] et [i+1]
Pour répéter un bloc pour chaque élément d'une liste, il faut deux lignes :
- une ligne modèle qui utilise l'indice
[i](« l'élément courant ») — c'est elle qui est répétée ; - une seconde ligne qui reprend au moins un marqueur de la liste avec
[i+1]. Cette ligne indique où s'arrête le motif et n'apparaît pas dans le résultat.
[i+1] est obligatoireSans la ligne [i+1], téo ne sait pas quelle zone répéter : la liste ne se répète pas. Un seul marqueur [i+1] suffit (inutile de recopier toute la ligne), par exemple {d.dossier.seances[i+1].date}.
Dans un tableau Word, créez deux lignes de tableau :
| Date | Action | Durée |
|---|---|---|
{d.dossier.seances[i].date:formatD(DD/MM/YYYY)} | {d.dossier.seances[i].action} | {d.dossier.seances[i].duree:formatD(H[h]mm, hh:mm:ss)} |
{d.dossier.seances[i+1].date} |
téo répète la 1ʳᵉ ligne pour chaque séance, puis supprime la ligne [i+1].
Exemple sur les lignes d'une facture (toujours 2 lignes de tableau) :
| Désignation | Qté | PU HT | Montant HT |
|---|---|---|---|
{d.facture.lignes[i].description} | {d.facture.lignes[i].quantite} | {d.facture.lignes[i].puHT:formatC()} | {d.facture.lignes[i].montantHT:formatC()} |
{d.facture.lignes[i+1].description} |
téo prend la 1ʳᵉ ligne ([i]) comme modèle et la répète pour chaque élément, quel que soit leur nombre. La 2ᵉ ligne ([i+1]) n'est qu'un repère de fin : elle disparaît à la génération.
5.2 Cibler un élément précis avec [i=0]
Pour viser un élément, indiquez son rang. La numérotation commence à 0 : le premier élément est [i=0], le deuxième [i=1], etc.
Exemple — informations du premier rendez-vous du dossier (les espaces sont entre les marqueurs) :
Votre premier rendez-vous : {d.dossier.seances[i=0].date:formatD(LL)} à {d.dossier.seances[i=0].debut:formatD(H[h]mm, hh:mm:ss)}, {d.dossier.seances[i=0].lieu.nom}.
5.3 Ne répéter que certains éléments (filtre)
Vous pouvez filtrer une boucle pour ne garder que les éléments correspondant à un critère, en ajoutant , champ='valeur' dans les crochets. Le filtre doit être répété à l'identique sur la ligne [i+1].
Exemple — ne lister que les séances en présentiel :
| Date | Action |
|---|---|
{d.dossier.seances[i, typeContact='Présentiel'].date:formatD(DD/MM/YYYY)} | {d.dossier.seances[i, typeContact='Présentiel'].action} |
{d.dossier.seances[i+1, typeContact='Présentiel'].date} |
5.4 Compter et gérer une liste vide
Compter les éléments d'une liste avec len :
Ce dossier comporte {d.dossier.seances:len} séance(s).
Masquer un tableau entier quand la liste est vide : encadrez-le entre ifEM:hideBegin et hideEnd (le tableau disparaît s'il n'y a aucun élément).
{d.dossier.seances:ifEM:hideBegin}
… votre tableau de séances ici …
{d.dossier.seances:hideEnd}
5.5 Lister des valeurs simples — arrayJoin
Pour une liste de valeurs simples (texte/nombres), arrayJoin les assemble en une seule ligne :
Mots-clés : {d.dossier.motsCles:arrayJoin(', ')}
→ Mots-clés : VAE, Bilan, CEP
arrayJoin ne fonctionne que sur des listes de valeurs simples. Pour une liste d'objets (bénéficiaires, séances, lignes de facture…), utilisez une boucle [i] / [i+1] (§5.1).
5.6 Boucles imbriquées
Une boucle peut en contenir une autre (par exemple : pour chaque groupe, lister ses bénéficiaires). Chaque niveau a son couple [i] / [i+1].
{d.groupes[i].nom} : {d.groupes[i].benefs[i].prenom}{d.groupes[i].benefs[i+1].prenom}
{d.groupes[i+1].nom}
6. Exemple complet commenté
Un extrait de convocation par email combinant variables, mise en forme et conditions :
Bonjour {d.benef.prenom:ucFirst},
Nous confirmons votre rendez-vous « {d.seance.action} » le {d.seance.date:formatD(dddd)} {d.seance.date:formatD(LL)} à {d.seance.debut:formatD(H[h]mm, hh:mm:ss)}.
{d.seance.typeContact:ifEQ('Téléphone'):show('Ce rendez-vous se fera à distance ; un lien vous sera transmis.'):ifEQ('Visio'):show('Ce rendez-vous se fera à distance ; un lien vous sera transmis.'):elseShow('Ce rendez-vous se déroulera sur place :')}
{d.seance.typeContact:ifEQ('Présentiel'):showBegin}
{d.seance.lieu.nom}, {d.seance.lieu.adresse} {d.seance.lieu.cp} {d.seance.lieu.ville}
{d.seance.typeContact:showEnd}
Votre conseiller : {d.conseiller.prenom:ucFirst} {d.conseiller.nom:upperCase}
{d.centre.nom}
7. Dépannage
« La condition affiche toujours le “sinon”, jamais le bon texte »
C'est l'erreur la plus fréquente. La comparaison ifEQ est exacte : elle distingue les majuscules/minuscules et les accents.
ifEQ('téléphone') ne correspond pas à une donnée enregistrée Téléphone (T majuscule). Résultat : la condition est toujours fausse, et seul le elseShow s'affiche.
Solutions :
- Recopiez le libellé exact tel qu'il apparaît dans votre paramétrage (mêmes majuscules, mêmes accents). Pour les modalités de séance : Admin > types de contact.
- Pour ignorer la casse et les accents, normalisez la valeur avant de comparer, et comparez à une valeur elle aussi en minuscules sans accent :
{d.seance.typeContact:unaccent:lowerCase:ifEQ('telephone'):show('…'):elseShow('…')}
Avant d'écrire une condition sur une donnée « à choix » (modalité, civilité, état…), vérifiez les libellés exacts dans le paramètre correspondant et copiez-les à l'identique.
« Mon texte est collé / il manque des espaces »
Les espaces à l'intérieur d'un marqueur sont supprimés. Mettez le texte de show / elseShow entre guillemets (show('Sur place')), et composez les dates longues avec formatD(LL) ou plusieurs marqueurs (voir §3.1).
« Ma liste ne se répète pas (un seul élément s'affiche) »
Il manque la 2ᵉ ligne de la boucle : il faut une ligne avec [i] et une seconde ligne contenant au moins un marqueur [i+1] (voir §5.1). Évitez aussi de mélanger deux listes dans la même boucle.
« Ma variable n'est pas remplacée et reste affichée telle quelle »
- Vérifiez la syntaxe exacte : accolades
{ }, points, et le préfixed.. - Vérifiez que la variable existe (bouton Variables de l'éditeur).
- Vérifiez le contexte : une variable séance ne fonctionne pas depuis un modèle « personne » (voir §1).
« Que se passe-t-il si une donnée est absente ? »
Pas de panique : un marqueur dont la donnée est vide ou manquante (par exemple un lieu non renseigné) s'affiche simplement en blanc — il ne provoque pas d'erreur et ne bloque pas la génération. Pour remplacer ce blanc par un texte, voir la valeur par défaut.
Tester avant de diffuser
Le bouton Tester d'un modèle le génère avec un dossier réel. Testez systématiquement vos conditions avec plusieurs cas (par exemple une séance présentielle et une séance à distance) pour vérifier les deux branches.
8. Aide-mémoire
| Besoin | Formule type |
|---|---|
| Date courte | {d.seance.date:formatD(DD/MM/YYYY)} |
| Date longue | {d.seance.date:formatD(LL)} |
| Jour + date | {d.seance.date:formatD(dddd)} {d.seance.date:formatD(LL)} |
| Heure « 9h00 » | {d.seance.debut:formatD(H[h]mm, hh:mm:ss)} |
| Montant en € | {d.facture.totalTTC:formatC()} |
| Majuscules | {d.benef.nom:upperCase} |
| Initiale en majuscule | {d.benef.prenom:ucFirst} |
| Valeur par défaut | {d.benef.tel.mobile:ifEM:show('Non renseigné')} |
| Petit calcul | {d.facture.totalHT:mul(1.2):formatC()} |
| Si / sinon | {d.x:ifEQ('A'):show('…'):elseShow('…')} |
| Oui / non (booléen) | {d.facture.avoir:ifEQ(true):show('Avoir'):elseShow('Facture')} |
| Choix multiple | {d.x:ifEQ('A'):show('…'):ifEQ('B'):show('…'):elseShow('…')} |
| Bloc conditionnel | {d.x:ifEQ('A'):showBegin} … {d.x:showEnd} |
| Répéter une liste (2 lignes) | ligne 1 {d.dossier.seances[i].date} + ligne 2 {d.dossier.seances[i+1].date} |
| Filtrer une liste | {d.dossier.seances[i, typeContact='Présentiel'].action} |
| Compter une liste | {d.dossier.seances:len} |
| Premier élément | {d.dossier.seances[i=0].date} |
Voir aussi
- Modèles de messages et documents — créer et tester vos modèles
- Automatisations — déclencher l'envoi automatiquement
- Référence des marqueurs — liste complète des variables disponibles
Cet article vous a été utile ?