mirror of
https://framagit.org/enfance-libre/statistiques
synced 2025-12-07 07:23:44 +00:00
feat: stats pénales par dept
This commit is contained in:
parent
f2d2744b6d
commit
376a79ae85
12 changed files with 235 additions and 108 deletions
51
src/notion/publish/v2/createStatBlock.ts
Normal file
51
src/notion/publish/v2/createStatBlock.ts
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
import { BlockObjectRequest } from "@notionhq/client/build/src/api-endpoints";
|
||||
import { ValueFormatOptions } from "../../../format/ValueFormatOptions";
|
||||
import {
|
||||
StatDesc,
|
||||
StatType,
|
||||
isStatGroupListDesc,
|
||||
isStatGroupDesc,
|
||||
isSingleValueStatDesc,
|
||||
StatsData,
|
||||
isMultiValueStatDesc,
|
||||
} from "../../../statistiques/v2/desc/StatsDesc";
|
||||
import { createMultiValueStatListItemBlock } from "./createMultiValueStatListItemBlock";
|
||||
import { createSingleValueStatListItemBlock } from "./createSingleValueStatListItemBlock";
|
||||
import { createStatGroupListItemBlock } from "./createStatGroupListItemBlock";
|
||||
import { createStatGroupListListItemBlock } from "./createStatGroupListListItemBlock";
|
||||
|
||||
export function createStatBlock<T extends StatDesc>(
|
||||
statDesc: T,
|
||||
statData: StatType<T>
|
||||
): BlockObjectRequest {
|
||||
if (isStatGroupListDesc(statDesc)) {
|
||||
return createStatGroupListListItemBlock(
|
||||
statDesc,
|
||||
statData as StatType<typeof statDesc>
|
||||
);
|
||||
}
|
||||
|
||||
if (isStatGroupDesc(statDesc)) {
|
||||
return createStatGroupListItemBlock(
|
||||
statDesc,
|
||||
statData as StatType<typeof statDesc>
|
||||
);
|
||||
}
|
||||
|
||||
if (isSingleValueStatDesc(statDesc)) {
|
||||
return createSingleValueStatListItemBlock(
|
||||
statDesc.label,
|
||||
statDesc as ValueFormatOptions,
|
||||
statData as StatsData
|
||||
);
|
||||
}
|
||||
|
||||
if (isMultiValueStatDesc(statDesc)) {
|
||||
return createMultiValueStatListItemBlock(
|
||||
statDesc,
|
||||
statData as Record<string, StatsData>
|
||||
);
|
||||
}
|
||||
|
||||
throw new Error("Unsupported stat descriptor type");
|
||||
}
|
||||
|
|
@ -1,21 +1,15 @@
|
|||
import {
|
||||
isMultiValueStatDesc,
|
||||
isSingleValueStatDesc,
|
||||
isStatGroupDesc,
|
||||
StatGroupDesc,
|
||||
StatsData,
|
||||
StatsType,
|
||||
StatType,
|
||||
} from "../../../statistiques/v2/desc/StatsDesc";
|
||||
import { createSingleValueStatListItemBlock } from "./createSingleValueStatListItemBlock";
|
||||
import { BulletedListItemBlockObjectRequest } from "../blocks/BulletedListItemBlockObjectRequest";
|
||||
import { BulletedListItemChildren } from "../blocks/BulletedListItemChildren";
|
||||
import { createMultiValueStatListItemBlock } from "./createMultiValueStatListItemBlock";
|
||||
import { ValueFormatOptions } from "../../../format/ValueFormatOptions";
|
||||
import { BlockObjectRequest } from "@notionhq/client/build/src/api-endpoints";
|
||||
import { createStatBlock } from "./createStatBlock";
|
||||
|
||||
export function createStatGroupListItemBlock<D extends StatGroupDesc>(
|
||||
descriptor: D,
|
||||
stats: StatsType<D>
|
||||
stats: StatType<D>
|
||||
): BulletedListItemBlockObjectRequest {
|
||||
return {
|
||||
bulleted_list_item: {
|
||||
|
|
@ -36,32 +30,12 @@ export function createStatGroupListItemBlock<D extends StatGroupDesc>(
|
|||
|
||||
export function createStatGroupChildrenListItemBlock<D extends StatGroupDesc>(
|
||||
descriptor: D,
|
||||
stats: StatsType<D>
|
||||
stats: StatType<D>
|
||||
): BlockObjectRequest[] {
|
||||
return Object.keys(descriptor.stats).map((statName) => {
|
||||
const childStatDesc = descriptor.stats[statName];
|
||||
const childStatData = stats[statName];
|
||||
|
||||
if (isStatGroupDesc(childStatDesc)) {
|
||||
return createStatGroupListItemBlock(
|
||||
childStatDesc,
|
||||
childStatData as StatsType<typeof childStatDesc>
|
||||
);
|
||||
}
|
||||
if (isSingleValueStatDesc(childStatDesc)) {
|
||||
return createSingleValueStatListItemBlock(
|
||||
childStatDesc.label,
|
||||
childStatDesc as ValueFormatOptions,
|
||||
childStatData as StatsData
|
||||
);
|
||||
}
|
||||
|
||||
if (isMultiValueStatDesc(childStatDesc)) {
|
||||
return createMultiValueStatListItemBlock(
|
||||
childStatDesc,
|
||||
childStatData as Record<string, StatsData>
|
||||
);
|
||||
}
|
||||
throw "Mussing case";
|
||||
return createStatBlock(childStatDesc, childStatData);
|
||||
});
|
||||
}
|
||||
|
|
|
|||
45
src/notion/publish/v2/createStatGroupListListItemBlock.ts
Normal file
45
src/notion/publish/v2/createStatGroupListListItemBlock.ts
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
import {
|
||||
StatGroupListDesc,
|
||||
StatType,
|
||||
} from "../../../statistiques/v2/desc/StatsDesc";
|
||||
import { BulletedListItemBlockObjectRequest } from "../blocks/BulletedListItemBlockObjectRequest";
|
||||
import { BulletedListItemChildren } from "../blocks/BulletedListItemChildren";
|
||||
import { createStatBlock } from "./createStatBlock";
|
||||
|
||||
export function createStatGroupListListItemBlock<D extends StatGroupListDesc>(
|
||||
descriptor: D,
|
||||
statsDictionnaryData: StatType<D>
|
||||
): BulletedListItemBlockObjectRequest {
|
||||
return {
|
||||
bulleted_list_item: {
|
||||
rich_text: [
|
||||
{
|
||||
text: {
|
||||
content: descriptor.label,
|
||||
},
|
||||
},
|
||||
],
|
||||
children: Object.entries(statsDictionnaryData).map(
|
||||
([keyName, statData]) => {
|
||||
return {
|
||||
bulleted_list_item: {
|
||||
rich_text: [
|
||||
{
|
||||
text: {
|
||||
content: keyName,
|
||||
},
|
||||
},
|
||||
],
|
||||
children: Object.keys(descriptor.stats).map((statName) => {
|
||||
const childStatDesc = descriptor.stats[statName];
|
||||
const childStatData = statData[statName];
|
||||
|
||||
return createStatBlock(childStatDesc, childStatData);
|
||||
}) as BulletedListItemChildren,
|
||||
},
|
||||
};
|
||||
}
|
||||
) as BulletedListItemChildren,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
import { Client } from "@notionhq/client";
|
||||
import {
|
||||
StatGroupDesc,
|
||||
StatsType,
|
||||
StatType,
|
||||
} from "../../../statistiques/v2/desc/StatsDesc";
|
||||
import { createStatGroupChildrenListItemBlock } from "./createStatGroupListItemBlock";
|
||||
import { updatePageContent } from "./updatePageContent";
|
||||
|
|
@ -12,7 +12,7 @@ export async function publishStatsToPage<D extends StatGroupDesc>(
|
|||
statsPageId: string,
|
||||
pageHeader: string,
|
||||
descriptor: D,
|
||||
stats: StatsType<D>
|
||||
stats: StatType<D>
|
||||
) {
|
||||
const statsBlocks = createStatGroupChildrenListItemBlock(descriptor, stats);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { statsPenalesDesc } from "./penales/StatsPenales";
|
||||
import { StatsType } from "./desc/StatsDesc";
|
||||
import { StatType } from "./desc/StatsDesc";
|
||||
|
||||
export const eLStatsV2Desc = {
|
||||
label: "Stats v2",
|
||||
|
|
@ -8,4 +8,4 @@ export const eLStatsV2Desc = {
|
|||
},
|
||||
};
|
||||
|
||||
export type ELStatsV2 = StatsType<typeof eLStatsV2Desc>;
|
||||
export type ELStatsV2 = StatType<typeof eLStatsV2Desc>;
|
||||
|
|
|
|||
|
|
@ -1,18 +1,18 @@
|
|||
import { StatsType } from "../desc/StatsDesc";
|
||||
import { StatType } from "../desc/StatsDesc";
|
||||
|
||||
export const statsAutresDesc = {
|
||||
label: "Stats Sociales",
|
||||
stats: {
|
||||
nbFamillesSuppressionCAF: {
|
||||
label: "Nb Familles avec une suppression CAF"
|
||||
label: "Nb Familles avec une suppression CAF",
|
||||
},
|
||||
nbFamillesControleFiscal: {
|
||||
label: "Nb Familles ayant eu un contrôle fiscal"
|
||||
label: "Nb Familles ayant eu un contrôle fiscal",
|
||||
},
|
||||
nbFamillesControleURSAFF: {
|
||||
label: "Nb Familles ayant eu un contrôle URSAFF"
|
||||
label: "Nb Familles ayant eu un contrôle URSAFF",
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
||||
export type StatsAutres = StatsType<typeof statsAutresDesc>;
|
||||
export type StatsAutres = StatType<typeof statsAutresDesc>;
|
||||
|
|
|
|||
|
|
@ -1,53 +0,0 @@
|
|||
import { ValueFormatOptions } from "../../../format/ValueFormatOptions";
|
||||
|
||||
type StatDescTypes = StatGroupDesc | StatDesc | MultiValueStatDesc;
|
||||
|
||||
/**
|
||||
* Descripteur d'une Section de stat
|
||||
*/
|
||||
export type StatGroupDesc = {
|
||||
label: string;
|
||||
desc?: string;
|
||||
stats: { [propName: string]: StatDescTypes };
|
||||
};
|
||||
|
||||
export function isStatGroupDesc(x: StatDescTypes): x is StatGroupDesc {
|
||||
if (!("stats" in x) || x.stats === null || typeof x.stats !== "object") {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Descripteur d'une valeur unique
|
||||
*/
|
||||
export type StatDesc = {
|
||||
label: string;
|
||||
} & ValueFormatOptions;
|
||||
|
||||
export function isSingleValueStatDesc(x: StatDescTypes): x is StatDesc {
|
||||
return !isStatGroupDesc(x) && !isMultiValueStatDesc(x);
|
||||
}
|
||||
|
||||
export type MultiValueStatDesc = {
|
||||
label: string;
|
||||
type: "multi";
|
||||
} & ValueFormatOptions;
|
||||
|
||||
export function isMultiValueStatDesc(
|
||||
x: StatDescTypes
|
||||
): x is MultiValueStatDesc {
|
||||
if (!("label" in x) || x.label === null || typeof x.label !== "string") {
|
||||
return false;
|
||||
}
|
||||
return "type" in x && x.type === "multi";
|
||||
}
|
||||
|
||||
export type StatsType<T extends StatGroupDesc> = {
|
||||
[Property in keyof T["stats"]]: T["stats"][Property] extends StatGroupDesc
|
||||
? StatsType<T["stats"][Property]>
|
||||
: T["stats"][Property] extends MultiValueStatDesc
|
||||
? Record<string, number>
|
||||
: number;
|
||||
};
|
||||
|
|
@ -1,14 +1,29 @@
|
|||
import { ValueFormatOptions } from "../../../format/ValueFormatOptions";
|
||||
|
||||
type StatDesc = StatGroupDesc | SingleValueStatDesc | MultiValueStatDesc;
|
||||
export type StatDesc =
|
||||
| StatGroupListDesc
|
||||
| StatGroupDesc
|
||||
| SingleValueStatDesc
|
||||
| MultiValueStatDesc;
|
||||
|
||||
type NamedStatsDescriptors = {
|
||||
[propName: string]: StatDesc;
|
||||
};
|
||||
|
||||
/**
|
||||
* Descripteur d'une Section de stat
|
||||
* Descripteur d'un groupe de stat
|
||||
*/
|
||||
export type StatGroupDesc = {
|
||||
label: string;
|
||||
desc?: string;
|
||||
stats: { [propName: string]: StatDesc };
|
||||
stats: NamedStatsDescriptors;
|
||||
};
|
||||
|
||||
export type StatGroupListDesc = {
|
||||
label: string;
|
||||
desc?: string;
|
||||
type: "group-list";
|
||||
stats: NamedStatsDescriptors;
|
||||
};
|
||||
|
||||
export function isStatGroupDesc(x: StatDesc): x is StatGroupDesc {
|
||||
|
|
@ -19,6 +34,14 @@ export function isStatGroupDesc(x: StatDesc): x is StatGroupDesc {
|
|||
return true;
|
||||
}
|
||||
|
||||
export function isStatGroupListDesc(x: StatDesc): x is StatGroupListDesc {
|
||||
if (!("stats" in x) || x.stats === null || typeof x.stats !== "object") {
|
||||
return false;
|
||||
}
|
||||
|
||||
return "type" in x && x.type === "group-list";
|
||||
}
|
||||
|
||||
/**
|
||||
* Descripteur d'une valeur unique
|
||||
*/
|
||||
|
|
@ -44,10 +67,21 @@ export function isMultiValueStatDesc(x: StatDesc): x is MultiValueStatDesc {
|
|||
|
||||
export type StatsData = number | { value: number; relatedPageIds: string[] };
|
||||
|
||||
export type StatsType<T extends StatGroupDesc> = {
|
||||
[Property in keyof T["stats"]]: T["stats"][Property] extends StatGroupDesc
|
||||
? StatsType<T["stats"][Property]>
|
||||
: T["stats"][Property] extends MultiValueStatDesc
|
||||
? Record<string, StatsData>
|
||||
: StatsData;
|
||||
export type StatType<T extends StatDesc> = T extends StatGroupListDesc
|
||||
? Record<
|
||||
string,
|
||||
{
|
||||
[Property in keyof T["stats"]]: StatType<T["stats"][Property]>;
|
||||
}
|
||||
>
|
||||
: T extends StatGroupDesc
|
||||
? {
|
||||
[Property in keyof T["stats"]]: StatType<T["stats"][Property]>;
|
||||
}
|
||||
: T extends MultiValueStatDesc
|
||||
? Record<string, StatsData>
|
||||
: StatsData;
|
||||
|
||||
export type NamedStatsType<T extends NamedStatsDescriptors> = {
|
||||
[Property in keyof T]: StatType<T[Property]>;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { StatsType } from "../desc/StatsDesc";
|
||||
import { StatType } from "../desc/StatsDesc";
|
||||
|
||||
export const statsGeneralesDesc = {
|
||||
label: "Stats Générales",
|
||||
|
|
@ -56,4 +56,4 @@ export const statsGeneralesDesc = {
|
|||
},
|
||||
} as const;
|
||||
|
||||
export type StatsGenerales = StatsType<typeof statsGeneralesDesc>;
|
||||
export type StatsGenerales = StatType<typeof statsGeneralesDesc>;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { StatsType } from "../desc/StatsDesc";
|
||||
import { StatType } from "../desc/StatsDesc";
|
||||
|
||||
export const statsTribunalCorrectionnelDesc = {
|
||||
nbFamillesConvoquees: {
|
||||
|
|
@ -181,7 +181,33 @@ export const statsPenalesDesc = {
|
|||
},
|
||||
},
|
||||
},
|
||||
parDepartements: {
|
||||
label: "Par départements",
|
||||
type: "group-list",
|
||||
stats: {
|
||||
nbFamilles: {
|
||||
label: "Nb familles",
|
||||
},
|
||||
pourcentageMED: {
|
||||
label: "% familles avec une Mise en demeure",
|
||||
unit: "%",
|
||||
},
|
||||
pourcentageProcedurePenaleHorsGendarmerie: {
|
||||
label:
|
||||
"% familles avec une Procédure Pénale différent de Gendarmerie (Procureur, Tribunal...)",
|
||||
unit: "%",
|
||||
},
|
||||
pourcentageTribunalCorrectionnel: {
|
||||
label: "% familles avec un evt Tribunal correctionnel",
|
||||
unit: "%",
|
||||
},
|
||||
pourcentageTribunalPolice: {
|
||||
label: "% familles avec un evt Tribunal de Police",
|
||||
unit: "%",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
||||
export type StatsPenales = StatsType<typeof statsPenalesDesc>;
|
||||
export type StatsPenales = StatType<typeof statsPenalesDesc>;
|
||||
|
|
|
|||
|
|
@ -22,6 +22,9 @@ import {
|
|||
FamilleAvecInfosProceduresPenales as FamilleAvecInfoProceduresPenales,
|
||||
} from "./computeFamilleAvecInfosProceduresPenales";
|
||||
import { computeIntervalMedGendarmerieOuProcureur } from "./intervals/computeIntervalMedGendarmerieOuProcureur";
|
||||
import { groupBy } from "lodash";
|
||||
import { percent } from "../../../utils/math/percent";
|
||||
import { isEvtTypeProcedurePenaleHorsGendarmerie } from "../../../data/TypeEvenementsPenal";
|
||||
|
||||
export type FamilleAvecInfoTribunaux = Famille & {
|
||||
infoTribunaux: InfoTribunalCorrectionnel[];
|
||||
|
|
@ -64,6 +67,12 @@ export function computeStatsPenales(familles: Famille[]): StatsPenales {
|
|||
};
|
||||
});
|
||||
|
||||
const famillesParDepartement = groupBy(
|
||||
famillesResistantesOuEx,
|
||||
(f) => f.Departement
|
||||
);
|
||||
const departements = Object.keys(famillesParDepartement).sort();
|
||||
|
||||
const famillesAvecInfoProceduresPenales: FamilleAvecInfoProceduresPenales[] =
|
||||
famillesResistantesOuEx.map(computeFamilleAvecInfosProceduresPenales);
|
||||
|
||||
|
|
@ -206,10 +215,51 @@ export function computeStatsPenales(familles: Famille[]): StatsPenales {
|
|||
),
|
||||
},
|
||||
},
|
||||
parDepartements: Object.fromEntries(
|
||||
departements.map((d) => [
|
||||
d,
|
||||
computeStatDepartement(famillesParDepartement[d]),
|
||||
])
|
||||
),
|
||||
};
|
||||
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"] {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { StatsType } from "../desc/StatsDesc";
|
||||
import { StatType } from "../desc/StatsDesc";
|
||||
|
||||
export const statsSocialesDesc = {
|
||||
label: "Stats Sociales",
|
||||
|
|
@ -72,4 +72,4 @@ export const statsSocialesDesc = {
|
|||
},
|
||||
} as const;
|
||||
|
||||
export type StatsSociales = StatsType<typeof statsSocialesDesc>;
|
||||
export type StatsSociales = StatType<typeof statsSocialesDesc>;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue