Calculer une valeur avec une formule
Le marqueur de formule, les fonctions de calcul sûres pour les montants et l'écriture dans un champ crédit
À quoi ça sert
Une variable recopie une valeur telle quelle. Une formule en calcule une : retrancher un montant à un solde de crédits, multiplier une quantité par un prix unitaire, additionner les prix des produits liés à une fiche, choisir une valeur selon une condition.
Une formule s'écrit dans les paramètres d'une action, entre {{= et }}. Elle
peut occuper toute la valeur — elle rend alors un nombre, un texte ou un oui/non
selon son résultat — ou être insérée dans une phrase, auquel cas son résultat est
converti en texte.
Sur une règle au déclencheur « Date », une formule ne peut lire aucune racine :
record, before, after, actor et related n'existent pas, faute de
fiche déclencheuse. Un calcul qui ne lit rien, par exemple {{= round(1.5) }},
reste utilisable.
Concepts clés
- Marqueur de formule — la paire
{{=et}}. Sans elle, le contenu est pris pour du texte. - Racines — les mêmes que dans une condition :
record,before,afteretactor. Une formule les lit sans le préfixetrigger.: on écritrecord.credits, pas{{trigger.record.credits}}. llm— une racine de plus, réservée aux formules des paramètres d'une action qui a un pré-traitement IA :llm.clélit une valeur renvoyée par le modèle, par exemple{{= mul(llm.seats, 2) }}. Voir Pré-traiter une action avec l'IA.analysis— la racine des valeurs renvoyées par l'analyse IA de la règle, lisible dans les formules des paramètres de toutes les actions :{{= mul(analysis.seats, 2) }}. La règle doit porter une analyse qui déclare la clé.- Fonctions de calcul sûres —
add,sub,mul,div,roundetsum. Elles doivent être employées pour tout ce qui touche à de l'argent. - Fonctions de date —
formatDateTimeetformatTimeécrivent une date ou une heure lisible, à l'heure locale ;addMonthsetaddDaysdécalent une date. - Fonction de liste —
rangefabrique une suite de nombres entiers, pour répéter une action (voir Répéter une action sur une liste). related— les enregistrements liés à l'objet déclencheur, chargés au moment du déclenchement. Accessible dans une formule et, pour le contrat d'une tâche, dans une condition écrite en expression.actor— la personne à l'origine de l'évènement :actor.idetactor.name. Les deux valentnullquand aucune personne n'a déclenché la règle.
Comment faire
Calculer un montant
- Dans les paramètres de l'action, écrivez la valeur sous forme de formule.
- Utilisez
add,sub,muloudivplutôt que+,-,*ou/. - Arrondissez le résultat final avec
round.
Exemple, pour décrémenter un solde de crédits du montant de la facture :
{{= round(sub(record.credits, record.totalTtc), 2) }}Les opérateurs natifs +, -, * et / restent acceptés, mais ils font un
calcul à virgule flottante imprécis : ne les utilisez jamais pour un montant.
Choisir une valeur selon une condition
- Écrivez une expression conditionnelle dans la formule.
Exemple :
{{= record.amount > 1000 ? "gold" : "standard" }}Insérer un résultat dans une phrase
- Écrivez la formule au milieu du texte.
Exemple :
Solde restant : {{= sub(record.credits, record.totalTtc) }} €Le résultat est converti en texte à l'endroit de la formule. Le reste de la phrase est conservé tel quel.
Additionner les données liées à une fiche
- Vérifiez que le champ à agréger est un champ de relation ou un champ catalogue de la fiche déclencheuse.
- Écrivez la formule avec
related,mapetsum.
Exemple, pour écrire dans un champ CRM la somme des prix de vente des produits liés :
{{= round(sum(related.produits.map(p, p.sellingPrice)), 2) }}Remplacez produits par le nom technique de votre champ. Seuls les champs
réellement cités par une formule sont chargés.
Écrire une date ou une heure lisible
- Passez la date par
formatDateTime, ou parformatTimepour l'heure seule. - Indiquez si besoin un fuseau horaire en second argument.
Exemple, pour écrire une ligne d'historique datée :
{{= formatDateTime(record.updatedAt) }} - DémarréAvec un fuseau : {{= formatTime(record.updatedAt, "America/Martinique") }}. Sans
fuseau, l'heure est celle de Paris. La date doit être un instant complet, avec
son fuseau (2026-10-19T15:02:00Z) : une date seule comme 2026-10-19 est
refusée.
Décaler une date
- Passez la date par
addMonths(date, n)pour un nombre de mois, ouaddDays(date, n)pour un nombre de jours. Un nombre négatif recule. - Le résultat garde la forme de la date de départ : une date seule
(
2026-11-01) donne une date seule, un instant complet (2026-11-01T10:00:00Z) donne un instant complet.
Exemple : {{= addMonths(record.startDate, 6) }} donne 2027-05-01 pour une date
de départ au 2026-11-01. Quand le mois d'arrivée est plus court, le jour est
ramené à sa fin : addMonths("2026-01-31", 1) donne 2026-02-28.
Le nombre doit être entier. Un nombre lu sur la fiche est décimal pour la
formule : écrivez 12.0 / record.visits et non 12 / record.visits. Une date
absente, illisible, impossible (2026-02-30) ou sans fuseau pour un instant
(2026-11-01T10:00:00) fait échouer l'action.
Fabriquer une liste de nombres
range(n) donne la liste 0, 1, …, n-1, avec n entier de 0 à 50. Combinée à
map, elle produit une liste de dates à répéter : range(record.visits).map(k, addMonths(record.startDate, k * 6)). Voir
Répéter une action sur une liste.
Citer la personne à l'origine de l'évènement
- Écrivez
actor.namedans la formule, ou{{trigger.actor.name}}dans un texte. - Testez-le d'abord quand la règle peut partir sans personne :
actor.namevaut alorsnull.
Exemple : {{= actor.name != null ? actor.name : "le système" }}.
Lire le contrat d'une tâche et ses minutes consommées
Sur une règle déclenchée par une tâche, related.contract donne le contrat
auquel la tâche est liée. Voir le tableau « Contenu de related » ci-dessous.
Alimenter un champ crédit
- Écrivez la valeur comme un montant signé à ajouter, jamais comme le solde visé.
- Renseignez un objet contenant le montant et sa note.
Exemple, pour débiter le montant d'une facture :
{
"Crédits": {
"amount": "{{= round(mul(record.totalTtc, -1), 2) }}",
"note": "facture"
}
}Un champ crédit fonctionne comme un cahier auquel on ajoute des écritures : la valeur écrite s'ajoute au solde, elle ne le remplace pas. Quand l'information complémentaire du champ est une liste, la note doit être une des valeurs configurées. Voir Champ crédit.
Référence
Fonctions disponibles
| Fonction | Effet |
|---|---|
add(a, b) | Addition sûre de deux montants |
sub(a, b) | Soustraction sûre |
mul(a, b) | Multiplication sûre : quantité par prix unitaire |
div(a, b) | Division sûre. Échoue si le diviseur vaut zéro |
round(valeur) ou round(valeur, décimales) | Arrondit à N décimales, zéro par défaut. À appliquer sur le résultat monétaire final |
sum(liste) | Somme sûre d'une liste de nombres, typiquement les prix des enregistrements liés |
size(valeur) | Taille d'une chaîne ou d'une liste |
has(champ) | Teste la présence d'une clé |
formatDateTime(date) ou formatDateTime(date, fuseau) | Écrit la date et l'heure au format jj/mm/aaaa hh:mm, en heure de Paris par défaut |
formatTime(date) ou formatTime(date, fuseau) | Écrit l'heure au format hh:mm, sur 24 h, en heure de Paris par défaut |
addMonths(date, n) | Décale la date de n mois (n entier, négatif pour reculer) ; le jour est ramené à la fin du mois d'arrivée s'il n'existe pas |
addDays(date, n) | Décale la date de n jours (n entier, négatif pour reculer) |
range(n) | Liste 0 à n-1, avec n entier de 0 à 50 |
Cette liste est complète : aucune autre fonction ne peut être appelée. Les
opérations sur les listes — map, filter, all, exists — s'écrivent
attachées à la liste, comme dans related.produits.map(p, p.sellingPrice).
Contenu de related
| Type de champ de la fiche | Ce que related contient |
|---|---|
| Champ catalogue à valeurs multiples | Un objet par produit avec id, name, sellingPrice, vatRate et unit |
| Champ de relation CRM | Un objet par enregistrement lié, avec ses champs |
| Champ utilisateur | Un objet par utilisateur, avec id, name et email |
Les objets auxquels vous n'avez pas accès sont absents de la liste : un total
calculé avec sum les exclut. Sur un enregistrement lié, les champs réservés à
un périmètre, à leur auteur ou masqués aux automatisations n'apparaissent pas dans
l'objet, même quand vous avez accès à l'enregistrement lui-même.
Pour un déclencheur de type tâche, ce sont les champs personnalisés du type de tâche qui sont chargés selon les mêmes règles.
Pour un déclencheur de type tâche, related.contract donne aussi le contrat lié
à la tâche :
| Clé | Contenu |
|---|---|
related.contract.templateId | Le modèle du contrat |
related.contract.fieldValues.<champ> | La valeur d'un champ du modèle : un nombre pour un champ nombre ou montant, un texte pour les autres, vide si non renseigné |
related.contract.ticketMinutes | Les minutes consommées. Si le contrat suit une unité dont le libellé est « minute » ou « minutes », c'est la quantité consommée de cette unité, ajustements et frais d'accès déduits (plusieurs unités de ce nom s'additionnent ; une unité jamais consommée vaut 0). Sinon, c'est la somme des durées saisies à la clôture des tickets liés au contrat, 0 sans ticket clôturé |
related.contract n'existe pas quand la tâche n'a pas de contrat : commencez la
condition par has(related.contract), sinon l'exécution échoue. Le ticket en
cours de création compte 0 minute, la lecture ignore les groupes de l'utilisateur,
et l'aperçu de la règle ne la remplit pas. Les conditions guidées ne la savent
pas écrire : choisissez « Expression (CEL) » dans le bloc « Condition ». Une règle
dont le déclencheur n'est pas une tâche ne peut pas la lire.
Refus à l'enregistrement
Une formule est contrôlée au moment de l'enregistrement de la règle.
| Message | Cause |
|---|---|
« Une règle planifiée n'a pas de déclencheur à lire : « <référence> » ne peut pas être utilisé. » | La règle a le déclencheur « Date » et une formule d'action lit malgré tout une racine |
| « L'expression de la règle d'automatisation est invalide. » | La formule ne s'analyse pas |
« <racine> n'existe pas dans le contexte de la règle. Racines disponibles : record, before, after, related, actor. » | La formule lit une racine inconnue |
« <référence> n'existe pas : record, before, after, related, actor sont des racines de premier niveau. Écrivez <champ> sans préfixe. » | Une racine a été imbriquée dans une autre |
« Le champ <champ> n'existe pas sur <entité>, ou n'est pas accessible aux automatisations. » | Faute de frappe sur un nom de champ |
« Fonction <nom> inconnue dans la formule. Fonctions autorisées : has, size, add, sub, mul, div, round. » | Une fonction hors de la liste autorisée est appelée |
Erreurs à l'exécution
| Situation | Conséquence |
|---|---|
| Une opérande n'est pas un nombre : champ vide, texte non numérique | L'action passe en erreur. Aucune valeur n'est écrite |
| Une division par zéro | L'action passe en erreur |
Une formule référence related alors qu'aucune donnée liée n'a pu être chargée | L'action passe en erreur |
Une date n'est pas une date valide, un fuseau n'est pas un fuseau reconnu (par exemple europe/paris) | L'action passe en erreur. Une date vide donne un texte vide |
Une formule ne fabrique jamais de valeur par défaut : plutôt qu'écrire zéro ou une valeur approchée, elle fait échouer l'action, visible dans l'onglet « Exécutions ».
Limite d'écriture
Une formule ne peut pas contenir la séquence }} autrement que pour se fermer.
Si votre calcul en a besoin, placez la formule seule dans la valeur plutôt que de
l'insérer dans une phrase.
Questions fréquentes
Puis-je utiliser une formule dans une condition ?
Non. Le marqueur {{= }} n'est reconnu que dans les paramètres d'une action, et
les fonctions de date n'y existent pas. Une condition s'écrit directement en expression, sans marqueur, et les fonctions de
calcul n'y sont pas disponibles. Voir
Restreindre une règle par une condition.
Pourquoi ne pas écrire simplement record.credits - record.totalTtc ?
Parce que la soustraction native est un calcul à virgule flottante : sur des
montants, elle produit des résultats faux au centime près. sub fait le calcul
exact.
Puis-je additionner les montants de plusieurs fiches liées ?
Oui, si elles sont liées par un champ de relation de la fiche déclencheuse :
{{= sum(related.<champ>.map(f, f.<montant>)) }}. Les fiches hors de votre
périmètre d'accès sont exclues du total.
Une formule peut-elle rendre autre chose qu'un nombre ?
Oui. Seule dans la valeur, elle rend son résultat avec son type : nombre, texte ou oui/non. Insérée dans une phrase, elle rend toujours du texte.
Demander une confirmation avant d'exécuter
Confirmation au niveau de la règle ou d'une action, effet d'un refus et cas où la confirmation n'est pas demandée
Créer une sortie de stock depuis une règle
Faire ouvrir par une règle une sortie de stock en brouillon, qu'une personne valide ensuite dans le module Stocks