From 29b35fceaac2c90b1fecb73eb37a479d6e03785e Mon Sep 17 00:00:00 2001 From: Manus Sandbox Date: Mon, 15 Dec 2025 16:20:33 -0500 Subject: [PATCH] =?UTF-8?q?Checkpoint:=20Correction=20du=20scheduler=20de?= =?UTF-8?q?=20remerciements=20pour=20=C3=A9viter=20les=20envois=20multiple?= =?UTF-8?q?s=20-=20la=20v=C3=A9rification=20des=20doublons=20est=20mainten?= =?UTF-8?q?ant=20faite=20en=20base=20de=20donn=C3=A9es=20(table=20logsNoti?= =?UTF-8?q?fications)=20au=20lieu=20de=20la=20m=C3=A9moire,=20ce=20qui=20p?= =?UTF-8?q?ersiste=20entre=20les=20red=C3=A9marrages=20du=20serveur?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/remerciementScheduler.ts | 58 ++++++++++++++++++++------------- 1 file changed, 36 insertions(+), 22 deletions(-) diff --git a/server/remerciementScheduler.ts b/server/remerciementScheduler.ts index 4b17b31..3c12bb3 100644 --- a/server/remerciementScheduler.ts +++ b/server/remerciementScheduler.ts @@ -1,5 +1,5 @@ import { getDb } from "./db"; -import { sequences, inscriptions, apprenants, formations, datesFormation, formateurs, questionnaires, envoisQuestionnaires } from "../drizzle/schema"; +import { sequences, inscriptions, apprenants, formations, datesFormation, formateurs, questionnaires, envoisQuestionnaires, logsNotifications } from "../drizzle/schema"; import { eq, and, lte, sql } from "drizzle-orm"; import { sendRemerciementPostFormation } from "./emailService"; import { logNotification } from "./notificationLogsDb"; @@ -79,24 +79,31 @@ async function getOrCreateQuestionnaireLink( } /** - * Table pour suivre les remerciements déjà envoyés + * Vérifie si un remerciement a déjà été envoyé pour une inscription en vérifiant dans la base de données */ -const remerciementsEnvoyes = new Map(); - -/** - * Vérifie si un remerciement a déjà été envoyé pour une inscription - */ -function remerciementDejaEnvoye(inscriptionId: number, sequenceId: number): boolean { - const key = `${inscriptionId}-${sequenceId}`; - return remerciementsEnvoyes.has(key); -} - -/** - * Marque un remerciement comme envoyé - */ -function marquerRemerciementEnvoye(inscriptionId: number, sequenceId: number): void { - const key = `${inscriptionId}-${sequenceId}`; - remerciementsEnvoyes.set(key, new Date()); +async function remerciementDejaEnvoye(apprenantId: number, sequenceId: number): Promise { + const db = await getDb(); + if (!db) return false; + + try { + const [existing] = await db + .select({ id: logsNotifications.id }) + .from(logsNotifications) + .where( + and( + eq(logsNotifications.type, "remerciement"), + eq(logsNotifications.apprenantId, apprenantId), + eq(logsNotifications.sequenceId, sequenceId), + eq(logsNotifications.statut, "success") + ) + ) + .limit(1); + + return !!existing; + } catch (error) { + console.error("[Remerciements] Erreur lors de la vérification du log:", error); + return false; + } } /** @@ -179,8 +186,9 @@ async function processRemerciementSequence( let errorsCount = 0; for (const { inscription, apprenant } of inscriptionsConfirmees) { - // Vérifier si le remerciement a déjà été envoyé - if (remerciementDejaEnvoye(inscription.id, sequence.id)) { + // Vérifier si le remerciement a déjà été envoyé (vérification en base de données) + const dejaEnvoye = await remerciementDejaEnvoye(apprenant.id, sequence.id); + if (dejaEnvoye) { console.log(`[Remerciements] Remerciement déjà envoyé pour ${apprenant.email}`); continue; } @@ -200,7 +208,7 @@ async function processRemerciementSequence( lienQuestionnaire: lienQuestionnaire || undefined, }); - // Logger la notification + // Logger la notification (sert aussi de marqueur pour éviter les doublons) await logNotification({ type: "remerciement", sequenceId: sequence.id, @@ -211,7 +219,6 @@ async function processRemerciementSequence( metadata: { lienQuestionnaire }, }); - marquerRemerciementEnvoye(inscription.id, sequence.id); envoyesCount++; console.log(`[Remerciements] Email envoyé à ${apprenant.email}`); } catch (error: any) { @@ -289,6 +296,13 @@ export async function envoyerRemerciementsSequence(sequenceId: number): Promise< let failed = 0; for (const { inscription, apprenant } of inscriptionsConfirmees) { + // Vérifier si le remerciement a déjà été envoyé + const dejaEnvoye = await remerciementDejaEnvoye(apprenant.id, sequenceId); + if (dejaEnvoye) { + console.log(`[Remerciements] Remerciement déjà envoyé pour ${apprenant.email}, ignoré`); + continue; + } + try { // Générer le lien questionnaire const lienQuestionnaire = await getOrCreateQuestionnaireLink(apprenant.id, sequenceId);