Rattraper le référentiel des absences des instances déjà installées
installReferentials() pose les types d'absence depuis WP-02, mais ne tourne qu'à la création du compte. Une instance installée avant garde zéro type : le menu « Type » du formulaire de demande reste vide et le module de congés est inutilisable, sans qu'aucune erreur ne le signale. Déployer le correctif ne suffisait donc pas. La migration ne touche que les comptes dont le référentiel est entièrement vide — un type délibérément archivé ne doit pas réapparaître. Elle lève FORCE ROW LEVEL SECURITY le temps de la transaction, faute de compte courant. Le formulaire dit désormais que le référentiel manque et renvoie aux réglages, plutôt que d'afficher un menu vide qui laisse saisir une demande impossible. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
dd01fb58f4
commit
49c311423d
2 files changed
+93
No files matched your search
@@ -0,0 +1,77 @@
|
|||||||
|
-- Types d'absence sur les comptes installés avant WP-02 — PLAN.md §7.
|
||||||
|
--
|
||||||
|
-- `installReferentials()` pose le référentiel des absences depuis WP-02, mais
|
||||||
|
-- il ne tourne qu'à la création du compte. Une instance installée **avant**
|
||||||
|
-- garde donc zéro type d'absence, et le menu « Type » du formulaire de demande
|
||||||
|
-- reste vide : le module de congés est inutilisable, sans qu'aucune erreur ne
|
||||||
|
-- le signale. Déployer le correctif ne suffit pas — d'où ce rattrapage.
|
||||||
|
--
|
||||||
|
-- Il ne s'applique qu'aux comptes dont le référentiel est **entièrement** vide.
|
||||||
|
-- Un compte qui a renommé ou archivé ses types garde les siens : personne ne
|
||||||
|
-- doit voir réapparaître un type qu'il a délibérément retiré.
|
||||||
|
--
|
||||||
|
-- La liste double celle de `referentials.ts`, à dessein. Une migration est
|
||||||
|
-- figée par nature — elle décrit l'état à rattraper au 12 août 2026, pas la
|
||||||
|
-- liste courante. Les évolutions ultérieures du référentiel se font depuis
|
||||||
|
-- `/reglages/types-absence`, pas en rééditant ce fichier.
|
||||||
|
|
||||||
|
-- `AbsenceType` porte FORCE ROW LEVEL SECURITY : la politique d'insertion vaut
|
||||||
|
-- pour le propriétaire de la table comme pour tout le monde, et une migration
|
||||||
|
-- n'a pas de compte courant. La levée tient le temps de la transaction — un
|
||||||
|
-- échec l'annule, la table ne peut pas rester ouverte.
|
||||||
|
ALTER TABLE "AbsenceType" NO FORCE ROW LEVEL SECURITY;
|
||||||
|
|
||||||
|
INSERT INTO "AbsenceType" (
|
||||||
|
"id", "accountId", "code", "name", "colorKey",
|
||||||
|
"isPaid", "countsAsWorkTime", "affectsPaidLeaveAccrual",
|
||||||
|
"isSocialSecurity", "requiresJustification", "minNoticeDays"
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
gen_random_uuid()::text,
|
||||||
|
a."id",
|
||||||
|
t."code", t."name", t."colorKey",
|
||||||
|
t."isPaid", FALSE, t."accrual",
|
||||||
|
t."social", t."justify", t."notice"
|
||||||
|
FROM "Account" a
|
||||||
|
CROSS JOIN (
|
||||||
|
VALUES
|
||||||
|
-- Congés et repos
|
||||||
|
('CP', 'Congé payé', 'cp', TRUE, TRUE, FALSE, FALSE, 30),
|
||||||
|
('RTT', 'RTT', 'rtt', TRUE, TRUE, FALSE, FALSE, 7),
|
||||||
|
('RC', 'Repos compensateur', 'rtt', TRUE, TRUE, FALSE, FALSE, 7),
|
||||||
|
('RC_NUIT', 'Repos compensateur de nuit', 'rtt', TRUE, TRUE, FALSE, FALSE, 7),
|
||||||
|
('RC_HAB', 'Repos compensateur d''habillement', 'rtt', TRUE, TRUE, FALSE, FALSE, 7),
|
||||||
|
('RECUP_JF', 'Récupération jour férié', 'rtt', TRUE, TRUE, FALSE, FALSE, 7),
|
||||||
|
('JF', 'Jour férié', 'ferie', TRUE, TRUE, FALSE, FALSE, NULL),
|
||||||
|
('CSS', 'Congé sans solde', 'sans-solde', FALSE, FALSE, FALSE, FALSE, 15),
|
||||||
|
|
||||||
|
-- Santé et accidents — catégories particulières au sens du RGPD
|
||||||
|
('MAL', 'Arrêt maladie', 'maladie', FALSE, FALSE, TRUE, TRUE, NULL),
|
||||||
|
('MP', 'Maladie professionnelle', 'maladie', FALSE, TRUE, TRUE, TRUE, NULL),
|
||||||
|
('AT', 'Accident du travail', 'maladie', FALSE, TRUE, TRUE, TRUE, NULL),
|
||||||
|
('AT_TRAJET', 'Accident de trajet', 'maladie', FALSE, TRUE, TRUE, TRUE, NULL),
|
||||||
|
('VM', 'Visite médicale', 'maladie', TRUE, TRUE, FALSE, TRUE, NULL),
|
||||||
|
|
||||||
|
-- Famille
|
||||||
|
('MAT', 'Congé maternité', 'famille', FALSE, TRUE, TRUE, TRUE, NULL),
|
||||||
|
('PAT', 'Congé paternité', 'famille', FALSE, TRUE, TRUE, TRUE, NULL),
|
||||||
|
('PAR', 'Congé parental', 'famille', FALSE, FALSE, FALSE, TRUE, 30),
|
||||||
|
('NAISS', 'Congé supplémentaire de naissance', 'famille', TRUE, TRUE, FALSE, TRUE, NULL),
|
||||||
|
('EVT_FAM', 'Évènement familial', 'famille', TRUE, TRUE, FALSE, TRUE, NULL),
|
||||||
|
|
||||||
|
-- Formation et obligations
|
||||||
|
('FORM', 'Formation', 'formation', TRUE, TRUE, FALSE, FALSE, 15),
|
||||||
|
('EXAM', 'Congé pour examen', 'formation', TRUE, TRUE, FALSE, TRUE, 15),
|
||||||
|
|
||||||
|
-- Absences non planifiées et sanctions
|
||||||
|
('ABS_JUS', 'Absence justifiée', 'sans-solde', FALSE, FALSE, FALSE, TRUE, NULL),
|
||||||
|
('ABS_INJ', 'Absence injustifiée', 'sans-solde', FALSE, FALSE, FALSE, FALSE, NULL),
|
||||||
|
('INDISPO', 'Indisponibilité ponctuelle', 'sans-solde', FALSE, FALSE, FALSE, FALSE, NULL),
|
||||||
|
('MAP_D', 'Mise à pied disciplinaire', 'sanction', FALSE, FALSE, FALSE, TRUE, NULL),
|
||||||
|
('MAP_C', 'Mise à pied conservatoire', 'sanction', FALSE, FALSE, FALSE, TRUE, NULL)
|
||||||
|
) AS t ("code", "name", "colorKey", "isPaid", "accrual", "social", "justify", "notice")
|
||||||
|
WHERE NOT EXISTS (
|
||||||
|
SELECT 1 FROM "AbsenceType" existing WHERE existing."accountId" = a."id"
|
||||||
|
);
|
||||||
|
|
||||||
|
ALTER TABLE "AbsenceType" FORCE ROW LEVEL SECURITY;
|
||||||
@@ -33,6 +33,22 @@ export function RequestForm({
|
|||||||
empty,
|
empty,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Un menu « Type » vide ne se voit pas : le formulaire paraît complet, la
|
||||||
|
// demande part sans type et échoue au serveur. Dire que le référentiel manque
|
||||||
|
// coûte moins qu'une saisie qui ne pouvait pas aboutir.
|
||||||
|
if (absenceTypes.length === 0) {
|
||||||
|
return (
|
||||||
|
<p className="rounded-3 border border-line-2 bg-surface-2 p-3 text-sm text-ink-2">
|
||||||
|
Aucun type d’absence n’est défini : une demande ne peut pas être
|
||||||
|
qualifiée, donc pas enregistrée. Le référentiel se pose depuis{' '}
|
||||||
|
<a className="underline" href="/reglages/types-absence">
|
||||||
|
Réglages · Types d’absence
|
||||||
|
</a>
|
||||||
|
.
|
||||||
|
</p>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PersistentForm
|
<PersistentForm
|
||||||
resetAfter={state.ok ? state : null}
|
resetAfter={state.ok ? state : null}
|
||||||
|
|||||||
Reference in new issue
Block a user