Lot 1, séquence A3 — Numérotation
1er octobre 2026. Mise en œuvre de la séquence A3 du plan du Lot 1. Décisions : EC-010, EC-023 ; écart ouvert : EC-068.
- Le rang d’un numéro vient de la base ; son format vient du domaine. La base garantit l’unicité et l’absence de trou,
numeroOfficiel(packages/domain) compose la chaîne. Un seul endroit connaît le format. - Le format par défaut est celui de l’avenant n°1 :
{AA}{code campagne}/{nature}/{produit}/{NNNN}, par exemple26A/MP/ANA/0001. Le préfixe entreprise existe comme segment, désactivé. - Aucune route REST en A3 : le premier consommateur est le Lot 2 (validation d’un lot). L’API expose un service interne.
| Table | Contenu |
|---|---|
app.modele_numerotation |
Une ligne par version du modèle d’une organisation, en ajout seul. segments est un tableau au format de numeroOfficiel, avec exactement un segment de séquence. |
app.sequence_numero |
Un compteur par (organisation, campagne, nature, produit). derniere_valeur ne revient jamais en arrière. Non journalisée : le numéro attribué l’est avec le document qui le porte. |
app.campagne pointe maintenant sur app.modele_numerotation (organisation_id, version) par une clé étrangère composée. Une campagne fige sa version à l’ouverture (déclencheur de A1) : publier une version 2 ne change donc pas les campagnes déjà ouvertes.
Modèle par défaut. La version 1 est créée avec l’organisation par un déclencheur AFTER INSERT (SECURITY DEFINER, car l’API écrit avec le rôle soumis à la RLS). La migration le crée aussi pour les organisations existantes.
Natures. MP (matière première), REC (réception), NET (nettoyage), PF (produit fini), d’après le cahier v1.2 §5.10. « Vente » a disparu (avenant n°1). Les codes sont à confirmer : voir EC-068.
Attribution
Section intitulée « Attribution »app.attribuer_numero(campagne_id, nature, produit_id) renvoie le rang suivant :
- la campagne doit exister dans l’organisation et être ouverte ;
- la ligne de séquence est créée au besoin, puis incrémentée par un
UPDATEqui la verrouille jusqu’à la fin de la transaction ; - deux appels simultanés se suivent ; une transaction annulée rend son rang.
La fonction s’exécute avec le rôle de l’appelant : la RLS s’applique.
attribuerNumero(trx, …) (apps/api/src/numerotation/numerotation.service.ts) lit la campagne, le produit et le modèle, appelle la fonction SQL, puis numeroOfficiel. Il rend { ok: true, numero, rang } ou une erreur : campagne_introuvable, campagne_non_ouverte, produit_introuvable, modele_corrompu, sequence_hors_capacite, segment_manquant.
Règle pour l’appelant : sur une erreur, annuler la transaction. Le rang est déjà pris dans cette transaction ; seule l’annulation le rend. C’est vrai surtout pour sequence_hors_capacite, qui ne peut être décidé qu’après coup puisque la largeur de la séquence est dans le modèle, que la base ne lit pas.
| Test | Ce qu’il vérifie |
|---|---|
db/tests/l1-a3.sql |
Modèle par défaut créé (y compris par le rôle de l’API), ajout seul, version unique, un seul segment de séquence, clé étrangère de la campagne, séquences indépendantes, nature « VTE » refusée, campagne non ouverte, rang rendu après annulation, isolation entre organisations |
A3-01 |
Deux campagnes la même année : 26A/MP/ANA/0001 et 26B/MP/ANA/0001 |
A3-02 |
Cent transactions simultanées : rangs 1 à 100, aucun doublon ni trou ; transaction annulée, rang rendu |
A3-03 |
Rang 10 000 refusé (sequence_hors_capacite), séquence laissée à 9 999 |
A3-04 |
Une version 2 du modèle ne touche pas une campagne ouverte sur la version 1 |
Hors séance
Section intitulée « Hors séance »Route de lecture du modèle pour l’écran B3 de la numérotation ; publication d’une nouvelle version par l’utilisateur (route et permission) ; source du préfixe entreprise quand il sera actif (EC-068) ; règles PowerSync (A9).