Campagne d’une filière. Toute opération appartient à une campagne. Plusieurs campagnes peuvent s’ouvrir la même année (EC-023).
| Name |
Type |
Default |
Nullable |
Extra Definition |
Children |
Parents |
Comment |
| id |
uuid |
app.uuid_v7() |
false |
|
app.sequence_numero app.contrat app.capacite_version app.solde_capacite app.lot app.reception app.ordre_transformation app.registre_annulation app.dossier_audit |
|
Identifiant stable (UUID v7). |
| organisation_id |
uuid |
|
false |
|
app.sequence_numero app.contrat app.capacite_version app.solde_capacite app.lot app.reception app.ordre_transformation app.registre_annulation app.dossier_audit |
app.organisation app.modele_numerotation |
Organisation propriétaire. Sert à l’isolation par RLS (EC-032). |
| code |
text |
|
false |
|
|
|
Code de campagne inséré dans le numéro officiel. Unique par organisation, toutes années confondues (EC-031). |
| nom |
text |
|
false |
|
|
|
Nom de la campagne. |
| date_ouverture_prevue |
date |
|
false |
|
|
|
Date d’ouverture prévue. Détermine « AA » tant que la campagne est en préparation. |
| date_cloture_prevue |
date |
|
false |
|
|
|
Date de clôture prévue. Jamais avant la date d’ouverture prévue. |
| date_ouverture |
date |
|
true |
|
|
|
Date d’ouverture réelle, renseignée à l’ouverture puis figée. |
| date_cloture |
date |
|
true |
|
|
|
Date de clôture réelle, renseignée à la clôture. |
| annee |
smallint |
|
true |
GENERATED ALWAYS AS (EXTRACT(year FROM COALESCE(date_ouverture, date_ouverture_prevue)))::smallint STORED |
|
|
Année d’ouverture (réelle, sinon prévue), calculée. Ses deux derniers chiffres forment « AA » du numéro (EC-023). |
| pack_version_id |
uuid |
|
false |
|
|
app.pack_version |
Version du pack de la filière. Figée à l’ouverture, qui exige une version publiée. |
| modele_numerotation_version |
integer |
|
true |
|
|
app.modele_numerotation |
Version du modèle de numérotation de l’organisation. Obligatoire et figée à l’ouverture ; la clé vers le modèle est posée à la séquence A3. |
| statut |
text |
‘preparation’::text |
false |
|
|
|
preparation, ouverte ou cloturee. Pas de retour en préparation. |
| cree_le |
timestamp with time zone |
now() |
false |
|
|
|
Date de création de la ligne. |
| modifie_le |
timestamp with time zone |
now() |
false |
|
|
|
Date de dernière modification. |
| Name |
Type |
Definition |
| campagne_check |
CHECK |
CHECK ((date_cloture_prevue >= date_ouverture_prevue)) |
| campagne_check1 |
CHECK |
CHECK (((statut = ‘preparation’::text) = (date_ouverture IS NULL))) |
| campagne_check2 |
CHECK |
CHECK (((statut = ‘cloturee’::text) = (date_cloture IS NOT NULL))) |
| campagne_check3 |
CHECK |
CHECK (((date_cloture IS NULL) OR (date_cloture >= date_ouverture))) |
| campagne_check4 |
CHECK |
CHECK (((statut = ‘preparation’::text) OR (modele_numerotation_version IS NOT NULL))) |
| campagne_code_check |
CHECK |
CHECK ((code <> ‘’::text)) |
| campagne_modele_numerotation_version_check |
CHECK |
CHECK ((modele_numerotation_version > 0)) |
| campagne_nom_check |
CHECK |
CHECK ((nom <> ‘’::text)) |
| campagne_statut_check |
CHECK |
CHECK ((statut = ANY (ARRAY[‘preparation’::text, ‘ouverte’::text, ‘cloturee’::text]))) |
| campagne_organisation_id_fkey |
FOREIGN KEY |
FOREIGN KEY (organisation_id) REFERENCES app.organisation(id) |
| campagne_pack_version_id_fkey |
FOREIGN KEY |
FOREIGN KEY (pack_version_id) REFERENCES app.pack_version(id) |
| campagne_pkey |
PRIMARY KEY |
PRIMARY KEY (id) |
| campagne_organisation_id_code_key |
UNIQUE |
UNIQUE (organisation_id, code) |
| campagne_organisation_id_id_key |
UNIQUE |
UNIQUE (organisation_id, id) |
| campagne_modele_numerotation_fk |
FOREIGN KEY |
FOREIGN KEY (organisation_id, modele_numerotation_version) REFERENCES app.modele_numerotation(organisation_id, version) |
| Name |
Definition |
| campagne_pkey |
CREATE UNIQUE INDEX campagne_pkey ON app.campagne USING btree (id) |
| campagne_organisation_id_code_key |
CREATE UNIQUE INDEX campagne_organisation_id_code_key ON app.campagne USING btree (organisation_id, code) |
| campagne_organisation_id_id_key |
CREATE UNIQUE INDEX campagne_organisation_id_id_key ON app.campagne USING btree (organisation_id, id) |
| Name |
Definition |
| journal |
CREATE TRIGGER journal AFTER INSERT OR DELETE OR UPDATE ON app.campagne FOR EACH ROW EXECUTE FUNCTION journal.tg_journaliser() |
| modifie_le |
CREATE TRIGGER modifie_le BEFORE UPDATE ON app.campagne FOR EACH ROW EXECUTE FUNCTION app.tg_modifie_le() |
| campagne_controle |
CREATE TRIGGER campagne_controle BEFORE INSERT OR UPDATE ON app.campagne FOR EACH ROW EXECUTE FUNCTION app.tg_campagne_controle() |
erDiagram
"app.sequence_numero" }o--|| "app.campagne" : "FOREIGN KEY (organisation_id, campagne_id) REFERENCES app.campagne(organisation_id, id)"
"app.contrat" }o--|| "app.campagne" : "FOREIGN KEY (organisation_id, campagne_id) REFERENCES app.campagne(organisation_id, id)"
"app.capacite_version" }o--|| "app.campagne" : "FOREIGN KEY (organisation_id, campagne_id) REFERENCES app.campagne(organisation_id, id)"
"app.solde_capacite" }o--|| "app.campagne" : "FOREIGN KEY (organisation_id, campagne_id) REFERENCES app.campagne(organisation_id, id)"
"app.lot" }o--|| "app.campagne" : "FOREIGN KEY (organisation_id, campagne_id) REFERENCES app.campagne(organisation_id, id)"
"app.reception" }o--|| "app.campagne" : "FOREIGN KEY (organisation_id, campagne_id) REFERENCES app.campagne(organisation_id, id)"
"app.ordre_transformation" }o--|| "app.campagne" : "FOREIGN KEY (organisation_id, campagne_id) REFERENCES app.campagne(organisation_id, id)"
"app.registre_annulation" }o--|| "app.campagne" : "FOREIGN KEY (organisation_id, campagne_id) REFERENCES app.campagne(organisation_id, id)"
"app.dossier_audit" }o--|| "app.campagne" : "FOREIGN KEY (organisation_id, campagne_id) REFERENCES app.campagne(organisation_id, id)"
"app.campagne" }o--|| "app.organisation" : "FOREIGN KEY (organisation_id) REFERENCES app.organisation(id)"
"app.campagne" }o--|| "app.modele_numerotation" : "FOREIGN KEY (organisation_id, modele_numerotation_version) REFERENCES app.modele_numerotation(organisation_id, version)"
"app.campagne" }o--|| "app.pack_version" : "FOREIGN KEY (pack_version_id) REFERENCES app.pack_version(id)"
"app.campagne" {
uuid id "Identifiant stable (UUID v7)."
uuid organisation_id FK "Organisation propriétaire. Sert à l'isolation par RLS (EC-032)."
text code "Code de campagne inséré dans le numéro officiel. Unique par organisation, toutes années confondues (EC-031)."
text nom "Nom de la campagne."
date date_ouverture_prevue "Date d'ouverture prévue. Détermine « AA » tant que la campagne est en préparation."
date date_cloture_prevue "Date de clôture prévue. Jamais avant la date d'ouverture prévue."
date date_ouverture "Date d'ouverture réelle, renseignée à l'ouverture puis figée."
date date_cloture "Date de clôture réelle, renseignée à la clôture."
smallint annee "Année d'ouverture (réelle, sinon prévue), calculée. Ses deux derniers chiffres forment « AA » du numéro (EC-023)."
uuid pack_version_id FK "Version du pack de la filière. Figée à l'ouverture, qui exige une version publiée."
integer modele_numerotation_version FK "Version du modèle de numérotation de l'organisation. Obligatoire et figée à l'ouverture ; la clé vers le modèle est posée à la séquence A3."
text statut "`preparation`, `ouverte` ou `cloturee`. Pas de retour en préparation."
timestamp_with_time_zone cree_le "Date de création de la ligne."
timestamp_with_time_zone modifie_le "Date de dernière modification."
}
"app.sequence_numero" {
uuid id "Identifiant stable (UUID v7)."
uuid organisation_id FK "Organisation propriétaire. Sert à l'isolation par RLS (EC-032)."
uuid campagne_id FK "Campagne de la séquence (de la même organisation)."
text nature "Nature du numéro : MP (matière première), REC (réception), NET (nettoyage), PF (produit fini). « Vente » n'existe plus (avenant n°1). Codes à confirmer, EC-068."
uuid produit_id FK "Produit de la séquence (de la même organisation)."
bigint derniere_valeur "Dernier rang attribué ; 0 tant qu'aucun numéro n'est sorti. Ne revient jamais en arrière."
timestamp_with_time_zone cree_le "Date de création de la ligne."
timestamp_with_time_zone modifie_le "Date de dernière modification."
}
"app.contrat" {
uuid id "Identifiant stable (UUID v7)."
uuid organisation_id FK "Organisation propriétaire. Sert à l'isolation par RLS (EC-032)."
text code "Code du contrat, unique par organisation."
text type "`achat` (producteur, groupement ou fournisseur), `vente` (client) ou `prestation` (client ou fournisseur, EC-052)."
uuid producteur_id FK "Contrepartie producteur (achat). Exactement une contrepartie entre producteur, groupement, fournisseur et client."
uuid groupement_id FK "Contrepartie groupement (achat)."
uuid fournisseur_id FK "Contrepartie fournisseur (achat ou prestation)."
uuid client_id FK "Contrepartie client (vente ou prestation)."
uuid campagne_id FK "Campagne du contrat (de la même organisation)."
date date_debut "Premier jour de la période du contrat."
date date_fin "Dernier jour de la période du contrat. Jamais avant le début."
text statut "`brouillon`, `actif`, `solde` ou `resilie`. Pas de retour en arrière ; l'activation exige une ligne."
text conditions_paiement "Conditions de paiement, en texte, facultatives."
uuid fichier_id FK "Pièce jointe du contrat (fichier de la même organisation), facultative."
timestamp_with_time_zone cree_le "Date de création de la ligne."
timestamp_with_time_zone modifie_le "Date de dernière modification."
}
"app.capacite_version" {
uuid id "Identifiant stable (UUID v7)."
uuid organisation_id FK "Organisation propriétaire. Sert à l'isolation par RLS (EC-032)."
uuid groupement_id FK "Groupement de la cible, repris d'elle par la base. Le téléphone filtre dessus."
uuid parcelle_id FK "Parcelle cible. Exactement une cible entre parcelle et zone de cueillette."
uuid zone_cueillette_id FK "Zone de cueillette cible (EC-050)."
uuid campagne_id FK "Campagne de la capacité. Deux campagnes la même année portent chacune la leur."
integer version "Numéro de version pour la cible et la campagne, attribué par la base."
uuid parcelle_version_id FK "Version de polygone sur laquelle la capacité est calculée, posée par la base. Si le polygone change, la capacité n'est plus applicable (EC-012)."
bigint surface_mesuree_m2 "Surface mesurée de cette version de polygone, en m², posée par la base. La surface déclarée n'entre jamais dans le calcul (AV1-01)."
bigint rendement_g_ha "Rendement de référence en vigueur lors de la saisie, en g/ha, posé par la base."
bigint capacite_g "Capacité en grammes, calculée : surface mesurée × rendement / 10 000, arrondie au plus proche (RG-020). Seule formule du projet pour la capacité."
uuid cree_par FK "Auteur de la proposition : il ne peut pas la valider (SB-11)."
timestamp_with_time_zone cree_le "Date de création de la version."
}
"app.solde_capacite" {
uuid id "Identifiant stable (UUID v7)."
uuid organisation_id FK "Organisation propriétaire. Sert à l'isolation par RLS (EC-032)."
uuid groupement_id FK "Groupement de la cible. Le téléphone filtre dessus."
uuid parcelle_id FK "Parcelle du solde. Exactement une cible entre parcelle et zone de cueillette."
uuid zone_cueillette_id FK "Zone de cueillette du solde."
uuid campagne_id FK "Campagne du solde."
uuid capacite_version_id FK "Version de capacité validée qui fonde le solde."
bigint capacite_g "Capacité validée, en grammes."
bigint consomme_g "Quantité déjà collectée, en grammes. Jamais écrasée par une nouvelle capacité."
bigint reste_g "Capacité moins consommé, en grammes. Négatif en cas de dépassement : un dépassement n'est jamais masqué (RG-022)."
timestamp_with_time_zone cree_le "Date de création de la ligne."
timestamp_with_time_zone modifie_le "Date de dernière modification."
}
"app.lot" {
uuid id "Identifiant du lot (UUID v7)."
uuid organisation_id FK "Organisation propriétaire (isolation par ligne)."
uuid campagne_id FK "Campagne du lot."
text reference_provisoire "Référence provisoire, tant que le lot n'est pas validé (BR-AAAA-MM-JJ-NNNN dans le cahier)."
bigint numero "Rang du numéro officiel, pris par app.attribuer_numero à la validation, jamais réutilisé (I3). Vide avant la validation."
text nature "Nature de la séquence de numérotation : MP matière première, REC réception, NET nettoyé, PF produit fini (EC-068)."
uuid produit_id FK "Produit du lot."
text qualite "Catégorie d'affichage du lot (EC-090) : saisie à la réception, calculée par le mélange (la plus basse catégorie des entrées et des états du résultat, EC-120). La qualité par référentiel est dans app.lot_qualite."
text statut "Statut : brouillon, en_attente, valide, rejete, annule, consomme, quarantaine, archive. Transitions contrôlées par app.tg_lot_controle."
uuid compte_matiere_id FK "Compte de matière du lot (nature lot) : son solde est la quantité du lot."
uuid mouvement_creation_id FK "Mouvement qui crée le lot (I4) : il crédite le compte du lot et n'est pas une contre-passation."
timestamp_with_time_zone date_operation "Date de l'opération qui crée le lot, saisie sur le terrain."
text motif_annulation "Motif de l'annulation ; renseigné si et seulement si le statut est annule."
uuid annule_par FK "Utilisateur qui a annulé le lot."
timestamp_with_time_zone date_annulation "Date de l'annulation."
uuid cree_par FK "Utilisateur qui a créé le lot."
timestamp_with_time_zone cree_le "Date d'enregistrement du lot."
timestamp_with_time_zone modifie_le "Date de la dernière modification (statut ou numéro)."
}
"app.reception" {
uuid id "Identifiant de la réception (UUID v7)."
uuid organisation_id FK "Organisation propriétaire (isolation par ligne)."
uuid campagne_id FK "Campagne de la réception."
uuid produit_id FK "Produit reçu."
uuid producteur_id FK "Producteur qui livre ; vide si la matière vient d'un fournisseur (l'un ou l'autre, jamais les deux)."
uuid fournisseur_id FK "Fournisseur qui livre ; vide si la matière vient d'un producteur."
uuid contrat_id FK "Contrat dont la formule de réfaction s'applique ; vide si aucun contrat (aucune réfaction)."
uuid lot_id FK "Lot créé par la réception, avec son mouvement de création (I4). Un lot naît d'une seule réception."
timestamp_with_time_zone date_operation "Date de la réception, saisie sur le terrain : c'est elle qui sert à apprécier l'état du certificat (RG-014)."
text statut "Statut : en_attente, validee ou rejetee. Ne revient jamais en arrière ; une erreur se corrige par annulation (L2-6)."
jsonb formule_refaction "Formule de réfaction retenue, copiée du contrat à l'enregistrement : c'est elle qui est imprimée sur le bon de réception (RG-171)."
jsonb detail_calcul "Détail du calcul du poids net marchand (brut, tare, net, excédent, réfaction), figé tel qu'imprimé (RG-171)."
bigint net_marchand_g "Poids net marchand en grammes : net de pesée moins la réfaction du contrat. Copie du détail pour les lectures."
uuid ticket_fichier_id FK "Ticket de pesée conservé (RG-170), facultatif tant que le stockage objet n'est pas en place."
text derogation_motif "Justification de la dérogation de la direction quand une règle bloque la réception (RG-014) ; vide sans dérogation."
uuid derogation_par FK "Utilisateur de la direction qui a donné la dérogation."
timestamp_with_time_zone derogation_le "Date de la dérogation."
uuid decide_par FK "Utilisateur qui a validé ou rejeté la réception ; vide tant qu'elle est en attente."
timestamp_with_time_zone decide_le "Date de la décision ; vide tant que la réception est en attente."
uuid cree_par FK "Utilisateur qui a enregistré la réception."
timestamp_with_time_zone cree_le "Date d'enregistrement de la réception."
timestamp_with_time_zone modifie_le "Date de la dernière modification (décision ou dérogation)."
}
"app.ordre_transformation" {
uuid id "Identifiant stable (UUID v7)."
uuid organisation_id FK "Organisation propriétaire (isolation par ligne)."
uuid campagne_id FK "Campagne des lots produits par l'ordre."
uuid site_id FK "Site où le procédé est réalisé ; le procédé doit y être actif."
uuid noeud_id FK "Procédé : nœud de l'arbre d'activités de l'organisation, de profondeur 2 ou 3, sous une activité du regroupement transformation."
text niveau_suivi "Niveau de suivi retenu à la création (réglage de l'organisation, par procédé) : global (une saisie couvre le procédé) ou detaille (une saisie par étape)."
text statut "brouillon, en_cours (dès qu'une étape démarre), termine (toutes les étapes validées) ou annule (aucune étape validée)."
timestamp_with_time_zone date_operation "Date de l'opération, saisie par l'opérateur."
text motif_annulation "Motif de l'annulation ; renseigné si et seulement si l'ordre est annulé."
uuid cree_par FK "Utilisateur qui a créé l'ordre."
timestamp_with_time_zone cree_le "Date de création de la ligne."
timestamp_with_time_zone modifie_le "Date de dernière modification."
}
"app.registre_annulation" {
uuid id "Identifiant de la ligne du registre (UUID v7)."
uuid organisation_id FK "Organisation propriétaire (isolation par ligne)."
text objet_type "Type d'objet défait : reception, etape_realisee, expedition, vente ou lot."
uuid objet_id "Identifiant de l'objet défait."
text nature "devalidation (retour à l'état précédent : réception, étape, expédition) ou annulation (clôture : vente, lot). Deux mécanismes distincts (EC-008)."
text motif "Justification écrite, obligatoire."
uuid lot_id FK "Lot annulé, avec son numéro conservé (RG-143) ; pour une dévalidation de réception, le lot d'origine annulé. Vide pour une vente, une étape ou une expédition."
uuid campagne_id FK "Campagne concernée, pour l'édition du registre par campagne (RG-144) ; vide pour une vente ou une expédition."
uuid mouvement_id FK "Mouvement de contre-passation écrit ; vide pour l'annulation d'une vente, qui n'a pas encore bougé la matière."
uuid constat_id FK "Constat consigné pour la dévalidation (AM-15) ; vide pour une annulation."
uuid cree_par FK "Utilisateur qui défait l'objet (direction)."
timestamp_with_time_zone cree_le "Date de la dévalidation ou de l'annulation."
}
"app.dossier_audit" {
uuid id "Identifiant du dossier (UUID v7)."
uuid organisation_id FK "Organisation propriétaire (isolation par ligne)."
uuid campagne_id FK "Campagne couverte."
text statut "en_attente (tâche inscrite), genere ou echec."
jsonb contenu "Dossier structuré (JSON), en forme canonique."
text edition_html "Édition imprimable du dossier (HTML). Le PDF n'est pas fourni : voir ecarts.md."
text empreinte "Empreinte SHA-256 (hexadécimal) de la forme canonique du contenu : même contenu, même empreinte."
text erreur "Message d'échec de la tâche ; vide sinon."
uuid demande_par FK "Utilisateur qui demande le dossier."
timestamp_with_time_zone demande_le "Date de la demande."
timestamp_with_time_zone genere_le "Date de génération."
timestamp_with_time_zone modifie_le "Dernière modification."
}
"app.organisation" {
uuid id "Identifiant de l'organisation (UUID v7)."
text code "Code court en majuscules. Immuable : il figure dans les identifiants Keycloak (coopa.agent01). « EXT » est réservé."
text nom "Nom de l'organisation."
text pays "Pays, code ISO 3166-1 alpha-2."
text langue "Langue de l'organisation : fr ou en."
text fuseau_horaire "Fuseau horaire IANA utilisé pour l'affichage des dates."
text devise_defaut "Devise par défaut des montants, code ISO 4217."
text keycloak_organisation_id "Identifiant de l'organisation dans Keycloak."
text organisme_certificateur "Organisme de certification de l'organisation. Aucun contrôle de format (EC-027)."
text code_operateur "Code d'opérateur attribué par l'organisme certificateur."
uuid logo_fichier_id FK "Fichier du logo (EC-029)."
timestamp_with_time_zone cree_le "Date de création de la ligne."
timestamp_with_time_zone modifie_le "Date de la dernière modification, tenue par un déclencheur."
text source_conformite "Source des décisions de conformité : `interne` (contrôle interne de BioTrace) ou `externe` (outil tiers). Une seule source active à la fois ; app.statut_conformite.source doit lui être égale."
text statut "État du compte client : `active` ou `suspendue`. Une organisation suspendue est refusée par la garde d'authentification (`organisation_suspendue`) ; ses données et ses comptes sont conservés. Décidé par l'équipe de l'éditeur (EC-126)."
timestamp_with_time_zone suspendue_le "Date de la suspension en cours ; nulle tant que l'organisation est active."
}
"app.modele_numerotation" {
uuid id "Identifiant stable (UUID v7)."
uuid organisation_id FK "Organisation propriétaire. Sert à l'isolation par RLS (EC-032)."
integer version "Numéro de version, à partir de 1, unique par organisation. Une campagne ouverte en fige un."
jsonb segments "Segments du numéro, dans l'ordre, au format de numeroOfficiel (packages/domain) : annee_campagne, code_campagne, nature, produit, prefixe_entreprise, texte, sequence. Exactement un segment de séquence."
text motif "Raison de cette version."
uuid cree_par FK "Utilisateur qui a publié la version. Absent pour la version créée avec l'organisation."
timestamp_with_time_zone cree_le "Date de création de la version."
}
"app.pack_version" {
uuid id "Identifiant de la version (UUID v7)."
uuid pack_id FK "Pack concerné."
text version "Version sémantique (majeure.mineure.correctif)."
jsonb contenu "Contenu du pack, en JSON."
text sha256 "Empreinte SHA-256 du contenu."
boolean calibre "Vrai si les rendements du pack ont été calibrés (EC-007)."
text statut "Statut : brouillon, publie ou retire."
timestamp_with_time_zone publie_le "Date de publication. Nulle pour un brouillon."
timestamp_with_time_zone cree_le "Date de création de la ligne."
timestamp_with_time_zone modifie_le "Date de la dernière modification, tenue par un déclencheur."
uuid publie_par "Identifiant Keycloak (sub) du membre de l'équipe de l'éditeur qui a publié la version depuis le cockpit. Nul pour les versions publiées par le pipeline ou la ligne de commande avant CP-5."
}
Generated by tbls