77 lines
4.2 KiB
SQL
77 lines
4.2 KiB
SQL
-- ============================================================
|
||
-- V2.2 — SaaS : formules_abonnement + souscriptions_organisation
|
||
-- Auteur: UnionFlow Team | BCEAO/OHADA compliant
|
||
-- ============================================================
|
||
|
||
CREATE TABLE IF NOT EXISTS formules_abonnement (
|
||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||
|
||
code VARCHAR(20) UNIQUE NOT NULL, -- STARTER, STANDARD, PREMIUM, CRYSTAL
|
||
libelle VARCHAR(100) NOT NULL,
|
||
description TEXT,
|
||
max_membres INTEGER, -- NULL = illimité (Crystal+)
|
||
max_stockage_mo INTEGER NOT NULL DEFAULT 1024, -- 1 Go par défaut
|
||
prix_mensuel DECIMAL(10,2) NOT NULL CHECK (prix_mensuel >= 0),
|
||
prix_annuel DECIMAL(10,2) NOT NULL CHECK (prix_annuel >= 0),
|
||
actif BOOLEAN NOT NULL DEFAULT TRUE,
|
||
ordre_affichage INTEGER DEFAULT 0,
|
||
|
||
-- Métadonnées BaseEntity
|
||
date_creation TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
date_modification TIMESTAMP,
|
||
cree_par VARCHAR(255),
|
||
modifie_par VARCHAR(255),
|
||
version BIGINT NOT NULL DEFAULT 0,
|
||
|
||
CONSTRAINT chk_formule_code CHECK (code IN ('STARTER','STANDARD','PREMIUM','CRYSTAL'))
|
||
);
|
||
|
||
-- Données initiales des forfaits (XOF, 1er Janvier 2026)
|
||
INSERT INTO formules_abonnement (id, code, libelle, description, max_membres, max_stockage_mo, prix_mensuel, prix_annuel, actif, ordre_affichage)
|
||
VALUES
|
||
(gen_random_uuid(), 'STARTER', 'Formule Starter', 'Idéal pour démarrer — jusqu''à 50 membres', 50, 1024, 5000.00, 50000.00, true, 1),
|
||
(gen_random_uuid(), 'STANDARD', 'Formule Standard', 'Pour les organisations en croissance', 200, 1024, 7000.00, 70000.00, true, 2),
|
||
(gen_random_uuid(), 'PREMIUM', 'Formule Premium', 'Organisations établies', 500, 1024, 9000.00, 90000.00, true, 3),
|
||
(gen_random_uuid(), 'CRYSTAL', 'Formule Crystal', 'Fédérations et grandes organisations', NULL,1024, 10000.00, 100000.00, true, 4)
|
||
ON CONFLICT (code) DO NOTHING;
|
||
|
||
-- ============================================================
|
||
CREATE TABLE IF NOT EXISTS souscriptions_organisation (
|
||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||
|
||
organisation_id UUID UNIQUE NOT NULL,
|
||
formule_id UUID NOT NULL,
|
||
type_periode VARCHAR(10) NOT NULL DEFAULT 'MENSUEL', -- MENSUEL | ANNUEL
|
||
date_debut DATE NOT NULL,
|
||
date_fin DATE NOT NULL,
|
||
quota_max INTEGER, -- snapshot de formule.max_membres
|
||
quota_utilise INTEGER NOT NULL DEFAULT 0,
|
||
statut VARCHAR(30) NOT NULL DEFAULT 'ACTIVE',
|
||
reference_paiement_wave VARCHAR(100),
|
||
wave_session_id VARCHAR(255),
|
||
date_dernier_paiement DATE,
|
||
date_prochain_paiement DATE,
|
||
|
||
-- Métadonnées BaseEntity
|
||
actif BOOLEAN NOT NULL DEFAULT TRUE,
|
||
date_creation TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
date_modification TIMESTAMP,
|
||
cree_par VARCHAR(255),
|
||
modifie_par VARCHAR(255),
|
||
version BIGINT NOT NULL DEFAULT 0,
|
||
|
||
CONSTRAINT fk_souscription_org FOREIGN KEY (organisation_id) REFERENCES organisations(id) ON DELETE CASCADE,
|
||
CONSTRAINT fk_souscription_formule FOREIGN KEY (formule_id) REFERENCES formules_abonnement(id),
|
||
CONSTRAINT chk_souscription_statut CHECK (statut IN ('ACTIVE','EXPIREE','SUSPENDUE','RESILIEE')),
|
||
CONSTRAINT chk_souscription_periode CHECK (type_periode IN ('MENSUEL','ANNUEL')),
|
||
CONSTRAINT chk_souscription_quota CHECK (quota_utilise >= 0)
|
||
);
|
||
|
||
CREATE INDEX idx_souscription_org ON souscriptions_organisation(organisation_id);
|
||
CREATE INDEX idx_souscription_statut ON souscriptions_organisation(statut);
|
||
CREATE INDEX idx_souscription_fin ON souscriptions_organisation(date_fin);
|
||
|
||
COMMENT ON TABLE formules_abonnement IS 'Catalogue des forfaits SaaS UnionFlow (Starter→Crystal, 5000–10000 XOF/mois)';
|
||
COMMENT ON TABLE souscriptions_organisation IS 'Abonnement actif d''une organisation racine — quota, durée, référence Wave';
|
||
COMMENT ON COLUMN souscriptions_organisation.quota_utilise IS 'Incrémenté automatiquement à chaque adhésion validée. Bloquant si = quota_max.';
|