Checkpoint: Checkpoint saved: Correction complète de l'enregistrement des logs de rappels :

**Problèmes corrigés :**
1. Type de rappel erroné : utilisait typeRappel au lieu de type, affichait le mauvais template (J-1 au lieu de J+2)
2. Statut erroné : utilisait "success"/"failed" (anglais) au lieu de "succes"/"echec" (français)
3. Email erroné : utilisait emailDestinataire au lieu de email
4. Champs obsolètes : supprimé dateSequence qui n'existe plus dans le schéma

**Fichiers modifiés :**
- server/rappelDb.ts : Réécriture complète avec les bons noms de colonnes (email, type, statut, typeEnvoi)
- server/rappelScheduler.ts : Correction des appels à logRappelEnvoye avec les bons paramètres
- server/routers.ts : Correction de l'enum du statut dans la procédure historique (succes/echec)

**Résultat :**
- Les logs de rappels enregistrent maintenant correctement le type de rappel (J+2, J-7, etc.)
- Le statut est correctement enregistré en français (succes/echec)
- L'email du destinataire est correctement enregistré
- Les tests de rappel sont distingués des envois automatiques via typeEnvoi

Déployé sur le VPS de production (https://formations.itinova.org)
This commit is contained in:
Manus
2026-01-16 06:33:12 -05:00
parent b9fbfafc69
commit 8f21fdd276
4 changed files with 31 additions and 29 deletions

View File

@@ -9,11 +9,11 @@ export async function logRappelEnvoye(data: {
rappelId: number;
sequenceId: number;
apprenantId: number;
emailDestinataire: string;
typeRappel: string;
statut: "success" | "failed";
email: string;
type: string;
typeEnvoi?: 'automatique' | 'test';
statut: "succes" | "echec";
messageErreur?: string;
dateSequence: Date;
}): Promise<void> {
const db = await getDb();
if (!db) {
@@ -26,13 +26,13 @@ export async function logRappelEnvoye(data: {
rappelId: data.rappelId,
sequenceId: data.sequenceId,
apprenantId: data.apprenantId,
emailDestinataire: data.emailDestinataire,
typeRappel: data.typeRappel,
email: data.email,
type: data.type as any,
typeEnvoi: data.typeEnvoi || 'automatique',
dateEnvoi: new Date(),
statut: data.statut,
messageErreur: data.messageErreur || null,
dateSequence: data.dateSequence,
} as InsertLogRappel);
});
} catch (error) {
console.error("[LogsRappels] Erreur lors de l'enregistrement du log:", error);
}
@@ -61,7 +61,8 @@ export async function rappelDejaEnvoye(
eq(logsRappels.rappelId, rappelId),
eq(logsRappels.sequenceId, sequenceId),
eq(logsRappels.apprenantId, apprenantId),
eq(logsRappels.statut, "success")
eq(logsRappels.statut, "succes"),
eq(logsRappels.typeEnvoi, "automatique") // Ne pas compter les tests
)
)
.limit(1);
@@ -108,7 +109,7 @@ export async function getLogsRappelsEchoues(): Promise<LogRappel[]> {
.from(logsRappels)
.where(
and(
eq(logsRappels.statut, "failed"),
eq(logsRappels.statut, "echec"),
// Note: Drizzle ne supporte pas directement les comparaisons de dates
// On récupère tous les échecs et on filtre en JS
)
@@ -134,7 +135,7 @@ export async function countRappelsEnvoyesSequence(sequenceId: number): Promise<n
.where(
and(
eq(logsRappels.sequenceId, sequenceId),
eq(logsRappels.statut, "success")
eq(logsRappels.statut, "succes")
)
);
@@ -152,7 +153,7 @@ export async function getLogsRappelsWithFilters(filters: {
dateDebut?: Date;
dateFin?: Date;
sequenceId?: number;
statut?: "success" | "failed";
statut?: "succes" | "echec";
email?: string;
limit?: number;
offset?: number;
@@ -182,7 +183,7 @@ export async function getLogsRappelsWithFilters(filters: {
// Filtrer par email si nécessaire
if (filters.email) {
logs = logs.filter(log => log.emailDestinataire.toLowerCase().includes(filters.email!.toLowerCase()));
logs = logs.filter(log => log.email.toLowerCase().includes(filters.email!.toLowerCase()));
}
// Filtrer par date si nécessaire
@@ -225,15 +226,15 @@ export async function getStatsRappels(): Promise<{
const logs = await db.select().from(logsRappels);
const totalEnvoyes = logs.length;
const totalSucces = logs.filter(l => l.statut === "success").length;
const totalEchecs = logs.filter(l => l.statut === "failed").length;
const totalSucces = logs.filter(l => l.statut === "succes").length;
const totalEchecs = logs.filter(l => l.statut === "echec").length;
const tauxSucces = totalEnvoyes > 0 ? (totalSucces / totalEnvoyes) * 100 : 0;
// Compter les échecs par email
const echecsParEmail = new Map<string, number>();
logs.filter(l => l.statut === "failed").forEach(log => {
const count = echecsParEmail.get(log.emailDestinataire) || 0;
echecsParEmail.set(log.emailDestinataire, count + 1);
logs.filter(l => l.statut === "echec").forEach(log => {
const count = echecsParEmail.get(log.email) || 0;
echecsParEmail.set(log.email, count + 1);
});
const emailsProblematiques = Array.from(echecsParEmail.entries())
@@ -282,7 +283,7 @@ export async function getEvolutionEnvois(): Promise<Array<{
const dateStr = new Date(log.dateEnvoi).toISOString().split('T')[0];
const stats = parJour.get(dateStr) || { nbEnvoyes: 0, nbSucces: 0, nbEchecs: 0 };
stats.nbEnvoyes++;
if (log.statut === "success") stats.nbSucces++;
if (log.statut === "succes") stats.nbSucces++;
else stats.nbEchecs++;
parJour.set(dateStr, stats);
});
@@ -310,7 +311,7 @@ export async function getLogsAReessayer(): Promise<LogRappel[]> {
.from(logsRappels)
.where(
and(
eq(logsRappels.statut, "failed"),
eq(logsRappels.statut, "echec"),
// Limiter à 3 tentatives maximum
)
);