Les réglages du module
Votre module a des choix qui ne vous appartiennent pas. La durée d’un prêt, l’envoi ou non d’une relance, l’adresse d’expédition des courriels : ce sont des décisions du client, pas des constantes de votre code. Elles ont un écran, et cet écran se déclare dans un fichier.
modules/library/├── module.json├── settings.json <- ici└── models/{ "parameters": [ { "code": "library.loan_days", "type": "integer", "default": 21 }, { "code": "library.reminder_enabled", "type": "boolean", "default": true } ], "groups": [{ "id": "library", "label": "settings.tab.library", "order": 90 }], "forms": [ { "key": "library.settings", "label": "settings.library.title", "read_groups": ["kws_admin"], "write_groups": ["kws_admin"], "settings_group": "library", "settings_order": 10, "fields": [ { "code": "library.loan_days", "label": "settings.library.loan_days" }, { "code": "library.reminder_enabled", "label": "settings.library.reminder" } ] } ]}Redémarrez : un onglet Bibliothèque apparaît dans Réglages, avec ses deux champs et leurs valeurs par défaut. Vous n’avez rien enregistré, rien importé, rien branché.
Les trois sections
Toutes sont facultatives, et elles répondent à trois questions différentes.
parameters déclare le paramètre lui-même : son code, son type, sa valeur par défaut. Cinq
types, pas un de plus : string, integer, decimal, boolean, json. Le défaut est validé
au démarrage, donc une faute de frappe se voit au boot et pas au premier clic.
groups crée un onglet de l’écran Réglages. Un module qui n’a qu’un formulaire peut s’en
passer et se ranger dans un onglet existant.
forms est l’écran : un titre, qui a le droit de le lire, qui a le droit d’y écrire, et la
liste des champs. Un champ ne redéclare pas son type : il pointe un code, et le type déclaré
plus haut choisit l’éditeur.
Les droits
read_groups vide veut dire ouvert en lecture. write_groups vide ne veut jamais dire
ouvert en écriture : un formulaire sans liste d’écriture n’est modifiable par personne. C’est
volontaire, et c’est le bon défaut : un réglage oublié est en lecture seule, pas grand ouvert.
Un champ peut faire un peu plus
{ "code": "mail.provider", "label": "settings.mail.provider", "choices": [["smtp", "SMTP (votre serveur)"], ["console", "Console (dev)"]]},{ "code": "mail.smtp.host", "label": "settings.mail.smtp_host", "show_when": { "field": "mail.provider", "in": ["smtp"] }},{ "code": "mail.smtp.password_secret_ref", "label": "settings.mail.password", "secret": true}choicestransforme le champ en liste déroulante.show_whenne montre le champ que si un autre a l’une des valeurs listées. Un champ caché n’est jamais obligatoire, donc il ne peut pas bloquer un enregistrement.secret: trueest le seul cas où la valeur ne fait pas l’aller-retour. Ce que l’administrateur tape part chiffré dans le coffre (kewos/secrets, interdiction n°16), le paramètre ne garde qu’une référence, et la lecture du formulaire renvoie un simple booléen « configuré ». Un mot de passe SMTP ne revient jamais dans une réponse HTTP.
Lire le réglage depuis votre code
from kewos.config import get_parameter
jours = get_parameter(engine, "library.loan_days") # défaut du tenantjours = get_parameter(engine, "library.loan_days", company_id) # surcharge de la sociétéLa résolution est une cascade à trois étages, exécutée ici sur une instance réelle :
avant toute écriture : 21 <- la valeur déclarée dans le fichieraprès écriture tenant : 30société 1 (héritée) : 30 <- pas de surcharge : elle héritesociété 1 (surcharge) : 7défaut du tenant : 30 <- inchangé par la surchargeUne société peut donc avoir sa propre durée de prêt sans que les autres bougent, et vous n’avez écrit aucune logique de cascade.
Ce que le fichier ne sait pas faire
Un validateur. Si votre paramètre doit refuser certaines valeurs (« au moins un jour »), on ne l’exprime pas en JSON. Vous le déclarez alors en Python, et le fichier se contente de le référencer dans un formulaire :
def register(registry): register_parameter( "library.loan_days", ParameterType.INTEGER, default=14, validator=_refuse_zero, )Le noyau lit votre settings.json après votre register(), précisément pour ça : votre
déclaration Python gagne, et le doublon du fichier est ignoré sans bruit. Le validateur survit.