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: {
|
intervalGendarmerieProcureur: {
|
||||||
label: "Délai moyen entre Gendarmerie et Procureur",
|
label: "Délai moyen entre Gendarmerie et Procureur",
|
||||||
unit: " jours",
|
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 {
|
import {
|
||||||
isCompositionPenale,
|
isCompositionPenale,
|
||||||
isCRPC,
|
isCRPC,
|
||||||
isProcureur,
|
|
||||||
isGendarmerie,
|
isGendarmerie,
|
||||||
isEvtProcedurePenale,
|
isEvtProcedurePenale,
|
||||||
EvenementFamille,
|
EvenementFamille,
|
||||||
isProcedurePenaleHorsGendarmerie,
|
isProcedurePenaleHorsGendarmerie,
|
||||||
} from "../../../data/EvenementFamille";
|
} from "../../../data/EvenementFamille";
|
||||||
import { Famille, isExResistant, isResistant } from "../../../data/Famille";
|
import { Famille, isExResistant, isResistant } from "../../../data/Famille";
|
||||||
import { average } from "../../../utils/math/average";
|
|
||||||
import { filterFamillesWithOneOfEvenements } from "../filterFamillesWithOneOfEvenements";
|
import { filterFamillesWithOneOfEvenements } from "../filterFamillesWithOneOfEvenements";
|
||||||
import { filterFamillesWithOneOfEvenementsOfType } from "../filterFamillesWithOneOfEvenementsOfType";
|
import { filterFamillesWithOneOfEvenementsOfType } from "../filterFamillesWithOneOfEvenementsOfType";
|
||||||
import { StatsPenales } from "./StatsPenales";
|
import { StatsPenales } from "./StatsPenales";
|
||||||
|
|
@ -18,6 +15,13 @@ import { buildInfoTribunauxCorrectionnel } from "./tc/buildInfoTribunauxCorrecti
|
||||||
import { InfoTribunalCorrectionnel } from "./tc/InfoTribunalCorrectionnel";
|
import { InfoTribunalCorrectionnel } from "./tc/InfoTribunalCorrectionnel";
|
||||||
import { computeTribunalCorrectionnel } from "./tc/computeTribunalCorrectionnel";
|
import { computeTribunalCorrectionnel } from "./tc/computeTribunalCorrectionnel";
|
||||||
import { computeTribunalPolice } from "./tp/computeTribunalPolice";
|
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 & {
|
export type FamilleAvecInfoTribunaux = Famille & {
|
||||||
infoTribunaux: InfoTribunalCorrectionnel[];
|
infoTribunaux: InfoTribunalCorrectionnel[];
|
||||||
|
|
@ -60,6 +64,9 @@ export function computeStatsPenales(familles: Famille[]): StatsPenales {
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const famillesAvecInfoProceduresPenales: FamilleAvecInfoProceduresPenales[] =
|
||||||
|
famillesResistantesOuEx.map(computeFamilleAvecInfosProceduresPenales);
|
||||||
|
|
||||||
const statsPenales: StatsPenales = {
|
const statsPenales: StatsPenales = {
|
||||||
nbFamillesMisesEnDemeure: nbFamillesAvecPagesLiees(famillesMisesEnDemeure),
|
nbFamillesMisesEnDemeure: nbFamillesAvecPagesLiees(famillesMisesEnDemeure),
|
||||||
nbFamillesAvecProcedurePenale: nbFamillesAvecPagesLiees(
|
nbFamillesAvecProcedurePenale: nbFamillesAvecPagesLiees(
|
||||||
|
|
@ -136,10 +143,17 @@ export function computeStatsPenales(familles: Famille[]): StatsPenales {
|
||||||
),
|
),
|
||||||
|
|
||||||
tribunalDePolice: computeTribunalPolice(famillesResistantesOuEx),
|
tribunalDePolice: computeTribunalPolice(famillesResistantesOuEx),
|
||||||
|
intervalMedGendarmerieOuProcureur: computeIntervalMedGendarmerieOuProcureur(
|
||||||
|
famillesAvecInfoProceduresPenales
|
||||||
|
),
|
||||||
|
|
||||||
intervalGendarmerieProcureur: computeIntervalGendarmerieProcureur(familles),
|
intervalGendarmerieProcureur: computeIntervalGendarmerieProcureur(
|
||||||
|
famillesAvecInfoProceduresPenales
|
||||||
|
),
|
||||||
intervalProcureurTribunalCorrectionnel:
|
intervalProcureurTribunalCorrectionnel:
|
||||||
computeIntervalProcureurTribunalCorrectionnel(familles),
|
computeIntervalProcureurTribunalCorrectionnel(
|
||||||
|
famillesAvecInfoProceduresPenales
|
||||||
|
),
|
||||||
};
|
};
|
||||||
return statsPenales;
|
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 {
|
export function isTribunalCorrectionnel(e: EvenementFamille): boolean {
|
||||||
return e.Type === "Tribunal correctionnel";
|
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