wip stats departementales

This commit is contained in:
Sébastien Arod 2025-06-23 09:28:57 +02:00
parent 456cb3279d
commit da5e450564
11 changed files with 440 additions and 284 deletions

4
src/data/Departement.ts Normal file
View file

@ -0,0 +1,4 @@
export type Departement = {
notionId: string;
name: string;
};

View file

@ -19,6 +19,7 @@ import { nettoyerDonneesFamilles } from "./data/nettoyage/familles/preparerDonne
import { statsAutresDesc } from "./statistiques/v2/autres/StatsAutres";
import { computeStatsAutres } from "./statistiques/v2/autres/computeStatsAutres";
import { updateUpdateDate as updateRootPageUpdateDate } from "./notion/publish/updateUpdateDate";
import { computeStatsDepartementales } from "./statistiques/v2/departemental/computeStatDepartement";
type ProcessOptions = {
dryRun: boolean;
@ -51,12 +52,12 @@ function buildProcessOptions(): ProcessOptions {
await checkDbSchemas(notionClient);
console.log("Téléchargement des données...");
const donneesFamillesBrutes = await fetchFamiliesWithEventsFromNotion(
notionClient
);
const donneesNotion = await fetchFamiliesWithEventsFromNotion(notionClient);
console.log("Nettoyage des données brutes...");
const { familles, messages } = nettoyerDonneesFamilles(donneesFamillesBrutes);
const { familles, messages } = nettoyerDonneesFamilles(
donneesNotion.familles
);
const donneesBloquantes = messages.filter(
(m) => m.severite === "Donnée incohérente bloquante"
@ -107,6 +108,10 @@ function buildProcessOptions(): ProcessOptions {
const statsSociales = computeStatsSociales(familles);
const statsAutres = computeStatsAutres(familles);
const statsGeneralesMensuelles = computeStatsGeneralesMensuelles(familles);
const statsDepartementales = computeStatsDepartementales(
familles,
donneesNotion.departements
);
const mermaidDiagramStatsGeneralesMensuellesCode =
mermaidDiagramStatsGeneralesMensuelles(statsGeneralesMensuelles);
writeFileSync(
@ -131,6 +136,7 @@ function buildProcessOptions(): ProcessOptions {
sociales: statsSociales,
statsAutres: statsAutres,
StatsGeneralesMensuelles: statsGeneralesMensuelles,
statsDepartementales: statsDepartementales,
},
null,
" "

View file

@ -0,0 +1,40 @@
import { Client, isFullPage } from "@notionhq/client";
import { Contact } from "../../data/Contact";
import { checkboxPropertyToBoolean } from "../utils/properties/checkboxPropertyToBoolean";
import { relationPropertyToPageId } from "../utils/properties/relationPropertyToPageId";
import { titlePropertyToText } from "../utils/properties/titlePropertyToText";
import { queryAllDbResults } from "../utils/queryAllDbResults";
import { contactsDbId } from "./dbIds";
export async function fetchContacts(
notionClient: Client,
cacheConfig: boolean | { ttl: number },
missions: Readonly<{
notionId: string;
Nom: string;
Equipe: string;
ContactsNotionIds: string[];
}>[]
) {
const contactPages = (
await queryAllDbResults(
notionClient,
{
database_id: contactsDbId,
},
{ cache: cacheConfig }
)
).filter(isFullPage);
const contacts: Contact[] = contactPages.map((page) => ({
notionId: page.id,
notionIdFamille: relationPropertyToPageId(page.properties, "Famille")!,
Nom: titlePropertyToText(page.properties, "Nom"),
AExercéUneMission: checkboxPropertyToBoolean(
page.properties,
"A exercé une mission"
),
Missions: missions.filter((m) => m.ContactsNotionIds.includes(page.id)),
}));
return contacts;
}

View file

@ -0,0 +1,26 @@
import { Client, isFullPage } from "@notionhq/client";
import { Departement } from "../../data/Departement";
import { titlePropertyToText } from "../utils/properties/titlePropertyToText";
import { queryAllDbResults } from "../utils/queryAllDbResults";
import { departementsDbId } from "./dbIds";
export async function fetchDepartements(
notionClient: Client,
cacheConfig: boolean | { ttl: number }
) {
const departementPages = (
await queryAllDbResults(
notionClient,
{
database_id: departementsDbId,
},
{ cache: cacheConfig }
)
).filter(isFullPage);
const departements: Departement[] = departementPages.map((page) => ({
notionId: page.id,
name: titlePropertyToText(page.properties, "Nom"),
}));
return departements;
}

View file

@ -0,0 +1,53 @@
import { Client, isFullPage } from "@notionhq/client";
import { Amende } from "../../data/Amende";
import { queryAllDbResults } from "../utils/queryAllDbResults";
import { familEventsDbId } from "./dbIds";
import { PageObjectResponse } from "@notionhq/client/build/src/api-endpoints";
import { EvenementFamille } from "../../data/EvenementFamille";
import { TypeEvenement } from "../../data/TypeEvenement";
import { datePropertyToDate } from "../utils/properties/datePropertyToDate";
import { relationPropertyToPageId } from "../utils/properties/relationPropertyToPageId";
import { selectPropertyToText } from "../utils/properties/selectPropertyToText";
import { titlePropertyToText } from "../utils/properties/titlePropertyToText";
import { richTextPropertyToPlainText } from "../utils/text/richTextPropertyToPlainText";
export async function fetchEvenements(
notionClient: Client,
cacheConfig: boolean | { ttl: number },
amendes: Amende[]
) {
const eventPages = (
await queryAllDbResults(
notionClient,
{
database_id: familEventsDbId,
sorts: [{ property: "Date", direction: "ascending" }],
},
{ cache: cacheConfig }
)
).filter(isFullPage);
const familyEvents = eventPages.map((pageObjectResponse) => {
return buildFamilyEvent(pageObjectResponse, amendes);
});
return familyEvents;
}
export function buildFamilyEvent(
page: PageObjectResponse,
amendes: Amende[]
): EvenementFamille {
const pageProperties = page.properties;
const familyEvent: EvenementFamille = {
notionId: page.id,
Évènement: titlePropertyToText(pageProperties, "Évènement"),
Type: selectPropertyToText(pageProperties, "Type")! as TypeEvenement,
"Enfants concernés": richTextPropertyToPlainText(
pageProperties,
"Enfants concernés"
),
Date: datePropertyToDate(pageProperties, "Date"),
notionIdFamille: relationPropertyToPageId(pageProperties, "Famille")!,
Amendes: amendes.filter((a) => a.notionIdEvenement === page.id),
};
return familyEvent;
}

View file

@ -1,47 +1,26 @@
import { Client, isFullPage } from "@notionhq/client";
import { PageObjectResponse } from "@notionhq/client/build/src/api-endpoints";
import { ContexteEntreeDC } from "../../data/ContexteEntreeDC";
import { EvenementFamille } from "../../data/EvenementFamille";
import { Client } from "@notionhq/client";
import { Famille } from "../../data/Famille";
import { StatutFamille } from "../../data/StatutFamille";
import { TypeEvenement } from "../../data/TypeEvenement";
import { datePropertyToDate } from "../utils/properties/datePropertyToDate";
import { relationPropertyToPageId } from "../utils/properties/relationPropertyToPageId";
import { selectPropertyToText } from "../utils/properties/selectPropertyToText";
import { statusPropertyToText } from "../utils/properties/statusPropertyToText";
import { titlePropertyToText } from "../utils/properties/titlePropertyToText";
import { CacheConfig, queryAllDbResults } from "../utils/queryAllDbResults";
import { richTextPropertyToPlainText } from "../utils/text/richTextPropertyToPlainText";
import {
contactsDbId,
departementsDbId,
familEventsDbId,
missionsDbId,
} from "./dbIds";
import {
propContexteEntree,
familiesDbId,
propDerniereModification,
propPenal,
propSocial,
} from "./dbfamilleDesc";
import { StatutPenal } from "../../data/StatutPenal";
import { StatutSocial } from "../../data/StatutSocial";
import { CacheConfig } from "../utils/queryAllDbResults";
import { Contact } from "../../data/Contact";
import { Mission } from "../../data/Mission";
import { relationPropertyToPageIds } from "../utils/properties/relationPropertyToPageIds";
import { checkboxPropertyToBoolean } from "../utils/properties/checkboxPropertyToBoolean";
import { Amende } from "../../data/Amende";
import { fetchAmendes } from "./fetchAmendes";
import { Departement } from "../../data/Departement";
import { fetchEvenements } from "./fetchEvenements";
import { fetchContacts } from "./fetchContacts";
import { fetchMissions } from "./fetchMissions";
import { fetchDepartements } from "./fetchDepartements";
import { fetchFamilles } from "./fetchFamilles";
type Departement = {
notionId: string;
name: string;
export type FetchedData = {
familles: Famille[];
departements: Departement[];
};
export async function fetchFamiliesWithEventsFromNotion(
notionClient: Client,
cacheConfig: CacheConfig = { ttl: 3600 * 1000 }
): Promise<Famille[]> {
): Promise<FetchedData> {
const departements: Departement[] = await fetchDepartements(
notionClient,
cacheConfig
@ -61,213 +40,5 @@ export async function fetchFamiliesWithEventsFromNotion(
departements,
contacts
);
return familles;
}
async function fetchFamilles(
notionClient: Client,
cacheConfig: boolean | { ttl: number },
familyEvents: Readonly<{
notionId: string;
notionIdFamille: string;
Évènement: string;
Date: Date | null;
Type: TypeEvenement;
Amendes: Amende[];
"Enfants concernés": string;
}>[],
departements: Departement[],
contacts: Readonly<{
notionId: string;
notionIdFamille: string;
Nom: string;
Missions: Mission[];
AExercéUneMission: boolean;
}>[]
) {
const familyPages = (
await queryAllDbResults(
notionClient,
{
database_id: familiesDbId,
},
{ cache: cacheConfig }
)
).filter(isFullPage);
const familles: Famille[] = await Promise.all(
familyPages.map((pageObjectResponse) => {
return buildFamily(
pageObjectResponse,
familyEvents,
departements,
contacts
);
})
);
return familles;
}
async function fetchEvenements(
notionClient: Client,
cacheConfig: boolean | { ttl: number },
amendes: Amende[]
) {
const eventPages = (
await queryAllDbResults(
notionClient,
{
database_id: familEventsDbId,
sorts: [{ property: "Date", direction: "ascending" }],
},
{ cache: cacheConfig }
)
).filter(isFullPage);
const familyEvents = eventPages.map((pageObjectResponse) => {
return buildFamilyEvent(pageObjectResponse, amendes);
});
return familyEvents;
}
async function fetchContacts(
notionClient: Client,
cacheConfig: boolean | { ttl: number },
missions: Readonly<{
notionId: string;
Nom: string;
Equipe: string;
ContactsNotionIds: string[];
}>[]
) {
const contactPages = (
await queryAllDbResults(
notionClient,
{
database_id: contactsDbId,
},
{ cache: cacheConfig }
)
).filter(isFullPage);
const contacts: Contact[] = contactPages.map((page) => ({
notionId: page.id,
notionIdFamille: relationPropertyToPageId(page.properties, "Famille")!,
Nom: titlePropertyToText(page.properties, "Nom"),
AExercéUneMission: checkboxPropertyToBoolean(
page.properties,
"A exercé une mission"
),
Missions: missions.filter((m) => m.ContactsNotionIds.includes(page.id)),
}));
return contacts;
}
async function fetchMissions(
notionClient: Client,
cacheConfig: boolean | { ttl: number }
) {
const missionsPages = (
await queryAllDbResults(
notionClient,
{
database_id: missionsDbId,
},
{ cache: cacheConfig }
)
).filter(isFullPage);
const missions: Mission[] = missionsPages.map((page) => ({
notionId: page.id,
Nom: titlePropertyToText(page.properties, "Nom"),
Equipe: selectPropertyToText(page.properties, "Équipe")!,
ContactsNotionIds: relationPropertyToPageIds(
page.properties,
"📔 Contacts"
),
}));
return missions;
}
async function fetchDepartements(
notionClient: Client,
cacheConfig: boolean | { ttl: number }
) {
const departementPages = (
await queryAllDbResults(
notionClient,
{
database_id: departementsDbId,
},
{ cache: cacheConfig }
)
).filter(isFullPage);
const departements: Departement[] = departementPages.map((page) => ({
notionId: page.id,
name: titlePropertyToText(page.properties, "Nom"),
}));
return departements;
}
function buildFamilyEvent(
page: PageObjectResponse,
amendes: Amende[]
): EvenementFamille {
const pageProperties = page.properties;
const familyEvent: EvenementFamille = {
notionId: page.id,
Évènement: titlePropertyToText(pageProperties, "Évènement"),
Type: selectPropertyToText(pageProperties, "Type")! as TypeEvenement,
"Enfants concernés": richTextPropertyToPlainText(
pageProperties,
"Enfants concernés"
),
Date: datePropertyToDate(pageProperties, "Date"),
notionIdFamille: relationPropertyToPageId(pageProperties, "Famille")!,
Amendes: amendes.filter((a) => a.notionIdEvenement === page.id),
};
return familyEvent;
}
function buildFamily(
page: PageObjectResponse,
familyEvents: EvenementFamille[],
departements: Departement[],
contacts: Contact[]
): Famille {
const pageProperties = page.properties;
const departementId = relationPropertyToPageId(pageProperties, "Département");
const departement = departementId
? departements.find((d) => d.notionId === departementId)
: null;
const family: Famille = {
notionId: page.id,
Titre: titlePropertyToText(pageProperties, ""),
Statut: statusPropertyToText(pageProperties, "Statut") as StatutFamille,
ContexteEntree: selectPropertyToText(
pageProperties,
propContexteEntree
) as ContexteEntreeDC,
Integration: datePropertyToDate(pageProperties, "Intégration"),
Sortie: datePropertyToDate(pageProperties, "Sortie"),
Evenements: familyEvents.filter((fe) => fe.notionIdFamille === page.id),
// Ces 4 propriétés seront peuplés après le data consistency check
EvenementsDates: [],
EvenementsEL: [],
EvenementsAvantEL: [],
EvenementsApresEL: [],
Departement: departement?.name || null,
DerniereModification: datePropertyToDate(
pageProperties,
propDerniereModification
)!,
Penal: statusPropertyToText(pageProperties, propPenal) as StatutPenal,
Social: statusPropertyToText(pageProperties, propSocial) as StatutSocial,
Missions: contacts
.filter((c) => c.notionIdFamille === page.id)
.flatMap((c) => c.Missions),
Contacts: contacts.filter((c) => c.notionIdFamille === page.id),
};
return family;
return { familles, departements };
}

View file

@ -0,0 +1,112 @@
import { Client, isFullPage } from "@notionhq/client";
import { Amende } from "../../data/Amende";
import { Departement } from "../../data/Departement";
import { Famille } from "../../data/Famille";
import { Mission } from "../../data/Mission";
import { TypeEvenement } from "../../data/TypeEvenement";
import { queryAllDbResults } from "../utils/queryAllDbResults";
import {
familiesDbId,
propContexteEntree,
propDerniereModification,
propPenal,
propSocial,
} from "./dbfamilleDesc";
import { PageObjectResponse } from "@notionhq/client/build/src/api-endpoints";
import { EvenementFamille } from "../../data/EvenementFamille";
import { Contact } from "../../data/Contact";
import { relationPropertyToPageId } from "../utils/properties/relationPropertyToPageId";
import { titlePropertyToText } from "../utils/properties/titlePropertyToText";
import { statusPropertyToText } from "../utils/properties/statusPropertyToText";
import { selectPropertyToText } from "../utils/properties/selectPropertyToText";
import { StatutFamille } from "../../data/StatutFamille";
import { ContexteEntreeDC } from "../../data/ContexteEntreeDC";
import { datePropertyToDate } from "../utils/properties/datePropertyToDate";
import { StatutPenal } from "../../data/StatutPenal";
import { StatutSocial } from "../../data/StatutSocial";
export async function fetchFamilles(
notionClient: Client,
cacheConfig: boolean | { ttl: number },
familyEvents: Readonly<{
notionId: string;
notionIdFamille: string;
Évènement: string;
Date: Date | null;
Type: TypeEvenement;
Amendes: Amende[];
"Enfants concernés": string;
}>[],
departements: Departement[],
contacts: Readonly<{
notionId: string;
notionIdFamille: string;
Nom: string;
Missions: Mission[];
AExercéUneMission: boolean;
}>[]
) {
const familyPages = (
await queryAllDbResults(
notionClient,
{
database_id: familiesDbId,
},
{ cache: cacheConfig }
)
).filter(isFullPage);
const familles: Famille[] = await Promise.all(
familyPages.map((pageObjectResponse) => {
return buildFamily(
pageObjectResponse,
familyEvents,
departements,
contacts
);
})
);
return familles;
}
function buildFamily(
page: PageObjectResponse,
familyEvents: EvenementFamille[],
departements: Departement[],
contacts: Contact[]
): Famille {
const pageProperties = page.properties;
const departementId = relationPropertyToPageId(pageProperties, "Département");
const departement = departementId
? departements.find((d) => d.notionId === departementId)
: null;
const family: Famille = {
notionId: page.id,
Titre: titlePropertyToText(pageProperties, ""),
Statut: statusPropertyToText(pageProperties, "Statut") as StatutFamille,
ContexteEntree: selectPropertyToText(
pageProperties,
propContexteEntree
) as ContexteEntreeDC,
Integration: datePropertyToDate(pageProperties, "Intégration"),
Sortie: datePropertyToDate(pageProperties, "Sortie"),
Evenements: familyEvents.filter((fe) => fe.notionIdFamille === page.id),
// Ces 4 propriétés seront peuplés après le data consistency check
EvenementsDates: [],
EvenementsEL: [],
EvenementsAvantEL: [],
EvenementsApresEL: [],
Departement: departement?.name || null,
DerniereModification: datePropertyToDate(
pageProperties,
propDerniereModification
)!,
Penal: statusPropertyToText(pageProperties, propPenal) as StatutPenal,
Social: statusPropertyToText(pageProperties, propSocial) as StatutSocial,
Missions: contacts
.filter((c) => c.notionIdFamille === page.id)
.flatMap((c) => c.Missions),
Contacts: contacts.filter((c) => c.notionIdFamille === page.id),
};
return family;
}

View file

@ -0,0 +1,32 @@
import { Client, isFullPage } from "@notionhq/client";
import { Mission } from "../../data/Mission";
import { relationPropertyToPageIds } from "../utils/properties/relationPropertyToPageIds";
import { selectPropertyToText } from "../utils/properties/selectPropertyToText";
import { titlePropertyToText } from "../utils/properties/titlePropertyToText";
import { queryAllDbResults } from "../utils/queryAllDbResults";
import { missionsDbId } from "./dbIds";
export async function fetchMissions(
notionClient: Client,
cacheConfig: boolean | { ttl: number }
) {
const missionsPages = (
await queryAllDbResults(
notionClient,
{
database_id: missionsDbId,
},
{ cache: cacheConfig }
)
).filter(isFullPage);
const missions: Mission[] = missionsPages.map((page) => ({
notionId: page.id,
Nom: titlePropertyToText(page.properties, "Nom"),
Equipe: selectPropertyToText(page.properties, "Équipe")!,
ContactsNotionIds: relationPropertyToPageIds(
page.properties,
"📔 Contacts"
),
}));
return missions;
}

View file

@ -0,0 +1,106 @@
import { groupBy } from "lodash";
import { Departement } from "../../../data/Departement";
import {
isInformationPreoccupante,
isProcedureCivile,
} from "../../../data/EvenementFamille";
import { Famille } from "../../../data/Famille";
import {
isEvtTypeProcedurePenale,
isEvtTypeProcedurePenaleHorsGendarmerie,
} from "../../../data/TypeEvenementsPenal";
import { filterFamillesWithOneOfEvenements } from "../filterFamillesWithOneOfEvenements";
import { filterFamillesWithOneOfEvenementsOfType } from "../filterFamillesWithOneOfEvenementsOfType";
import { percent } from "../math/percent";
export type StatDepartementales = {
[departement: string]: StatDepartement;
};
export function computeStatsDepartementales(
familles: Famille[],
departements: Departement[]
): StatDepartementales {
const famillesByDepartement: Record<string, Famille[]> = groupBy(
familles,
(f) => f.Departement
);
return Object.fromEntries(
departements.map((d) => [
d.name,
computeStatsDepartement(famillesByDepartement[d.name] || []),
])
);
}
export type StatDepartement = {
nbFamilles: number;
hasProcedurePenale: boolean;
pourcentageMED: number | undefined;
pourcentageProcedurePenaleHorsGendarmerie: number | undefined;
pourcentageTC: number | undefined;
pourcentageTP: number | undefined;
hasProcedureCivile: boolean;
pourcentageIP: number | undefined;
pourcentageMJIEouAEMO: number | undefined;
};
function computeStatsDepartement(
famillesDepartements: Famille[]
): StatDepartement {
return {
nbFamilles: famillesDepartements.length,
hasProcedurePenale:
filterFamillesWithOneOfEvenements(famillesDepartements, (e) =>
isEvtTypeProcedurePenale(e.Type)
).length > 0,
pourcentageMED: percent(
filterFamillesWithOneOfEvenementsOfType(
famillesDepartements,
"Mise en demeure de scolarisation"
).length,
famillesDepartements.length
),
pourcentageProcedurePenaleHorsGendarmerie: percent(
filterFamillesWithOneOfEvenements(famillesDepartements, (e) =>
isEvtTypeProcedurePenaleHorsGendarmerie(e.Type)
).length,
famillesDepartements.length
),
pourcentageTC: percent(
filterFamillesWithOneOfEvenements(
famillesDepartements,
(e) => e.Type === "Tribunal de police judiciaire"
).length,
famillesDepartements.length
),
pourcentageTP: percent(
filterFamillesWithOneOfEvenements(
famillesDepartements,
(e) => e.Type === "Tribunal de police judiciaire"
).length,
famillesDepartements.length
),
hasProcedureCivile:
filterFamillesWithOneOfEvenements(famillesDepartements, (e) =>
isProcedureCivile(e)
).length > 0,
pourcentageIP: percent(
filterFamillesWithOneOfEvenements(famillesDepartements, (e) =>
isInformationPreoccupante(e)
).length,
famillesDepartements.length
),
pourcentageMJIEouAEMO: percent(
famillesDepartements.filter(
(f) =>
f.Social === "MJIE" ||
f.Social === "AEMO" ||
f.EvenementsEL.some(
(e) => e.Type === "Classement suite AEMO MIJE ou..."
)
).length,
famillesDepartements.length
),
};
}

View file

@ -0,0 +1,42 @@
import { Famille } from "../../../data/Famille";
import { isEvtTypeProcedurePenaleHorsGendarmerie } from "../../../data/TypeEvenementsPenal";
import { filterFamillesWithOneOfEvenements } from "../filterFamillesWithOneOfEvenements";
import { filterFamillesWithOneOfEvenementsOfType } from "../filterFamillesWithOneOfEvenementsOfType";
import { percent } from "../math/percent";
import { nbFamillesAvecPagesLiees } from "../nbFamillesAvecPagesLiees";
import { StatsPenales } from "./StatsPenales";
export function computeStatDepartement(
famillesDepartements: Famille[]
): StatsPenales["parDepartements"][string] {
return {
nbFamilles: nbFamillesAvecPagesLiees(famillesDepartements),
pourcentageMED: percent(
filterFamillesWithOneOfEvenementsOfType(
famillesDepartements,
"Mise en demeure de scolarisation"
).length,
famillesDepartements.length
),
pourcentageProcedurePenaleHorsGendarmerie: percent(
filterFamillesWithOneOfEvenements(famillesDepartements, (e) =>
isEvtTypeProcedurePenaleHorsGendarmerie(e.Type)
).length,
famillesDepartements.length
),
pourcentageTribunalCorrectionnel: percent(
filterFamillesWithOneOfEvenements(
famillesDepartements,
(e) => e.Type === "Tribunal correctionnel"
).length,
famillesDepartements.length
),
pourcentageTribunalPolice: percent(
filterFamillesWithOneOfEvenements(
famillesDepartements,
(e) => e.Type === "Tribunal de police judiciaire"
).length,
famillesDepartements.length
),
};
}

View file

@ -23,9 +23,8 @@ import {
} from "./computeFamilleAvecInfosProceduresPenales";
import { computeIntervalMedGendarmerieOuProcureur } from "./intervals/computeIntervalMedGendarmerieOuProcureur";
import { groupBy } from "lodash";
import { percent } from "../math/percent";
import { isEvtTypeProcedurePenaleHorsGendarmerie } from "../../../data/TypeEvenementsPenal";
import { computeStatsAmendes } from "./computeStatsAmendes";
import { computeStatDepartement } from "./computeStatDepartement";
export type FamilleAvecInfoTribunaux = Famille & {
infoTribunaux: InfoTribunalCorrectionnel[];
@ -175,41 +174,6 @@ export function computeStatsPenales(familles: Famille[]): StatsPenales {
return statsPenales;
}
function computeStatDepartement(
famillesDepartements: Famille[]
): StatsPenales["parDepartements"][string] {
return {
nbFamilles: nbFamillesAvecPagesLiees(famillesDepartements),
pourcentageMED: percent(
filterFamillesWithOneOfEvenementsOfType(
famillesDepartements,
"Mise en demeure de scolarisation"
).length,
famillesDepartements.length
),
pourcentageProcedurePenaleHorsGendarmerie: percent(
filterFamillesWithOneOfEvenements(famillesDepartements, (e) =>
isEvtTypeProcedurePenaleHorsGendarmerie(e.Type)
).length,
famillesDepartements.length
),
pourcentageTribunalCorrectionnel: percent(
filterFamillesWithOneOfEvenements(
famillesDepartements,
(e) => e.Type === "Tribunal correctionnel"
).length,
famillesDepartements.length
),
pourcentageTribunalPolice: percent(
filterFamillesWithOneOfEvenements(
famillesDepartements,
(e) => e.Type === "Tribunal de police judiciaire"
).length,
famillesDepartements.length
),
};
}
function computeCrpc(
famillesResistantesOuEx: Famille[]
): StatsPenales["procureur"]["crpc"] {