mirror of
https://framagit.org/enfance-libre/statistiques
synced 2025-12-07 07:23:44 +00:00
feat: stat Délai moyen entre MED et (Gendarmerie ou Procureur)
améliore stats délai en introduisant une notion de "procedéure"
This commit is contained in:
parent
cc16a203a0
commit
4433ae466f
7 changed files with 219 additions and 61 deletions
|
|
@ -134,6 +134,11 @@ export const statsPenalesDesc = {
|
|||
},
|
||||
},
|
||||
},
|
||||
intervalMedGendarmerieOuProcureur: {
|
||||
label: "Délai moyen entre MED et (Gendarmerie ou Procureur)",
|
||||
unit: " jours",
|
||||
valueMaxFractioDigits: 0,
|
||||
},
|
||||
intervalGendarmerieProcureur: {
|
||||
label: "Délai moyen entre Gendarmerie et Procureur",
|
||||
unit: " jours",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,78 @@
|
|||
import { isEmpty } from "lodash";
|
||||
import {
|
||||
EvenementFamille,
|
||||
isGendarmerie,
|
||||
isProcureur,
|
||||
} from "../../../data/EvenementFamille";
|
||||
import { isTribunalCorrectionnel } from "./computeStatsPenales";
|
||||
import { Famille } from "../../../data/Famille";
|
||||
import { differenceInDays } from "date-fns";
|
||||
|
||||
export interface InfosProcedurePenale {
|
||||
evtMiseEnDemeure?: EvenementFamille;
|
||||
evtGendarmerie?: EvenementFamille;
|
||||
evtProcureur?: EvenementFamille;
|
||||
evtTribunalCorrectionnel?: EvenementFamille;
|
||||
}
|
||||
|
||||
export interface FamilleAvecInfosProceduresPenales extends Famille {
|
||||
proceduresPenales: InfosProcedurePenale[];
|
||||
}
|
||||
|
||||
export function computeFamilleAvecInfosProceduresPenales(
|
||||
famille: Famille
|
||||
): FamilleAvecInfosProceduresPenales {
|
||||
const proceduresPenales = computeProceduresPenales(famille.Evenements);
|
||||
return {
|
||||
...famille,
|
||||
proceduresPenales: proceduresPenales,
|
||||
};
|
||||
}
|
||||
|
||||
function computeProceduresPenales(
|
||||
evenenemts: EvenementFamille[]
|
||||
): InfosProcedurePenale[] {
|
||||
const procedures: InfosProcedurePenale[] = [];
|
||||
let currentProcedure: InfosProcedurePenale = {};
|
||||
for (let i = 0; i < evenenemts.length; i++) {
|
||||
const evt = evenenemts[i];
|
||||
if (evt.Type === "Mise en demeure de scolarisation") {
|
||||
if (currentProcedure.evtMiseEnDemeure) {
|
||||
// Si l'événement Mise en demeure est déjà présent, on considère que c'est une nouvelle procédure
|
||||
procedures.push(currentProcedure);
|
||||
currentProcedure = {};
|
||||
}
|
||||
currentProcedure.evtMiseEnDemeure = evt;
|
||||
} else if (isGendarmerie(evt)) {
|
||||
if (
|
||||
currentProcedure.evtGendarmerie &&
|
||||
evt.Date &&
|
||||
currentProcedure.evtGendarmerie.Date &&
|
||||
differenceInDays(evt.Date, currentProcedure.evtGendarmerie.Date) > 60
|
||||
) {
|
||||
// Si l'événement Gendarmerie est déjà présent et les 2 evt gendarmerie sont séparé de plus de 60 jours
|
||||
// on considère que c'est une nouvelle procédure
|
||||
procedures.push(currentProcedure);
|
||||
currentProcedure = {};
|
||||
}
|
||||
currentProcedure.evtGendarmerie = evt;
|
||||
} else if (isProcureur(evt)) {
|
||||
if (currentProcedure.evtProcureur) {
|
||||
// Si l'événement Procureur est déjà présent, on considère que c'est une nouvelle procédure
|
||||
procedures.push(currentProcedure);
|
||||
currentProcedure = {};
|
||||
}
|
||||
currentProcedure.evtProcureur = evt;
|
||||
} else if (isTribunalCorrectionnel(evt)) {
|
||||
// Le tribunal correctionnel est le dernier événement d'une procédure pénale
|
||||
currentProcedure.evtTribunalCorrectionnel = evt;
|
||||
procedures.push(currentProcedure);
|
||||
currentProcedure = {};
|
||||
}
|
||||
}
|
||||
|
||||
if (!isEmpty(currentProcedure)) {
|
||||
procedures.push(currentProcedure);
|
||||
}
|
||||
return procedures;
|
||||
}
|
||||
|
|
@ -1,15 +1,12 @@
|
|||
import { differenceInDays } from "date-fns";
|
||||
import {
|
||||
isCompositionPenale,
|
||||
isCRPC,
|
||||
isProcureur,
|
||||
isGendarmerie,
|
||||
isEvtProcedurePenale,
|
||||
EvenementFamille,
|
||||
isProcedurePenaleHorsGendarmerie,
|
||||
} from "../../../data/EvenementFamille";
|
||||
import { Famille, isExResistant, isResistant } from "../../../data/Famille";
|
||||
import { average } from "../../../utils/math/average";
|
||||
import { filterFamillesWithOneOfEvenements } from "../filterFamillesWithOneOfEvenements";
|
||||
import { filterFamillesWithOneOfEvenementsOfType } from "../filterFamillesWithOneOfEvenementsOfType";
|
||||
import { StatsPenales } from "./StatsPenales";
|
||||
|
|
@ -18,6 +15,13 @@ import { buildInfoTribunauxCorrectionnel } from "./tc/buildInfoTribunauxCorrecti
|
|||
import { InfoTribunalCorrectionnel } from "./tc/InfoTribunalCorrectionnel";
|
||||
import { computeTribunalCorrectionnel } from "./tc/computeTribunalCorrectionnel";
|
||||
import { computeTribunalPolice } from "./tp/computeTribunalPolice";
|
||||
import { computeIntervalGendarmerieProcureur } from "./intervals/computeIntervalGendarmerieProcureur";
|
||||
import { computeIntervalProcureurTribunalCorrectionnel } from "./intervals/computeIntervalProcureurTribunalCorrectionnel";
|
||||
import {
|
||||
computeFamilleAvecInfosProceduresPenales,
|
||||
FamilleAvecInfosProceduresPenales as FamilleAvecInfoProceduresPenales,
|
||||
} from "./computeFamilleAvecInfosProceduresPenales";
|
||||
import { computeIntervalMedGendarmerieOuProcureur } from "./intervals/computeIntervalMedGendarmerieOuProcureur";
|
||||
|
||||
export type FamilleAvecInfoTribunaux = Famille & {
|
||||
infoTribunaux: InfoTribunalCorrectionnel[];
|
||||
|
|
@ -60,6 +64,9 @@ export function computeStatsPenales(familles: Famille[]): StatsPenales {
|
|||
};
|
||||
});
|
||||
|
||||
const famillesAvecInfoProceduresPenales: FamilleAvecInfoProceduresPenales[] =
|
||||
famillesResistantesOuEx.map(computeFamilleAvecInfosProceduresPenales);
|
||||
|
||||
const statsPenales: StatsPenales = {
|
||||
nbFamillesMisesEnDemeure: nbFamillesAvecPagesLiees(famillesMisesEnDemeure),
|
||||
nbFamillesAvecProcedurePenale: nbFamillesAvecPagesLiees(
|
||||
|
|
@ -136,10 +143,17 @@ export function computeStatsPenales(familles: Famille[]): StatsPenales {
|
|||
),
|
||||
|
||||
tribunalDePolice: computeTribunalPolice(famillesResistantesOuEx),
|
||||
intervalMedGendarmerieOuProcureur: computeIntervalMedGendarmerieOuProcureur(
|
||||
famillesAvecInfoProceduresPenales
|
||||
),
|
||||
|
||||
intervalGendarmerieProcureur: computeIntervalGendarmerieProcureur(familles),
|
||||
intervalGendarmerieProcureur: computeIntervalGendarmerieProcureur(
|
||||
famillesAvecInfoProceduresPenales
|
||||
),
|
||||
intervalProcureurTribunalCorrectionnel:
|
||||
computeIntervalProcureurTribunalCorrectionnel(familles),
|
||||
computeIntervalProcureurTribunalCorrectionnel(
|
||||
famillesAvecInfoProceduresPenales
|
||||
),
|
||||
};
|
||||
return statsPenales;
|
||||
}
|
||||
|
|
@ -190,62 +204,6 @@ function computeCompositionPenales(
|
|||
};
|
||||
}
|
||||
|
||||
function computeIntervalGendarmerieProcureur(familles: Famille[]): number {
|
||||
const intervals = familles.flatMap((f) => {
|
||||
const evtGendarmerie = f.EvenementsEL.find((e) => isGendarmerie(e));
|
||||
const evtProcureur = f.EvenementsEL.find((e) => isProcureur(e));
|
||||
|
||||
// consider only intervals for families with both events date
|
||||
if (!evtGendarmerie?.Date || !evtProcureur?.Date) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const intervalInDays = differenceInDays(
|
||||
evtProcureur.Date,
|
||||
evtGendarmerie.Date
|
||||
);
|
||||
if (intervalInDays < 0) {
|
||||
console.warn(
|
||||
`IntervalGendarmerieProcureur < 0 pour ${f.Titre} (${f.notionId}): Cet interval sera ignoré.`
|
||||
);
|
||||
return [];
|
||||
} else {
|
||||
return [intervalInDays];
|
||||
}
|
||||
});
|
||||
return average(intervals);
|
||||
}
|
||||
|
||||
function computeIntervalProcureurTribunalCorrectionnel(
|
||||
familles: Famille[]
|
||||
): number {
|
||||
const intervals = familles.flatMap((f) => {
|
||||
const evtProcureur = f.EvenementsEL.find((e) => isProcureur(e));
|
||||
const evtTribunal = f.EvenementsEL.find(
|
||||
(e) => e.Type === "Tribunal correctionnel"
|
||||
);
|
||||
|
||||
// consider only intervals for families with both events date
|
||||
if (!evtProcureur?.Date || !evtTribunal?.Date) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const intervalInDays = differenceInDays(
|
||||
evtTribunal.Date,
|
||||
evtProcureur.Date
|
||||
);
|
||||
if (intervalInDays < 0) {
|
||||
console.warn(
|
||||
`IntervalProcureurTribunalCorrectionnel < 0 for ${f.Titre} (${f.notionId})`
|
||||
);
|
||||
return [];
|
||||
} else {
|
||||
return [intervalInDays];
|
||||
}
|
||||
});
|
||||
return average(intervals);
|
||||
}
|
||||
|
||||
export function isTribunalCorrectionnel(e: EvenementFamille): boolean {
|
||||
return e.Type === "Tribunal correctionnel";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
import { differenceInDays } from "date-fns";
|
||||
import { computeIntervalProcedurePenale } from "./computeIntervalProcedurePenale";
|
||||
import {
|
||||
FamilleAvecInfosProceduresPenales,
|
||||
InfosProcedurePenale,
|
||||
} from "../computeFamilleAvecInfosProceduresPenales";
|
||||
|
||||
export function computeIntervalGendarmerieProcureur(
|
||||
familles: FamilleAvecInfosProceduresPenales[]
|
||||
): number {
|
||||
return computeIntervalProcedurePenale(
|
||||
familles,
|
||||
(procPenal: InfosProcedurePenale): number | undefined => {
|
||||
if (procPenal.evtGendarmerie?.Date && procPenal.evtProcureur?.Date) {
|
||||
return differenceInDays(
|
||||
procPenal.evtProcureur.Date,
|
||||
procPenal.evtGendarmerie.Date
|
||||
);
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
"IntervalGendarmerieProcureur"
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
import { differenceInDays } from "date-fns";
|
||||
import {
|
||||
FamilleAvecInfosProceduresPenales as FamilleAvecInfoProceduresPenales,
|
||||
InfosProcedurePenale,
|
||||
} from "../computeFamilleAvecInfosProceduresPenales";
|
||||
import { computeIntervalProcedurePenale } from "./computeIntervalProcedurePenale";
|
||||
import { min } from "lodash";
|
||||
|
||||
export function computeIntervalMedGendarmerieOuProcureur(
|
||||
familles: FamilleAvecInfoProceduresPenales[]
|
||||
): number {
|
||||
return computeIntervalProcedurePenale(
|
||||
familles,
|
||||
(procPenal: InfosProcedurePenale): number | undefined => {
|
||||
if (
|
||||
procPenal.evtMiseEnDemeure?.Date &&
|
||||
(procPenal.evtGendarmerie?.Date || procPenal.evtProcureur?.Date)
|
||||
) {
|
||||
const earliestGendarmerieOuProcureur: Date = min(
|
||||
[procPenal.evtGendarmerie?.Date, procPenal.evtProcureur?.Date].filter(
|
||||
(d) => d !== undefined && d !== null
|
||||
)
|
||||
) as Date;
|
||||
|
||||
return differenceInDays(
|
||||
earliestGendarmerieOuProcureur,
|
||||
procPenal.evtMiseEnDemeure.Date
|
||||
);
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
"IntervalMedGendarmerieOuProcureur"
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
import { Famille } from "../../../../data/Famille";
|
||||
import { average } from "../../../../utils/math/average";
|
||||
import {
|
||||
FamilleAvecInfosProceduresPenales as FamilleAvecInfoProceduresPenales,
|
||||
InfosProcedurePenale,
|
||||
} from "../computeFamilleAvecInfosProceduresPenales";
|
||||
|
||||
export function computeIntervalProcedurePenale(
|
||||
famillesAvecInfoProceduresPenales: FamilleAvecInfoProceduresPenales[],
|
||||
// Function to extract the interval from each procedure returns undefined if not applicable
|
||||
intervalFn: (
|
||||
procPenal: InfosProcedurePenale,
|
||||
famille: Famille
|
||||
) => number | undefined,
|
||||
intervalName: string
|
||||
): number {
|
||||
const intervals: number[] = famillesAvecInfoProceduresPenales.flatMap((f) => {
|
||||
return f.proceduresPenales
|
||||
.map((pp) => {
|
||||
const interval = intervalFn(pp, f);
|
||||
if (interval !== undefined && interval < 0) {
|
||||
console.warn(
|
||||
`${intervalName} < 0 pour ${f.Titre} (${f.notionId}): Cet interval sera ignoré.`
|
||||
);
|
||||
return undefined;
|
||||
}
|
||||
return interval;
|
||||
})
|
||||
.filter((i) => i !== undefined) as number[];
|
||||
});
|
||||
return average(intervals);
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
import { differenceInDays } from "date-fns";
|
||||
import { computeIntervalProcedurePenale } from "./computeIntervalProcedurePenale";
|
||||
import {
|
||||
FamilleAvecInfosProceduresPenales,
|
||||
InfosProcedurePenale,
|
||||
} from "../computeFamilleAvecInfosProceduresPenales";
|
||||
|
||||
export function computeIntervalProcureurTribunalCorrectionnel(
|
||||
familles: FamilleAvecInfosProceduresPenales[]
|
||||
): number {
|
||||
return computeIntervalProcedurePenale(
|
||||
familles,
|
||||
(procPenal: InfosProcedurePenale): number | undefined => {
|
||||
if (
|
||||
procPenal.evtProcureur?.Date &&
|
||||
procPenal.evtTribunalCorrectionnel?.Date
|
||||
) {
|
||||
return differenceInDays(
|
||||
procPenal.evtTribunalCorrectionnel.Date,
|
||||
procPenal.evtProcureur.Date
|
||||
);
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
"IntervalProcureurTribunalCorrectionnel"
|
||||
);
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue