Rollback to eebcb648
This commit is contained in:
164
deployment-package/source_server/questionnaireSuiviDb.ts
Normal file
164
deployment-package/source_server/questionnaireSuiviDb.ts
Normal file
@@ -0,0 +1,164 @@
|
||||
import { eq, sql, and, gte, lte } from "drizzle-orm";
|
||||
import { getDb } from "./db";
|
||||
import {
|
||||
questionnaires,
|
||||
envoisQuestionnaires,
|
||||
reponsesQuestionnaires,
|
||||
reponsesQuestions,
|
||||
questions,
|
||||
sequences,
|
||||
formations,
|
||||
formateurs
|
||||
} from "../drizzle/schema";
|
||||
|
||||
/**
|
||||
* Statistiques de taux de réponse par formation
|
||||
*/
|
||||
export async function getStatsByFormation() {
|
||||
const db = await getDb();
|
||||
if (!db) throw new Error("Database not available");
|
||||
|
||||
const results = await db
|
||||
.select({
|
||||
formationId: formations.id,
|
||||
formationNom: formations.nom,
|
||||
totalEnvois: sql<number>`COUNT(DISTINCT ${envoisQuestionnaires.id})`,
|
||||
totalReponses: sql<number>`SUM(CASE WHEN ${envoisQuestionnaires.dateReponse} IS NOT NULL THEN 1 ELSE 0 END)`,
|
||||
})
|
||||
.from(envoisQuestionnaires)
|
||||
.innerJoin(sequences, eq(envoisQuestionnaires.sequenceId, sequences.id))
|
||||
.innerJoin(formations, eq(sequences.formationId, formations.id))
|
||||
.groupBy(formations.id, formations.nom);
|
||||
|
||||
return results.map(r => ({
|
||||
formationId: r.formationId,
|
||||
formationNom: r.formationNom,
|
||||
totalEnvois: Number(r.totalEnvois),
|
||||
totalReponses: Number(r.totalReponses),
|
||||
tauxReponse: Number(r.totalEnvois) > 0
|
||||
? Math.round((Number(r.totalReponses) / Number(r.totalEnvois)) * 100)
|
||||
: 0
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Évolution temporelle des réponses (par mois)
|
||||
*/
|
||||
export async function getEvolutionTemporelle(startDate?: Date, endDate?: Date) {
|
||||
const db = await getDb();
|
||||
if (!db) throw new Error("Database not available");
|
||||
|
||||
const conditions = [];
|
||||
if (startDate) {
|
||||
conditions.push(gte(envoisQuestionnaires.dateEnvoi, startDate));
|
||||
}
|
||||
if (endDate) {
|
||||
conditions.push(lte(envoisQuestionnaires.dateEnvoi, endDate));
|
||||
}
|
||||
|
||||
const results = await db
|
||||
.select({
|
||||
mois: sql<string>`DATE_FORMAT(${envoisQuestionnaires.dateEnvoi}, '%Y-%m')`,
|
||||
totalEnvois: sql<number>`COUNT(DISTINCT ${envoisQuestionnaires.id})`,
|
||||
totalReponses: sql<number>`SUM(CASE WHEN ${envoisQuestionnaires.dateReponse} IS NOT NULL THEN 1 ELSE 0 END)`,
|
||||
})
|
||||
.from(envoisQuestionnaires)
|
||||
.where(conditions.length > 0 ? and(...conditions) : undefined)
|
||||
.groupBy(sql`DATE_FORMAT(${envoisQuestionnaires.dateEnvoi}, '%Y-%m')`)
|
||||
.orderBy(sql`DATE_FORMAT(${envoisQuestionnaires.dateEnvoi}, '%Y-%m')`);
|
||||
|
||||
return results.map(r => ({
|
||||
mois: r.mois,
|
||||
totalEnvois: Number(r.totalEnvois),
|
||||
totalReponses: Number(r.totalReponses),
|
||||
tauxReponse: Number(r.totalEnvois) > 0
|
||||
? Math.round((Number(r.totalReponses) / Number(r.totalEnvois)) * 100)
|
||||
: 0
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Comparaison par formateur
|
||||
*/
|
||||
export async function getStatsByFormateur() {
|
||||
const db = await getDb();
|
||||
if (!db) throw new Error("Database not available");
|
||||
|
||||
// Première requête : statistiques d'envois et réponses par formateur
|
||||
const statsEnvois = await db
|
||||
.select({
|
||||
formateurId: formateurs.id,
|
||||
formateurNom: formateurs.nom,
|
||||
totalEnvois: sql<number>`COUNT(DISTINCT ${envoisQuestionnaires.id})`,
|
||||
totalReponses: sql<number>`SUM(CASE WHEN ${envoisQuestionnaires.dateReponse} IS NOT NULL THEN 1 ELSE 0 END)`,
|
||||
})
|
||||
.from(envoisQuestionnaires)
|
||||
.innerJoin(sequences, eq(envoisQuestionnaires.sequenceId, sequences.id))
|
||||
.innerJoin(formateurs, eq(sequences.formateurId, formateurs.id))
|
||||
.groupBy(formateurs.id, formateurs.nom);
|
||||
|
||||
// Pour chaque formateur, calculer la moyenne de satisfaction
|
||||
const results = await Promise.all(statsEnvois.map(async (stat) => {
|
||||
// Calculer la moyenne des réponses de type échelle pour ce formateur
|
||||
const satisfactionResult = await db
|
||||
.select({
|
||||
moyenne: sql<number>`AVG(CAST(${reponsesQuestions.reponseNumerique} AS DECIMAL(10,2)))`,
|
||||
})
|
||||
.from(reponsesQuestionnaires)
|
||||
.innerJoin(sequences, eq(reponsesQuestionnaires.sequenceId, sequences.id))
|
||||
.innerJoin(reponsesQuestions, eq(reponsesQuestionnaires.id, reponsesQuestions.reponseQuestionnaireId))
|
||||
.innerJoin(questions, eq(reponsesQuestions.questionId, questions.id))
|
||||
.where(
|
||||
and(
|
||||
eq(sequences.formateurId, stat.formateurId),
|
||||
eq(reponsesQuestionnaires.complete, true),
|
||||
eq(questions.typeQuestion, 'echelle')
|
||||
)
|
||||
);
|
||||
|
||||
const moyenneSatisfaction = satisfactionResult[0]?.moyenne
|
||||
? Number(satisfactionResult[0].moyenne).toFixed(1)
|
||||
: null;
|
||||
|
||||
return {
|
||||
formateurId: stat.formateurId,
|
||||
formateurNom: stat.formateurNom || "Non spécifié",
|
||||
totalEnvois: Number(stat.totalEnvois),
|
||||
totalReponses: Number(stat.totalReponses),
|
||||
tauxReponse: Number(stat.totalEnvois) > 0
|
||||
? Math.round((Number(stat.totalReponses) / Number(stat.totalEnvois)) * 100)
|
||||
: 0,
|
||||
moyenneSatisfaction
|
||||
};
|
||||
}));
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Statistiques globales pour le tableau de bord
|
||||
*/
|
||||
export async function getStatsGlobales() {
|
||||
const db = await getDb();
|
||||
if (!db) throw new Error("Database not available");
|
||||
|
||||
const results = await db
|
||||
.select({
|
||||
totalQuestionnaires: sql<number>`COUNT(DISTINCT ${questionnaires.id})`,
|
||||
totalEnvois: sql<number>`COUNT(DISTINCT ${envoisQuestionnaires.id})`,
|
||||
totalReponses: sql<number>`SUM(CASE WHEN ${envoisQuestionnaires.dateReponse} IS NOT NULL THEN 1 ELSE 0 END)`,
|
||||
})
|
||||
.from(questionnaires)
|
||||
.leftJoin(envoisQuestionnaires, eq(questionnaires.id, envoisQuestionnaires.questionnaireId));
|
||||
|
||||
const stats = results[0];
|
||||
const totalEnvois = Number(stats.totalEnvois) || 0;
|
||||
const totalReponses = Number(stats.totalReponses) || 0;
|
||||
|
||||
return {
|
||||
totalQuestionnaires: Number(stats.totalQuestionnaires) || 0,
|
||||
totalEnvois,
|
||||
totalReponses,
|
||||
tauxReponseGlobal: totalEnvois > 0 ? Number(((totalReponses / totalEnvois) * 100).toFixed(1)) : 0
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user