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:
@@ -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
|
||||
)
|
||||
);
|
||||
|
||||
@@ -224,10 +224,10 @@ async function processRappel(rappel: any) {
|
||||
rappelId: rappel.id,
|
||||
sequenceId: sequence.id,
|
||||
apprenantId: apprenant.id,
|
||||
emailDestinataire: apprenant.email,
|
||||
typeRappel: rappel.templateType,
|
||||
statut: "success",
|
||||
dateSequence: toutesLesDates[0].dateDebut,
|
||||
email: apprenant.email,
|
||||
type: rappel.templateType,
|
||||
typeEnvoi: 'automatique',
|
||||
statut: "succes",
|
||||
});
|
||||
nbEnvoyes++;
|
||||
} catch (emailError: any) {
|
||||
@@ -239,11 +239,11 @@ async function processRappel(rappel: any) {
|
||||
rappelId: rappel.id,
|
||||
sequenceId: sequence.id,
|
||||
apprenantId: apprenant.id,
|
||||
emailDestinataire: apprenant.email,
|
||||
typeRappel: rappel.templateType,
|
||||
statut: "failed",
|
||||
email: apprenant.email,
|
||||
type: rappel.templateType,
|
||||
typeEnvoi: 'automatique',
|
||||
statut: "echec",
|
||||
messageErreur: messageErreur,
|
||||
dateSequence: toutesLesDates[0].dateDebut,
|
||||
});
|
||||
nbEchecs++;
|
||||
echecs.push({ email: apprenant.email, erreur: messageErreur });
|
||||
|
||||
@@ -1519,7 +1519,7 @@ export const appRouter = router({
|
||||
dateDebut: z.string().optional(),
|
||||
dateFin: z.string().optional(),
|
||||
sequenceId: z.number().optional(),
|
||||
statut: z.enum(['success', 'failed']).optional(),
|
||||
statut: z.enum(['succes', 'echec']).optional(),
|
||||
email: z.string().optional(),
|
||||
limit: z.number().default(100),
|
||||
offset: z.number().default(0),
|
||||
|
||||
1
todo.md
1
todo.md
@@ -832,3 +832,4 @@
|
||||
- [x] Modifier le DashboardLayout pour réduire tous les menus sauf "Gestion" à la connexion
|
||||
- [x] Supprimer les boutons "Aperçu rappel J-7", "Envoyer rappel J-7", "Aperçu rappel J-1", "Envoyer rappel J-1" de la fenêtre de détails des séquences
|
||||
- [x] Corriger le bouton "Tester le rappel" pour enregistrer les envois dans l'historique des rappels (table logsRappels)
|
||||
- [x] Corriger l'enregistrement des logs de rappels : type erroné (J-1 au lieu de J+2), statut erroné (success/failed au lieu de succes/echec), email erroné (emailDestinataire au lieu de email)
|
||||
|
||||
Reference in New Issue
Block a user