Files
unionflow-server-impl-quarkus/src/main/resources/db/migration/V11__Souscription_Workflow.sql
dahoud 139642c4cd fix: apply plural table name renames to all migrations V2-V16
Same rename applied to V1 must propagate to V2-V16 which referenced
old singular table names (compte_comptable, suggestion, etc.)
2026-04-08 17:32:48 +00:00

280 lines
13 KiB
SQL
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

-- =============================================================================
-- V11 — Workflow de souscription/onboarding UnionFlow
-- =============================================================================
-- Auteur : UnionFlow Team
-- Date : 2026-03-30
-- Objectif:
-- 0. Renommer les tables singulières créées par V1 vers les noms pluriels attendus
-- par les entités JPA (FormuleAbonnement → formules_abonnement, etc.)
-- 1. Ajouter les colonnes manquantes à formules_abonnement (entité refactorisée)
-- 2. Ajouter la colonne `plage` à formules_abonnement (PETITE/MOYENNE/GRANDE/TRES_GRANDE)
-- 3. Supprimer le code unique sur `code` seul (nouvelle contrainte sur code+plage)
-- 4. Migrer les anciennes valeurs TypeFormule (STARTER→BASIC, CRYSTAL supprimé)
-- 5. Vider et re-seeder avec la matrice tarifaire 4×3 (12 formules)
-- 6. Ajouter les colonnes du workflow de validation à souscriptions_organisation
-- 7. Ajouter EN_ATTENTE au statut (déjà en DB comme VARCHAR, pas de contrainte CHECK)
-- =============================================================================
-- -----------------------------------------------------------------------------
-- 0. Renommer les tables singulières → plurielles (alignement entités JPA)
-- -----------------------------------------------------------------------------
-- formules_abonnement → formules_abonnement (FormuleAbonnement entity @Table)
DO $$
BEGIN
IF EXISTS (SELECT 1 FROM pg_tables WHERE schemaname = 'public' AND tablename = 'formules_abonnement')
AND NOT EXISTS (SELECT 1 FROM pg_tables WHERE schemaname = 'public' AND tablename = 'formules_abonnement') THEN
ALTER TABLE formules_abonnement RENAME TO formules_abonnement;
END IF;
END $$;
-- souscriptions_organisation → souscriptions_organisation (SouscriptionOrganisation entity @Table)
DO $$
BEGIN
IF EXISTS (SELECT 1 FROM pg_tables WHERE schemaname = 'public' AND tablename = 'souscriptions_organisation')
AND NOT EXISTS (SELECT 1 FROM pg_tables WHERE schemaname = 'public' AND tablename = 'souscriptions_organisation') THEN
ALTER TABLE souscriptions_organisation RENAME TO souscriptions_organisation;
END IF;
END $$;
-- Mise à jour des noms de contraintes FK après le renommage
-- (PostgreSQL met à jour automatiquement les FK qui référencent la table renommée)
-- -----------------------------------------------------------------------------
-- 0b. Ajouter les colonnes manquantes à formules_abonnement (entité refactorisée)
-- -----------------------------------------------------------------------------
-- Colonne libelle (libellé de la formule — nullable temporairement, NOT NULL après seed)
ALTER TABLE formules_abonnement ADD COLUMN IF NOT EXISTS libelle VARCHAR(100);
-- Colonne plage (taille organisation cible)
ALTER TABLE formules_abonnement ADD COLUMN IF NOT EXISTS plage VARCHAR(20);
-- Nombre max de membres (NULL = illimité)
ALTER TABLE formules_abonnement ADD COLUMN IF NOT EXISTS max_membres INTEGER;
-- Stockage max en Mo (défaut 1 Go)
ALTER TABLE formules_abonnement ADD COLUMN IF NOT EXISTS max_stockage_mo INTEGER DEFAULT 1024;
-- Ordre d'affichage dans le catalogue
ALTER TABLE formules_abonnement ADD COLUMN IF NOT EXISTS ordre_affichage INTEGER DEFAULT 0;
-- La colonne `nom` de V1 n'est pas dans l'entité JPA — rendre nullable pour compatibilité
ALTER TABLE formules_abonnement ALTER COLUMN nom DROP NOT NULL;
-- -----------------------------------------------------------------------------
-- 0c. Supprimer les contraintes CHECK Hibernate obsolètes
-- -----------------------------------------------------------------------------
-- Hibernate génère automatiquement des CHECK constraints pour les enums @Enumerated(STRING).
-- Les valeurs ont changé (STARTER→BASIC, CRYSTAL supprimé) : on supprime ces contraintes
-- avant toute modification de données.
ALTER TABLE formules_abonnement DROP CONSTRAINT IF EXISTS formules_abonnement_code_check;
ALTER TABLE souscriptions_organisation DROP CONSTRAINT IF EXISTS souscriptions_organisation_statut_check;
ALTER TABLE souscriptions_organisation DROP CONSTRAINT IF EXISTS souscriptions_organisation_type_periode_check;
ALTER TABLE souscriptions_organisation DROP CONSTRAINT IF EXISTS souscriptions_organisation_statut_validation_check;
-- -----------------------------------------------------------------------------
-- 1. Préparer formules_abonnement
-- -----------------------------------------------------------------------------
-- Ajouter la colonne plage si elle n'existe pas encore
ALTER TABLE formules_abonnement ADD COLUMN IF NOT EXISTS plage VARCHAR(20);
-- Supprimer toutes les contraintes unicité sur code seul (V1 ou Hibernate)
DO $$
DECLARE r RECORD;
BEGIN
FOR r IN
SELECT conname FROM pg_constraint
WHERE conrelid = 'formules_abonnement'::regclass
AND contype = 'u'
AND conname NOT IN ('idx_formule_code_plage')
AND array_length(conkey, 1) = 1
AND conkey[1] = (
SELECT attnum FROM pg_attribute
WHERE attrelid = 'formules_abonnement'::regclass AND attname = 'code'
)
LOOP
EXECUTE 'ALTER TABLE formules_abonnement DROP CONSTRAINT ' || quote_ident(r.conname);
END LOOP;
END $$;
-- Supprimer les index uniques sur code seul s'ils existent
DROP INDEX IF EXISTS idx_formule_code;
DROP INDEX IF EXISTS formule_abonnement_code_key;
-- -----------------------------------------------------------------------------
-- 2. Migrer les anciennes données TypeFormule
-- -----------------------------------------------------------------------------
UPDATE formules_abonnement SET code = 'BASIC' WHERE code = 'STARTER';
DELETE FROM formules_abonnement WHERE code = 'CRYSTAL';
-- -----------------------------------------------------------------------------
-- 3. Vider et re-seeder avec la nouvelle matrice 4 plages × 3 formules
-- -----------------------------------------------------------------------------
DELETE FROM formules_abonnement;
INSERT INTO formules_abonnement (
id, version, actif, cree_par, modifie_par, date_creation, date_modification,
code, libelle, description, plage, max_membres, max_stockage_mo,
prix_mensuel, prix_annuel, ordre_affichage
) VALUES
-- ── PETITE (1100 membres) ──────────────────────────────────────────────────
(gen_random_uuid(), 0, true, 'SYSTEM', 'SYSTEM', NOW(), NOW(),
'BASIC', 'Basic — Petites structures',
'Idéal pour les petites associations de moins de 100 membres',
'PETITE', 100, 1024, 3000, 28800, 1),
(gen_random_uuid(), 0, true, 'SYSTEM', 'SYSTEM', NOW(), NOW(),
'STANDARD', 'Standard — Petites structures',
'Pour les associations actives de moins de 100 membres',
'PETITE', 100, 5120, 6000, 57600, 2),
(gen_random_uuid(), 0, true, 'SYSTEM', 'SYSTEM', NOW(), NOW(),
'PREMIUM', 'Premium — Petites structures',
'Fonctionnalités avancées pour petites structures ambitieuses',
'PETITE', 100, 10240, 10000, 96000, 3),
-- ── MOYENNE (101500 membres) ────────────────────────────────────────────────
(gen_random_uuid(), 0, true, 'SYSTEM', 'SYSTEM', NOW(), NOW(),
'BASIC', 'Basic — Moyennes structures',
'Gestion complète pour moyennes structures',
'MOYENNE', 500, 2048, 8000, 76800, 4),
(gen_random_uuid(), 0, true, 'SYSTEM', 'SYSTEM', NOW(), NOW(),
'STANDARD', 'Standard — Moyennes structures',
'Fonctionnalités étendues pour organisations en croissance',
'MOYENNE', 500, 10240, 15000, 144000, 5),
(gen_random_uuid(), 0, true, 'SYSTEM', 'SYSTEM', NOW(), NOW(),
'PREMIUM', 'Premium — Moyennes structures',
'Suite complète pour organisations actives',
'MOYENNE', 500, 20480, 25000, 240000, 6),
-- ── GRANDE (5012 000 membres) ────────────────────────────────────────────────
(gen_random_uuid(), 0, true, 'SYSTEM', 'SYSTEM', NOW(), NOW(),
'BASIC', 'Basic — Grandes structures',
'Solution économique pour grandes organisations',
'GRANDE', 2000, 5120, 20000, 192000, 7),
(gen_random_uuid(), 0, true, 'SYSTEM', 'SYSTEM', NOW(), NOW(),
'STANDARD', 'Standard — Grandes structures',
'Gestion avancée pour grandes structures',
'GRANDE', 2000, 20480, 35000, 336000, 8),
(gen_random_uuid(), 0, true, 'SYSTEM', 'SYSTEM', NOW(), NOW(),
'PREMIUM', 'Premium — Grandes structures',
'Fonctionnalités entreprise pour grandes organisations',
'GRANDE', 2000, 51200, 60000, 576000, 9),
-- ── TRES_GRANDE (2 000+ membres) ─────────────────────────────────────────────
(gen_random_uuid(), 0, true, 'SYSTEM', 'SYSTEM', NOW(), NOW(),
'BASIC', 'Basic — Très grandes structures',
'Gestion de base pour très grandes organisations',
'TRES_GRANDE', NULL, 10240, 50000, 480000, 10),
(gen_random_uuid(), 0, true, 'SYSTEM', 'SYSTEM', NOW(), NOW(),
'STANDARD', 'Standard — Très grandes structures',
'Suite complète pour très grandes organisations',
'TRES_GRANDE', NULL, 51200, 80000, 768000, 11),
(gen_random_uuid(), 0, true, 'SYSTEM', 'SYSTEM', NOW(), NOW(),
'PREMIUM', 'Premium — Très grandes structures',
'Solution enterprise multi-sites avec analytics avancé',
'TRES_GRANDE', NULL, 102400, 120000, 1152000, 12);
-- Appliquer NOT NULL sur plage après le seed
DO $$
BEGIN
-- PostgreSQL ne supporte pas ADD COLUMN ... NOT NULL ... en une seule commande
-- quand la table est déjà peuplée. On pose la contrainte séparément.
ALTER TABLE formules_abonnement ALTER COLUMN plage SET NOT NULL;
EXCEPTION
WHEN others THEN
RAISE NOTICE 'Contrainte NOT NULL sur plage déjà présente ou erreur: %', SQLERRM;
END $$;
-- Créer l'index unique sur la combinaison code+plage
CREATE UNIQUE INDEX IF NOT EXISTS idx_formule_code_plage
ON formules_abonnement (code, plage);
CREATE INDEX IF NOT EXISTS idx_formule_plage
ON formules_abonnement (plage);
-- -----------------------------------------------------------------------------
-- 4. Colonnes workflow de validation dans souscriptions_organisation
-- -----------------------------------------------------------------------------
ALTER TABLE souscriptions_organisation
ADD COLUMN IF NOT EXISTS plage VARCHAR(20);
ALTER TABLE souscriptions_organisation
ADD COLUMN IF NOT EXISTS type_organisation VARCHAR(30);
ALTER TABLE souscriptions_organisation
ADD COLUMN IF NOT EXISTS coefficient_applique NUMERIC(4, 2);
ALTER TABLE souscriptions_organisation
ADD COLUMN IF NOT EXISTS statut_validation VARCHAR(40);
ALTER TABLE souscriptions_organisation
ADD COLUMN IF NOT EXISTS montant_total NUMERIC(12, 2);
ALTER TABLE souscriptions_organisation
ADD COLUMN IF NOT EXISTS date_validation DATE;
ALTER TABLE souscriptions_organisation
ADD COLUMN IF NOT EXISTS validated_by_id UUID;
ALTER TABLE souscriptions_organisation
ADD COLUMN IF NOT EXISTS commentaire_rejet VARCHAR(500);
ALTER TABLE souscriptions_organisation
ADD COLUMN IF NOT EXISTS mot_de_passe_temporaire VARCHAR(100);
-- Backfill des lignes existantes avant d'ajouter les contraintes NOT NULL
UPDATE souscriptions_organisation
SET plage = 'PETITE',
type_organisation = 'ASSOCIATION',
coefficient_applique = 1.0,
statut_validation = 'VALIDEE'
WHERE plage IS NULL;
-- Appliquer NOT NULL sur statut_validation uniquement (les autres sont optionnels)
DO $$
BEGIN
ALTER TABLE souscriptions_organisation
ALTER COLUMN statut_validation SET NOT NULL;
EXCEPTION
WHEN others THEN
RAISE NOTICE 'Contrainte NOT NULL sur statut_validation: %', SQLERRM;
END $$;
-- Valeur par défaut pour les nouvelles lignes
ALTER TABLE souscriptions_organisation
ALTER COLUMN statut_validation SET DEFAULT 'EN_ATTENTE_PAIEMENT';
-- Index pour les requêtes SuperAdmin sur le workflow
CREATE INDEX IF NOT EXISTS idx_souscription_statut_validation
ON souscriptions_organisation (statut_validation);
CREATE INDEX IF NOT EXISTS idx_souscription_plage
ON souscriptions_organisation (plage);
-- Mise à jour du statut global pour les souscriptions existantes actives
-- (l'ancienne valeur ACTIVE reste cohérente avec VALIDEE côté validation)
UPDATE souscriptions_organisation
SET statut = 'ACTIVE'
WHERE statut IS NULL OR statut NOT IN ('ACTIVE', 'EXPIREE', 'SUSPENDUE', 'RESILIEE', 'EN_ATTENTE');
-- =============================================================================
-- Fin de V11
-- =============================================================================