Merge branch 'develop' (squash) – Numéro de dossier #103 et autres avancements
Made-with: Cursor
This commit is contained in:
@@ -355,6 +355,20 @@ ALTER TABLE utilisateurs
|
||||
ADD COLUMN IF NOT EXISTS privacy_acceptee_le TIMESTAMPTZ,
|
||||
ADD COLUMN IF NOT EXISTS relais_id UUID REFERENCES relais(id) ON DELETE SET NULL;
|
||||
|
||||
-- ==========================================================
|
||||
-- Ticket #103 : Numéro de dossier (AAAA-NNNNNN, séquence par année)
|
||||
-- ==========================================================
|
||||
CREATE TABLE IF NOT EXISTS numero_dossier_sequence (
|
||||
annee INT PRIMARY KEY,
|
||||
prochain INT NOT NULL DEFAULT 1
|
||||
);
|
||||
ALTER TABLE utilisateurs ADD COLUMN IF NOT EXISTS numero_dossier VARCHAR(20) NULL;
|
||||
ALTER TABLE assistantes_maternelles ADD COLUMN IF NOT EXISTS numero_dossier VARCHAR(20) NULL;
|
||||
ALTER TABLE parents ADD COLUMN IF NOT EXISTS numero_dossier VARCHAR(20) NULL;
|
||||
CREATE INDEX IF NOT EXISTS idx_utilisateurs_numero_dossier ON utilisateurs(numero_dossier) WHERE numero_dossier IS NOT NULL;
|
||||
CREATE INDEX IF NOT EXISTS idx_assistantes_maternelles_numero_dossier ON assistantes_maternelles(numero_dossier) WHERE numero_dossier IS NOT NULL;
|
||||
CREATE INDEX IF NOT EXISTS idx_parents_numero_dossier ON parents(numero_dossier) WHERE numero_dossier IS NOT NULL;
|
||||
|
||||
-- ==========================================================
|
||||
-- Seed : Documents légaux génériques v1
|
||||
-- ==========================================================
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
-- Migration #103 : Numéro de dossier (format AAAA-NNNNNN, séquence par année)
|
||||
-- Colonnes sur utilisateurs, assistantes_maternelles, parents.
|
||||
-- Table de séquence par année pour génération unique.
|
||||
|
||||
BEGIN;
|
||||
|
||||
-- Table de séquence : une ligne par année, prochain = prochain numéro à attribuer (1..999999)
|
||||
CREATE TABLE IF NOT EXISTS numero_dossier_sequence (
|
||||
annee INT PRIMARY KEY,
|
||||
prochain INT NOT NULL DEFAULT 1
|
||||
);
|
||||
|
||||
-- Colonne sur utilisateurs (AM et parents : numéro attribué à la soumission)
|
||||
ALTER TABLE utilisateurs
|
||||
ADD COLUMN IF NOT EXISTS numero_dossier VARCHAR(20) NULL;
|
||||
|
||||
-- Colonne sur assistantes_maternelles (redondant avec users pour accès direct)
|
||||
ALTER TABLE assistantes_maternelles
|
||||
ADD COLUMN IF NOT EXISTS numero_dossier VARCHAR(20) NULL;
|
||||
|
||||
-- Colonne sur parents (un numéro par famille, même valeur sur les deux lignes si co-parent)
|
||||
ALTER TABLE parents
|
||||
ADD COLUMN IF NOT EXISTS numero_dossier VARCHAR(20) NULL;
|
||||
|
||||
-- Index pour recherche par numéro
|
||||
CREATE INDEX IF NOT EXISTS idx_utilisateurs_numero_dossier
|
||||
ON utilisateurs(numero_dossier) WHERE numero_dossier IS NOT NULL;
|
||||
CREATE INDEX IF NOT EXISTS idx_assistantes_maternelles_numero_dossier
|
||||
ON assistantes_maternelles(numero_dossier) WHERE numero_dossier IS NOT NULL;
|
||||
CREATE INDEX IF NOT EXISTS idx_parents_numero_dossier
|
||||
ON parents(numero_dossier) WHERE numero_dossier IS NOT NULL;
|
||||
|
||||
COMMIT;
|
||||
@@ -0,0 +1,122 @@
|
||||
-- Backfill #103 : attribuer un numero_dossier aux entrées existantes (NULL)
|
||||
-- Famille = lien co_parent OU partage d'au moins un enfant (même dossier).
|
||||
-- Ordre : par année, AM puis familles (une entrée par famille), séquence 000001, 000002...
|
||||
-- À exécuter après 2026_numero_dossier.sql
|
||||
|
||||
DO $$
|
||||
DECLARE
|
||||
yr INT;
|
||||
seq INT;
|
||||
num TEXT;
|
||||
r RECORD;
|
||||
family_user_ids UUID[];
|
||||
BEGIN
|
||||
-- Réinitialiser pour rejouer le backfill (cohérence AM + familles)
|
||||
UPDATE parents SET numero_dossier = NULL;
|
||||
UPDATE utilisateurs SET numero_dossier = NULL
|
||||
WHERE role IN ('parent', 'assistante_maternelle');
|
||||
UPDATE assistantes_maternelles SET numero_dossier = NULL;
|
||||
|
||||
FOR yr IN
|
||||
SELECT DISTINCT EXTRACT(YEAR FROM u.cree_le)::INT
|
||||
FROM utilisateurs u
|
||||
WHERE (
|
||||
(u.role = 'assistante_maternelle' AND u.numero_dossier IS NULL)
|
||||
OR EXISTS (SELECT 1 FROM parents p WHERE p.id_utilisateur = u.id AND p.numero_dossier IS NULL)
|
||||
)
|
||||
ORDER BY 1
|
||||
LOOP
|
||||
seq := 0;
|
||||
|
||||
-- 1) AM : par ordre de création
|
||||
FOR r IN
|
||||
SELECT u.id
|
||||
FROM utilisateurs u
|
||||
WHERE u.role = 'assistante_maternelle'
|
||||
AND u.numero_dossier IS NULL
|
||||
AND EXTRACT(YEAR FROM u.cree_le) = yr
|
||||
ORDER BY u.cree_le
|
||||
LOOP
|
||||
seq := seq + 1;
|
||||
num := yr || '-' || LPAD(seq::TEXT, 6, '0');
|
||||
UPDATE utilisateurs SET numero_dossier = num WHERE id = r.id;
|
||||
UPDATE assistantes_maternelles SET numero_dossier = num WHERE id_utilisateur = r.id;
|
||||
END LOOP;
|
||||
|
||||
-- 2) Familles : une entrée par "dossier" (co_parent OU enfants partagés)
|
||||
-- family_rep = min(id) de la composante connexe (lien co_parent + partage d'enfants)
|
||||
FOR r IN
|
||||
WITH RECURSIVE
|
||||
links AS (
|
||||
SELECT p.id_utilisateur AS p1, p.id_co_parent AS p2 FROM parents p WHERE p.id_co_parent IS NOT NULL
|
||||
UNION ALL
|
||||
SELECT p.id_co_parent AS p1, p.id_utilisateur AS p2 FROM parents p WHERE p.id_co_parent IS NOT NULL
|
||||
UNION ALL
|
||||
SELECT ep1.id_parent AS p1, ep2.id_parent AS p2
|
||||
FROM enfants_parents ep1
|
||||
JOIN enfants_parents ep2 ON ep2.id_enfant = ep1.id_enfant AND ep1.id_parent < ep2.id_parent
|
||||
UNION ALL
|
||||
SELECT ep2.id_parent AS p1, ep1.id_parent AS p2
|
||||
FROM enfants_parents ep1
|
||||
JOIN enfants_parents ep2 ON ep2.id_enfant = ep1.id_enfant AND ep1.id_parent < ep2.id_parent
|
||||
),
|
||||
rec AS (
|
||||
SELECT id_utilisateur AS id, id_utilisateur AS rep FROM parents
|
||||
UNION
|
||||
SELECT l.p2 AS id, LEAST(rec_alias.rep, l.p2) AS rep FROM links l JOIN rec rec_alias ON rec_alias.id = l.p1
|
||||
),
|
||||
family_rep AS (
|
||||
SELECT id, MIN(rep::text)::uuid AS rep FROM rec GROUP BY id
|
||||
),
|
||||
fam_ordered AS (
|
||||
SELECT fr.rep AS family_rep, MIN(u.cree_le) AS cree_le
|
||||
FROM family_rep fr
|
||||
JOIN parents p ON p.id_utilisateur = fr.id
|
||||
JOIN utilisateurs u ON u.id = p.id_utilisateur
|
||||
WHERE p.numero_dossier IS NULL
|
||||
AND EXTRACT(YEAR FROM u.cree_le) = yr
|
||||
GROUP BY fr.rep
|
||||
ORDER BY MIN(u.cree_le)
|
||||
)
|
||||
SELECT fo.family_rep
|
||||
FROM fam_ordered fo
|
||||
LOOP
|
||||
seq := seq + 1;
|
||||
num := yr || '-' || LPAD(seq::TEXT, 6, '0');
|
||||
|
||||
WITH RECURSIVE
|
||||
links AS (
|
||||
SELECT p.id_utilisateur AS p1, p.id_co_parent AS p2 FROM parents p WHERE p.id_co_parent IS NOT NULL
|
||||
UNION ALL
|
||||
SELECT p.id_co_parent AS p1, p.id_utilisateur AS p2 FROM parents p WHERE p.id_co_parent IS NOT NULL
|
||||
UNION ALL
|
||||
SELECT ep1.id_parent AS p1, ep2.id_parent AS p2
|
||||
FROM enfants_parents ep1
|
||||
JOIN enfants_parents ep2 ON ep2.id_enfant = ep1.id_enfant AND ep1.id_parent < ep2.id_parent
|
||||
UNION ALL
|
||||
SELECT ep2.id_parent AS p1, ep1.id_parent AS p2
|
||||
FROM enfants_parents ep1
|
||||
JOIN enfants_parents ep2 ON ep2.id_enfant = ep1.id_enfant AND ep1.id_parent < ep2.id_parent
|
||||
),
|
||||
rec AS (
|
||||
SELECT id_utilisateur AS id, id_utilisateur AS rep FROM parents
|
||||
UNION
|
||||
SELECT l.p2 AS id, LEAST(rec_alias.rep, l.p2) AS rep FROM links l JOIN rec rec_alias ON rec_alias.id = l.p1
|
||||
),
|
||||
family_rep AS (
|
||||
SELECT id, MIN(rep::text)::uuid AS rep FROM rec GROUP BY id
|
||||
)
|
||||
SELECT array_agg(DISTINCT fr.id) INTO family_user_ids
|
||||
FROM family_rep fr
|
||||
WHERE fr.rep = r.family_rep;
|
||||
|
||||
UPDATE utilisateurs SET numero_dossier = num WHERE id = ANY(family_user_ids);
|
||||
UPDATE parents SET numero_dossier = num WHERE id_utilisateur = ANY(family_user_ids);
|
||||
END LOOP;
|
||||
|
||||
INSERT INTO numero_dossier_sequence (annee, prochain)
|
||||
VALUES (yr, seq + 1)
|
||||
ON CONFLICT (annee) DO UPDATE
|
||||
SET prochain = GREATEST(numero_dossier_sequence.prochain, seq + 1);
|
||||
END LOOP;
|
||||
END $$;
|
||||
Reference in New Issue
Block a user