Aller au contenu

Lot 1, séquence A8 — Capacité

1er octobre 2026. Mise en œuvre de la séquence A8 du plan du Lot 1. Décisions : EC-007, EC-012, EC-050 ; écarts ouverts : EC-074, EC-075.

  • La capacité d’une parcelle (ou d’une zone de cueillette, EC-050) pour une campagne vaut surface mesurée × rendement de référence. La surface déclarée n’entre jamais dans le calcul (AV1-01).
  • La base calcule, une seule fois. capacite_g est une colonne générée ; le déclencheur d’insertion lit lui-même la version de polygone en vigueur et le rendement en vigueur. L’appelant ne fournit ni surface, ni rendement, ni montant.
  • La base refuse la saisie quand la cible n’est pas éligible : c’est le critère de fin n° 2 du Lot 1.
  • Une capacité n’est applicable qu’après la validation de la direction et du RSCI, par deux personnes différentes de l’auteur, et tant qu’elle repose sur le polygone en vigueur.
  • Aucune route REST en A8 : le contrat est gelé en A9, les écrans B3 demanderont leurs routes.

app.rendement_parcelle est en ajout seul : une valeur en g/ha par cible, un motif obligatoire à chaque ligne, un numéro de version ; la plus récente est en vigueur. Aucune valeur par défaut : sans rendement, la capacité est refusée (rendement_inconnu). On n’invente pas de rendement.

Le jeu de règles rendement.reference du pack n’est pas une alternative : c’est un rendement de transformation (en centièmes de point) et il est vide. La résolution d’un rendement agricole par défaut demanderait un chargeur de paramètres que l’API n’a pas (elle n’appelle jamais resoudre) : EC-074.

Chaque refus de la base est une erreur P0001 dont le DETAIL porte un code stable, que le service traduit :

Code Cause
polygone_absent Aucun polygone n’est enregistré pour la cible
polygone_invalide La version en vigueur est invalide (ST_IsValid)
chevauchement_non_leve Un chevauchement de parcelles n’est pas levé (A5)
producteur_en_controle Le producteur a un contrôle ouvert, par exemple un doublon de pièce (AV1-02, A4)
rendement_inconnu Aucun rendement de référence enregistré
campagne_cloturee La campagne est clôturée
cible_introuvable La parcelle ou la zone n’existe pas dans l’organisation
Table Contenu
app.rendement_parcelle Ajout seul. Cible (parcelle ou zone), version, valeur_g_ha, motif, auteur
app.capacite_version Ajout seul. Cible, campagne, version, parcelle_version_id et surface_mesuree_m2 posés par la base, rendement_g_ha, capacite_g générée, auteur, groupement_id
app.validation Étendue : colonne capacite_version_id, une capacité se valide une fois par rôle (direction, rsci) et une fois par personne ; auteur_objet_id posé par la base
app.solde_capacite Une ligne par (cible, campagne) : capacité validée, consommé, reste (négatif en cas de dépassement), groupement_id pour le téléphone

Formule : capacite_g = (surface mesurée en m² × rendement en g/ha + 5 000) / 10 000, soit 10 000 m² par hectare et un arrondi au plus proche. Une version est créée à chaque modification ; deux campagnes la même année portent chacune la leur (SR-L1-09).

app.etat_validation_capacite rend refusee dès qu’un rôle refuse, validee quand direction et RSCI ont approuvé, sinon en_attente. C’est le seul endroit qui décide. À la deuxième approbation, un déclencheur (SECURITY DEFINER) crée ou met à jour le solde : le consommé n’est jamais écrasé et une version plus ancienne ne remplace pas une plus récente. L’API n’a aucun droit d’écrire dans solde_capacite ; la consommation par les collectes (Lot 2) ouvrira son propre droit.

Le service validerCapacite ajoute ce que la base ne sait pas : le rôle se prouve par l’ensemble de permissions que le validateur détient (direction ou rsci) en plus de capacity.approve (EC-075), et la séparation des tâches est prévenue par droits.verifierSeparation (premier appelant de ce module) avant l’envoi ; la base reste l’autorité (SB-11).

app.validation n’impose qu’une cible au plus : « aucune » reste possible tant que SB-11 teste la règle d’auteur sans objet ; la validation d’un lot (Lot 2) passera à « exactement une ».

app.capacite_applicable(parcelle, zone, campagne) rend la dernière capacité validée si elle repose encore sur la version de polygone en vigueur, que la cible reste éligible (parcelle_eligible_capacite) et que le producteur n’est pas en contrôle (producteur_en_controle). Un nouveau relevé du polygone fait donc repasser la capacité en validation. C’est la garde que le Lot 2 appellera avant toute collecte.

apps/api/src/capacite/capacite.service.ts : definirRendement, proposerCapacite, validerCapacite, evaluerCollecteSurSolde (lit le solde de la base et appelle capacite.evaluerCollecte : premier appelant ; normal, seuil ou dépassement, jamais masqué, RG-022). Le seuil d’alerte vaut PARAMETRES_CAPACITE.seuil_alerte_cp (80 %), constante nommée en attendant le mécanisme de paramètres. Sur un refus, la transaction est à annuler.

Nouveaux fichiers utilisateurs.json (3 comptes fictifs, sans lien avec Keycloak) et rendements.json (30 t/ha fictif par parcelle, marqué fictif, motif « non calibrée (EC-007) ») ; capacites.json n’a plus aucun montant en dur : 19 capacités proposées puis validées par la direction et le RSCI, 1 en attente avec une seule validation, aucune sur la parcelle au polygone invalide. Le chargement est rejouable et produit 19 soldes.

Test Ce qu’il vérifie
db/tests/l1-a8.sql Chaque cause de refus avec son code, surface mesurée et non déclarée, formule et arrondi, rendement motivé et versionné, auteur et rôles (SB-11), états de validation, solde créé et conservé, solde non écrivable par l’API, capacité non applicable avant la validation et après un nouveau relevé, deux campagnes, zone de cueillette, isolation
apps/api/test/capacite.test.ts Parcours complet par les services, refus de rôle, de permission et de séparation des tâches, evaluerCollecte sur un solde issu de la base, polygone en vigueur
packages/schemas/src/capacite.test.ts La proposition n’accepte aucun montant ; deux rôles de validation seulement

Routes REST de la capacité (écrans B3) ; rendement par défaut issu du pack (EC-074) ; collecte et consommation du solde (Lot 2) ; règles PowerSync de solde_capacite et des autres tables (A9).