🧑‍🎓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 :

À gauche : un fichier téléversé, à droite : l'extension utilisée
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.

Pour extraire le prénom
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
)
Pour extraire le nom
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 :

Pour extraire le prénom
LET(
    prenom, {prenom nom},
    liste, SPLIT(prenom, " "),
    
    prenom, liste[0], 
    prenom
)
Pour extraire le nom
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 :

À gauche : le nom complet, à droite : le retour des formules
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 :

À gauche : le chiffre en entrée, à droite : le résultat de la formule

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 :

À gauche : le chiffre en entrée, à droite : le prix au format texte avec denominations

💻 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 :

À gauche : l'association et son produit vendu, à droite : le commentaire stylisé avec du HTML
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 :

Dans les 3 premières colonnes : un choix de date, dans la dernière colonne : la date la plus récente des 3
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 :

À gauche : une date, à droite : le numéro du jour de la semaine
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 :

À gauche : les deux dates et heures, à droite : la plage sous format texte
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 :

Dans les colonnes de gauche : les bornes des 2 plages de dates, à droite : la validation de chevauchement

🔗 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 :

À gauche : des contacts, au milieu : les articles choisis, à droite : les articles au-dessus d'un certain prix

Mis à jour

Ce contenu vous a-t-il été utile ?