🧑🎓Bibliothèque de formules classiques
Vous pouvez trouver sur cette page des exemples typiques de formules à utiliser dans Ksaar. N'oubliez pas d'adapter les variables à l'architecture de votre application.
🔤 Champs Texte
Liste de champs manquants
Formule de type : Texte
Cette formule vérifie si certains champs sont vides (comme le nom et la date de début de l'évènement ici). Si c’est le cas, elle affiche un message listant les champs manquants, sinon elle ne renvoie rien.
Vous pouvez évidemment modifier la liste champs
pour ajouter ou supprimer des éléments.
LET(
champs, [
IF(IS_EMPTY({txt_nom_event}), "Nom de l'événement", ""),
IF(IS_EMPTY({dateH_debut_Event}), "Date de début", "")
],
comment, "ajoutez les champs à tester",
champsManquants, FILTER(champs, x => x != ""),
IF(
IS_EMPTY(champsManquants),
"",
"Attention, vous devez remplir " & JOIN(", ", champsManquants) & " pour continuer."
)
)
Exemple de rendu :

Extraire l’extension d’un fichier
Formule de type : Texte
Cette formule extrait l’extension d’un fichier à partir d’un champ fichier {fichier}
, puis la convertit en minuscules.
LET(
filename, FILENAME({fichier}),
LOWER(REGEX_EXTRACT(filename, "\.([^.]+)$"))
)
Exemple de rendu :

Extraire le prénom ou le nom d'un champ qui réunit les deux
Formules de type : Texte
Cette formule extrait le prénom ou le nom à partir d’un champ {prenom nom}
contenant le prénom et le nom concaténés, en inversant d’abord la chaîne, puis en récupérant la partie correspondant au prénom (qui se retrouve à droite après inversion), avant de la ré-inverser pour obtenir le prénom original.
Le procédé est similaire pour extraire le nom.
Ces formules partent du principe que le prénom ne contient pas d'espaces, mais prennent en charge les noms à particule.
LET(
txt, {prenom nom},
rev, JOIN("", REVERSE(SPLIT(txt, ""))),
pos, FIND(" ", rev),
prenom_rev, LEFT(rev, pos - 1),
prenom, JOIN("", REVERSE(SPLIT(prenom_rev, ""))),
prenom
)
LET(
txt, {prenom nom},
rev, JOIN("", REVERSE(SPLIT(txt, ""))),
pos, FIND(" ", rev),
nom_rev, RIGHT(rev, LEN(rev) - pos),
nom, JOIN("", REVERSE(SPLIT(nom_rev, ""))),
nom
)
Il existe aussi une option alternative :
LET(
prenom, {prenom nom},
liste, SPLIT(prenom, " "),
prenom, liste[0],
prenom
)
LET(
nom, {prenom nom},
liste, SPLIT(nom, " "),
liste_sliced, SLICE(liste, 2, LEN(liste) + 1),
nom, JOIN(" ", liste_sliced),
nom
)
Exemple d'application de la formule :

Transformer un nombre ou prix en texte
Formule de type : Texte
Cette formule convertit un tarif mensuel en lettres ({nb_prix_contrat}
) jusqu'à 99 999 €, en français, avec les règles spécifiques de la langue.
LET(
dizaineMillier, FLOOR({nb_prix_contrat} / 10000),
millier, FLOOR( {nb_prix_contrat}/ 1000) % 10,
resteMilliers, {nb_prix_contrat} % 1000,
centaine, FLOOR(resteMilliers / 100),
resteCentaines, resteMilliers % 100,
dizaine, FLOOR(resteCentaines / 10),
unité, resteCentaines % 10,
dizaineMillierTexte,
IF(dizaineMillier == 0, "",
IF(dizaineMillier == 1,
CHOOSE(millier, "ONZE MILLE", "DOUZE MILLE", "TREIZE MILLE", "QUATORZE MILLE", "QUINZE MILLE", "SEIZE MILLE", "DIX-SEPT MILLE", "DIX-HUIT MILLE", "DIX-NEUF MILLE") & " ",
CHOOSE(dizaineMillier, "DIX", "VINGT", "TRENTE", "QUARANTE", "CINQUANTE", "SOIXANTE", "SOIXANTE-DIX", "QUATRE-VINGT", "QUATRE-VINGT-DIX") & IF(millier == 0, " MILLE ", " ")
)
),
millierTexte,
IF(millier == 0 || dizaineMillier == 1, "",
IF(millier == 1, "MILLE ",
CHOOSE(millier,"", "DEUX MILLE", "TROIS MILLE", "QUATRE MILLE", "CINQ MILLE", "SIX MILLE", "SEPT MILLE", "HUIT MILLE", "NEUF MILLE") & " "
)
),
centaineTexte,
IF(centaine == 0, "",
IF(centaine == 1 && resteCentaines == 0, "CENT ",
CHOOSE(centaine, "CENT", "DEUX CENT", "TROIS CENT", "QUATRE CENT", "CINQ CENT", "SIX CENT", "SEPT CENT", "HUIT CENT", "NEUF CENT") & " "
)
),
dizaineTexte,
IF(dizaine == 0, "",
IF(dizaine == 1,
CHOOSE(unité, "DIX", "ONZE", "DOUZE", "TREIZE", "QUATORZE", "QUINZE", "SEIZE", "DIX-SEPT", "DIX-HUIT", "DIX-NEUF") & " ",
CHOOSE(dizaine, "DIX", "VINGT", "TRENTE", "QUARANTE", "CINQUANTE", "SOIXANTE", "SOIXANTE-DIX", "QUATRE-VINGT", "QUATRE-VINGT-DIX") & IF(unité > 0 && dizaine != 7 && dizaine != 9, "-", " ")
)
),
unitéTexte,
IF(dizaine == 1 || dizaine == 7 || dizaine == 9, "",
CHOOSE(unité, "UN", "DEUX", "TROIS", "QUATRE", "CINQ", "SIX", "SEPT", "HUIT", "NEUF") & " "
),
texteFinal, TRIM(dizaineMillierTexte & millierTexte & centaineTexte & dizaineTexte & unitéTexte),
IF(
OR(
RIGHT(texteFinal, 12) = "QUATRE-VINGT",
RIGHT(texteFinal, 9) = "DEUX CENT",
RIGHT(texteFinal, 10) = "TROIS CENT",
RIGHT(texteFinal, 11) = "QUATRE CENT",
RIGHT(texteFinal, 9) = "CINQ CENT",
RIGHT(texteFinal, 8) = "SIX CENT",
RIGHT(texteFinal, 9) = "SEPT CENT",
RIGHT(texteFinal, 9) = "HUIT CENT",
RIGHT(texteFinal, 9) = "NEUF CENT"
),
texteFinal & "S",
texteFinal
)
)
Exemple de rendu :

Une autre formulation du même principe est la suivante. Cette formule transforme un chiffre en texte avec la dénomination appropriée et prend en compte les chiffres jusqu'aux trilliards.
LET (
Nombre, {nb_prix_contrat},
absNombre, ABS(Nombre),
estNegatif, Nombre < 0,
estNul, Nombre = 0,
separateur, "-",
espaceInsecable, CHAR(8239),
parts, SPLIT(FORMAT_CURRENCY(absNombre,"fr-FR","EUR"),","),
centimes, "0" & LEFT(parts[1],2),
blocs, FLATTEN([SPLIT(parts[0],espaceInsecable), centimes]),
texte, {
dénominations: ["centime", "Euro", "mille", "million", "milliard", "billion", "billiard", "trillion", "trilliard"],
chiffres: ["","un","deux","trois","quatre","cinq","six","sept","huit","neuf"],
dixvingt: ["dix","onze","douze","treize","quatorze","quinze","seize","dix-sept","dix-huit","dix-neuf"],
dizaines: ["","dix","vingt","trente","quarante","cinquante","soixante","soixante","quatre-vingt","quatre-vingt"]
},
enLettre, LAMBDA(c, d, u,
LET(
Htxt, IF( c, IF(c>1 , texte.chiffres[c] & separateur & "cent", "cent"), ""),
Ttxt, IF( d>1, texte.dizaines[d] & IF( u>0, "", "" ), "" ) & IF(d=8 && u=0,"s",""),
Utxt, IF( d+u, IF(OR(d=1,d=7,d=9),texte.dixvingt[u], IF(u=1 && d>0 && d<8, "et" & separateur, "") & texte.chiffres[u]), ""),
JOIN(separateur, FILTER([Htxt,Ttxt,Utxt],x=>x))
)),
converted, REVERSE(
MAP(blocs, LAMBDA(bloc,
LET(
numbers, MAP(
FLATTEN([REVERSE(SPLIT(bloc,"")),0,0]),
LAMBDA(x, TO_NUMBER(x))
),
centaine, numbers[2],
dizaine, numbers[1],
unites, numbers[0],
{ lettres: enLettre(centaine, dizaine, unites), chiffres: TO_NUMBER(bloc) }
)
)
)),
parts, MAP([0,1,2,3,4,5,6,7,8],i =>
LET(last,LEN(converted)-1,
IF(
i<=last,
LET(
number, converted[i].chiffres,
txtNum, converted[i].lettres,
preparateur, IF(
AND(i>=1, i<last, number),
separateur,
IF(AND(i=0, number, i<last), " ", "")),
quantite, IF(AND(number=1, i=2), "", txtNum),
pluriel, IF(AND(quantite, i=1, absNombre % 100 = 0, absNombre > 100, absNombre % 1000 <>0),"s",""),
separation, IF(i<=1," ",IF(AND(quantite, number>1 || i=last), separateur, "")),
denomination, IF(
number || AND(i=1, absNombre>=1),
texte.dénominations[i] & IF(
AND(i=0 || i>2, number>1) || AND(i=1, absNombre>1),
"s", ""),
""
),
preparateur & quantite & pluriel & separation & denomination
)
,""
)
)),
resultat, JOIN("",REVERSE(parts)),
IFS(estNul, "zéro Euro", estNegatif, "moins " & resultat, true, resultat)
)
Exemple de rendu :

💻 HTML
Notification formatée en HTML
Formule de type : HTML
Cette formule construit un texte HTML formaté affichant le nom du créateur, la date de création, les agents notifiés (avec @
) et le contenu du commentaire. Elle est utilisée pour présenter un commentaire dans l’interface Ksaar.
La fonction MAP
a besoin d'une liste en premier paramètre, d'où l'utilisation d'un liaison multiple.
LET(
createur, "<h6 style = 'margin-bottom :0px'>" & {nom du createur du commentaire} & " - " & FORMAT_DATE({Créé le}, "dddd DD/MM/YY HH:mm") & "</h6>",
listeNotifies, MAP({liaison multiple vers les noms des agents notifies}, x => "@" & x),
notifiesTexte, JOIN(", ", listeNotifies)
notifies, IF(
IS_EMPTY(notifiesTexte),
"",
"<h6 style = 'color : #896853'>" & notifiesTexte & "</h6>"
),
contenu, {contenu du commentaire},
createur & notifies & contenu
)
Exemple de retour :

Liaison multiple sous forme de pastilles
Formule de type : HTML
Cette formule génère un bloc HTML stylisé contenant des pastilles (badges) pour chaque prénom d’enfant listé dans le champ {lnkM_enfant_parent → txt_prenom_enfant}
, en les séparant par des virgules et en les affichant verticalement dans un conteneur avec un style personnalisé.
LET(
style, "<style> #pastilles_uniformes .badge-grey "
&" {display: inline-block;background-color: #6c757d;color: #fff;padding: 0.25rem 0.75rem;margin-bottom: 0.5rem;border-radius: 1rem;font-size: 0.875rem;text-align: center;width: 100%;}"
&"#pastilles_uniformes .d-flex {gap: 0.5rem;}</style>",
tags, SPLIT(TO_TEXT({lnkM_enfant_parent → txt_prenom_enfant}), ","),
spans, JOIN("", MAP(tags, tag => "<span class='badge-grey'>" & TRIM(tag) & "</span>")),
style & "<div id='pastilles_uniformes' class='container my-3' style='max-width: 200px;'><div class='d-flex flex-column'>" & spans & "</div></div>"
)
Exemple de rendu :

🗓️ Dates
Récupérer la date la plus récente
Formule de type : Date
Cette formule retourne la date la plus récente dans la liste {listeDate}
en triant les dates par ordre décroissant, puis en prenant la première. Elle est utile pour identifier la dernière date d’un ensemble.
LET(
listeDate, {listeDate},
INDEX(SORT(listeDate,(a,b) => DATE_DIFF(b,a)),1)
)
Exemple de rendu :

Récupérer le numéro du jour
Formule de type : Nombre
Cette formule transforme le résultat de WEEKDAY(date)
pour obtenir le jour de la semaine au format ISO (lundi = 1, dimanche = 7).
LET(
date, {Date},
jour, IF(WEEKDAY(date)=1,7,WEEKDAY(date)-1)
)
Exemple de retour :

Formatage de date de début et de fin
Formule de type : Texte
Cette formule formate une plage horaire lisible à partir des champs {dateH_debut_event}
et {dateH_fin_event}
, en affichant les dates et heures de début et de fin avec des transitions adaptées, tout en gérant les cas où la date est vide ou où les deux dates sont le même jour.
LET(
dateDebut, {dateH_debut_event},
dateFin, {dateH_fin_event},
txtDateDebut, FORMAT_DATE(dateDebut,"fr-FR, dateStyle=full")& " ",
txtHeureDebut, FORMAT_DATE(dateDebut, "HH[h]mm") & " ",
noDate, IF(
IS_EMPTY(dateDebut),
true,
false
),
sameDay, IF(
FORMAT_DATE(dateDebut,"DD/MM/YYYY")==FORMAT_DATE(dateFin,"DD/MM/YYYY"),
true,
false
),
txtTransitionUn, IF(
noDate,
"",
" de "
),
txtTransitionDeux,
IF(
noDate,
" ",
IF(
sameDay,
" à ",
" au "
)
),
txtDateFin, IF(
sameDay,
" ",
FORMAT_DATE(dateFin,"fr-FR, dateStyle=full") & " à " & " "
),
txtHeureFin, FORMAT_DATE(dateFin, "HH[h]mm") & " ",
return, TRIM(txtDateDebut & txtTransitionUn & txtHeureDebut & txtTransitionDeux & txtDateFin & txtHeureFin),
return
)
Exemple de rendu :

Vérifier le chevauchement de 2 plages de dates
Formule de type : Booléen
Cette formule vérifie si deux plages de dates {debutPlageA} {finPlageA}
et {debutPlageB} {finPlageB}
, se chevauchent. Elle renvoie True si les deux se chevauchent et False sinon.
LET(
debutA, {debutPlageA},
finA, {finPlageA},
debutB, {debutPlageB},
finB, {finPlageB},
IF(
debutA <= finB && finA >= debutB,
true,
false
)
)
Exemple de rendu :

🔗 Liaisons
Filtrer une liste issue d'une liaison multiple
Formule de type : Liaison (multiple, utilisateur en fonction de vos besoins)
Cette formule filtre les éléments d’une liste liaisonAFiltrer
en se basant sur une deuxième liste parallèle liaisonUtiliseePourFiltre
, en appliquant une condition à chaque paire d’éléments de même position. Elle est utile pour garder uniquement certains éléments d’une liaison multiple selon des critères associés (exemple : statut, valeur, date).
Veillez à compléter les ...
par la condition qui vous intéresse. Par exemple si vous voulez garder tous les éléments supérieurs à 100 il suffit d'écrire INDEX(liaisonUtiliseePourFiltre,i+1) > 100 )
ou si vous ne voulez garder que les éléments qui ne sont pas nuls !IS_EMPTY(INDEX(liaisonUtiliseePourFiltre, i+1))
.
LET(
liaisonAFiltrer, {LM_nourritureFavorite_contact},
liaisonUtiliseePourFiltre, {LM_nourritureFavorite_contact → Prix},
FILTER(liaisonAFiltrer, (x, i) => INDEX(liaisonUtiliseePourFiltre, i+1) ...)
)
Exemple de retour :

Mis à jour
Ce contenu vous a-t-il été utile ?