Checkpoint: Ajout d'un bouton "Tout renvoyer" dans la page de gestion des attestations pour envoyer en masse toutes les attestations d'une formation. Création de la procédure backend sendAllAttestations qui envoie toutes les attestations disponibles et enregistre chaque envoi dans l'historique. Correction du scheduler de rappels pour vérifier l'heure configurée (intervalle 15 min au lieu de 1h).

This commit is contained in:
Manus
2026-01-18 08:39:13 -05:00
parent 6c4ca249a9
commit 2c0f379c52
3 changed files with 143 additions and 4 deletions

View File

@@ -2574,6 +2574,99 @@ export const appRouter = router({
}
}),
// Envoyer toutes les attestations d'une formation en masse
sendAllAttestations: adminProcedure
.input(z.object({ formationId: z.number() }))
.mutation(async ({ input }) => {
const { getApprenantsWithAttestationStatus } = await import("./gestionAttestationsDb");
const { sendAttestationEmail } = await import("./emailService");
const { markAttestationAsSent } = await import("./gestionAttestationsDb");
const { enregistrerEnvoiAttestation } = await import("./attestationsDb");
const { getDb } = await import("./db");
const { formations } = await import("../drizzle/schema");
const { eq } = await import("drizzle-orm");
try {
// Récupérer tous les apprenants avec attestations
const apprenants = await getApprenantsWithAttestationStatus(input.formationId);
// Récupérer le nom de la formation
const db = await getDb();
if (!db) throw new Error("Database not available");
const formation = await db.select().from(formations).where(eq(formations.id, input.formationId)).limit(1);
const formationNom = formation[0]?.nom || "";
let succes = 0;
let echecs = 0;
const erreurs: string[] = [];
// Filtrer les apprenants qui ont une attestation prête
const apprenantsAvecAttestation = apprenants.filter(item => {
const hasDocument = item.attestation && item.attestation.documentUrl;
return hasDocument;
});
console.log(`[sendAllAttestations] Envoi de ${apprenantsAvecAttestation.length} attestation(s) pour la formation ${formationNom}`);
// Envoyer chaque attestation
for (const item of apprenantsAvecAttestation) {
if (!item.attestation || !item.attestation.documentUrl) continue;
const pdfUrl = item.attestation.documentUrl;
try {
// Envoyer l'email
await sendAttestationEmail({
to: item.apprenant.email,
apprenantNom: item.apprenant.nom,
apprenantPrenom: item.apprenant.prenom,
formationNom: formationNom,
pdfUrl: pdfUrl,
});
// Marquer comme envoyé
await markAttestationAsSent(item.attestation.id);
// Enregistrer dans l'historique
await enregistrerEnvoiAttestation({
sequenceId: item.sequence.id,
apprenantId: item.apprenant.id,
statut: "envoye",
urlAttestation: pdfUrl,
});
succes++;
console.log(`[sendAllAttestations] Envoi réussi pour ${item.apprenant.email}`);
} catch (error: any) {
echecs++;
const messageErreur = error?.message || String(error);
erreurs.push(`${item.apprenant.email}: ${messageErreur}`);
console.error(`[sendAllAttestations] Erreur pour ${item.apprenant.email}:`, error);
// Enregistrer l'échec dans l'historique
await enregistrerEnvoiAttestation({
sequenceId: item.sequence.id,
apprenantId: item.apprenant.id,
statut: "erreur",
messageErreur: messageErreur,
urlAttestation: pdfUrl,
});
}
}
console.log(`[sendAllAttestations] Terminé: ${succes} succès, ${echecs} échecs`);
return {
succes,
echecs,
erreurs,
total: apprenantsAvecAttestation.length,
};
} catch (error: any) {
console.error("[sendAllAttestations] Erreur globale:", error);
throw error;
}
}),
}),
});