Checkpoint: Refonte complète du système de rappels pour permettre une gestion granulaire par séquence

Fonctionnalités ajoutées :
- Table de liaison rappelSequences pour associer rappels et séquences
- Composant SequenceMultiSelect avec recherche et multi-sélection
- Gestion des associations dans les procédures create/update
- Modification du scheduler pour filtrer les séquences selon les associations
- Si aucune séquence n'est sélectionnée, le rappel s'applique à toutes les séquences (comportement par défaut)

Le système permet maintenant de configurer des rappels spécifiques pour certaines dates/séquences particulières, offrant une flexibilité complète dans la gestion des rappels automatiques.
This commit is contained in:
Manus
2026-01-08 08:27:20 -05:00
parent 5de295a18c
commit 6ee87f9b22
12 changed files with 2462 additions and 15 deletions

View File

@@ -1,6 +1,6 @@
import { getDb } from "./db";
import { rappels, sequences, inscriptions, apprenants, formations, datesFormation, formateurs } from "../drizzle/schema";
import { eq, and, gte, lte, sql } from "drizzle-orm";
import { eq, and, gte, lte, sql, inArray } from "drizzle-orm";
import { sendRappelJ7Email, sendRappelJ1Email } from "./emailService";
import { logRappelEnvoye, rappelDejaEnvoye } from "./rappelDb";
import { notifyOwner } from "./_core/notification";
@@ -55,16 +55,38 @@ async function processRappel(rappel: any) {
console.log(`[Rappels] Recherche des séquences débutant le ${dateCible.toLocaleDateString()}`);
// CORRECTION DU BUG: Récupérer d'abord toutes les séquences
const toutesSequences = await db
.select({
sequence: sequences,
formation: formations,
formateur: formateurs,
})
.from(sequences)
.leftJoin(formations, eq(sequences.formationId, formations.id))
.leftJoin(formateurs, eq(sequences.formateurId, formateurs.id));
// Vérifier si ce rappel est associé à des séquences spécifiques
const sequencesAssociees = rappel.sequenceIds || [];
const filtreSequences = sequencesAssociees.length > 0;
console.log(`[Rappels] ${filtreSequences ? `Filtré sur ${sequencesAssociees.length} séquence(s) spécifique(s)` : 'Toutes les séquences'}`);
// Récupérer toutes les séquences (ou uniquement celles associées)
let toutesSequences;
if (filtreSequences) {
// Seulement les séquences associées à ce rappel
toutesSequences = await db
.select({
sequence: sequences,
formation: formations,
formateur: formateurs,
})
.from(sequences)
.leftJoin(formations, eq(sequences.formationId, formations.id))
.leftJoin(formateurs, eq(sequences.formateurId, formateurs.id))
.where(inArray(sequences.id, sequencesAssociees));
} else {
// Toutes les séquences
toutesSequences = await db
.select({
sequence: sequences,
formation: formations,
formateur: formateurs,
})
.from(sequences)
.leftJoin(formations, eq(sequences.formationId, formations.id))
.leftJoin(formateurs, eq(sequences.formateurId, formateurs.id));
}
// Filtrer les séquences dont la première date correspond à la date cible
const sequencesConcernees = [];