Aller au contenu

app.producteur

Producteur, objet pivot partagé avec le futur système de contrôle interne. Jamais supprimé, jamais réutilisé (RG-010). Un doublon de pièce d’identité ouvre un contrôle sans refuser la fiche (AV1-02).

Name Type Default Nullable Extra Definition Children Parents Comment
id uuid app.uuid_v7() false sync.controle app.producteur app.parcelle app.statut_conformite app.contrat app.certificat_portee app.reception Identifiant stable (UUID v7), clé d’échange avec le système de contrôle interne.
organisation_id uuid false sync.controle app.producteur app.parcelle app.statut_conformite app.contrat app.certificat_portee app.reception app.organisation app.fichier app.groupement app.producteur Organisation qui enrôle le producteur. Sert à l’isolation par RLS (EC-032).
groupement_id uuid false app.parcelle app.statut_conformite app.groupement Groupement d’appartenance (de la même organisation). Le téléphone filtre sur ce groupement.
code text false Code du producteur, unique par organisation et définitif (RG-010, EC-031).
nom_complet text false Nom complet du producteur.
telephone text true Téléphone. Donnée personnelle : accès réservé aux rôles qui en ont l’usage (EX-063).
village text true Village.
canton text true Canton.
zone_production text true Zone de production.
date_inscription date true Date d’inscription du producteur, transmise au système de contrôle interne.
type_piece_identite text true Type de la pièce d’identité (carte nationale, passeport…). Vocabulaire non contrôlé pour l’instant. Renseigné avec le numéro, ou absent avec lui.
numero_piece_identite text true Numéro de la pièce d’identité, tel que saisi. Le doublon ne bloque rien : il ouvre un contrôle (AV1-02).
numero_piece_normalise text true GENERATED ALWAYS AS upper(regexp_replace(numero_piece_identite, ‘[^A-Za-z0-9]’::text, ‘’::text, ‘g’::text)) STORED Numéro de pièce en majuscules, sans espace ni tiret, calculé. Sert à rapprocher deux saisies du même numéro.
photo_fichier_id uuid true app.fichier Photo du producteur (fichier de la même organisation).
piece_fichier_id uuid true app.fichier Image de la pièce d’identité (fichier de la même organisation).
chiffre_affaires_valeur bigint true Chiffre d’affaires annuel, en unités mineures de sa devise (EC-028). Sert à l’éligibilité au groupe (EC-014).
chiffre_affaires_devise text true Devise ISO 4217 du chiffre d’affaires. Renseignée avec la valeur, ou absente avec elle.
actif boolean true false Faux quand le producteur est retiré des listes de saisie sans altérer l’historique (RG-011). Toujours faux pour une fiche fusionnée.
statut text ‘actif’::text false actif ou fusionnee. Une fiche fusionnée renvoie à la fiche retenue et ne se réactive pas.
fusionnee_dans_id uuid true app.producteur Fiche retenue quand celle-ci a été absorbée par une fusion. Renseignée si et seulement si le statut est fusionnee.
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
producteur_check CHECK CHECK (((type_piece_identite IS NULL) = (numero_piece_identite IS NULL)))
producteur_check1 CHECK CHECK (((chiffre_affaires_valeur IS NULL) = (chiffre_affaires_devise IS NULL)))
producteur_check2 CHECK CHECK (((statut = ‘fusionnee’::text) = (fusionnee_dans_id IS NOT NULL)))
producteur_check3 CHECK CHECK ((fusionnee_dans_id IS DISTINCT FROM id))
producteur_chiffre_affaires_devise_check CHECK CHECK ((chiffre_affaires_devise ~ ‘^[A-Z]{3}$’::text))
producteur_chiffre_affaires_valeur_check CHECK CHECK ((chiffre_affaires_valeur >= 0))
producteur_code_check CHECK CHECK ((code <> ‘’::text))
producteur_nom_complet_check CHECK CHECK ((nom_complet <> ‘’::text))
producteur_numero_piece_identite_check CHECK CHECK ((numero_piece_identite <> ‘’::text))
producteur_statut_check CHECK CHECK ((statut = ANY (ARRAY[‘actif’::text, ‘fusionnee’::text])))
producteur_type_piece_identite_check CHECK CHECK ((type_piece_identite <> ‘’::text))
producteur_organisation_id_fkey FOREIGN KEY FOREIGN KEY (organisation_id) REFERENCES app.organisation(id)
producteur_organisation_id_photo_fichier_id_fkey FOREIGN KEY FOREIGN KEY (organisation_id, photo_fichier_id) REFERENCES app.fichier(organisation_id, id)
producteur_organisation_id_piece_fichier_id_fkey FOREIGN KEY FOREIGN KEY (organisation_id, piece_fichier_id) REFERENCES app.fichier(organisation_id, id)
producteur_organisation_id_groupement_id_fkey FOREIGN KEY FOREIGN KEY (organisation_id, groupement_id) REFERENCES app.groupement(organisation_id, id)
producteur_pkey PRIMARY KEY PRIMARY KEY (id)
producteur_organisation_id_code_key UNIQUE UNIQUE (organisation_id, code)
producteur_organisation_id_fusionnee_dans_id_fkey FOREIGN KEY FOREIGN KEY (organisation_id, fusionnee_dans_id) REFERENCES app.producteur(organisation_id, id)
producteur_organisation_id_id_key UNIQUE UNIQUE (organisation_id, id)
producteur_org_groupement_id_key UNIQUE UNIQUE (organisation_id, groupement_id, id)
Name Definition
producteur_pkey CREATE UNIQUE INDEX producteur_pkey ON app.producteur USING btree (id)
producteur_organisation_id_code_key CREATE UNIQUE INDEX producteur_organisation_id_code_key ON app.producteur USING btree (organisation_id, code)
producteur_organisation_id_id_key CREATE UNIQUE INDEX producteur_organisation_id_id_key ON app.producteur USING btree (organisation_id, id)
producteur_piece_idx CREATE INDEX producteur_piece_idx ON app.producteur USING btree (organisation_id, type_piece_identite, numero_piece_normalise) WHERE (numero_piece_normalise IS NOT NULL)
producteur_groupement_idx CREATE INDEX producteur_groupement_idx ON app.producteur USING btree (organisation_id, groupement_id)
producteur_org_groupement_id_key CREATE UNIQUE INDEX producteur_org_groupement_id_key ON app.producteur USING btree (organisation_id, groupement_id, id)
Name Definition
journal CREATE TRIGGER journal AFTER INSERT OR DELETE OR UPDATE ON app.producteur FOR EACH ROW EXECUTE FUNCTION journal.tg_journaliser()
modifie_le CREATE TRIGGER modifie_le BEFORE UPDATE ON app.producteur FOR EACH ROW EXECUTE FUNCTION app.tg_modifie_le()
producteur_doublon CREATE TRIGGER producteur_doublon AFTER INSERT OR UPDATE OF type_piece_identite, numero_piece_identite, statut ON app.producteur FOR EACH ROW EXECUTE FUNCTION app.tg_producteur_doublon()
erDiagram

"sync.controle" }o--|| "app.producteur" : "FOREIGN KEY (organisation_id, producteur_id) REFERENCES app.producteur(organisation_id, id)"
"app.producteur" }o--|| "app.producteur" : "FOREIGN KEY (organisation_id, fusionnee_dans_id) REFERENCES app.producteur(organisation_id, id)"
"app.parcelle" }o--|| "app.producteur" : "FOREIGN KEY (organisation_id, groupement_id, producteur_id) REFERENCES app.producteur(organisation_id, groupement_id, id)"
"app.statut_conformite" }o--|| "app.producteur" : "FOREIGN KEY (organisation_id, groupement_id, producteur_id) REFERENCES app.producteur(organisation_id, groupement_id, id)"
"app.contrat" }o--|| "app.producteur" : "FOREIGN KEY (organisation_id, producteur_id) REFERENCES app.producteur(organisation_id, id)"
"app.certificat_portee" }o--|| "app.producteur" : "FOREIGN KEY (organisation_id, producteur_id) REFERENCES app.producteur(organisation_id, id)"
"app.reception" }o--|| "app.producteur" : "FOREIGN KEY (organisation_id, producteur_id) REFERENCES app.producteur(organisation_id, id)"
"app.producteur" }o--|| "app.organisation" : "FOREIGN KEY (organisation_id) REFERENCES app.organisation(id)"
"app.producteur" }o--|| "app.fichier" : "FOREIGN KEY (organisation_id, photo_fichier_id) REFERENCES app.fichier(organisation_id, id)"
"app.producteur" }o--|| "app.fichier" : "FOREIGN KEY (organisation_id, piece_fichier_id) REFERENCES app.fichier(organisation_id, id)"
"app.producteur" }o--|| "app.groupement" : "FOREIGN KEY (organisation_id, groupement_id) REFERENCES app.groupement(organisation_id, id)"

"app.producteur" {
  uuid id "Identifiant stable (UUID v7), clé d'échange avec le système de contrôle interne."
  uuid organisation_id FK "Organisation qui enrôle le producteur. Sert à l'isolation par RLS (EC-032)."
  uuid groupement_id FK "Groupement d'appartenance (de la même organisation). Le téléphone filtre sur ce groupement."
  text code "Code du producteur, unique par organisation et définitif (RG-010, EC-031)."
  text nom_complet "Nom complet du producteur."
  text telephone "Téléphone. Donnée personnelle : accès réservé aux rôles qui en ont l'usage (EX-063)."
  text village "Village."
  text canton "Canton."
  text zone_production "Zone de production."
  date date_inscription "Date d'inscription du producteur, transmise au système de contrôle interne."
  text type_piece_identite "Type de la pièce d'identité (carte nationale, passeport…). Vocabulaire non contrôlé pour l'instant. Renseigné avec le numéro, ou absent avec lui."
  text numero_piece_identite "Numéro de la pièce d'identité, tel que saisi. Le doublon ne bloque rien : il ouvre un contrôle (AV1-02)."
  text numero_piece_normalise "Numéro de pièce en majuscules, sans espace ni tiret, calculé. Sert à rapprocher deux saisies du même numéro."
  uuid photo_fichier_id FK "Photo du producteur (fichier de la même organisation)."
  uuid piece_fichier_id FK "Image de la pièce d'identité (fichier de la même organisation)."
  bigint chiffre_affaires_valeur "Chiffre d'affaires annuel, en unités mineures de sa devise (EC-028). Sert à l'éligibilité au groupe (EC-014)."
  text chiffre_affaires_devise "Devise ISO 4217 du chiffre d'affaires. Renseignée avec la valeur, ou absente avec elle."
  boolean actif "Faux quand le producteur est retiré des listes de saisie sans altérer l'historique (RG-011). Toujours faux pour une fiche fusionnée."
  text statut "`actif` ou `fusionnee`. Une fiche fusionnée renvoie à la fiche retenue et ne se réactive pas."
  uuid fusionnee_dans_id FK "Fiche retenue quand celle-ci a été absorbée par une fusion. Renseignée si et seulement si le statut est `fusionnee`."
  timestamp_with_time_zone cree_le "Date de création de la ligne."
  timestamp_with_time_zone modifie_le "Date de dernière modification."
}
"sync.controle" {
  uuid id "Identifiant du contrôle (UUID v7)."
  uuid organisation_id FK "Organisation propriétaire de la ligne. Sert à l'isolation par RLS (EC-032) et au filtrage de la synchronisation."
  uuid commande_id FK "Commande à l'origine du contrôle."
  text motif "Motif du contrôle, parmi le catalogue du protocole (§9). « module_inactif » (EC-096) : commande d'un module inactif, conservée sans écriture métier."
  jsonb details "Éléments de contexte, en JSON."
  text statut "Statut : ouvert, en_cours ou leve."
  text decision "Décision de levée. Renseignée si et seulement si le contrôle est levé."
  text motif_decision "Motif de la décision."
  uuid decide_par FK "Utilisateur qui a levé le contrôle. Jamais l'auteur de la commande."
  timestamp_with_time_zone decide_le "Date de la levée."
  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 producteur_id FK "Producteur concerné par le contrôle (de la même organisation), par exemple pour un doublon de pièce d'identité (AV1-02)."
  uuid parcelle_version_id FK "Version de polygone concernée par le contrôle (de la même organisation) : polygone invalide ou chevauchement."
}
"app.parcelle" {
  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 parcelle, identique à celui de son producteur (clé composée) : un producteur qui a des parcelles ne change pas de groupement."
  uuid producteur_id FK "Producteur propriétaire de la parcelle (de la même organisation)."
  uuid produit_id FK "Produit cultivé (de la même organisation)."
  text code "Code de la parcelle, unique par organisation."
  text type_surface "`cultures`, `serres` ou `prairies` : sert aux seuils d'éligibilité au groupe (RG-024)."
  bigint surface_declaree_m2 "Surface déclarée par le producteur, en m² (EC-030). Jamais la base d'une capacité : c'est la surface mesurée (AV1-01)."
  text region_facteur FK "Constante `region` : nom du facteur de la clé étrangère composée vers facteur_valeur."
  text region FK "Région (valeur du facteur `region`), facultative."
  text mode_culture_facteur FK "Constante `mode_culture` : nom du facteur de la clé étrangère composée vers facteur_valeur."
  text mode_culture FK "Mode de culture (`pluvial` ou `irrigue`), facultatif."
  text type_sol_facteur FK "Constante `type_sol` : nom du facteur de la clé étrangère composée vers facteur_valeur."
  text type_sol FK "Type de sol (valeur du facteur `type_sol`), facultatif."
  boolean actif "Faux quand la parcelle n'est plus utilisée. Une parcelle n'est jamais supprimée."
  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.statut_conformite" {
  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 l'unité, repris d'elle par la base. Le téléphone filtre dessus."
  uuid producteur_id FK "Unité producteur. Exactement une unité entre producteur, parcelle et zone de cueillette (EC-025)."
  uuid parcelle_id FK "Unité parcelle."
  uuid zone_cueillette_id FK "Unité zone de cueillette."
  uuid referentiel_id FK "Référentiel coché par l'organisation (app.organisation_referentiel) pour lequel le statut vaut (EC-101)."
  text etat "État de conformité, défini par le pack référentiel (AM-16) : bio, conversion_annee_2_et_plus, conversion_annee_1, conventionnel, suspendu, retiré pour l'UE. Contrôlé par la base contre les états publiés."
  date debut_conversion "Début de la conversion. Obligatoire pour les deux états de conversion."
  date date_eligibilite "Date à laquelle l'unité devient éligible (fin de conversion prévue), facultative."
  date date_effet "Date d'effet du statut : il vaut à partir de ce jour, jusqu'à la ligne suivante."
  text source "`interne` ou `externe`. Doit égaler organisation.source_conformite."
  text reference_decision "Référence de la décision de la source (par exemple du contrôle interne)."
  text motif "Justification écrite. Absente pour la première ligne d'une unité, obligatoire pour toute révision (RG-150)."
  timestamp_with_time_zone mis_a_jour_le "Date de réception de la mise à jour par BioTrace. Départage deux lignes de même date d'effet."
  uuid cree_par FK "Utilisateur qui a enregistré ou révisé le statut."
}
"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.certificat_portee" {
  uuid id "Identifiant stable (UUID v7)."
  uuid organisation_id FK "Organisation propriétaire. Sert à l'isolation par RLS (EC-032)."
  uuid certificat_id FK "Certificat dont la ligne précise la portée (de la même organisation)."
  text dimension "`activite`, `produit`, `site` ou `unite`. Détermine la seule colonne d'élément renseignée."
  text activite_code FK "Activité du catalogue fermé (dimension `activite`)."
  uuid produit_id FK "Produit du catalogue de l'organisation (dimension `produit`). Les produits sont listés un à un : le catalogue n'a pas de catégorie (EC-102)."
  uuid site_id FK "Site de l'organisation (dimension `site`)."
  uuid producteur_id FK "Unité producteur (dimension `unite`). Exactement une unité entre producteur, parcelle et zone de cueillette."
  uuid parcelle_id FK "Unité parcelle (dimension `unite`)."
  uuid zone_cueillette_id FK "Unité zone de cueillette (dimension `unite`)."
  boolean inclus "Vrai : l'élément est couvert par le certificat. Faux : il est exclu expressément, et l'exclusion l'emporte sur une inclusion plus large."
  uuid cree_par FK "Utilisateur qui a déclaré la ligne."
  timestamp_with_time_zone cree_le "Date de création de la ligne."
}
"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.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.fichier" {
  uuid id "Identifiant du fichier (UUID v7, généré sur l'appareil ou par l'API)."
  uuid organisation_id FK "Organisation propriétaire de la ligne. Sert à l'isolation par RLS (EC-032) et au filtrage de la synchronisation."
  text cle_objet "Clé de l'objet dans le stockage."
  text type_mime "Type MIME du contenu."
  bigint taille_octets "Taille en octets."
  text sha256 "Empreinte SHA-256 du contenu, en hexadécimal."
  text statut "Statut : attendu, recu ou empreinte_invalide. Un fichier reçu n'est plus modifiable."
  uuid appareil_id FK "Appareil d'origine du dépôt."
  uuid depose_par FK "Utilisateur qui a déposé le fichier."
  timestamp_with_time_zone depose_le "Date de réception du contenu par le stockage."
  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."
}
"app.groupement" {
  uuid id "Identifiant stable (UUID v7)."
  uuid organisation_id FK "Organisation propriétaire. Sert à l'isolation par RLS (EC-032)."
  text code "Code du groupement, unique par organisation."
  text nom "Nom du groupement."
  boolean actif "Faux quand le groupement n'est plus utilisé. Un groupement n'est jamais supprimé."
  timestamp_with_time_zone cree_le "Date de création de la ligne."
  timestamp_with_time_zone modifie_le "Date de dernière modification."
}

Generated by tbls