mirror of
https://framagit.org/enfance-libre/statistiques
synced 2025-12-07 13:53:45 +00:00
feat: Revue des stats sur + draft pénale et civile
This commit is contained in:
parent
af0fba621a
commit
f328137c30
24 changed files with 515 additions and 264 deletions
6
src/data/ContexteEntreeDC.ts
Normal file
6
src/data/ContexteEntreeDC.ts
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
export type ContexteEntreeDC =
|
||||||
|
| "Pas de demande (Plein droit)"
|
||||||
|
| "Pas de demande"
|
||||||
|
| "Après refus"
|
||||||
|
| "Après mise en demeure"
|
||||||
|
| "Après poursuite procureur";
|
||||||
70
src/data/EvenementFamille.ts
Normal file
70
src/data/EvenementFamille.ts
Normal file
|
|
@ -0,0 +1,70 @@
|
||||||
|
import { Period } from "../period/Period";
|
||||||
|
import { isPeriodContaining } from "../period/isPeriodContaining";
|
||||||
|
import { TypeEvenement } from "./TypeEvenement";
|
||||||
|
|
||||||
|
export type EvenementFamille = {
|
||||||
|
notionId: string;
|
||||||
|
notionIdFamille: string;
|
||||||
|
Évènement: string;
|
||||||
|
Date: Date | null;
|
||||||
|
Type: TypeEvenement;
|
||||||
|
"Enfants concernés": string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function isProcedurePenale(evenement: EvenementFamille): boolean {
|
||||||
|
return categorieEvenement[evenement.Type] === "Procédure Pénale";
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isProcedureCivile(evenement: EvenementFamille): boolean {
|
||||||
|
return categorieEvenement[evenement.Type] === "Procédure Civile";
|
||||||
|
}
|
||||||
|
|
||||||
|
const categorieEvenement: {
|
||||||
|
[evt in TypeEvenement]: CategorieEvenement;
|
||||||
|
} = {
|
||||||
|
["Récidive gendarmerie"]: "Procédure Pénale",
|
||||||
|
["Appel du jugement"]: "Procédure Pénale",
|
||||||
|
["Tribunal de police judiciaire"]: "Procédure Pénale",
|
||||||
|
["Signalement au procureur"]: "Procédure Civile", // TBC
|
||||||
|
["Mise en demeure de scolarisation"]: "Procédure Pénale",
|
||||||
|
["Signalement"]: "Procédure Civile",
|
||||||
|
["Audition gendarmerie / police"]: "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 social sans suite"]: "Procédure Civile",
|
||||||
|
["Classement pénal sans suite"]: "Procédure Pénale",
|
||||||
|
["Enquête sociale"]: "Procédure Civile",
|
||||||
|
["Information préoccupante"]: "Procédure Civile",
|
||||||
|
["Juge pour enfants"]: "Procédure Civile",
|
||||||
|
["Tribunal correctionnel"]: "Procédure Pénale",
|
||||||
|
["Convocation CRPC"]: "Procédure Pénale",
|
||||||
|
["Plaidoirie"]: "Procédure Pénale",
|
||||||
|
["Audience CRPC"]: "Procédure Pénale",
|
||||||
|
["Refus CRPC"]: "Procédure Pénale",
|
||||||
|
["Audition des enfants"]: "Procédure Civile",
|
||||||
|
["Assistance éducative"]: "Procédure Civile",
|
||||||
|
["Contrôle forcé"]: "Autre",
|
||||||
|
["Refus de contrôle"]: "Autre",
|
||||||
|
["Rappel à la loi"]: "Procédure Pénale",
|
||||||
|
["Passage police municipale"]: "Procédure Pénale",
|
||||||
|
["Administrateur AD'HOC"]: "Autre",
|
||||||
|
["Validation désobéissance"]: "Autre",
|
||||||
|
};
|
||||||
|
|
||||||
|
export type CategorieEvenement =
|
||||||
|
| "Procédure Pénale"
|
||||||
|
| "Procédure Civile"
|
||||||
|
| "Autre";
|
||||||
|
|
||||||
|
export function isEvenementInPeriod(
|
||||||
|
evt: EvenementFamille,
|
||||||
|
period: Period
|
||||||
|
): unknown {
|
||||||
|
return evt.Date && isPeriodContaining(period, evt.Date);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isEvenementBefore(evt: EvenementFamille, date: Date): unknown {
|
||||||
|
return evt.Date !== null && evt.Date < date;
|
||||||
|
}
|
||||||
|
|
@ -2,6 +2,9 @@ import { differenceInDays } from "date-fns";
|
||||||
import { Period } from "../period/Period";
|
import { Period } from "../period/Period";
|
||||||
import { arePeriodsOverlaping } from "../period/arePeriodsOverlaping";
|
import { arePeriodsOverlaping } from "../period/arePeriodsOverlaping";
|
||||||
import { isPeriodContaining } from "../period/isPeriodContaining";
|
import { isPeriodContaining } from "../period/isPeriodContaining";
|
||||||
|
import { ContexteEntreeDC } from "./ContexteEntreeDC";
|
||||||
|
import { EvenementFamille } from "./EvenementFamille";
|
||||||
|
import { StatutFamille } from "./StatutFamille";
|
||||||
|
|
||||||
export type Famille = {
|
export type Famille = {
|
||||||
notionId: string;
|
notionId: string;
|
||||||
|
|
@ -13,38 +16,6 @@ export type Famille = {
|
||||||
Evenements: EvenementFamille[];
|
Evenements: EvenementFamille[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export type EvenementFamille = {
|
|
||||||
notionId: string;
|
|
||||||
notionIdFamille: string;
|
|
||||||
Évènement: string;
|
|
||||||
Date: Date | null;
|
|
||||||
Type: TypeEvenement;
|
|
||||||
"Enfants concernés": string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type ContexteEntreeDC =
|
|
||||||
| "Pas de demande (Plein droit)"
|
|
||||||
| "Pas de demande"
|
|
||||||
| "Après refus"
|
|
||||||
| "Après mise en demeure"
|
|
||||||
| "Après poursuite procureur";
|
|
||||||
|
|
||||||
export type TypeEvenement =
|
|
||||||
| "Mise en demeure de scolarisation"
|
|
||||||
| "Composition pénale refusée"
|
|
||||||
| "Composition pénale acceptée";
|
|
||||||
|
|
||||||
export type StatutFamille =
|
|
||||||
| "Résistant.e"
|
|
||||||
| "Ex résistant·e·s"
|
|
||||||
| "À préciser"
|
|
||||||
| "Se questionne"
|
|
||||||
| "Désobéissence décidée"
|
|
||||||
| "Rédaction Déclaration"
|
|
||||||
| "Déclaration Validée - Attente éléments"
|
|
||||||
| "Abdandon"
|
|
||||||
| "Incompatible";
|
|
||||||
|
|
||||||
export function periodOfResistance(
|
export function periodOfResistance(
|
||||||
family: Famille,
|
family: Famille,
|
||||||
atDate: Date = new Date(Date.now())
|
atDate: Date = new Date(Date.now())
|
||||||
|
|
|
||||||
10
src/data/StatutFamille.ts
Normal file
10
src/data/StatutFamille.ts
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
export type StatutFamille =
|
||||||
|
| "Résistant.e"
|
||||||
|
| "Ex résistant·e·s"
|
||||||
|
| "À préciser"
|
||||||
|
| "Se questionne"
|
||||||
|
| "Désobéissence décidée"
|
||||||
|
| "Rédaction Déclaration"
|
||||||
|
| "Déclaration Validée - Attente éléments"
|
||||||
|
| "Abdandon"
|
||||||
|
| "Incompatible";
|
||||||
30
src/data/TypeEvenement.ts
Normal file
30
src/data/TypeEvenement.ts
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
export type TypeEvenement =
|
||||||
|
| "Récidive gendarmerie"
|
||||||
|
| "Appel du jugement"
|
||||||
|
| "Tribunal de police judiciaire"
|
||||||
|
| "Signalement au procureur"
|
||||||
|
| "Mise en demeure de scolarisation"
|
||||||
|
| "Signalement"
|
||||||
|
| "Audition gendarmerie / police"
|
||||||
|
| "Convocation procureur"
|
||||||
|
| "Audition procureur"
|
||||||
|
| "Composition pénale refusée"
|
||||||
|
| "Composition pénale acceptée"
|
||||||
|
| "Classement social sans suite"
|
||||||
|
| "Classement pénal sans suite"
|
||||||
|
| "Enquête sociale"
|
||||||
|
| "Information préoccupante"
|
||||||
|
| "Juge pour enfants"
|
||||||
|
| "Tribunal correctionnel"
|
||||||
|
| "Convocation CRPC"
|
||||||
|
| "Plaidoirie"
|
||||||
|
| "Audience CRPC"
|
||||||
|
| "Refus CRPC"
|
||||||
|
| "Audition des enfants"
|
||||||
|
| "Assistance éducative"
|
||||||
|
| "Contrôle forcé"
|
||||||
|
| "Refus de contrôle"
|
||||||
|
| "Rappel à la loi"
|
||||||
|
| "Passage police municipale"
|
||||||
|
| "Administrateur AD'HOC"
|
||||||
|
| "Validation désobéissance";
|
||||||
|
|
@ -30,7 +30,7 @@ import { computeELStats } from "./statistiques/computeELStats";
|
||||||
const currentDate = new Date(Date.now());
|
const currentDate = new Date(Date.now());
|
||||||
|
|
||||||
console.log("Building statistics...");
|
console.log("Building statistics...");
|
||||||
const resistantCountStats = computeELStats(families);
|
const resistantCountStats = computeELStats(families, currentDate);
|
||||||
|
|
||||||
console.log("Publishing statistics...");
|
console.log("Publishing statistics...");
|
||||||
publishStatisticsToNotion(resistantCountStats, currentDate, notionClient);
|
publishStatisticsToNotion(resistantCountStats, currentDate, notionClient);
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,10 @@
|
||||||
import { Client, isFullPage } from "@notionhq/client";
|
import { Client, isFullPage } from "@notionhq/client";
|
||||||
import { PageObjectResponse } from "@notionhq/client/build/src/api-endpoints";
|
import { PageObjectResponse } from "@notionhq/client/build/src/api-endpoints";
|
||||||
import {
|
import { ContexteEntreeDC } from "../../data/ContexteEntreeDC";
|
||||||
ContexteEntreeDC,
|
import { EvenementFamille } from "../../data/EvenementFamille";
|
||||||
EvenementFamille,
|
import { Famille } from "../../data/Famille";
|
||||||
Famille,
|
import { StatutFamille } from "../../data/StatutFamille";
|
||||||
StatutFamille,
|
import { TypeEvenement } from "../../data/TypeEvenement";
|
||||||
TypeEvenement,
|
|
||||||
} from "../../data/Famille";
|
|
||||||
import { datePropertyToDate } from "../utils/properties/datePropertyToDate";
|
import { datePropertyToDate } from "../utils/properties/datePropertyToDate";
|
||||||
import { relationPropertyToPageId } from "../utils/properties/relationPropertyToPageId";
|
import { relationPropertyToPageId } from "../utils/properties/relationPropertyToPageId";
|
||||||
import { selectPropertyToText } from "../utils/properties/selectPropertyToText";
|
import { selectPropertyToText } from "../utils/properties/selectPropertyToText";
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { StatPublishOptions } from "../../statPropsPublishOptions";
|
import { StatPublishOptions } from "../../statPublishOptions";
|
||||||
|
|
||||||
export function formatValue(value: number, publishOptions: StatPublishOptions) {
|
export function formatValue(value: number, publishOptions: StatPublishOptions) {
|
||||||
const valueStr = value.toLocaleString("fr-FR", {
|
const valueStr = value.toLocaleString("fr-FR", {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { ValueWithEvol } from "../../../statistiques/ELStats";
|
import { ValueWithEvol } from "../../../statistiques/ELStats";
|
||||||
import { StatPublishOptions } from "../../statPropsPublishOptions";
|
import { StatPublishOptions } from "../../statPublishOptions";
|
||||||
import { formatValue } from "./formatValue";
|
import { formatValue } from "./formatValue";
|
||||||
|
|
||||||
export function formatValueWithEvol(
|
export function formatValueWithEvol(
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,30 @@
|
||||||
import { Client, isFullPage } from "@notionhq/client";
|
import { Client, isFullPage } from "@notionhq/client";
|
||||||
import { PageObjectResponse } from "@notionhq/client/build/src/api-endpoints";
|
|
||||||
import { ELPeriodStats, ValueWithEvol } from "../../statistiques/ELStats";
|
|
||||||
import {
|
import {
|
||||||
StatPublishOptions,
|
PageObjectResponse,
|
||||||
statPropsPublishOptions,
|
UpdateDatabaseParameters,
|
||||||
} from "../statPropsPublishOptions";
|
} from "@notionhq/client/build/src/api-endpoints";
|
||||||
|
import {
|
||||||
|
ELStatsPeriod,
|
||||||
|
PeriodStatsValues,
|
||||||
|
ValueWithEvol,
|
||||||
|
} from "../../statistiques/ELStats";
|
||||||
|
import { StatPublishOptions, statPublishOptions } from "../statPublishOptions";
|
||||||
import { titlePropertyToText } from "../utils/properties/titlePropertyToText";
|
import { titlePropertyToText } from "../utils/properties/titlePropertyToText";
|
||||||
import { queryAllDbResults } from "../utils/queryAllDbResults";
|
import { queryAllDbResults } from "../utils/queryAllDbResults";
|
||||||
import { removeBlocks } from "../utils/removeBlocks";
|
import { removeBlocks } from "../utils/removeBlocks";
|
||||||
import { CreatePageProperties } from "../utils/types/CreatePageProperties";
|
import { CreatePageProperties } from "../utils/types/CreatePageProperties";
|
||||||
import { formatValueWithEvol } from "./format/formatValueWithEvol";
|
import { formatValueWithEvol } from "./format/formatValueWithEvol";
|
||||||
|
|
||||||
|
const periodeDbPropertyName = "Période";
|
||||||
|
|
||||||
export async function publishPeriodStats(
|
export async function publishPeriodStats(
|
||||||
notionClient: Client,
|
notionClient: Client,
|
||||||
periodStatsDbId: string,
|
periodStatsDbId: string,
|
||||||
stats: ELPeriodStats[]
|
statsPeriods: ELStatsPeriod[]
|
||||||
) {
|
) {
|
||||||
|
if (statsPeriods.length > 0) {
|
||||||
|
await updateDbProps(notionClient, periodStatsDbId, statsPeriods[0].stats);
|
||||||
|
}
|
||||||
const periodRows = (
|
const periodRows = (
|
||||||
await queryAllDbResults(notionClient, {
|
await queryAllDbResults(notionClient, {
|
||||||
database_id: periodStatsDbId,
|
database_id: periodStatsDbId,
|
||||||
|
|
@ -24,11 +33,14 @@ export async function publishPeriodStats(
|
||||||
|
|
||||||
const indexedPeriodRows: { [period: string]: PageObjectResponse } =
|
const indexedPeriodRows: { [period: string]: PageObjectResponse } =
|
||||||
Object.fromEntries(
|
Object.fromEntries(
|
||||||
periodRows.map((r) => [titlePropertyToText(r.properties, "Période"), r])
|
periodRows.map((r) => [
|
||||||
|
titlePropertyToText(r.properties, periodeDbPropertyName),
|
||||||
|
r,
|
||||||
|
])
|
||||||
);
|
);
|
||||||
|
|
||||||
const indexedPeriodStats = Object.fromEntries(
|
const indexedPeriodStats = Object.fromEntries(
|
||||||
stats.map((stat) => [stat.periodId, stat])
|
statsPeriods.map((stat) => [stat.periodId, stat])
|
||||||
);
|
);
|
||||||
|
|
||||||
const rowIdsToDelete = Object.entries(indexedPeriodRows)
|
const rowIdsToDelete = Object.entries(indexedPeriodRows)
|
||||||
|
|
@ -76,15 +88,59 @@ export async function publishPeriodStats(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function updateDbProps(
|
||||||
|
notionClient: Client,
|
||||||
|
periodStatsDbId: string,
|
||||||
|
stats: PeriodStatsValues<ValueWithEvol>
|
||||||
|
) {
|
||||||
|
const db = await notionClient.databases.retrieve({
|
||||||
|
database_id: periodStatsDbId,
|
||||||
|
});
|
||||||
|
const statsNotionProps: UpdateDatabaseParameters["properties"] =
|
||||||
|
Object.fromEntries(
|
||||||
|
(Object.keys(stats) as Array<keyof PeriodStatsValues<ValueWithEvol>>).map(
|
||||||
|
(jsProp) => {
|
||||||
|
const publishOptions = statPublishOptions(jsProp);
|
||||||
|
return [
|
||||||
|
publishOptions.notionPropName,
|
||||||
|
{
|
||||||
|
rich_text: {},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
const propsToRemove = Object.fromEntries(
|
||||||
|
Object.keys(db.properties)
|
||||||
|
.filter(
|
||||||
|
(k) =>
|
||||||
|
!Object.prototype.hasOwnProperty.call(statsNotionProps, k) &&
|
||||||
|
k !== periodeDbPropertyName
|
||||||
|
)
|
||||||
|
.map((k) => [k, null])
|
||||||
|
);
|
||||||
|
|
||||||
|
await notionClient.databases.update({
|
||||||
|
database_id: periodStatsDbId,
|
||||||
|
properties: {
|
||||||
|
[periodeDbPropertyName]: {
|
||||||
|
title: {},
|
||||||
|
},
|
||||||
|
...statsNotionProps,
|
||||||
|
...propsToRemove,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function buildRowPropertiesForUpsert(
|
function buildRowPropertiesForUpsert(
|
||||||
periodId: string,
|
periodId: string,
|
||||||
stats: ELPeriodStats["stats"]
|
stats: PeriodStatsValues<ValueWithEvol>
|
||||||
): CreatePageProperties {
|
): CreatePageProperties {
|
||||||
const statsNotionProps: CreatePageProperties = Object.fromEntries(
|
const statsNotionProps: CreatePageProperties = Object.fromEntries(
|
||||||
(Object.keys(stats) as Array<keyof ELPeriodStats["stats"]>).map(
|
(Object.keys(stats) as Array<keyof PeriodStatsValues<ValueWithEvol>>).map(
|
||||||
(jsProp) => {
|
(jsProp) => {
|
||||||
const value: ValueWithEvol = stats[jsProp];
|
const value: ValueWithEvol = stats[jsProp];
|
||||||
const publishOptions = statPropsPublishOptions[jsProp];
|
const publishOptions = statPublishOptions(jsProp);
|
||||||
return [
|
return [
|
||||||
publishOptions.notionPropName,
|
publishOptions.notionPropName,
|
||||||
valueWithEvolProp(value, publishOptions),
|
valueWithEvolProp(value, publishOptions),
|
||||||
|
|
@ -93,7 +149,7 @@ function buildRowPropertiesForUpsert(
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
return {
|
return {
|
||||||
Période: {
|
[periodeDbPropertyName]: {
|
||||||
title: [
|
title: [
|
||||||
{
|
{
|
||||||
text: {
|
text: {
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,7 @@
|
||||||
import { Client, isFullBlock } from "@notionhq/client";
|
import { Client, isFullBlock } from "@notionhq/client";
|
||||||
import { BlockObjectRequest } from "@notionhq/client/build/src/api-endpoints";
|
import { BlockObjectRequest } from "@notionhq/client/build/src/api-endpoints";
|
||||||
import { ELStatsActuelles } from "../../statistiques/ELStats";
|
import { ELStatsAtDate } from "../../statistiques/ELStats";
|
||||||
import {
|
import { StatPublishOptions, statPublishOptions } from "../statPublishOptions";
|
||||||
StatPublishOptions,
|
|
||||||
statPropsPublishOptions,
|
|
||||||
} from "../statPropsPublishOptions";
|
|
||||||
import { listAllChildrenBlocks } from "../utils/listAllChildrenBlocks";
|
import { listAllChildrenBlocks } from "../utils/listAllChildrenBlocks";
|
||||||
import { removeBlocks } from "../utils/removeBlocks";
|
import { removeBlocks } from "../utils/removeBlocks";
|
||||||
import { richTextToPlainText } from "../utils/text/richTextToPlainText";
|
import { richTextToPlainText } from "../utils/text/richTextToPlainText";
|
||||||
|
|
@ -13,13 +10,13 @@ import { currentStatsHeading, statsPageId } from "./publishStatisticsToNotion";
|
||||||
|
|
||||||
export async function publishStatsActuelles(
|
export async function publishStatsActuelles(
|
||||||
notionClient: Client,
|
notionClient: Client,
|
||||||
statsActuelles: ELStatsActuelles
|
statsActuelles: ELStatsAtDate<number>
|
||||||
) {
|
) {
|
||||||
const newBlocks = (
|
const newBlocks = (
|
||||||
Object.keys(statsActuelles) as Array<keyof ELStatsActuelles>
|
Object.keys(statsActuelles) as Array<keyof typeof statsActuelles>
|
||||||
).map((jsProp) => {
|
).map((jsProp) => {
|
||||||
const value: number = statsActuelles[jsProp];
|
const value: number = statsActuelles[jsProp];
|
||||||
const publishOptions = statPropsPublishOptions[jsProp];
|
const publishOptions = statPublishOptions(jsProp);
|
||||||
return currentStatBlock(value, publishOptions);
|
return currentStatBlock(value, publishOptions);
|
||||||
});
|
});
|
||||||
await updateStatsActuellesBlocks(notionClient, newBlocks);
|
await updateStatsActuellesBlocks(notionClient, newBlocks);
|
||||||
|
|
|
||||||
|
|
@ -1,41 +0,0 @@
|
||||||
import { ELPeriodStats, ELStatsActuelles } from "../statistiques/ELStats";
|
|
||||||
|
|
||||||
export const statPropsPublishOptions: {
|
|
||||||
[jsPropName in statsPropNames]: StatPublishOptions;
|
|
||||||
} = {
|
|
||||||
nbFamilleResistantes: {
|
|
||||||
notionPropName: "Nb familles résistantes",
|
|
||||||
},
|
|
||||||
nbFamilleResistantesOrEx: {
|
|
||||||
notionPropName: "Nb familles résistantes ou ex-résistantes",
|
|
||||||
},
|
|
||||||
dureeResistanceMoyenne: {
|
|
||||||
notionPropName: "Durée résistance moyenne",
|
|
||||||
unit: "j",
|
|
||||||
},
|
|
||||||
dureeResistanceMediane: {
|
|
||||||
notionPropName: "Durée résistance médiane",
|
|
||||||
unit: "j",
|
|
||||||
},
|
|
||||||
nbFamillesMisesEnDemeure: {
|
|
||||||
notionPropName: "Nb familles mises en demeure",
|
|
||||||
},
|
|
||||||
pourcentageFamillesMisesEnDemeure: {
|
|
||||||
notionPropName: "Pourcentage de familles mises en demeure",
|
|
||||||
unit: "%",
|
|
||||||
},
|
|
||||||
pourcentageEntreeApresMiseEnDemeure: {
|
|
||||||
notionPropName: "Pourcentage d'entrées après mises en demeure",
|
|
||||||
unit: "%",
|
|
||||||
},
|
|
||||||
};
|
|
||||||
export type statsPropNames =
|
|
||||||
| keyof ELPeriodStats["stats"]
|
|
||||||
| keyof ELStatsActuelles;
|
|
||||||
export type StatPublishOptions = {
|
|
||||||
notionPropName: string;
|
|
||||||
unit?: string;
|
|
||||||
valueMaxFractioDigits?: number;
|
|
||||||
evolMaxFractioDigits?: number;
|
|
||||||
evolPctMaxFractioDigits?: number;
|
|
||||||
};
|
|
||||||
71
src/notion/statPublishOptions.ts
Normal file
71
src/notion/statPublishOptions.ts
Normal file
|
|
@ -0,0 +1,71 @@
|
||||||
|
import { AllStatsPropNames } from "../statistiques/ELStats";
|
||||||
|
|
||||||
|
export function statPublishOptions(
|
||||||
|
statJsPropName: AllStatsPropNames
|
||||||
|
): StatPublishOptions {
|
||||||
|
return statPropsPublishOptions[statJsPropName];
|
||||||
|
}
|
||||||
|
const statPropsPublishOptions: {
|
||||||
|
[jsPropName in AllStatsPropNames]: StatPublishOptions;
|
||||||
|
} = {
|
||||||
|
nbFamilleResistantes: {
|
||||||
|
notionPropName: "Nb familles résistantes",
|
||||||
|
},
|
||||||
|
|
||||||
|
nbFamilleResistantesSurPeriode: {
|
||||||
|
notionPropName: "Nb familles résistantes sur période",
|
||||||
|
},
|
||||||
|
nbFamilleResistantesOrEx: {
|
||||||
|
notionPropName: "Nb familles résistantes ou ex-résistantes",
|
||||||
|
},
|
||||||
|
dureeResistanceMoyenne: {
|
||||||
|
notionPropName: "Durée résistance moyenne",
|
||||||
|
unit: "j",
|
||||||
|
},
|
||||||
|
dureeResistanceMediane: {
|
||||||
|
notionPropName: "Durée résistance médiane",
|
||||||
|
unit: "j",
|
||||||
|
},
|
||||||
|
nbFamillesMisesEnDemeure: {
|
||||||
|
notionPropName: "Nb familles mises en demeure",
|
||||||
|
},
|
||||||
|
pourcentageFamillesMisesEnDemeure: {
|
||||||
|
notionPropName: "% de familles mises en demeure",
|
||||||
|
unit: "%",
|
||||||
|
},
|
||||||
|
pourcentageEntreeApresMiseEnDemeure: {
|
||||||
|
notionPropName: "% d'entrées après mises en demeure",
|
||||||
|
unit: "%",
|
||||||
|
},
|
||||||
|
pourcentageEntreeApresMiseEnDemeureSurPeriode: {
|
||||||
|
notionPropName: "% d'entrées après mises en demeure sur période",
|
||||||
|
},
|
||||||
|
nbFamillesProcedurePenale: {
|
||||||
|
notionPropName: "Nb familles avec procédure pénale",
|
||||||
|
},
|
||||||
|
pourcentageFamillesProcedurePenale: {
|
||||||
|
notionPropName: "% familles avec procédure pénale",
|
||||||
|
unit: "%",
|
||||||
|
},
|
||||||
|
nbFamilleAvecProcedurePenaleSurPeriode: {
|
||||||
|
notionPropName: "Nb familles avec procédure pénale sur période",
|
||||||
|
},
|
||||||
|
|
||||||
|
nbFamillesProcedureCivile: {
|
||||||
|
notionPropName: "Nb familles avec procédure civile",
|
||||||
|
},
|
||||||
|
pourcentageFamillesProcedureCivile: {
|
||||||
|
notionPropName: "% familles avec procédure civile",
|
||||||
|
unit: "%",
|
||||||
|
},
|
||||||
|
nbFamilleAvecProcedureCivileSurPeriode: {
|
||||||
|
notionPropName: "Nb familles avec procédure civile sur période",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
export type StatPublishOptions = {
|
||||||
|
notionPropName: string;
|
||||||
|
unit?: string;
|
||||||
|
valueMaxFractioDigits?: number;
|
||||||
|
evolMaxFractioDigits?: number;
|
||||||
|
evolPctMaxFractioDigits?: number;
|
||||||
|
};
|
||||||
|
|
@ -1,29 +1,36 @@
|
||||||
export type ELStats = {
|
export type ELStats = {
|
||||||
actuelles: ELStatsActuelles;
|
actuelles: ELStatsAtDate<number>;
|
||||||
annees: ELPeriodStats[];
|
annees: ELStatsPeriod[];
|
||||||
|
|
||||||
mois: ELPeriodStats[];
|
mois: ELStatsPeriod[];
|
||||||
};
|
|
||||||
export type ELStatsActuelles = {
|
|
||||||
nbFamilleResistantes: number;
|
|
||||||
nbFamilleResistantesOrEx: number;
|
|
||||||
dureeResistanceMoyenne: number;
|
|
||||||
dureeResistanceMediane: number;
|
|
||||||
nbFamillesMisesEnDemeure: number;
|
|
||||||
pourcentageFamillesMisesEnDemeure: number;
|
|
||||||
pourcentageEntreeApresMiseEnDemeure: number;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ELPeriodStats = {
|
export type ELStatsAtDate<V> = {
|
||||||
|
nbFamilleResistantes: V;
|
||||||
|
nbFamilleResistantesOrEx: V;
|
||||||
|
dureeResistanceMoyenne: V;
|
||||||
|
dureeResistanceMediane: V;
|
||||||
|
nbFamillesMisesEnDemeure: V;
|
||||||
|
pourcentageFamillesMisesEnDemeure: V;
|
||||||
|
pourcentageEntreeApresMiseEnDemeure: V;
|
||||||
|
nbFamillesProcedurePenale: V;
|
||||||
|
pourcentageFamillesProcedurePenale: V;
|
||||||
|
nbFamillesProcedureCivile: V;
|
||||||
|
pourcentageFamillesProcedureCivile: V;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ELStatsPeriod = {
|
||||||
periodId: string;
|
periodId: string;
|
||||||
stats: {
|
stats: PeriodStatsValues<ValueWithEvol>;
|
||||||
nbFamilleResistantes: ValueWithEvol;
|
};
|
||||||
nbFamilleResistantesOrEx: ValueWithEvol;
|
|
||||||
dureeResistanceMoyenne: ValueWithEvol;
|
export type PeriodStatsValues<V> = ELStatsAtDate<V> | ELStatsOverPeriod<V>;
|
||||||
dureeResistanceMediane: ValueWithEvol;
|
|
||||||
nbFamillesMisesEnDemeure: ValueWithEvol;
|
export type ELStatsOverPeriod<V> = {
|
||||||
pourcentageEntreeApresMiseEnDemeure: ValueWithEvol;
|
pourcentageEntreeApresMiseEnDemeureSurPeriode: V;
|
||||||
};
|
nbFamilleResistantesSurPeriode: V;
|
||||||
|
nbFamilleAvecProcedurePenaleSurPeriode: V;
|
||||||
|
nbFamilleAvecProcedureCivileSurPeriode: V;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ValueWithEvol = {
|
export type ValueWithEvol = {
|
||||||
|
|
@ -31,3 +38,7 @@ export type ValueWithEvol = {
|
||||||
evol: number;
|
evol: number;
|
||||||
evolPercent: number;
|
evolPercent: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type AllStatsPropNames =
|
||||||
|
| keyof ELStatsOverPeriod<number>
|
||||||
|
| keyof ELStatsAtDate<number>;
|
||||||
|
|
|
||||||
|
|
@ -1,94 +1,68 @@
|
||||||
import {
|
import { Famille } from "../data/Famille";
|
||||||
Famille,
|
|
||||||
dureeResistanceInDays,
|
|
||||||
isResistantOverPeriod,
|
|
||||||
periodOfResistance,
|
|
||||||
} from "../data/Famille";
|
|
||||||
import { IdentifiedPeriod } from "../period/IdentifiedPeriod";
|
import { IdentifiedPeriod } from "../period/IdentifiedPeriod";
|
||||||
import { isPeriodContaining } from "../period/isPeriodContaining";
|
import { Period } from "../period/Period";
|
||||||
import { ELPeriodStats, ValueWithEvol } from "./ELStats";
|
import {
|
||||||
import { average } from "./math/average";
|
ELStatsOverPeriod,
|
||||||
import { median } from "./math/median";
|
ELStatsPeriod,
|
||||||
|
PeriodStatsValues,
|
||||||
|
ValueWithEvol,
|
||||||
|
} from "./ELStats";
|
||||||
|
import { computeELStatsAtDate } from "./computeELStatsAtDate";
|
||||||
|
import { computeELStatsOverPeriod } from "./computeELStatsOverPeriod";
|
||||||
|
|
||||||
export function computeELPeriodStats(
|
export function computeELPeriodStats(
|
||||||
familles: Famille[],
|
familles: Famille[],
|
||||||
periods: IdentifiedPeriod[]
|
periods: IdentifiedPeriod[]
|
||||||
): ELPeriodStats[] {
|
): ELStatsPeriod[] {
|
||||||
const periodStats: ELPeriodStats[] = [];
|
let previousPeriodStatNumberValues: PeriodStatsValues<number> | null = null;
|
||||||
let previousELPeriodStats: ELPeriodStats["stats"] | null = null;
|
return periods.map((period) => {
|
||||||
for (const period of periods) {
|
const periodStatNumberValues: PeriodStatsValues<number> =
|
||||||
const periodEndOrNow =
|
computePeriodStatsNumberValues(familles, period);
|
||||||
period.end.getTime() > Date.now() ? new Date(Date.now()) : period.end;
|
|
||||||
|
|
||||||
const nbFamilleResistantes = familles.filter((famille) =>
|
// Compute evol
|
||||||
isResistantOverPeriod(famille, period)
|
const statsWithEvol = computeStatsEvol(
|
||||||
).length;
|
periodStatNumberValues,
|
||||||
|
previousPeriodStatNumberValues
|
||||||
const nbFamilleResistantesOrEx = familles.filter((famille) => {
|
|
||||||
const por = periodOfResistance(famille, periodEndOrNow);
|
|
||||||
return por !== null && por.start < periodEndOrNow;
|
|
||||||
}).length;
|
|
||||||
|
|
||||||
const dureesResistances = familles
|
|
||||||
.map((famille) => dureeResistanceInDays(famille, periodEndOrNow))
|
|
||||||
.filter(notNull);
|
|
||||||
const dureeResistanceMediane = Math.round(median(dureesResistances));
|
|
||||||
const dureeResistanceMoyenne = Math.round(average(dureesResistances));
|
|
||||||
|
|
||||||
const nbFamillesMiseEnDemeure = familles.filter((famille) =>
|
|
||||||
famille.Evenements.find(
|
|
||||||
(e) =>
|
|
||||||
e.Type === "Mise en demeure de scolarisation" &&
|
|
||||||
e.Date &&
|
|
||||||
isPeriodContaining(period, e.Date)
|
|
||||||
)
|
|
||||||
).length;
|
|
||||||
const famillesEntreesOverPeriod = familles.filter((f) => {
|
|
||||||
const por = periodOfResistance(f);
|
|
||||||
return por != null && isPeriodContaining(period, por.start);
|
|
||||||
});
|
|
||||||
const entreeApresMiseEnDemeure = famillesEntreesOverPeriod.filter(
|
|
||||||
(f) =>
|
|
||||||
f.ContexteEntree === "Après mise en demeure" ||
|
|
||||||
f.ContexteEntree === "Après poursuite procureur"
|
|
||||||
);
|
);
|
||||||
const pourcentageEntreeApresMiseEnDemeure =
|
previousPeriodStatNumberValues = periodStatNumberValues;
|
||||||
(100 * entreeApresMiseEnDemeure.length) /
|
const periodStats: ELStatsPeriod = {
|
||||||
famillesEntreesOverPeriod.length;
|
|
||||||
|
|
||||||
const stats: ELPeriodStats = {
|
|
||||||
periodId: period.id,
|
periodId: period.id,
|
||||||
stats: {
|
stats: statsWithEvol,
|
||||||
nbFamilleResistantes: valueWithEvol(
|
|
||||||
nbFamilleResistantes,
|
|
||||||
previousELPeriodStats?.nbFamilleResistantes.value
|
|
||||||
),
|
|
||||||
nbFamilleResistantesOrEx: valueWithEvol(
|
|
||||||
nbFamilleResistantesOrEx,
|
|
||||||
previousELPeriodStats?.nbFamilleResistantesOrEx.value
|
|
||||||
),
|
|
||||||
dureeResistanceMediane: valueWithEvol(
|
|
||||||
dureeResistanceMediane,
|
|
||||||
previousELPeriodStats?.dureeResistanceMediane.value
|
|
||||||
),
|
|
||||||
dureeResistanceMoyenne: valueWithEvol(
|
|
||||||
dureeResistanceMoyenne,
|
|
||||||
previousELPeriodStats?.dureeResistanceMoyenne.value
|
|
||||||
),
|
|
||||||
nbFamillesMisesEnDemeure: valueWithEvol(
|
|
||||||
nbFamillesMiseEnDemeure,
|
|
||||||
previousELPeriodStats?.nbFamillesMisesEnDemeure.value
|
|
||||||
),
|
|
||||||
pourcentageEntreeApresMiseEnDemeure: valueWithEvol(
|
|
||||||
pourcentageEntreeApresMiseEnDemeure,
|
|
||||||
previousELPeriodStats?.pourcentageEntreeApresMiseEnDemeure.value
|
|
||||||
),
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
periodStats.push(stats);
|
return periodStats;
|
||||||
previousELPeriodStats = stats?.stats;
|
});
|
||||||
}
|
}
|
||||||
return periodStats;
|
|
||||||
|
function computePeriodStatsNumberValues(
|
||||||
|
familles: Famille[],
|
||||||
|
period: Period
|
||||||
|
): PeriodStatsValues<number> {
|
||||||
|
const statsAtPeriodEnd = computeELStatsAtDate(familles, period.end);
|
||||||
|
|
||||||
|
const statsOverPeriod: ELStatsOverPeriod<number> = computeELStatsOverPeriod(
|
||||||
|
familles,
|
||||||
|
period
|
||||||
|
);
|
||||||
|
return {
|
||||||
|
...statsAtPeriodEnd,
|
||||||
|
...statsOverPeriod,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function computeStatsEvol(
|
||||||
|
periodStatNumberValues: PeriodStatsValues<number>,
|
||||||
|
previousPeriodStatNumberValues: PeriodStatsValues<number> | null | undefined
|
||||||
|
): PeriodStatsValues<ValueWithEvol> {
|
||||||
|
return Object.fromEntries(
|
||||||
|
(
|
||||||
|
Object.entries(periodStatNumberValues) as Array<
|
||||||
|
[prop: keyof PeriodStatsValues<number>, number]
|
||||||
|
>
|
||||||
|
).map(([k, v]) => [
|
||||||
|
k,
|
||||||
|
valueWithEvol(v, previousPeriodStatNumberValues?.[k]),
|
||||||
|
])
|
||||||
|
) as PeriodStatsValues<ValueWithEvol>;
|
||||||
}
|
}
|
||||||
|
|
||||||
function valueWithEvol(
|
function valueWithEvol(
|
||||||
|
|
@ -111,9 +85,3 @@ function evol(current: number, previous: number | undefined): number {
|
||||||
if (previous === undefined) return NaN;
|
if (previous === undefined) return NaN;
|
||||||
return current - previous;
|
return current - previous;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Typescript is not able to infer this inline see
|
|
||||||
// https://stackoverflow.com/questions/43118692/typescript-filter-out-nulls-from-an-array
|
|
||||||
function notNull<TValue>(value: TValue | null): value is TValue {
|
|
||||||
return value !== null;
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,19 @@
|
||||||
import { Famille } from "../data/Famille";
|
import { Famille } from "../data/Famille";
|
||||||
import { ELStats } from "./ELStats";
|
import { ELStats } from "./ELStats";
|
||||||
import { computeELPeriodStats } from "./computeELPeriodStats";
|
import { computeELPeriodStats } from "./computeELPeriodStats";
|
||||||
import { computeStatsActuelles } from "./computeStatsActuelles";
|
import { computeELStatsAtDate } from "./computeELStatsAtDate";
|
||||||
import { generateELMonths } from "./generateELMonths";
|
import { generateELMonths } from "./generateELMonths";
|
||||||
import { generateELYears } from "./generateELYears";
|
import { generateELYears } from "./generateELYears";
|
||||||
|
|
||||||
export function computeELStats(families: Famille[]): ELStats {
|
export function computeELStats(
|
||||||
const actuelles = computeStatsActuelles(families);
|
families: Famille[],
|
||||||
const elYears = generateELYears();
|
currentDate: Date
|
||||||
const yearsStats = computeELPeriodStats(families, elYears);
|
): ELStats {
|
||||||
|
const actuelles = computeELStatsAtDate(families, currentDate);
|
||||||
|
|
||||||
const months = generateELMonths();
|
const yearsStats = computeELPeriodStats(families, generateELYears());
|
||||||
const monthsStats = computeELPeriodStats(families, months);
|
|
||||||
|
const monthsStats = computeELPeriodStats(families, generateELMonths());
|
||||||
|
|
||||||
return {
|
return {
|
||||||
actuelles: actuelles,
|
actuelles: actuelles,
|
||||||
|
|
|
||||||
74
src/statistiques/computeELStatsAtDate.ts
Normal file
74
src/statistiques/computeELStatsAtDate.ts
Normal file
|
|
@ -0,0 +1,74 @@
|
||||||
|
import { isEvenementBefore, isProcedurePenale } from "../data/EvenementFamille";
|
||||||
|
import {
|
||||||
|
Famille,
|
||||||
|
dureeResistanceInDays,
|
||||||
|
isExResistant,
|
||||||
|
isResistant,
|
||||||
|
} from "../data/Famille";
|
||||||
|
import { average } from "../utils/math/average";
|
||||||
|
import { median } from "../utils/math/median";
|
||||||
|
import { percent } from "../utils/math/percent";
|
||||||
|
import { notNull } from "../utils/notNull";
|
||||||
|
import { ELStatsAtDate } from "./ELStats";
|
||||||
|
import { computePourcentageEntreeApresMiseEnDemeure } from "./computePourcentageEntreeApresMiseEnDemeure";
|
||||||
|
|
||||||
|
export function computeELStatsAtDate(
|
||||||
|
familles: Famille[],
|
||||||
|
asOfDate: Date
|
||||||
|
): ELStatsAtDate<number> {
|
||||||
|
const familleResistantes = familles.filter((f) => isResistant(f, asOfDate));
|
||||||
|
const familleResistantesOrEx = familles.filter(
|
||||||
|
(famille) =>
|
||||||
|
isResistant(famille, asOfDate) || isExResistant(famille, asOfDate)
|
||||||
|
);
|
||||||
|
const dureesResistances = familles
|
||||||
|
.map((famille) => dureeResistanceInDays(famille, asOfDate))
|
||||||
|
.filter(notNull);
|
||||||
|
|
||||||
|
const nbFamillesMiseEnDemeure = familleResistantesOrEx.filter((f) =>
|
||||||
|
f.Evenements.find((e) => e.Type === "Mise en demeure de scolarisation")
|
||||||
|
).length;
|
||||||
|
const pourcentageFamillesMisesEnDemeure = percent(
|
||||||
|
nbFamillesMiseEnDemeure,
|
||||||
|
familleResistantesOrEx.length
|
||||||
|
);
|
||||||
|
|
||||||
|
const pourcentageEntreeApresMiseEnDemeure =
|
||||||
|
computePourcentageEntreeApresMiseEnDemeure(familleResistantesOrEx);
|
||||||
|
|
||||||
|
const famillesAvecProcedurePenale = familleResistantesOrEx.filter((famille) =>
|
||||||
|
famille.Evenements.find(
|
||||||
|
(evt) => isProcedurePenale(evt) && isEvenementBefore(evt, asOfDate)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
const pourcentageFamillesProcedurePenale = percent(
|
||||||
|
famillesAvecProcedurePenale.length,
|
||||||
|
familleResistantesOrEx.length
|
||||||
|
);
|
||||||
|
const famillesAvecProcedureCivile = familleResistantesOrEx.filter((famille) =>
|
||||||
|
famille.Evenements.find(
|
||||||
|
(evt) => isProcedurePenale(evt) && isEvenementBefore(evt, asOfDate)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
const pourcentageFamillesProcedureCivile = percent(
|
||||||
|
famillesAvecProcedureCivile.length,
|
||||||
|
familleResistantesOrEx.length
|
||||||
|
);
|
||||||
|
|
||||||
|
const actuelles: ELStatsAtDate<number> = {
|
||||||
|
nbFamilleResistantes: familleResistantes.length,
|
||||||
|
nbFamilleResistantesOrEx: familleResistantesOrEx.length,
|
||||||
|
|
||||||
|
dureeResistanceMoyenne: average(dureesResistances),
|
||||||
|
dureeResistanceMediane: median(dureesResistances),
|
||||||
|
|
||||||
|
nbFamillesMisesEnDemeure: nbFamillesMiseEnDemeure,
|
||||||
|
pourcentageFamillesMisesEnDemeure: pourcentageFamillesMisesEnDemeure,
|
||||||
|
pourcentageEntreeApresMiseEnDemeure: pourcentageEntreeApresMiseEnDemeure,
|
||||||
|
nbFamillesProcedurePenale: famillesAvecProcedurePenale.length,
|
||||||
|
pourcentageFamillesProcedurePenale: pourcentageFamillesProcedurePenale,
|
||||||
|
nbFamillesProcedureCivile: famillesAvecProcedureCivile.length,
|
||||||
|
pourcentageFamillesProcedureCivile: pourcentageFamillesProcedureCivile,
|
||||||
|
};
|
||||||
|
return actuelles;
|
||||||
|
}
|
||||||
48
src/statistiques/computeELStatsOverPeriod.ts
Normal file
48
src/statistiques/computeELStatsOverPeriod.ts
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
import {
|
||||||
|
isEvenementInPeriod,
|
||||||
|
isProcedurePenale,
|
||||||
|
} from "../data/EvenementFamille";
|
||||||
|
import {
|
||||||
|
Famille,
|
||||||
|
isResistantOverPeriod,
|
||||||
|
periodOfResistance,
|
||||||
|
} from "../data/Famille";
|
||||||
|
import { Period } from "../period/Period";
|
||||||
|
import { isPeriodContaining } from "../period/isPeriodContaining";
|
||||||
|
import { ELStatsOverPeriod } from "./ELStats";
|
||||||
|
import { computePourcentageEntreeApresMiseEnDemeure } from "./computePourcentageEntreeApresMiseEnDemeure";
|
||||||
|
|
||||||
|
export function computeELStatsOverPeriod(
|
||||||
|
familles: Famille[],
|
||||||
|
period: Period
|
||||||
|
): ELStatsOverPeriod<number> {
|
||||||
|
const famillesEntreesSurPeriode = familles.filter((f) => {
|
||||||
|
const por = periodOfResistance(f);
|
||||||
|
return por != null && isPeriodContaining(period, por.start);
|
||||||
|
});
|
||||||
|
|
||||||
|
const nbFamilleResistantesSurPeriode = familles.filter((famille) =>
|
||||||
|
isResistantOverPeriod(famille, period)
|
||||||
|
).length;
|
||||||
|
const pourcentageEntreeApresMiseEnDemeureSurPeriode =
|
||||||
|
computePourcentageEntreeApresMiseEnDemeure(famillesEntreesSurPeriode);
|
||||||
|
const familleAvecProcedurePenaleSurPeriode = familles.filter((famille) =>
|
||||||
|
famille.Evenements.find(
|
||||||
|
(evt) => isProcedurePenale(evt) && isEvenementInPeriod(evt, period)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
const familleAvecProcedureCivileSurPeriode = familles.filter((famille) =>
|
||||||
|
famille.Evenements.find(
|
||||||
|
(evt) => isProcedurePenale(evt) && isEvenementInPeriod(evt, period)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
return {
|
||||||
|
nbFamilleResistantesSurPeriode,
|
||||||
|
pourcentageEntreeApresMiseEnDemeureSurPeriode,
|
||||||
|
nbFamilleAvecProcedurePenaleSurPeriode:
|
||||||
|
familleAvecProcedurePenaleSurPeriode.length,
|
||||||
|
|
||||||
|
nbFamilleAvecProcedureCivileSurPeriode:
|
||||||
|
familleAvecProcedureCivileSurPeriode.length,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
import { Famille } from "../data/Famille";
|
||||||
|
import { percent } from "../utils/math/percent";
|
||||||
|
|
||||||
|
export function computePourcentageEntreeApresMiseEnDemeure(
|
||||||
|
familles: Famille[]
|
||||||
|
) {
|
||||||
|
const entreeApresMiseEnDemeure = familles.filter(
|
||||||
|
(f) =>
|
||||||
|
f.ContexteEntree === "Après mise en demeure" ||
|
||||||
|
f.ContexteEntree === "Après poursuite procureur"
|
||||||
|
);
|
||||||
|
const pourcentageEntreeApresMiseEnDemeure = percent(
|
||||||
|
entreeApresMiseEnDemeure.length,
|
||||||
|
familles.length
|
||||||
|
);
|
||||||
|
return pourcentageEntreeApresMiseEnDemeure;
|
||||||
|
}
|
||||||
|
|
@ -1,45 +0,0 @@
|
||||||
import {
|
|
||||||
Famille,
|
|
||||||
isExResistant,
|
|
||||||
isResistant,
|
|
||||||
periodOfResistance,
|
|
||||||
} from "../data/Famille";
|
|
||||||
import { daysInPeriod } from "../period/daysInPeriod";
|
|
||||||
import { ELStatsActuelles } from "./ELStats";
|
|
||||||
import { average } from "./math/average";
|
|
||||||
import { median } from "./math/median";
|
|
||||||
|
|
||||||
export function computeStatsActuelles(familles: Famille[]): ELStatsActuelles {
|
|
||||||
const resistantsCount = familles.filter((f) => isResistant(f)).length;
|
|
||||||
const resistantsOrEx = familles.filter(
|
|
||||||
(f) => isResistant(f) || isExResistant(f)
|
|
||||||
);
|
|
||||||
const durations = resistantsOrEx.map((f) =>
|
|
||||||
daysInPeriod(periodOfResistance(f)!)
|
|
||||||
);
|
|
||||||
const dureeMoyenne = average(durations);
|
|
||||||
const dureeMediane = median(durations);
|
|
||||||
|
|
||||||
const familleAvecMiseEnDemeure = resistantsOrEx.filter((f) =>
|
|
||||||
f.Evenements.find((e) => e.Type === "Mise en demeure de scolarisation")
|
|
||||||
);
|
|
||||||
|
|
||||||
const entreeApresMiseEnDemeure = resistantsOrEx.filter(
|
|
||||||
(f) =>
|
|
||||||
f.ContexteEntree === "Après mise en demeure" ||
|
|
||||||
f.ContexteEntree === "Après poursuite procureur"
|
|
||||||
);
|
|
||||||
|
|
||||||
const actuelles: ELStatsActuelles = {
|
|
||||||
nbFamilleResistantes: resistantsCount,
|
|
||||||
nbFamilleResistantesOrEx: resistantsOrEx.length,
|
|
||||||
dureeResistanceMoyenne: dureeMoyenne,
|
|
||||||
dureeResistanceMediane: dureeMediane,
|
|
||||||
nbFamillesMisesEnDemeure: familleAvecMiseEnDemeure.length,
|
|
||||||
pourcentageFamillesMisesEnDemeure:
|
|
||||||
(100 * familleAvecMiseEnDemeure.length) / resistantsOrEx.length,
|
|
||||||
pourcentageEntreeApresMiseEnDemeure:
|
|
||||||
(100 * entreeApresMiseEnDemeure.length) / resistantsOrEx.length,
|
|
||||||
};
|
|
||||||
return actuelles;
|
|
||||||
}
|
|
||||||
3
src/utils/math/percent.ts
Normal file
3
src/utils/math/percent.ts
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
export function percent(value: number, total: number): number {
|
||||||
|
return (100 * value) / total;
|
||||||
|
}
|
||||||
5
src/utils/notNull.ts
Normal file
5
src/utils/notNull.ts
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
// Typescript is not able to infer this inline see
|
||||||
|
// https://stackoverflow.com/questions/43118692/typescript-filter-out-nulls-from-an-array
|
||||||
|
export function notNull<TValue>(value: TValue | null): value is TValue {
|
||||||
|
return value !== null;
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue