210 lines
6.8 KiB
TypeScript
210 lines
6.8 KiB
TypeScript
import { getDb } from "./db";
|
|
import { sequences, inscriptions, apprenants, formations, datesFormation, formateurs } from "../drizzle/schema";
|
|
import { eq, and, lte, sql } from "drizzle-orm";
|
|
import { sendRemerciementPostFormation } from "./emailService";
|
|
|
|
/**
|
|
* Table pour suivre les remerciements déjà envoyés
|
|
*/
|
|
const remerciementsEnvoyes = new Map<string, Date>();
|
|
|
|
/**
|
|
* 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());
|
|
}
|
|
|
|
/**
|
|
* Job automatique qui vérifie quotidiennement les séquences terminées
|
|
* et envoie les emails de remerciement aux apprenants
|
|
*/
|
|
export async function processRemerciementsAutomatiques() {
|
|
console.log("[Remerciements] Démarrage du traitement des remerciements post-formation...");
|
|
|
|
const db = await getDb();
|
|
if (!db) {
|
|
console.error("[Remerciements] Base de données non disponible");
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const now = new Date();
|
|
const hier = new Date();
|
|
hier.setDate(hier.getDate() - 1);
|
|
hier.setHours(23, 59, 59, 999);
|
|
|
|
// Récupérer les séquences dont la dernière date est passée (terminées hier ou avant)
|
|
const sequencesTerminees = await db
|
|
.select({
|
|
sequence: sequences,
|
|
formation: formations,
|
|
formateur: formateurs,
|
|
derniereDate: sql<Date>`MAX(${datesFormation.dateFin})`.as('derniereDate'),
|
|
})
|
|
.from(sequences)
|
|
.innerJoin(formations, eq(sequences.formationId, formations.id))
|
|
.leftJoin(formateurs, eq(sequences.formateurId, formateurs.id))
|
|
.innerJoin(datesFormation, eq(sequences.id, datesFormation.sequenceId))
|
|
.where(eq(sequences.statut, 'ouverte')) // Séquences encore ouvertes (pas encore marquées terminées)
|
|
.groupBy(sequences.id, formations.id, formateurs.id)
|
|
.having(lte(sql`MAX(${datesFormation.dateFin})`, hier));
|
|
|
|
console.log(`[Remerciements] ${sequencesTerminees.length} séquence(s) terminée(s) trouvée(s)`);
|
|
|
|
for (const { sequence, formation, formateur, derniereDate } of sequencesTerminees) {
|
|
await processRemerciementSequence(sequence, formation, formateur, derniereDate);
|
|
}
|
|
|
|
console.log("[Remerciements] Traitement terminé");
|
|
} catch (error) {
|
|
console.error("[Remerciements] Erreur lors du traitement des remerciements:", error);
|
|
}
|
|
}
|
|
|
|
async function processRemerciementSequence(
|
|
sequence: any,
|
|
formation: any,
|
|
formateur: any | null,
|
|
derniereDate: Date
|
|
) {
|
|
console.log(`[Remerciements] Traitement de la séquence: ${sequence.nom} (terminée le ${derniereDate})`);
|
|
|
|
const db = await getDb();
|
|
if (!db) return;
|
|
|
|
try {
|
|
// Récupérer les inscriptions confirmées pour cette séquence
|
|
const inscriptionsConfirmees = await db
|
|
.select({
|
|
inscription: inscriptions,
|
|
apprenant: apprenants,
|
|
})
|
|
.from(inscriptions)
|
|
.innerJoin(apprenants, eq(inscriptions.apprenantId, apprenants.id))
|
|
.where(
|
|
and(
|
|
eq(inscriptions.sequenceId, sequence.id),
|
|
eq(inscriptions.statut, 'confirmee')
|
|
)
|
|
);
|
|
|
|
console.log(`[Remerciements] ${inscriptionsConfirmees.length} inscription(s) confirmée(s) pour ${sequence.nom}`);
|
|
|
|
let envoyesCount = 0;
|
|
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)) {
|
|
console.log(`[Remerciements] Remerciement déjà envoyé pour ${apprenant.email}`);
|
|
continue;
|
|
}
|
|
|
|
try {
|
|
await sendRemerciementPostFormation({
|
|
apprenantEmail: apprenant.email,
|
|
apprenantNom: apprenant.nom,
|
|
apprenantPrenom: apprenant.prenom,
|
|
apprenantFonction: apprenant.fonction,
|
|
formationNom: formation.nom,
|
|
sequenceNom: sequence.nom,
|
|
formateurNom: formateur?.nom,
|
|
});
|
|
|
|
marquerRemerciementEnvoye(inscription.id, sequence.id);
|
|
envoyesCount++;
|
|
console.log(`[Remerciements] Email envoyé à ${apprenant.email}`);
|
|
} catch (error) {
|
|
errorsCount++;
|
|
console.error(`[Remerciements] Erreur envoi à ${apprenant.email}:`, error);
|
|
}
|
|
}
|
|
|
|
console.log(`[Remerciements] Séquence ${sequence.nom}: ${envoyesCount} envoyé(s), ${errorsCount} erreur(s)`);
|
|
|
|
// Optionnel: Marquer la séquence comme terminée
|
|
// await db.update(sequences).set({ statut: 'terminee' }).where(eq(sequences.id, sequence.id));
|
|
|
|
} catch (error) {
|
|
console.error(`[Remerciements] Erreur pour la séquence ${sequence.nom}:`, error);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Envoie manuellement un email de remerciement pour une séquence spécifique
|
|
* Utilisé par l'interface admin pour envoyer les remerciements à la demande
|
|
*/
|
|
export async function envoyerRemerciementsSequence(sequenceId: number): Promise<{ sent: number; failed: number }> {
|
|
const db = await getDb();
|
|
if (!db) {
|
|
throw new Error("Base de données non disponible");
|
|
}
|
|
|
|
// Récupérer la séquence avec formation et formateur
|
|
const sequenceData = await db
|
|
.select({
|
|
sequence: sequences,
|
|
formation: formations,
|
|
formateur: formateurs,
|
|
})
|
|
.from(sequences)
|
|
.innerJoin(formations, eq(sequences.formationId, formations.id))
|
|
.leftJoin(formateurs, eq(sequences.formateurId, formateurs.id))
|
|
.where(eq(sequences.id, sequenceId))
|
|
.limit(1);
|
|
|
|
if (sequenceData.length === 0) {
|
|
throw new Error("Séquence introuvable");
|
|
}
|
|
|
|
const { sequence, formation, formateur } = sequenceData[0];
|
|
|
|
// Récupérer les inscriptions confirmées
|
|
const inscriptionsConfirmees = await db
|
|
.select({
|
|
inscription: inscriptions,
|
|
apprenant: apprenants,
|
|
})
|
|
.from(inscriptions)
|
|
.innerJoin(apprenants, eq(inscriptions.apprenantId, apprenants.id))
|
|
.where(
|
|
and(
|
|
eq(inscriptions.sequenceId, sequenceId),
|
|
eq(inscriptions.statut, 'confirmee')
|
|
)
|
|
);
|
|
|
|
let sent = 0;
|
|
let failed = 0;
|
|
|
|
for (const { inscription, apprenant } of inscriptionsConfirmees) {
|
|
try {
|
|
await sendRemerciementPostFormation({
|
|
apprenantEmail: apprenant.email,
|
|
apprenantNom: apprenant.nom,
|
|
apprenantPrenom: apprenant.prenom,
|
|
apprenantFonction: apprenant.fonction,
|
|
formationNom: formation.nom,
|
|
sequenceNom: sequence.nom,
|
|
formateurNom: formateur?.nom,
|
|
});
|
|
sent++;
|
|
} catch (error) {
|
|
console.error(`[Remerciements] Erreur envoi à ${apprenant.email}:`, error);
|
|
failed++;
|
|
}
|
|
}
|
|
|
|
return { sent, failed };
|
|
}
|