/** * Requêtes analytiques pour le tableau de bord */ import { eq, sql, and, gte, lte, desc } from "drizzle-orm"; import { getDb } from "./db"; import { inscriptions, sequences, apprenants, datesFormation, formations } from "../drizzle/schema"; /** * Récupère les statistiques d'inscriptions par mois * @param startDate - Date de début de la période * @param endDate - Date de fin de la période */ export async function getInscriptionsByMonth(startDate?: Date, endDate?: Date) { const db = await getDb(); if (!db) return []; const conditions = []; if (startDate) { conditions.push(gte(inscriptions.dateInscription, startDate)); } if (endDate) { conditions.push(lte(inscriptions.dateInscription, endDate)); } const result = await db .select({ mois: sql`DATE_FORMAT(${inscriptions.dateInscription}, '%Y-%m')`, total: sql`COUNT(*)`, confirmees: sql`SUM(CASE WHEN ${inscriptions.statut} = 'confirmee' THEN 1 ELSE 0 END)`, listeAttente: sql`SUM(CASE WHEN ${inscriptions.statut} = 'liste_attente' THEN 1 ELSE 0 END)`, annulees: sql`SUM(CASE WHEN ${inscriptions.statut} = 'annulee' THEN 1 ELSE 0 END)`, }) .from(inscriptions) .where(conditions.length > 0 ? and(...conditions) : undefined) .groupBy(sql`DATE_FORMAT(${inscriptions.dateInscription}, '%Y-%m')`) .orderBy(sql`DATE_FORMAT(${inscriptions.dateInscription}, '%Y-%m')`); return result; } /** * Récupère le taux de remplissage des séquences par mois */ export async function getTauxRemplissageByMonth() { const db = await getDb(); if (!db) return []; const result = await db .select({ mois: sql`DATE_FORMAT(${sequences.createdAt}, '%Y-%m')`, capaciteTotale: sql`SUM(${sequences.capaciteMax})`, inscritsConfirmes: sql`COUNT(CASE WHEN ${inscriptions.statut} = 'confirmee' THEN ${inscriptions.id} END)`, tauxRemplissage: sql`ROUND( (COUNT(CASE WHEN ${inscriptions.statut} = 'confirmee' THEN ${inscriptions.id} END) / SUM(${sequences.capaciteMax})) * 100, 2 )`, }) .from(sequences) .leftJoin(inscriptions, eq(sequences.id, inscriptions.sequenceId)) .groupBy(sql`DATE_FORMAT(${sequences.createdAt}, '%Y-%m')`) .orderBy(sql`DATE_FORMAT(${sequences.createdAt}, '%Y-%m')`); return result; } /** * Récupère les statistiques de participation par établissement */ export async function getParticipationByEtablissement() { const db = await getDb(); if (!db) return []; const result = await db .select({ codeEtablissement: apprenants.codeEtablissement, totalApprenants: sql`COUNT(DISTINCT ${apprenants.id})`, totalInscriptions: sql`COUNT(${inscriptions.id})`, inscriptionsConfirmees: sql`SUM(CASE WHEN ${inscriptions.statut} = 'confirmee' THEN 1 ELSE 0 END)`, inscriptionsListeAttente: sql`SUM(CASE WHEN ${inscriptions.statut} = 'liste_attente' THEN 1 ELSE 0 END)`, inscriptionsAnnulees: sql`SUM(CASE WHEN ${inscriptions.statut} = 'annulee' THEN 1 ELSE 0 END)`, }) .from(apprenants) .leftJoin(inscriptions, eq(apprenants.id, inscriptions.apprenantId)) .groupBy(apprenants.codeEtablissement) .orderBy(desc(sql`COUNT(${inscriptions.id})`)); return result; } /** * Récupère les statistiques globales du tableau de bord */ export async function getGlobalStats() { const db = await getDb(); if (!db) return null; const [stats] = await db .select({ totalFormations: sql`(SELECT COUNT(*) FROM ${formations} WHERE ${formations.actif} = 1)`, totalSequences: sql`(SELECT COUNT(*) FROM ${sequences})`, sequencesOuvertes: sql`(SELECT COUNT(*) FROM ${sequences} WHERE ${sequences.statut} = 'ouverte')`, totalApprenants: sql`(SELECT COUNT(*) FROM ${apprenants})`, totalInscriptions: sql`(SELECT COUNT(*) FROM ${inscriptions})`, inscriptionsConfirmees: sql`(SELECT COUNT(*) FROM ${inscriptions} WHERE ${inscriptions.statut} = 'confirmee')`, inscriptionsListeAttente: sql`(SELECT COUNT(*) FROM ${inscriptions} WHERE ${inscriptions.statut} = 'liste_attente')`, tauxRemplissageMoyen: sql`ROUND( (SELECT COUNT(*) FROM ${inscriptions} WHERE ${inscriptions.statut} = 'confirmee') / (SELECT SUM(${sequences.capaciteMax}) FROM ${sequences}) * 100, 2 )`, }) .from(sql`dual`); return stats; } /** * Récupère les statistiques de participation par fonction */ export async function getParticipationByFonction() { const db = await getDb(); if (!db) return []; const result = await db .select({ fonction: apprenants.fonction, totalApprenants: sql`COUNT(DISTINCT ${apprenants.id})`, totalInscriptions: sql`COUNT(${inscriptions.id})`, inscriptionsConfirmees: sql`SUM(CASE WHEN ${inscriptions.statut} = 'confirmee' THEN 1 ELSE 0 END)`, }) .from(apprenants) .leftJoin(inscriptions, eq(apprenants.id, inscriptions.apprenantId)) .groupBy(apprenants.fonction) .orderBy(desc(sql`COUNT(${inscriptions.id})`)); return result; }