314 lines
16 KiB
SQL
314 lines
16 KiB
SQL
-- ============================================================================
|
||
-- PTA V7 - Socle métier annuel, postes, contraintes et équipes
|
||
-- MySQL 8.0.16+
|
||
-- À exécuter après le schéma V5.20 / V6.
|
||
-- ============================================================================
|
||
|
||
START TRANSACTION;
|
||
|
||
-- --------------------------------------------------------------------------
|
||
-- 1. Postes éligibles au PTA
|
||
-- --------------------------------------------------------------------------
|
||
CREATE TABLE IF NOT EXISTS poste_agent (
|
||
id_poste INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||
code VARCHAR(50) NOT NULL,
|
||
libelle VARCHAR(150) NOT NULL,
|
||
famille ENUM('ANIMATION', 'RESTAURATION_ENTRETIEN') NOT NULL,
|
||
heures_mercredi_minutes SMALLINT UNSIGNED NOT NULL,
|
||
heures_extrascolaire_minutes SMALLINT UNSIGNED NOT NULL,
|
||
autorise_preparation BOOLEAN NOT NULL DEFAULT TRUE,
|
||
peut_assurer_animation BOOLEAN NOT NULL DEFAULT TRUE,
|
||
preparation_lundi_si_100 BOOLEAN NOT NULL DEFAULT FALSE,
|
||
actif BOOLEAN NOT NULL DEFAULT TRUE,
|
||
ordre_affichage SMALLINT UNSIGNED NOT NULL DEFAULT 100,
|
||
CONSTRAINT uk_poste_agent_code UNIQUE (code)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||
|
||
INSERT INTO poste_agent (
|
||
code, libelle, famille, heures_mercredi_minutes, heures_extrascolaire_minutes,
|
||
autorise_preparation, peut_assurer_animation, preparation_lundi_si_100, ordre_affichage
|
||
) VALUES
|
||
('RESPONSABLE', 'Responsable d’accueil', 'ANIMATION', 570, 570, TRUE, TRUE, TRUE, 10),
|
||
('ANIMATION_RELAIS', 'Agent d’animation relais', 'ANIMATION', 570, 570, TRUE, TRUE, TRUE, 20),
|
||
('ANIMATION', 'Agent d’animation', 'ANIMATION', 570, 570, TRUE, TRUE, TRUE, 30),
|
||
('RESTAURATION_ENTRETIEN', 'Agent de restauration collective et d’entretien', 'RESTAURATION_ENTRETIEN', 420, 420, FALSE, FALSE, FALSE, 40)
|
||
ON DUPLICATE KEY UPDATE
|
||
libelle = VALUES(libelle),
|
||
famille = VALUES(famille),
|
||
heures_mercredi_minutes = VALUES(heures_mercredi_minutes),
|
||
heures_extrascolaire_minutes = VALUES(heures_extrascolaire_minutes),
|
||
autorise_preparation = VALUES(autorise_preparation),
|
||
peut_assurer_animation = VALUES(peut_assurer_animation),
|
||
preparation_lundi_si_100 = VALUES(preparation_lundi_si_100),
|
||
ordre_affichage = VALUES(ordre_affichage),
|
||
actif = TRUE;
|
||
|
||
-- --------------------------------------------------------------------------
|
||
-- 2. Compléments métier de l’agent
|
||
-- --------------------------------------------------------------------------
|
||
ALTER TABLE agent
|
||
ADD COLUMN id_poste INT UNSIGNED NULL AFTER date_debut_contrat,
|
||
ADD COLUMN type_contrat ENUM('PERMANENT', 'TEMPORAIRE') NOT NULL DEFAULT 'PERMANENT' AFTER id_poste,
|
||
ADD COLUMN date_fin_contrat DATE NULL AFTER type_contrat,
|
||
ADD COLUMN formation_repartition_annuelle BOOLEAN NOT NULL DEFAULT FALSE AFTER date_fin_contrat,
|
||
ADD COLUMN commentaire_pta VARCHAR(1000) NULL AFTER formation_repartition_annuelle;
|
||
|
||
ALTER TABLE agent
|
||
ADD CONSTRAINT fk_agent_poste
|
||
FOREIGN KEY (id_poste) REFERENCES poste_agent(id_poste)
|
||
ON UPDATE CASCADE ON DELETE SET NULL,
|
||
ADD CONSTRAINT chk_agent_dates_contrat_v7
|
||
CHECK (date_fin_contrat IS NULL OR date_debut_contrat IS NULL OR date_fin_contrat >= date_debut_contrat);
|
||
|
||
CREATE INDEX idx_agent_poste ON agent(id_poste);
|
||
CREATE INDEX idx_agent_type_contrat ON agent(type_contrat, actif);
|
||
|
||
-- --------------------------------------------------------------------------
|
||
-- 3. PTA annuel de l’agent
|
||
-- --------------------------------------------------------------------------
|
||
CREATE TABLE IF NOT EXISTS pta_annuel (
|
||
id_pta INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||
id_agent INT UNSIGNED NOT NULL,
|
||
date_debut DATE NOT NULL,
|
||
date_fin DATE NOT NULL,
|
||
quotite_travail DECIMAL(5,2) NOT NULL,
|
||
quota_reference_minutes INT UNSIGNED NOT NULL DEFAULT 96420,
|
||
quota_cible_minutes INT UNSIGNED NOT NULL,
|
||
enveloppe_formation_minutes SMALLINT UNSIGNED NOT NULL DEFAULT 840,
|
||
conges_annuels_jours_cible DECIMAL(5,2) NOT NULL DEFAULT 25.00,
|
||
jours_fractionnement_cible TINYINT UNSIGNED NOT NULL DEFAULT 2,
|
||
statut ENUM('BROUILLON', 'A_CONTROLER', 'VALIDE') NOT NULL DEFAULT 'BROUILLON',
|
||
commentaire VARCHAR(1000) NULL,
|
||
date_validation DATETIME NULL,
|
||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||
|
||
CONSTRAINT fk_pta_annuel_agent
|
||
FOREIGN KEY (id_agent) REFERENCES agent(id_agent)
|
||
ON UPDATE CASCADE ON DELETE CASCADE,
|
||
CONSTRAINT chk_pta_annuel_dates CHECK (date_fin >= date_debut),
|
||
CONSTRAINT chk_pta_annuel_quotite CHECK (quotite_travail > 0 AND quotite_travail <= 100),
|
||
CONSTRAINT chk_pta_annuel_quota CHECK (quota_reference_minutes > 0 AND quota_cible_minutes > 0),
|
||
CONSTRAINT uk_pta_annuel_agent_periode UNIQUE (id_agent, date_debut, date_fin),
|
||
INDEX idx_pta_annuel_agent_statut (id_agent, statut),
|
||
INDEX idx_pta_annuel_periode (date_debut, date_fin)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||
|
||
-- --------------------------------------------------------------------------
|
||
-- 4. Préférences, interdictions et proximité des lieux
|
||
-- --------------------------------------------------------------------------
|
||
CREATE TABLE IF NOT EXISTS agent_structure_souhait (
|
||
id_souhait INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||
id_agent INT UNSIGNED NOT NULL,
|
||
id_structure INT UNSIGNED NOT NULL,
|
||
type_souhait ENUM('PREFERENCE', 'INTERDICTION') NOT NULL,
|
||
priorite TINYINT UNSIGNED NOT NULL DEFAULT 1,
|
||
distance_km DECIMAL(7,2) NULL,
|
||
commentaire VARCHAR(500) NULL,
|
||
actif BOOLEAN NOT NULL DEFAULT TRUE,
|
||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||
|
||
CONSTRAINT fk_souhait_agent FOREIGN KEY (id_agent) REFERENCES agent(id_agent)
|
||
ON UPDATE CASCADE ON DELETE CASCADE,
|
||
CONSTRAINT fk_souhait_structure FOREIGN KEY (id_structure) REFERENCES structure(id_structure)
|
||
ON UPDATE CASCADE ON DELETE CASCADE,
|
||
CONSTRAINT chk_souhait_priorite CHECK (priorite BETWEEN 1 AND 5),
|
||
CONSTRAINT chk_souhait_distance CHECK (distance_km IS NULL OR distance_km >= 0),
|
||
CONSTRAINT uk_souhait_agent_structure UNIQUE (id_agent, id_structure),
|
||
INDEX idx_souhait_agent_type (id_agent, type_souhait, actif)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||
|
||
-- --------------------------------------------------------------------------
|
||
-- 5. Contraintes médicales et temps partiels thérapeutiques
|
||
-- --------------------------------------------------------------------------
|
||
CREATE TABLE IF NOT EXISTS agent_contrainte (
|
||
id_contrainte INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||
id_agent INT UNSIGNED NOT NULL,
|
||
type_contrainte ENUM('MEDICALE', 'TEMPS_PARTIEL_THERAPEUTIQUE') NOT NULL,
|
||
date_debut DATE NOT NULL,
|
||
date_fin DATE NULL,
|
||
quotite_temporaire DECIMAL(5,2) NULL,
|
||
maximum_minutes_jour SMALLINT UNSIGNED NULL,
|
||
maximum_minutes_semaine SMALLINT UNSIGNED NULL,
|
||
interdit_matin BOOLEAN NOT NULL DEFAULT FALSE,
|
||
interdit_midi BOOLEAN NOT NULL DEFAULT FALSE,
|
||
interdit_soir BOOLEAN NOT NULL DEFAULT FALSE,
|
||
commentaire VARCHAR(1000) NOT NULL,
|
||
actif BOOLEAN NOT NULL DEFAULT TRUE,
|
||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||
|
||
CONSTRAINT fk_contrainte_agent FOREIGN KEY (id_agent) REFERENCES agent(id_agent)
|
||
ON UPDATE CASCADE ON DELETE CASCADE,
|
||
CONSTRAINT chk_contrainte_dates CHECK (date_fin IS NULL OR date_fin >= date_debut),
|
||
CONSTRAINT chk_contrainte_quotite CHECK (quotite_temporaire IS NULL OR (quotite_temporaire > 0 AND quotite_temporaire <= 100)),
|
||
CONSTRAINT chk_contrainte_max_jour CHECK (maximum_minutes_jour IS NULL OR maximum_minutes_jour > 0),
|
||
CONSTRAINT chk_contrainte_max_semaine CHECK (maximum_minutes_semaine IS NULL OR maximum_minutes_semaine > 0),
|
||
INDEX idx_contrainte_agent_dates (id_agent, actif, date_debut, date_fin)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||
|
||
-- --------------------------------------------------------------------------
|
||
-- 6. Équipes périscolaires des mercredis et extrascolaires
|
||
-- --------------------------------------------------------------------------
|
||
CREATE TABLE IF NOT EXISTS equipe_pta (
|
||
id_equipe INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||
id_structure INT UNSIGNED NOT NULL,
|
||
type_equipe ENUM('MERCREDI_PERISCOLAIRE', 'EXTRASCOLAIRE', 'PERISCOLAIRE_SEMAINE') NOT NULL,
|
||
libelle VARCHAR(180) NOT NULL,
|
||
date_debut DATE NOT NULL,
|
||
date_fin DATE NOT NULL,
|
||
nombre_enfants_moins_6 SMALLINT UNSIGNED NOT NULL DEFAULT 0,
|
||
nombre_enfants_6_plus SMALLINT UNSIGNED NOT NULL DEFAULT 0,
|
||
ratio_moins_6 TINYINT UNSIGNED NOT NULL DEFAULT 8,
|
||
ratio_6_plus TINYINT UNSIGNED NOT NULL DEFAULT 12,
|
||
minimum_agents TINYINT UNSIGNED NOT NULL DEFAULT 1,
|
||
pourcentage_diplomes_min DECIMAL(5,2) NOT NULL DEFAULT 50.00,
|
||
statut ENUM('BROUILLON', 'A_CONTROLER', 'VALIDEE') NOT NULL DEFAULT 'BROUILLON',
|
||
commentaire VARCHAR(1000) NULL,
|
||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||
|
||
CONSTRAINT fk_equipe_pta_structure FOREIGN KEY (id_structure) REFERENCES structure(id_structure)
|
||
ON UPDATE CASCADE ON DELETE RESTRICT,
|
||
CONSTRAINT chk_equipe_dates CHECK (date_fin >= date_debut),
|
||
CONSTRAINT chk_equipe_ratios CHECK (ratio_moins_6 > 0 AND ratio_6_plus > 0),
|
||
CONSTRAINT chk_equipe_minimum CHECK (minimum_agents > 0),
|
||
CONSTRAINT chk_equipe_diplomes CHECK (pourcentage_diplomes_min BETWEEN 0 AND 100),
|
||
INDEX idx_equipe_pta_type_dates (type_equipe, date_debut, date_fin),
|
||
INDEX idx_equipe_pta_structure_dates (id_structure, date_debut, date_fin)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||
|
||
CREATE TABLE IF NOT EXISTS equipe_pta_membre (
|
||
id_equipe_membre INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||
id_equipe INT UNSIGNED NOT NULL,
|
||
id_agent INT UNSIGNED NOT NULL,
|
||
fonction_equipe ENUM('RESPONSABLE', 'ANIMATION', 'RESTAURATION_ENTRETIEN') NOT NULL DEFAULT 'ANIMATION',
|
||
date_debut DATE NULL,
|
||
date_fin DATE NULL,
|
||
commentaire VARCHAR(500) NULL,
|
||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
|
||
CONSTRAINT fk_equipe_membre_equipe FOREIGN KEY (id_equipe) REFERENCES equipe_pta(id_equipe)
|
||
ON UPDATE CASCADE ON DELETE CASCADE,
|
||
CONSTRAINT fk_equipe_membre_agent FOREIGN KEY (id_agent) REFERENCES agent(id_agent)
|
||
ON UPDATE CASCADE ON DELETE RESTRICT,
|
||
CONSTRAINT chk_equipe_membre_dates CHECK (date_fin IS NULL OR date_debut IS NULL OR date_fin >= date_debut),
|
||
CONSTRAINT uk_equipe_membre UNIQUE (id_equipe, id_agent),
|
||
INDEX idx_equipe_membre_agent (id_agent, id_equipe)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||
|
||
-- --------------------------------------------------------------------------
|
||
-- 7. Références horaires des lieux pour les automatismes de préparation
|
||
-- --------------------------------------------------------------------------
|
||
CREATE TABLE IF NOT EXISTS structure_creneau_reference (
|
||
id_reference INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||
id_structure INT UNSIGNED NOT NULL,
|
||
code_plage ENUM('ALP_MATIN', 'RESTAURATION', 'ALP_SOIR') NOT NULL,
|
||
jour_semaine TINYINT UNSIGNED NOT NULL COMMENT '1=lundi ... 5=vendredi',
|
||
heure_debut TIME NOT NULL,
|
||
heure_fin TIME NOT NULL,
|
||
actif BOOLEAN NOT NULL DEFAULT TRUE,
|
||
|
||
CONSTRAINT fk_reference_structure FOREIGN KEY (id_structure) REFERENCES structure(id_structure)
|
||
ON UPDATE CASCADE ON DELETE CASCADE,
|
||
CONSTRAINT chk_reference_jour CHECK (jour_semaine BETWEEN 1 AND 5),
|
||
CONSTRAINT chk_reference_ordre CHECK (heure_fin > heure_debut),
|
||
CONSTRAINT uk_reference_structure_plage_jour UNIQUE (id_structure, code_plage, jour_semaine),
|
||
INDEX idx_reference_structure_jour (id_structure, jour_semaine, actif)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||
|
||
-- --------------------------------------------------------------------------
|
||
-- 8. Motifs détaillés du PTA
|
||
-- --------------------------------------------------------------------------
|
||
INSERT INTO motif_planning (code, libelle, compte_dans_quota, ordre_affichage, actif)
|
||
VALUES
|
||
('ALP_MATIN', 'ALP matin', TRUE, 10, TRUE),
|
||
('RESTAURATION', 'Restauration', TRUE, 20, TRUE),
|
||
('ALP_SOIR', 'ALP soir', TRUE, 30, TRUE),
|
||
('MERCREDI_PERISCOLAIRE', 'Mercredi périscolaire', TRUE, 40, TRUE),
|
||
('EXTRASCOLAIRE', 'Temps extrascolaire', TRUE, 50, TRUE),
|
||
('FORMATION', 'Formation', TRUE, 60, TRUE),
|
||
('CONGE', 'Congé annuel (non décompté)', FALSE, 70, TRUE),
|
||
('JOUR_FRACTIONNEMENT', 'Journée de fractionnement', TRUE, 80, TRUE),
|
||
('PREPARATION_PERISCOLAIRE', 'Préparation périscolaire', TRUE, 90, TRUE),
|
||
('PREPARATION_EXTRASCOLAIRE', 'Préparation extrascolaire', TRUE, 100, TRUE),
|
||
('PREPARATION_LUNDI', 'Préparation du lundi', TRUE, 110, TRUE),
|
||
('MENAGE_FOND', 'Ménage de fond', TRUE, 120, TRUE),
|
||
('JNT', 'Journée non travaillée', FALSE, 130, TRUE)
|
||
ON DUPLICATE KEY UPDATE
|
||
libelle = VALUES(libelle),
|
||
compte_dans_quota = VALUES(compte_dans_quota),
|
||
ordre_affichage = VALUES(ordre_affichage),
|
||
actif = TRUE;
|
||
|
||
-- La règle métier communiquée précise que les congés annuels ne sont pas
|
||
-- redécomptés du quota puisqu'ils sont déjà intégrés dans le calcul initial.
|
||
UPDATE motif_planning
|
||
SET libelle = 'Congé annuel (non décompté)', compte_dans_quota = FALSE
|
||
WHERE code = 'CONGE';
|
||
|
||
-- --------------------------------------------------------------------------
|
||
-- 9. Vues de synthèse
|
||
-- --------------------------------------------------------------------------
|
||
CREATE OR REPLACE VIEW v_pta_annuel_synthese AS
|
||
SELECT
|
||
pa.id_pta,
|
||
pa.id_agent,
|
||
a.matricule,
|
||
a.nom,
|
||
a.prenom,
|
||
po.code AS poste_code,
|
||
po.libelle AS poste_libelle,
|
||
a.type_contrat,
|
||
pa.date_debut,
|
||
pa.date_fin,
|
||
pa.quotite_travail,
|
||
pa.quota_cible_minutes,
|
||
COALESCE(SUM(CASE WHEN mp.compte_dans_quota = TRUE THEN TIMESTAMPDIFF(MINUTE, CONCAT(ch.date_jour, ' ', ch.heure_debut), CONCAT(ch.date_jour, ' ', ch.heure_fin)) ELSE 0 END), 0) AS minutes_decomptees,
|
||
pa.quota_cible_minutes - COALESCE(SUM(CASE WHEN mp.compte_dans_quota = TRUE THEN TIMESTAMPDIFF(MINUTE, CONCAT(ch.date_jour, ' ', ch.heure_debut), CONCAT(ch.date_jour, ' ', ch.heure_fin)) ELSE 0 END), 0) AS minutes_restantes,
|
||
pa.statut
|
||
FROM pta_annuel pa
|
||
JOIN agent a ON a.id_agent = pa.id_agent
|
||
LEFT JOIN poste_agent po ON po.id_poste = a.id_poste
|
||
LEFT JOIN planning p ON p.id_agent = pa.id_agent
|
||
LEFT JOIN creneau_horaire ch ON ch.id_planning = p.id_planning AND ch.date_jour BETWEEN pa.date_debut AND pa.date_fin
|
||
LEFT JOIN motif_planning mp ON mp.id_motif = ch.id_motif
|
||
GROUP BY pa.id_pta, pa.id_agent, a.matricule, a.nom, a.prenom, po.code, po.libelle,
|
||
a.type_contrat, pa.date_debut, pa.date_fin, pa.quotite_travail,
|
||
pa.quota_cible_minutes, pa.statut;
|
||
|
||
CREATE OR REPLACE VIEW v_equipe_pta_controle AS
|
||
SELECT
|
||
e.id_equipe,
|
||
e.libelle,
|
||
e.type_equipe,
|
||
e.id_structure,
|
||
s.nom AS structure_nom,
|
||
e.date_debut,
|
||
e.date_fin,
|
||
e.nombre_enfants_moins_6,
|
||
e.nombre_enfants_6_plus,
|
||
GREATEST(
|
||
e.minimum_agents,
|
||
CEIL(e.nombre_enfants_moins_6 / e.ratio_moins_6) + CEIL(e.nombre_enfants_6_plus / e.ratio_6_plus)
|
||
) AS agents_requis,
|
||
COUNT(em.id_agent) AS agents_affectes,
|
||
SUM(CASE WHEN a.est_diplome = TRUE THEN 1 ELSE 0 END) AS agents_diplomes,
|
||
CASE WHEN COUNT(em.id_agent) = 0 THEN 0
|
||
ELSE ROUND(100 * SUM(CASE WHEN a.est_diplome = TRUE THEN 1 ELSE 0 END) / COUNT(em.id_agent), 2)
|
||
END AS pourcentage_diplomes,
|
||
e.pourcentage_diplomes_min,
|
||
SUM(CASE WHEN em.fonction_equipe = 'RESPONSABLE' THEN 1 ELSE 0 END) AS responsables,
|
||
e.statut
|
||
FROM equipe_pta e
|
||
JOIN structure s ON s.id_structure = e.id_structure
|
||
LEFT JOIN equipe_pta_membre em ON em.id_equipe = e.id_equipe
|
||
LEFT JOIN agent a ON a.id_agent = em.id_agent
|
||
GROUP BY e.id_equipe, e.libelle, e.type_equipe, e.id_structure, s.nom,
|
||
e.date_debut, e.date_fin, e.nombre_enfants_moins_6, e.nombre_enfants_6_plus,
|
||
e.ratio_moins_6, e.ratio_6_plus, e.minimum_agents,
|
||
e.pourcentage_diplomes_min, e.statut;
|
||
|
||
COMMIT;
|