Profils de statuts : restreindre sans élargir
La machine à états reste codée ; un profil de statuts ne fait que retirer des transitions, jamais en ajouter, et peut exiger un rôle minimal par transition. Simulation avant activation, comme une règle métier.
Le principe
La machine à états reste dans le code
Chaque document qui passe par un statut au ferme — demandes d’achat, devis, ordres de fabrication, non-conformités, et les tables que ferme le CRUD générique (factures, commandes d’achat, commandes clients, bons de livraison, avoirs, réceptions, bons de consommation) — a déjà une machine à états codée : un graphe Go ValidTransitions par module (achats, production, qualité…), enregistré au démarrage. Un profil de statuts ne touche jamais ce graphe. Il ne peut que retirer une transition que le code autorise, jamais en ajouter une que le code n’autorise pas — la même asymétrie qu’une règle métier a envers l’écriture qu’elle garde : restreindre, jamais élargir.
Un point d’application unique l’applique : Autoriser (pkg/statuts), appelé à la fois par la route de ferme du CRUD générique et par chaque route dédiée de transition de statut (ordres de fabrication, devis, demandes d’achat, non-conformités) — le même motif de garde partagée que pkg/documentsrequis.GardeOF ou pkg/sod.Verifier pour le type de règle séparation des tâches.
Paramètres › Profils de statuts
La matrice de transitions
L’écran se trouve dans Paramètres → Profils de statuts, une table à la fois (GET /api/v1/status-machine/{table}). Pour une table dont le graphe codé est connu, une matrice de cases à cocher montre chaque transition codée depuis → vers, cochée par défaut — décocher une case la restreint, et décocher est la seule action que l’écran permet : impossible d’ajouter une case pour une transition que le graphe ne contient pas.

La matrice ne montre que les transitions déjà autorisées par le code ; décocher restreint, rien ne peut être ajouté.
Onze tables portent un profil aujourd’hui :
purchase_requestsquotesmanufacturing_ordersnon_conformitiesconsumption_vouchersinvoicespurchase_orderssales_ordersdelivery_notescredit_notesreceptions
Pour une table sans graphe codé connu, l’écran bascule sur une liste libre de transitions à autoriser explicitement plutôt qu’une matrice — même principe de restriction, une saisie différente.
Un rôle par transition
Exiger un rôle minimal
Au-delà de restreindre quelles transitions existent, un profil peut exiger un rôle minimal pour une transition précise (roles_par_transition, clé depuis:vers → rôle) — une demande d’achat qui passe de submitted à approved peut être réservée à un rôle direction achat, indépendamment de l’approbation par montant qu’une règle métier applique déjà sur le même document. Les deux contrôles se cumulent : une règle métier peut exiger un workflow d’approbation, et un profil de statuts peut en plus exiger le rôle qui le ferme.
Simuler avant de restreindre
Rejouer les 90 derniers jours
Exactement comme une règle métier, un profil enregistré peut être simulé avant d’activer son affectation : POST /api/v1/status-profiles/{id}/simulate rejoue les 90 derniers jours de transitions réelles sur cette table et rapporte combien auraient été refusées sous le profil restreint — évaluées, refusées, et quelques exemples avec leur depuis → vers et leur date. Rien n’est écrit ; la même discipline « observer avant de durcir » que décrivent les pages sur les règles métier.
POST /api/v1/status-profiles/{id}/simulate { "jours": 90 }
{
"table": "purchase_requests",
"profil": "Achats — restreint",
"jours": 90,
"disponible": true,
"total": 86,
"refusees": 4,
"exemples": [
{ "record_id": "DA-2026-0031", "de": "submitted", "vers": "approved", "date": "2026-08-12" }
]
}Portée et précédence
Client, fournisseur, type de document, locataire
Un profil ne s’applique qu’une fois affecté (status_profile_assignments), et une affectation porte une portée : locataire par défaut, ou restreinte à un client, un fournisseur, ou une classification de type de document (ex. le type d’une non-conformité) — cette dernière résolue depuis le document lui-même, par une lecture bornée à une seule ligne (LireContexteDocumentEnBase), jamais une seconde copie des données du document. Quand plusieurs affectations pourraient correspondre au même document, la plus précise l’emporte : client, puis fournisseur, puis type de document, puis locataire — les portées client et fournisseur visent un tiers, le type de document vise une catégorie, et un tiers est traité comme plus précis qu’une catégorie.
Pour la portée type de document, dont la classification source est un texte libre en base (ex. non_conformities.type), le scope_id de l’affectation reste un UUID : ScopeIDTypeDocument dérive un identifiant UUID stable et déterministe (v5) depuis le libellé choisi, ce qui permet à l’écran de réglages de calculer exactement le même identifiant sans demander à un consultant de le saisir à la main.
← Retour à Règles métier et contrôle
Voir aussi : Mise en service · Pilotage et signaux de risque · Le copilote
