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