From 16cc607b9c4f6e19659c6fdbe282f3ab3489ee2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Arod?= Date: Sat, 7 Sep 2024 22:11:20 +0200 Subject: [PATCH] feat: stats sociales v2 --- src/data/EvenementFamille.ts | 74 ++++--------------- src/data/TypeEvenement.ts | 35 +-------- src/data/TypeEvenementsPenal.ts | 23 ++++++ src/data/TypeEvenementsSocial.ts | 12 +++ src/data/checkDataConsistency.ts | 1 - src/index.ts | 25 +++++-- src/statistiques/v2/sociales/StatsSociales.ts | 38 ++++++++++ .../v2/sociales/computeStatsSociales.ts | 48 ++++++++++++ 8 files changed, 157 insertions(+), 99 deletions(-) create mode 100644 src/data/TypeEvenementsPenal.ts create mode 100644 src/data/TypeEvenementsSocial.ts create mode 100644 src/statistiques/v2/sociales/StatsSociales.ts create mode 100644 src/statistiques/v2/sociales/computeStatsSociales.ts diff --git a/src/data/EvenementFamille.ts b/src/data/EvenementFamille.ts index 98db9b6..72194b8 100644 --- a/src/data/EvenementFamille.ts +++ b/src/data/EvenementFamille.ts @@ -1,6 +1,10 @@ import { Period } from "../period/Period"; import { isPeriodContaining } from "../period/isPeriodContaining"; import { TypeEvenement } from "./TypeEvenement"; +import { typesEvenementsPenal } from "./TypeEvenementsPenal"; +import { TypeEvenementsPenal } from "./TypeEvenementsPenal"; +import { typesEvenementsSocial as typesEvenementsCivil } from "./TypeEvenementsSocial"; +import { TypesEvenementsSocial as TypesEvenementsCivil } from "./TypeEvenementsSocial"; export type EvenementFamille = Readonly<{ notionId: string; @@ -12,8 +16,10 @@ export type EvenementFamille = Readonly<{ }>; export function isProcedurePenale(evenement: EvenementFamille): boolean { - return categorieEvenement[evenement.Type] === "Procédure Pénale" && evenement.Type !== "Validation désobéissance" - && evenement.Type !== "Mise en demeure de scolarisation"; + return ( + typesEvenementsPenal.includes(evenement.Type as TypeEvenementsPenal) && + evenement.Type !== "Mise en demeure de scolarisation" + ); } export function isCompositionPenale(evenement: EvenementFamille): boolean { @@ -32,56 +38,9 @@ export function isCRPC(evenement: EvenementFamille): boolean { } export function isProcedureCivile(evenement: EvenementFamille): boolean { - return categorieEvenement[evenement.Type] === "Procédure Civile"; + return typesEvenementsCivil.includes(evenement.Type as TypesEvenementsCivil); } -const categorieEvenement: { - [evt in TypeEvenement]: CategorieEvenement; -} = { - // Procédure civile/social - ["Signalement au procureur"]: "Procédure Civile", - ["Classement social sans suite"]: "Procédure Civile", - ["Enquête sociale"]: "Procédure Civile", - ["Information préoccupante"]: "Procédure Civile", - ["Juge pour enfants"]: "Procédure Civile", - ["Audition des enfants"]: "Procédure Civile", - ["Assistance éducative"]: "Procédure Civile", - ["Contrôle forcé"]: "Procédure Civile", - - // Procédure pénale - ["Récidive gendarmerie"]: "Procédure Pénale", - ["Appel du jugement"]: "Procédure Pénale", - ["Tribunal de police judiciaire"]: "Procédure Pénale", - ["Mise en demeure de scolarisation"]: "Procédure Pénale", - ["Audition gendarmerie / police"]: "Procédure Pénale", - ["Gendarmerie/Forces de l'ordre"]: "Procédure Pénale", - ["Passage police municipale"]: "Procédure Pénale", - ["Convocation procureur"]: "Procédure Pénale", - ["Audition procureur"]: "Procédure Pénale", - ["Composition pénale refusée"]: "Procédure Pénale", - ["Composition pénale acceptée"]: "Procédure Pénale", - ["Classement pénal sans suite"]: "Procédure Pénale", - ["Tribunal correctionnel"]: "Procédure Pénale", - ["Convocation CRPC"]: "Procédure Pénale", - ["Audience CRPC"]: "Procédure Pénale", - ["Refus CRPC"]: "Procédure Pénale", - ["Acceptation CRPC"]: "Procédure Pénale", - ["Rappel à la loi"]: "Procédure Pénale", - ["Validation désobéissance"]: "Procédure Pénale", - // Autre - ["Plaidoirie"]: "Autre", - ["Refus de contrôle"]: "Autre", - ["Administrateur AD'HOC"]: "Autre", - ["Signalement"]: "Autre", - ["Contrôle URSSAF"]: "Autre", - ["Contrôle fiscal"]: "Autre", -}; - -export type CategorieEvenement = - | "Procédure Pénale" - | "Procédure Civile" - | "Autre"; - export function isEvenementInPeriod( evt: EvenementFamille, period: Period @@ -97,12 +56,6 @@ export function isEvenementBefore(evt: EvenementFamille, date: Date): boolean { return evt.Date < date; } -export function isValidEvenementFamille(str: string | null): boolean { - return ( - str === null || - Object.prototype.hasOwnProperty.call(categorieEvenement, str) - ); -} export function isGendarmerie(e: EvenementFamille): boolean { return ( e.Type === "Audition gendarmerie / police" || @@ -112,8 +65,13 @@ export function isGendarmerie(e: EvenementFamille): boolean { ); } export function isAuditionProcureurOuCRPC(e: EvenementFamille): boolean { + return e.Type === "Audition procureur" || e.Type === "Audience CRPC"; +} + +export function isInformationPreoccupante(e: EvenementFamille): boolean { return ( - e.Type === "Audition procureur" || - e.Type === "Audience CRPC" + e.Type === "Information préoccupante 1" || + e.Type === "Information préoccupante 2" || + e.Type === "Information préoccupante 3" ); } diff --git a/src/data/TypeEvenement.ts b/src/data/TypeEvenement.ts index 01d8eec..85c3c52 100644 --- a/src/data/TypeEvenement.ts +++ b/src/data/TypeEvenement.ts @@ -1,37 +1,6 @@ -export const typesEvenementsPenal = [ - "Récidive gendarmerie", - "Appel du jugement", - "Tribunal de police judiciaire", - "Mise en demeure de scolarisation", - "Audition gendarmerie / police", - "Convocation procureur", - "Audition procureur", - "Composition pénale refusée", - "Composition pénale acceptée", - "Classement pénal sans suite", - "Tribunal correctionnel", - "Convocation CRPC", - "Plaidoirie", - "Audience CRPC", - "Refus CRPC", - "Acceptation CRPC", // PLaceholder see does not exist in Notion yet // See https://discord.com/channels/990921361121746984/1245360366322585691/1248260713634336839 - "Rappel à la loi", - "Passage police municipale", - "Administrateur AD'HOC", - "Gendarmerie/Forces de l'ordre", -] as const; +import { typesEvenementsPenal } from "./TypeEvenementsPenal"; +import { typesEvenementsSocial } from "./TypeEvenementsSocial"; -export const typesEvenementsSocial = [ - "Information préoccupante 1", - "Information préoccupante 2", - "Information préoccupante 3", - "Classement social sans suite", - "Enquête sociale", - "Juge pour enfants", - "Audition des enfants", - "Assistance éducative", - "Signalement", -]; export const typesEvenements = [ ...typesEvenementsPenal, ...typesEvenementsSocial, diff --git a/src/data/TypeEvenementsPenal.ts b/src/data/TypeEvenementsPenal.ts new file mode 100644 index 0000000..5d98632 --- /dev/null +++ b/src/data/TypeEvenementsPenal.ts @@ -0,0 +1,23 @@ +export type TypeEvenementsPenal = (typeof typesEvenementsPenal)[number]; +export const typesEvenementsPenal = [ + "Récidive gendarmerie", + "Appel du jugement", + "Tribunal de police judiciaire", + "Mise en demeure de scolarisation", + "Audition gendarmerie / police", + "Convocation procureur", + "Audition procureur", + "Composition pénale refusée", + "Composition pénale acceptée", + "Classement pénal sans suite", + "Tribunal correctionnel", + "Convocation CRPC", + "Plaidoirie", + "Audience CRPC", + "Refus CRPC", + "Acceptation CRPC", // PLaceholder see does not exist in Notion yet // See https://discord.com/channels/990921361121746984/1245360366322585691/1248260713634336839 + "Rappel à la loi", + "Passage police municipale", + "Administrateur AD'HOC", + "Gendarmerie/Forces de l'ordre", +] as const; diff --git a/src/data/TypeEvenementsSocial.ts b/src/data/TypeEvenementsSocial.ts new file mode 100644 index 0000000..ee0084d --- /dev/null +++ b/src/data/TypeEvenementsSocial.ts @@ -0,0 +1,12 @@ +export type TypesEvenementsSocial = (typeof typesEvenementsSocial)[number]; +export const typesEvenementsSocial = [ + "Information préoccupante 1", + "Information préoccupante 2", + "Information préoccupante 3", + "Classement social sans suite", + "Enquête sociale", + "Juge pour enfants", + "Audition des enfants", + "Assistance éducative", + "Signalement", +] as const; diff --git a/src/data/checkDataConsistency.ts b/src/data/checkDataConsistency.ts index 4bc0cec..101c3f6 100644 --- a/src/data/checkDataConsistency.ts +++ b/src/data/checkDataConsistency.ts @@ -1,4 +1,3 @@ -import { isValidEvenementFamille } from "./EvenementFamille"; import { Famille, isExResistant, isResistant } from "./Famille"; export function checkDataConsistency(families: Famille[]): ConsistencyReport { diff --git a/src/index.ts b/src/index.ts index 839bdf5..178f4f6 100644 --- a/src/index.ts +++ b/src/index.ts @@ -10,6 +10,8 @@ import { computeStatsPenales } from "./statistiques/v2/penales/computeStatsPenal import { statsPenalesDesc } from "./statistiques/v2/penales/StatsPenales"; import { computeStatsGenerales } from "./statistiques/v2/generales/computeStatsGenerales"; import { statsGeneralesDesc } from "./statistiques/v2/generales/StatsGenerales"; +import { computeStatsSociales } from "./statistiques/v2/sociales/computeStatsSociales"; +import { statsSocialesDesc } from "./statistiques/v2/sociales/StatsSociales"; type ProcessOptions = { dryRun: boolean; @@ -71,8 +73,9 @@ function buildProcessOptions(): ProcessOptions { JSON.stringify(statsParAnciennete, null, " ") ); - const statsPenales = computeStatsPenales(familles); const statsGenerales = computeStatsGenerales(familles); + const statsPenales = computeStatsPenales(familles); + const statsSociales = computeStatsSociales(familles); if (options.dryRun) { console.log( @@ -83,7 +86,11 @@ function buildProcessOptions(): ProcessOptions { writeFileSync( "./el-stats-v2.json", JSON.stringify( - { generales: statsGenerales, penales: statsPenales }, + { + generales: statsGenerales, + penales: statsPenales, + sociales: statsSociales, + }, null, " " ) @@ -92,19 +99,23 @@ function buildProcessOptions(): ProcessOptions { console.log("Publishing statistics..."); await publishStatisticsToNotion(elStats, currentDate, notionClient); + await publishStatsToPage( + notionClient, + "313751fb-daed-4b33-992f-c86d7ac2de37", + statsGeneralesDesc, + statsGenerales + ); await publishStatsToPage( notionClient, "969eac5c-a4eb-49d4-b4ad-c341c9c4c785", - statsPenalesDesc, statsPenales ); await publishStatsToPage( notionClient, - "313751fb-daed-4b33-992f-c86d7ac2de37", - - statsGeneralesDesc, - statsGenerales + "68a8c03a-a4a2-4ff3-b044-7c8dbbdc28ce", + statsSocialesDesc, + statsSociales ); } })(); diff --git a/src/statistiques/v2/sociales/StatsSociales.ts b/src/statistiques/v2/sociales/StatsSociales.ts new file mode 100644 index 0000000..48115e6 --- /dev/null +++ b/src/statistiques/v2/sociales/StatsSociales.ts @@ -0,0 +1,38 @@ +import { StatsType } from "../StatsDesc"; + +export const statsSocialesDesc = { + label: "Stats Sociales", + stats: { + nbFamillesProcedureCivile: { + label: "Nb Familles avec une procedure sociale", + }, + nbFamilleAvecClassementSansSuite: { + label: "Nb Familles avec un classement sans suite", + }, + + nbFamilleAvecIP: { + label: "Nb Familles avec une Information Préoccupante", + }, + nbFamilleAvecAssistanceEducative: { + label: "Nb Familles avec une Assistance educative", + }, + + nbFamilleAvecAuditionDesEnfants: { + label: "Nb Familles avec audition des enfants", + }, + + jugePourEnfant: { + label: "Juge pour enfant", + stats: { + nbFamillesPassees: { + label: "Nb familles passées", + }, + nbFamillesConvoquées: { + label: "Nb familles convoquées", + }, + }, + }, + }, +} as const; + +export type StatsSociales = StatsType; diff --git a/src/statistiques/v2/sociales/computeStatsSociales.ts b/src/statistiques/v2/sociales/computeStatsSociales.ts new file mode 100644 index 0000000..96f84d4 --- /dev/null +++ b/src/statistiques/v2/sociales/computeStatsSociales.ts @@ -0,0 +1,48 @@ +import { + isEvenementBefore, + isInformationPreoccupante, + isProcedureCivile, +} from "../../../data/EvenementFamille"; +import { Famille } from "../../../data/Famille"; +import { filterFamillesWithOneOfEvenements } from "../filterFamillesWithOneOfEvenements"; +import { filterFamillesWithOneOfEvenementsOfType } from "../filterFamillesWithOneOfEvenementsOfType"; +import { StatsSociales } from "./StatsSociales"; + +export function computeStatsSociales(familles: Famille[]): StatsSociales { + const now = new Date(); + const statsCiviles: StatsSociales = { + nbFamillesProcedureCivile: filterFamillesWithOneOfEvenements( + familles, + (e) => isProcedureCivile(e) + ).length, + + nbFamilleAvecIP: filterFamillesWithOneOfEvenements( + familles, + isInformationPreoccupante + ).length, + nbFamilleAvecAssistanceEducative: filterFamillesWithOneOfEvenementsOfType( + familles, + "Assistance éducative" + ).length, + + nbFamilleAvecAuditionDesEnfants: filterFamillesWithOneOfEvenementsOfType( + familles, + "Audition des enfants" + ).length, + jugePourEnfant: { + nbFamillesPassees: filterFamillesWithOneOfEvenements( + familles, + (e) => e.Type === "Juge pour enfants" && isEvenementBefore(e, now) + ).length, + nbFamillesConvoquées: filterFamillesWithOneOfEvenements( + familles, + (e) => e.Type === "Juge pour enfants" && !isEvenementBefore(e, now) + ).length, + }, + nbFamilleAvecClassementSansSuite: filterFamillesWithOneOfEvenementsOfType( + familles, + "Classement social sans suite" + ).length, + }; + return statsCiviles; +}