Écrire une règle métier
Objectif
Faire réagir un formulaire à ce que fait la personne qui le remplit : n’afficher le champ Responsable que pour les dépenses de plus de 100 £, désactiver Date de clôture tant que l’affaire n’est pas gagnée, reprendre par défaut la Devise du compte.
Prérequis
- Vous êtes connecté en tant que créateur, avec la solution de la table ouverte.
- La table possède les champs dont parle la règle et — si vous voulez lier la règle à un formulaire — ce formulaire existe.
Ce qu’est une règle métier, et ce qu’elle n’est pas
Une règle métier s’exécute dans le navigateur, sur le formulaire, et modifie le comportement du formulaire. Elle dispose de quatre verbes : afficher ou masquer un champ, l’activer ou le désactiver, le rendre obligatoire ou non, et définir une valeur.
Elle ne décide pas de ce qui peut être enregistré. Quelqu’un peut désactiver une règle, utiliser un autre écran ou appeler directement l’API, et l’enregistrement est quand même sauvegardé. Tout ce qui doit être vrai des données relève d’une étape de plug-in serveur, qui s’exécute quoi qu’ait fait le navigateur. Utilisez une règle métier pour rendre un formulaire agréable ; utilisez une étape de plug-in pour rendre une règle réelle. Il est normal de vouloir les deux, et elles s’écrivent séparément à dessein.
Étapes
-
Ouvrez le formulaire auquel la règle est destinée — la table, puis Formulaires, puis le formulaire — et sélectionnez Événements dans sa barre d’outils. La liste affiche toutes les règles qui s’exécutent sur ce formulaire, y compris celles liées à tous les formulaires de la table.
-
Sélectionnez Nouveau. Le concepteur de règles s’ouvre.
-
Saisissez un nom d’affichage. Le nom logique se remplit tout seul, précédé du préfixe de votre éditeur, et est figé une fois la règle enregistrée.
-
Vérifiez le formulaire. C’est déjà celui d’où vous venez, ce qui est presque toujours le bon choix — une règle parle de champs, et les champs dont elle parle sont ceux que vous avez sous les yeux. Passez-le sur Tous les formulaires pour quelque chose qui doit s’appliquer partout où la table est affichée, comme « masquer ceci sauf si le statut est Approuvé ». Une règle liée à tous les formulaires apparaît quand même dans la liste Événements de chaque formulaire, signalée comme telle.
-
Choisissez quand elle s’exécute — un événement par règle :
- À l’ouverture du formulaire applique la règle au moment où l’enregistrement s’affiche.
- À la modification d’un champ affiche un sélecteur de champs. Choisissez un champ et il apparaît sous forme de pastille ; ajoutez-en autant que la règle en a besoin, et retirez-en un avec le ✕ de sa pastille.
- À l’enregistrement du formulaire exécute la règle entre l’appui sur le bouton et
l’écriture : elle peut ainsi renseigner quelque chose — ou arrêter l’enregistrement avec
cancelSave, ci-dessous.
Une r ègle sans déclencheur ne s’exécute jamais : Enregistrer reste donc désactivé tant qu’une règle de modification de champ n’a pas au moins un champ.
Un événement par règle, c’est délibéré. Lorsque la même chose doit se produire à deux moments — le cas habituel, « afficher ceci quand le statut est rejeté », qui doit être juste à l’ouverture du formulaire et à chaque changement de statut —, écrivez deux règles qui importent un même script de solution, chacune longue de deux lignes. La logique est écrite une seule fois ; là où les deux moments diffèrent réellement, le script interroge
eventType()et décide lui-même. Plusieurs déclencheurs sur une même règle ne placeraient cette décision nulle part : rien à l’écran n’indiquerait quelle moitié du script appartient à quel événement. -
Écrivez le script dans l’éditeur. Il souligne les erreurs pendant la saisie, complète les fonctions de la plateforme et affiche les arguments de chacune dès que vous tapez la parenthèse ouvrante. L’œil dans le coin supérieur de l’éditeur ouvre Ce qu’un script peut appeler par-dessus le code.
-
Laissez Activée cochée, ou décochez-la pour conserver la règle sans l’exécuter.
-
Sélectionnez Enregistrer.
Ce qu’un script peut appeler
| Appel | Ce qu’il fait |
|---|---|
getValue(field) | La valeur actuelle du champ sur le formulaire. |
setValue(field, value) | Définit un champ sur le formulaire. |
setVisible(field, visible) | Affiche ou masque un champ. |
setDisabled(field, disabled) | Met un champ en lecture seule, ou non. |
setRequired(field, required) | Rend un champ obligatoire, ou non. |
eventType() | "OnLoad", "OnChange" ou "OnSave" — l’événement en cours. |
changedField() | Le champ dont la modification a déclenché un OnChange, sinon "". |
isNewRecord() | true tant que l’enregistrement n’a jamais été sauvegardé. Servez-vous-en pour verrouiller un champ choisi une fois puis figé, comme le type d’une activité. |
cancelSave(message) | À l’enregistrement uniquement : arrête l’enregistrement de ce formulaire et affiche le message. |
isEmpty(value) | Indique si une valeur n’est pas renseignée. Un texte vide et l’absence de valeur sont vides ; 0 et false sont des valeurs que quelqu’un a choisies. |
Un champ est désigné par son nom logique (par_amount), et non par son nom d’affichage.
Un champ vide se lit comme un texte vide : getValue("par_currency") == "" est donc le
test pour « pas encore renseigné » — c’est ainsi que fonctionne l’exemple de devise
ci-dessous. Pour un nombre, une date ou un champ de recherche, il n’y a pas de texte vide
auquel comparer : utilisez plutôt isEmpty(getValue("par_due")). Cette fonction reprend la
même définition du vide que la vérification d’obligation du formulaire, ce qui explique
qu’une règle ne puisse pas renseigner par défaut un champ que le formulaire vient
d’accepter comme rempli.
getValue et setValue s’écrivent et se comportent exactement comme dans une étape de
plug-in serveur : la logique que vous mettez au point une fois se lit de la même façon des
deux côtés.
Un champ numérique se lit comme un nombre — 1200.5, et non "1200.5" — même pendant la
saisie, et un champ non renseigné se lit toujours comme vide. Cela compte dès que vous
écrivez votre propre fonction : func needsApproval(amount: number) n’accepte pas un
morceau de texte, et l’échec se présente sous la forme
Function overload for needsApproval not found. plutôt que d’évoquer les types. Déclarez
donc un montant en number, et non en int — une colonne décimale contient 1200.50, et
un paramètre entier la refuse — et substituez un zéro à une zone vide avant d’effectuer un
calcul :
func claimAmount(): number {
var raw = getValue("par_amount");
if (isEmpty(raw)) { return 0; }
return raw;
}
… et tout ce qu’exporte un script de solution. Lorsque les mêmes quelques lignes
commencent à apparaître dans plusieurs règles, déplacez-les dans un script de
solution et importez-le en tapant
import 'par_expense_helpers'; en haut de la règle — l’éditeur complète le nom et, dès lors,
sait ce que le module exporte.
Les choix, et afficher une section pour l’un d’eux
Un choix se lit comme son numéro, la valeur attribuée à l’option (110000001), que le
formulaire vienne de s’ouvrir ou que quelqu’un vienne de le sélectionner. Comparez-le donc à
un nombre, et non à un texte :
if (getValue("pw_type") == 110000001) { setVisible("pw_to", true); }
Auparavant, un choix qui venait d’être sélectionné se lisait comme du texte
("110000001"), et la comparaison ci-dessus cessait discrètement de fonctionner après la
première sélection. Une règle qui comparait à un texte entre guillemets doit être débarrassée
de ces guillemets.
Pour n’afficher une section que pour un choix, masquez les champs qu’elle contient. Une section dont tous les champs sont masqués disparaît, titre compris, et réapparaît dès qu’une règle affiche de nouveau l’un d’eux. C’est ainsi que le formulaire d’activité de Sales affiche une section E-mail pour un e-mail et une section Appel téléphonique pour un appel.
Pour qu’un champ ne puisse être choisi qu’une fois, désactivez-le lorsque l’enregistrement n’est pas nouveau :
setDisabled("pw_type", !isNewRecord());
Lorsqu’un nouvel enregistrement est sauvegardé, les règles exécutées à l’ouverture s’exécutent de nouveau : le champ se verrouille donc aussitôt. Comme toute règle, celle-ci n’arrête que le formulaire. Pour empêcher aussi l’API ou une importation de modifier le champ, écrivez également une étape de plug-in serveur.
Arrêter un enregistrement
Une règle qui s’exécute à l’enregistrement du formulaire peut refuser l’enregistrement :
if (getValue("par_status") == "rejected" && getValue("par_reason") == "") {
cancelSave("Give a reason before rejecting this claim.");
}
L’enregistrement s’arrête, votre message apparaît en haut du formulaire, et rien n’est perdu — le formulaire reste ouvert avec tout ce qui y a été saisi.
Ce n’est toujours pas une contrainte. Cela arrête ce formulaire, dans ce navigateur : l’API, une importation, une application personnalisée et tout autre formulaire sans la règle enregistrent l’enregistrement malgré tout. Cette fonction existe parce que « ne me laisse pas soumettre ceci à moitié rempli » mérite d’être dit sur le formulaire — mais si la chose doit être vraie des données, écrivez aussi une étape de plug-in serveur.
Un exemple
Afficher le champ responsable, et le rendre obligatoire, uniquement pour les dépenses de plus de 100 — à l’ouverture et à chaque modification du montant :
var over = getValue("par_amount") > 100;
setVisible("par_manager", over);
setRequired("par_manager", over);
Remarquez qu’elle dit ce qui doit être vrai dans les deux sens. Une règle qui ne fait qu’afficher un champ le laissera à l’écran une fois le montant redescendu, puisque rien n’a demandé à le masquer de nouveau.
Deux règles sur un même formulaire
Toutes les règles activées qui correspondent au formulaire et à l’événement s’exécutent, dans l’ordre de leur nom logique, chacune avec ses propres variables. Elles partagent les valeurs du formulaire : une règle qui définit un champ est donc vue par les règles suivantes. Si deux règles portent sur le même champ, la dernière l’emporte — ce qui est stable, mais relève du hasard plutôt que de la conception : préférez une règle par champ.
Une règle ne peut pas s’exécuter indéfiniment
Chaque règle s’exécute avec un budget, et une règle qui le dépasse est arrêtée et signalée sous son propre nom. Il y a trois limites, et chacune détecte une erreur différente :
| Elle arrête | Quand |
|---|---|
| une boucle qui ne se termine jamais | while (true), ou une condition qui n’est jamais tout à fait remplie |
| une règle qui en fait tout simplement trop | elle tourne encore au bout d’une demi-seconde |
| une fonction qui s’appelle elle-même sans fin | elle en est à cent appels imbriqués sans fin en vue |
Le formulaire continue de fonctionner, la personne conserve ce qu’elle était en train de
saisir, et le message nomme la règle et la ligne. Envelopper la boucle dans un try
n’y change rien — le budget n’est pas quelque chose qu’un script peut intercepter.
Vous ne le rencontrerez pas par hasard : la plus grosse règle de tous les exemples utilise
bien moins d’un centième de l’allocation. Si vous le rencontrez, la règle contient un bogue
— le plus souvent un while dont le corps ne modifie jamais la condition.
Une remarque sur la comparaison des valeurs. == compare au sein d’un même type : deux
nombres, deux textes, deux valeurs vrai/faux. Deux types différents ne sont jamais égaux —
1 == "1" est faux — et rien n’est égal à rien : un champ non défini n’est donc pas égal à
"". C’est pourquoi un champ sans valeur se lit comme un texte vide, et pourquoi isEmpty()
existe pour les nombres et les dates.
Dépannage
- Une règle qui ne semble jamais s’exécuter. Vérifiez qu’elle est activée, que sa liaison de formulaire correspond au formulaire que vous regardez, et que son déclencheur inclut le champ que vous modifiez.
- « BS Lang script is invalid: … » à l’enregistrement — le script ne peut pas être analysé. L’éditeur souligne la même erreur ; le message nomme la ligne.
- « Form '…' was not found on '…'. » — la règle est liée à un formulaire que la table ne possède pas. Choisissez-en un dans la liste, ou liez-la à tous les formulaires.
- Un message rouge en haut d’un formulaire dans l’application, nommant une règle. La règle a levé une erreur pendant son exécution. Le formulaire continue de fonctionner ; la règle s’est arrêtée là où elle a échoué.
- Des soulignements sous
getValue— l’éditeur ne signale plus les fonctions propres à la plateforme comme non définies. Si vous voyez cela, le script appelle quelque chose qui ne figure pas dans la liste ci-dessus.
Scénarios associés
- Créer un formulaire.
- Rendre un champ obligatoire ou en lecture seule — la version figée de la même idée, pour quand la réponse ne dépend jamais de l’enregistrement.