Aller au contenu

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
}
  • choices transforme le champ en liste déroulante.
  • show_when ne 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: true est 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 tenant
jours = 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 fichier
après écriture tenant : 30
société 1 (héritée) : 30 <- pas de surcharge : elle hérite
société 1 (surcharge) : 7
défaut du tenant : 30 <- inchangé par la surcharge

Une 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.