/** * Service d'export des rapports analytiques en PDF et Excel */ import ExcelJS from 'exceljs'; import { getGlobalStats, getInscriptionsByMonth, getTauxRemplissageByMonth, getParticipationByEtablissement, getParticipationByFonction } from './analyticsDb'; /** * Génère un rapport Excel des statistiques analytiques */ export async function generateAnalyticsExcel(startDate?: Date, endDate?: Date): Promise { const workbook = new ExcelJS.Workbook(); // Récupérer toutes les données const globalStats = await getGlobalStats(); const inscriptionsByMonth = await getInscriptionsByMonth(startDate, endDate); const tauxRemplissage = await getTauxRemplissageByMonth(); const participationEtablissement = await getParticipationByEtablissement(); const participationFonction = await getParticipationByFonction(); // Feuille 1: Statistiques globales const statsSheet = workbook.addWorksheet('Statistiques globales'); statsSheet.columns = [ { header: 'Indicateur', key: 'indicateur', width: 30 }, { header: 'Valeur', key: 'valeur', width: 15 }, ]; if (globalStats) { statsSheet.addRows([ { indicateur: 'Total Formations actives', valeur: globalStats.totalFormations }, { indicateur: 'Total Séquences', valeur: globalStats.totalSequences }, { indicateur: 'Séquences ouvertes', valeur: globalStats.sequencesOuvertes }, { indicateur: 'Total Apprenants', valeur: globalStats.totalApprenants }, { indicateur: 'Total Inscriptions', valeur: globalStats.totalInscriptions }, { indicateur: 'Inscriptions confirmées', valeur: globalStats.inscriptionsConfirmees }, { indicateur: 'Inscriptions en liste d\'attente', valeur: globalStats.inscriptionsListeAttente }, { indicateur: 'Taux de remplissage moyen (%)', valeur: globalStats.tauxRemplissageMoyen }, ]); } // Feuille 2: Inscriptions par mois const inscriptionsSheet = workbook.addWorksheet('Inscriptions par mois'); inscriptionsSheet.columns = [ { header: 'Mois', key: 'mois', width: 15 }, { header: 'Total', key: 'total', width: 12 }, { header: 'Confirmées', key: 'confirmees', width: 12 }, { header: 'Liste d\'attente', key: 'listeAttente', width: 15 }, { header: 'Annulées', key: 'annulees', width: 12 }, ]; inscriptionsByMonth.forEach(item => { inscriptionsSheet.addRow({ mois: item.mois, total: Number(item.total), confirmees: Number(item.confirmees), listeAttente: Number(item.listeAttente), annulees: Number(item.annulees), }); }); // Feuille 3: Taux de remplissage const tauxSheet = workbook.addWorksheet('Taux de remplissage'); tauxSheet.columns = [ { header: 'Mois', key: 'mois', width: 15 }, { header: 'Capacité totale', key: 'capaciteTotale', width: 15 }, { header: 'Inscrits confirmés', key: 'inscritsConfirmes', width: 18 }, { header: 'Taux de remplissage (%)', key: 'tauxRemplissage', width: 20 }, ]; tauxRemplissage.forEach(item => { tauxSheet.addRow({ mois: item.mois, capaciteTotale: Number(item.capaciteTotale), inscritsConfirmes: Number(item.inscritsConfirmes), tauxRemplissage: Number(item.tauxRemplissage), }); }); // Feuille 4: Participation par établissement const etablissementSheet = workbook.addWorksheet('Participation par établissement'); etablissementSheet.columns = [ { header: 'Code établissement', key: 'codeEtablissement', width: 20 }, { header: 'Total apprenants', key: 'totalApprenants', width: 15 }, { header: 'Total inscriptions', key: 'totalInscriptions', width: 18 }, { header: 'Confirmées', key: 'confirmees', width: 12 }, { header: 'Liste d\'attente', key: 'listeAttente', width: 15 }, { header: 'Annulées', key: 'annulees', width: 12 }, ]; participationEtablissement.forEach(item => { etablissementSheet.addRow({ codeEtablissement: item.codeEtablissement, totalApprenants: Number(item.totalApprenants), totalInscriptions: Number(item.totalInscriptions), confirmees: Number(item.inscriptionsConfirmees), listeAttente: Number(item.inscriptionsListeAttente), annulees: Number(item.inscriptionsAnnulees), }); }); // Feuille 5: Participation par fonction const fonctionSheet = workbook.addWorksheet('Participation par fonction'); fonctionSheet.columns = [ { header: 'Fonction', key: 'fonction', width: 20 }, { header: 'Total apprenants', key: 'totalApprenants', width: 15 }, { header: 'Total inscriptions', key: 'totalInscriptions', width: 18 }, { header: 'Confirmées', key: 'confirmees', width: 12 }, ]; participationFonction.forEach(item => { fonctionSheet.addRow({ fonction: item.fonction === 'directeur' ? 'Directeurs' : item.fonction === 'chef_service' ? 'Chefs de service' : 'Autres', totalApprenants: Number(item.totalApprenants), totalInscriptions: Number(item.totalInscriptions), confirmees: Number(item.inscriptionsConfirmees), }); }); // Styliser les en-têtes [statsSheet, inscriptionsSheet, tauxSheet, etablissementSheet, fonctionSheet].forEach(sheet => { sheet.getRow(1).font = { bold: true }; sheet.getRow(1).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF3B82F6' }, }; sheet.getRow(1).font = { bold: true, color: { argb: 'FFFFFFFF' } }; }); // Générer le buffer const buffer = await workbook.xlsx.writeBuffer(); return Buffer.from(buffer); } /** * Génère un rapport PDF des statistiques analytiques * Note: Cette fonction retourne actuellement un placeholder * Une implémentation complète nécessiterait une bibliothèque comme puppeteer ou pdfkit */ export async function generateAnalyticsPDF(startDate?: Date, endDate?: Date): Promise { // Pour l'instant, retourner un message indiquant que la fonctionnalité est en développement // Une implémentation complète nécessiterait de générer un HTML et de le convertir en PDF throw new Error("L'export PDF sera implémenté dans une prochaine version"); }