remove proc pénale
parent
21f50efb5a
commit
b4d1a7edad
|
@ -16,5 +16,4 @@
|
|||
dist
|
||||
test-coverage
|
||||
node_modules
|
||||
el-stats-par-anciennete.json
|
||||
el-stats.json
|
||||
el-stats*.json
|
||||
|
|
|
@ -90,6 +90,7 @@ export function isEvenementInPeriod(
|
|||
|
||||
export function isEvenementBefore(evt: EvenementFamille, date: Date): boolean {
|
||||
if (evt.Date === null) {
|
||||
// Assume lack of date are oldest events
|
||||
return true;
|
||||
}
|
||||
return evt.Date < date;
|
||||
|
@ -101,3 +102,18 @@ export function isValidEvenementFamille(str: string | null): boolean {
|
|||
Object.prototype.hasOwnProperty.call(categorieEvenement, str)
|
||||
);
|
||||
}
|
||||
export function isGendarmerie(e: EvenementFamille): boolean {
|
||||
return (
|
||||
e.Type === "Audition gendarmerie / police" ||
|
||||
e.Type === "Gendarmerie/Forces de l'ordre" ||
|
||||
e.Type === "Récidive gendarmerie" ||
|
||||
e.Type === "Passage police municipale"
|
||||
);
|
||||
}
|
||||
export function isEvtProcureur(e: EvenementFamille): boolean {
|
||||
return (
|
||||
e.Type === "Audition procureur" ||
|
||||
e.Type === "Audience CRPC" ||
|
||||
e.Type === "Convocation CRPC"
|
||||
);
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ export type Famille = {
|
|||
Integration: Date | null;
|
||||
ContexteEntree: ContexteEntreeDC;
|
||||
Sortie: Date | null;
|
||||
// sorted by date asc
|
||||
Evenements: EvenementFamille[];
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
export type EvolFormatOptions = {
|
||||
evolMaxFractioDigits?: number;
|
||||
evolPctMaxFractioDigits?: number;
|
||||
};
|
|
@ -0,0 +1,4 @@
|
|||
export type ValueFormatOptions = {
|
||||
unit?: string;
|
||||
valueMaxFractioDigits?: number;
|
||||
};
|
|
@ -3,19 +3,17 @@ import { formatValue } from "./formatValue";
|
|||
|
||||
describe("formatValue", () => {
|
||||
test("format with default options", () => {
|
||||
expect(formatValue(42.42, { notionPropName: "whatever" })).toBe("42,4");
|
||||
expect(formatValue(42, { notionPropName: "whatever" })).toBe("42");
|
||||
expect(formatValue(42.42, {})).toBe("42,4");
|
||||
expect(formatValue(42, {})).toBe("42");
|
||||
});
|
||||
test("format with valueMaxFractioDigits: 2", () => {
|
||||
expect(
|
||||
formatValue(42.4242, {
|
||||
notionPropName: "whatever",
|
||||
valueMaxFractioDigits: 2,
|
||||
})
|
||||
).toBe("42,42");
|
||||
expect(
|
||||
formatValue(42, {
|
||||
notionPropName: "whatever",
|
||||
valueMaxFractioDigits: 2,
|
||||
})
|
||||
).toBe("42");
|
||||
|
@ -24,7 +22,6 @@ describe("formatValue", () => {
|
|||
test("format with unit", () => {
|
||||
expect(
|
||||
formatValue(42, {
|
||||
notionPropName: "whatever",
|
||||
unit: "%",
|
||||
})
|
||||
).toBe("42%");
|
|
@ -1,6 +1,6 @@
|
|||
import { StatPublishOptions } from "../../statPublishOptions";
|
||||
import { ValueFormatOptions } from "./ValueFormatOptions";
|
||||
|
||||
export function formatValue(value: number, publishOptions: StatPublishOptions) {
|
||||
export function formatValue(value: number, publishOptions: ValueFormatOptions) {
|
||||
const valueStr = value.toLocaleString("fr-FR", {
|
||||
useGrouping: false,
|
||||
maximumFractionDigits:
|
|
@ -1,5 +1,5 @@
|
|||
import { ValueWithEvol } from "../../../statistiques/ELStats";
|
||||
import { StatPublishOptions } from "../../statPublishOptions";
|
||||
import { StatPublishOptions } from "../notion/publish/v1/statPublishOptions";
|
||||
import { ValueWithEvol } from "../statistiques/v1/ELStats";
|
||||
import { formatValue } from "./formatValue";
|
||||
|
||||
export function formatValueWithEvol(
|
28
src/index.ts
28
src/index.ts
|
@ -2,9 +2,12 @@ import { Client } from "@notionhq/client";
|
|||
import { writeFileSync } from "fs";
|
||||
import { checkDataConsistency } from "./data/checkDataConsistency";
|
||||
import { fetchFamiliesWithEventsFromNotion } from "./notion/fetch/fetchFamiliesWithEventsFromNotion";
|
||||
import { publishStatisticsToNotion } from "./notion/publish/publishStatisticsToNotion";
|
||||
import { computeELStats } from "./statistiques/computeELStats";
|
||||
import { computeStatsParAnciennete } from "./statistiques/computeEvenementsParAnciennete";
|
||||
import { publishStatisticsToNotion } from "./notion/publish/v1/publishStatisticsToNotion";
|
||||
import { publishStatsToPage } from "./notion/publish/v2/publishStatsToPage";
|
||||
import { computeELStats } from "./statistiques/v1/computeELStats";
|
||||
import { computeStatsParAnciennete } from "./statistiques/v1/computeEvenementsParAnciennete";
|
||||
import { computeStatsPenales } from "./statistiques/v2/penales/computeStatsPenales";
|
||||
import { statsPenalesDesc } from "./statistiques/v2/penales/StatsPenales";
|
||||
|
||||
type ProcessOptions = {
|
||||
dryRun: boolean;
|
||||
|
@ -65,13 +68,26 @@ function buildProcessOptions(): ProcessOptions {
|
|||
"./el-stats-par-anciennete.json",
|
||||
JSON.stringify(statsParAnciennete, null, " ")
|
||||
);
|
||||
|
||||
const statsV2 = computeStatsPenales(familles);
|
||||
|
||||
if (options.dryRun) {
|
||||
console.log(
|
||||
"Dry run => Skip Publishing. Stats are dumped in file el-stats.json"
|
||||
"Dry run => Skip Publishing. Stats are dumped in file el-stats-xxx.json"
|
||||
);
|
||||
writeFileSync("./el-stats.json", JSON.stringify(elStats, null, " "));
|
||||
writeFileSync("./el-stats-v1.json", JSON.stringify(elStats, null, " "));
|
||||
|
||||
writeFileSync("./el-stats-v2.json", JSON.stringify(statsV2, null, " "));
|
||||
} else {
|
||||
console.log("Publishing statistics...");
|
||||
publishStatisticsToNotion(elStats, currentDate, notionClient);
|
||||
await publishStatisticsToNotion(elStats, currentDate, notionClient);
|
||||
|
||||
await publishStatsToPage(
|
||||
notionClient,
|
||||
"969eac5c-a4eb-49d4-b4ad-c341c9c4c785",
|
||||
|
||||
statsPenalesDesc,
|
||||
statsV2
|
||||
);
|
||||
}
|
||||
})();
|
||||
|
|
|
@ -22,6 +22,11 @@ export async function fetchFamiliesWithEventsFromNotion(
|
|||
const eventPages = (
|
||||
await queryAllDbResults(notionClient, {
|
||||
database_id: familEventsDbId,
|
||||
sorts: [
|
||||
{property: "Date",
|
||||
direction: "ascending"
|
||||
}
|
||||
]
|
||||
})
|
||||
).filter(isFullPage);
|
||||
const familyPages = (
|
||||
|
|
|
@ -3,17 +3,17 @@ import {
|
|||
PageObjectResponse,
|
||||
UpdateDatabaseParameters,
|
||||
} from "@notionhq/client/build/src/api-endpoints";
|
||||
import { formatValueWithEvol } from "../../../format/formatValueWithEvol";
|
||||
import {
|
||||
ELStatsPeriod,
|
||||
PeriodStatsValues,
|
||||
ValueWithEvol,
|
||||
} from "../../statistiques/ELStats";
|
||||
import { StatPublishOptions, statPublishOptions } from "../statPublishOptions";
|
||||
import { titlePropertyToText } from "../utils/properties/titlePropertyToText";
|
||||
import { queryAllDbResults } from "../utils/queryAllDbResults";
|
||||
import { removeBlocks } from "../utils/removeBlocks";
|
||||
import { CreatePageProperties } from "../utils/types/CreatePageProperties";
|
||||
import { formatValueWithEvol } from "./format/formatValueWithEvol";
|
||||
} from "../../../statistiques/v1/ELStats";
|
||||
import { titlePropertyToText } from "../../utils/properties/titlePropertyToText";
|
||||
import { queryAllDbResults } from "../../utils/queryAllDbResults";
|
||||
import { removeBlocks } from "../../utils/removeBlocks";
|
||||
import { CreatePageProperties } from "../../utils/types/CreatePageProperties";
|
||||
import { StatPublishOptions, statPublishOptions } from "./statPublishOptions";
|
||||
|
||||
const periodeDbPropertyName = "Période";
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
import { Client, isFullBlock } from "@notionhq/client";
|
||||
import { ELStats } from "../../statistiques/ELStats";
|
||||
import { listAllChildrenBlocks } from "../utils/listAllChildrenBlocks";
|
||||
import { richTextToPlainText } from "../utils/text/richTextToPlainText";
|
||||
import { ELStats } from "../../../statistiques/v1/ELStats";
|
||||
import { listAllChildrenBlocks } from "../../utils/listAllChildrenBlocks";
|
||||
import { richTextToPlainText } from "../../utils/text/richTextToPlainText";
|
||||
import { publishPeriodStats } from "./publishPeriodStats";
|
||||
import { publishStatsActuelles } from "./publishStatsActuelles";
|
||||
|
|
@ -1,12 +1,12 @@
|
|||
import { Client, isFullBlock } from "@notionhq/client";
|
||||
import { BlockObjectRequest } from "@notionhq/client/build/src/api-endpoints";
|
||||
import { ELStatsAtDate } from "../../statistiques/ELStats";
|
||||
import { StatPublishOptions, statPublishOptions } from "../statPublishOptions";
|
||||
import { listAllChildrenBlocks } from "../utils/listAllChildrenBlocks";
|
||||
import { removeBlocks } from "../utils/removeBlocks";
|
||||
import { richTextToPlainText } from "../utils/text/richTextToPlainText";
|
||||
import { formatValue } from "./format/formatValue";
|
||||
import { formatValue } from "../../../format/formatValue";
|
||||
import { ELStatsAtDate } from "../../../statistiques/v1/ELStats";
|
||||
import { listAllChildrenBlocks } from "../../utils/listAllChildrenBlocks";
|
||||
import { removeBlocks } from "../../utils/removeBlocks";
|
||||
import { richTextToPlainText } from "../../utils/text/richTextToPlainText";
|
||||
import { currentStatsHeading, statsPageId } from "./publishStatisticsToNotion";
|
||||
import { StatPublishOptions, statPublishOptions } from "./statPublishOptions";
|
||||
|
||||
export async function publishStatsActuelles(
|
||||
notionClient: Client,
|
|
@ -1,4 +1,6 @@
|
|||
import { AllStatsPropNames } from "../statistiques/ELStats";
|
||||
import { EvolFormatOptions } from "../../../format/EvolFormatOptions";
|
||||
import { ValueFormatOptions } from "../../../format/ValueFormatOptions";
|
||||
import { AllStatsPropNames } from "../../../statistiques/v1/ELStats";
|
||||
|
||||
export function statPublishOptions(
|
||||
statJsPropName: AllStatsPropNames
|
||||
|
@ -185,8 +187,5 @@ const statPropsPublishOptions: {
|
|||
};
|
||||
export type StatPublishOptions = {
|
||||
notionPropName: string;
|
||||
unit?: string;
|
||||
valueMaxFractioDigits?: number;
|
||||
evolMaxFractioDigits?: number;
|
||||
evolPctMaxFractioDigits?: number;
|
||||
};
|
||||
} & ValueFormatOptions &
|
||||
EvolFormatOptions;
|
|
@ -0,0 +1,97 @@
|
|||
import { Client, isFullBlock } from "@notionhq/client";
|
||||
import { BlockObjectRequest } from "@notionhq/client/build/src/api-endpoints";
|
||||
import { formatValue } from "../../../format/formatValue";
|
||||
import {
|
||||
isStatGroupDesc,
|
||||
StatDesc,
|
||||
StatGroupDesc,
|
||||
StatsType,
|
||||
} from "../../../statistiques/v2/StatsDesc";
|
||||
import { listAllChildrenBlocks } from "../../utils/listAllChildrenBlocks";
|
||||
import { removeBlocks } from "../../utils/removeBlocks";
|
||||
|
||||
export async function publishStatsToPage<D extends StatGroupDesc>(
|
||||
notionClient: Client,
|
||||
statsPageId: string,
|
||||
descriptor: D,
|
||||
stats: StatsType<D>
|
||||
) {
|
||||
const childrenBlocks = (
|
||||
await listAllChildrenBlocks(notionClient, {
|
||||
block_id: statsPageId,
|
||||
})
|
||||
).filter(isFullBlock);
|
||||
const blocksIdsToRemove = childrenBlocks.map((b) => b.id);
|
||||
await removeBlocks(notionClient, blocksIdsToRemove);
|
||||
|
||||
const newBlocks = createStatGroupChildrenListItemBlock(descriptor, stats);
|
||||
|
||||
await notionClient.blocks.children.append({
|
||||
block_id: statsPageId,
|
||||
children: [...newBlocks],
|
||||
});
|
||||
}
|
||||
|
||||
function createStatGroupListItemBlock<D extends StatGroupDesc>(
|
||||
descriptor: D,
|
||||
stats: StatsType<D>
|
||||
): BulletedListItemBlockObjectRequest {
|
||||
return {
|
||||
bulleted_list_item: {
|
||||
rich_text: [
|
||||
{
|
||||
text: {
|
||||
content: descriptor.label,
|
||||
},
|
||||
},
|
||||
],
|
||||
children: createStatGroupChildrenListItemBlock(
|
||||
descriptor,
|
||||
stats
|
||||
) as BulletedListItemChildren,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
type BulletedListItemBlockObjectRequest = Extract<
|
||||
BlockObjectRequest,
|
||||
{ bulleted_list_item: object }
|
||||
>;
|
||||
|
||||
type BulletedListItemChildren =
|
||||
BulletedListItemBlockObjectRequest["bulleted_list_item"]["children"];
|
||||
|
||||
function createStatGroupChildrenListItemBlock<D extends StatGroupDesc>(
|
||||
descriptor: D,
|
||||
stats: StatsType<D>
|
||||
): BulletedListItemBlockObjectRequest[] {
|
||||
return Object.keys(descriptor.stats).map((statName) => {
|
||||
const childStatDesc = descriptor.stats[statName];
|
||||
const childStatValue = stats[statName];
|
||||
|
||||
return isStatGroupDesc(childStatDesc)
|
||||
? createStatGroupListItemBlock(
|
||||
childStatDesc,
|
||||
childStatValue as StatsType<typeof childStatDesc>
|
||||
)
|
||||
: createStatListItemBlock(childStatDesc, childStatValue as number);
|
||||
});
|
||||
}
|
||||
|
||||
function createStatListItemBlock(
|
||||
descriptor: StatDesc,
|
||||
statValue: number
|
||||
): BulletedListItemBlockObjectRequest {
|
||||
return {
|
||||
bulleted_list_item: {
|
||||
rich_text: [
|
||||
{
|
||||
text: {
|
||||
content:
|
||||
descriptor.label + ": " + formatValue(statValue, descriptor),
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
import { Famille } from "../data/Famille";
|
||||
import { IdentifiedPeriod } from "../period/IdentifiedPeriod";
|
||||
import { Period } from "../period/Period";
|
||||
import { Famille } from "../../data/Famille";
|
||||
import { IdentifiedPeriod } from "../../period/IdentifiedPeriod";
|
||||
import { Period } from "../../period/Period";
|
||||
import {
|
||||
ELStatsOverPeriod,
|
||||
ELStatsPeriod,
|
|
@ -1,7 +1,7 @@
|
|||
import { Famille } from "../data/Famille";
|
||||
import { ELStats } from "./ELStats";
|
||||
import { Famille } from "../../data/Famille";
|
||||
import { computeELPeriodStats } from "./computeELPeriodStats";
|
||||
import { computeELStatsAtDate } from "./computeELStatsAtDate";
|
||||
import { ELStats } from "./ELStats";
|
||||
import { generateELMonths } from "./generateELMonths";
|
||||
import { generateELYears } from "./generateELYears";
|
||||
|
|
@ -4,17 +4,17 @@ import {
|
|||
isEvenementBefore,
|
||||
isProcedureCivile,
|
||||
isProcedurePenale,
|
||||
} from "../data/EvenementFamille";
|
||||
} 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";
|
||||
} 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";
|
||||
|
|
@ -1,14 +1,14 @@
|
|||
import {
|
||||
isEvenementInPeriod,
|
||||
isProcedurePenale,
|
||||
} from "../data/EvenementFamille";
|
||||
} from "../../data/EvenementFamille";
|
||||
import {
|
||||
Famille,
|
||||
isResistantOverPeriod,
|
||||
periodOfResistance,
|
||||
} from "../data/Famille";
|
||||
import { Period } from "../period/Period";
|
||||
import { isPeriodContaining } from "../period/isPeriodContaining";
|
||||
} from "../../data/Famille";
|
||||
import { Period } from "../../period/Period";
|
||||
import { isPeriodContaining } from "../../period/isPeriodContaining";
|
||||
import { ELStatsOverPeriod } from "./ELStats";
|
||||
import { computePourcentageEntreeApresMiseEnDemeure } from "./computePourcentageEntreeApresMiseEnDemeure";
|
||||
|
|
@ -1,5 +1,8 @@
|
|||
import { isProcedureCivile, isProcedurePenale } from "../data/EvenementFamille";
|
||||
import { Famille } from "../data/Famille";
|
||||
import {
|
||||
isProcedureCivile,
|
||||
isProcedurePenale,
|
||||
} from "../../data/EvenementFamille";
|
||||
import { Famille } from "../../data/Famille";
|
||||
import { computeFamillesWithEventsConditionInEarlyPeriod } from "./computeFamilleWithEventAfterDurationOfDC";
|
||||
|
||||
export function computeStatsParAnciennete(familles: Famille[]) {
|
|
@ -1,7 +1,10 @@
|
|||
import { addMonths } from "date-fns";
|
||||
import { EvenementFamille, isEvenementBefore } from "../data/EvenementFamille";
|
||||
import { Famille } from "../data/Famille";
|
||||
import { percent } from "../utils/math/percent";
|
||||
import {
|
||||
EvenementFamille,
|
||||
isEvenementBefore,
|
||||
} from "../../data/EvenementFamille";
|
||||
import { Famille } from "../../data/Famille";
|
||||
import { percent } from "../../utils/math/percent";
|
||||
|
||||
type FamillesWithEventsConditionInEarlyPeriod = {
|
||||
[name: string]: {
|
|
@ -1,5 +1,5 @@
|
|||
import { Famille } from "../data/Famille";
|
||||
import { percent } from "../utils/math/percent";
|
||||
import { Famille } from "../../data/Famille";
|
||||
import { percent } from "../../utils/math/percent";
|
||||
|
||||
export function computePourcentageEntreeApresMiseEnDemeure(
|
||||
familles: Famille[]
|
|
@ -1,6 +1,6 @@
|
|||
import { getMonth, getYear, setMonth, setYear } from "date-fns";
|
||||
import { IdentifiedPeriod } from "../period/IdentifiedPeriod";
|
||||
import { generateConsecutiveIdentifiedPeriods } from "../period/generateConsecutiveIdentifiedPeriods";
|
||||
import { IdentifiedPeriod } from "../../period/IdentifiedPeriod";
|
||||
import { generateConsecutiveIdentifiedPeriods } from "../../period/generateConsecutiveIdentifiedPeriods";
|
||||
|
||||
export function generateELMonths(): IdentifiedPeriod[] {
|
||||
const months = generateConsecutiveIdentifiedPeriods({
|
|
@ -1,6 +1,6 @@
|
|||
import { addYears } from "date-fns/fp";
|
||||
import { IdentifiedPeriod } from "../period/IdentifiedPeriod";
|
||||
import { generateConsecutiveIdentifiedPeriods } from "../period/generateConsecutiveIdentifiedPeriods";
|
||||
import { IdentifiedPeriod } from "../../period/IdentifiedPeriod";
|
||||
import { generateConsecutiveIdentifiedPeriods } from "../../period/generateConsecutiveIdentifiedPeriods";
|
||||
|
||||
export function generateELYears(): IdentifiedPeriod[] {
|
||||
return generateConsecutiveIdentifiedPeriods({
|
|
@ -0,0 +1,11 @@
|
|||
import { statsPenalesDesc } from "./penales/StatsPenales";
|
||||
import { StatsType } from "./StatsDesc";
|
||||
|
||||
export const eLStatsV2Desc = {
|
||||
label: "Stats v2",
|
||||
stats: {
|
||||
penales: statsPenalesDesc,
|
||||
},
|
||||
};
|
||||
|
||||
export type ELStatsV2 = StatsType<typeof eLStatsV2Desc>;
|
|
@ -0,0 +1,32 @@
|
|||
import { ValueFormatOptions } from "../../format/ValueFormatOptions";
|
||||
|
||||
export type StatGroupDesc = {
|
||||
label: string;
|
||||
desc?: string;
|
||||
stats: { [propName: string]: StatDesc | StatGroupDesc };
|
||||
};
|
||||
|
||||
export type StatDesc = {
|
||||
label: string;
|
||||
} & ValueFormatOptions;
|
||||
|
||||
export function isStatGroupDesc(x: unknown): x is StatGroupDesc {
|
||||
if (typeof x !== "object" || Array.isArray(x) || x === null) {
|
||||
return false;
|
||||
}
|
||||
if (!("label" in x) || x.label === null || typeof x.label !== "string") {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!("stats" in x) || x.stats === null || typeof x.stats !== "object") {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
export type StatsType<T extends StatGroupDesc> = {
|
||||
[Property in keyof T["stats"]]: T["stats"][Property] extends StatGroupDesc
|
||||
? StatsType<T["stats"][Property]>
|
||||
: number;
|
||||
};
|
|
@ -0,0 +1,11 @@
|
|||
import { EvenementFamille } from "../../data/EvenementFamille";
|
||||
import { Famille } from "../../data/Famille";
|
||||
|
||||
export function filterFamillesWithOneOfEvenements(
|
||||
familles: Famille[],
|
||||
evenementtPredicated: (evt: EvenementFamille) => boolean
|
||||
): Famille[] {
|
||||
return familles.filter(
|
||||
(f) => f.Evenements.find((e) => evenementtPredicated(e)) !== undefined
|
||||
);
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
import { Famille } from "../../data/Famille";
|
||||
import { TypeEvenement } from "../../data/TypeEvenement";
|
||||
import { filterFamillesWithOneOfEvenements } from "./filterFamillesWithOneOfEvenements";
|
||||
|
||||
export function filterFamillesWithOneOfEvenementsOfType(
|
||||
familles: Famille[],
|
||||
eventType: TypeEvenement
|
||||
): Famille[] {
|
||||
return filterFamillesWithOneOfEvenements(
|
||||
familles,
|
||||
(e) => e.Type === eventType
|
||||
);
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
import { StatsType } from "../StatsDesc";
|
||||
|
||||
export const statsPenalesDesc = {
|
||||
label: "Stats Pénales",
|
||||
stats: {
|
||||
nbFamillesMisesEnDemeure: {
|
||||
label: "Nb familles mises en demeure",
|
||||
},
|
||||
nbFamillesAvecGendarmerie: {
|
||||
label: "Nb familles avec un evenement lié à la Gendarmerie",
|
||||
},
|
||||
compositionPenales: {
|
||||
label: "Compositions Pénales",
|
||||
stats: {
|
||||
nbFamilles: {
|
||||
label: "Nb familles concernées",
|
||||
},
|
||||
acceptees: {
|
||||
label: "Nb familles ayant acceptées",
|
||||
},
|
||||
refusees: {
|
||||
label: "Nb familles ayant refusées",
|
||||
},
|
||||
},
|
||||
},
|
||||
crpc: {
|
||||
label: "CRPC",
|
||||
stats: {
|
||||
nbFamilles: {
|
||||
label: "Nb familles concernées",
|
||||
},
|
||||
acceptees: {
|
||||
label: "Nb familles ayant acceptées",
|
||||
},
|
||||
refusees: {
|
||||
label: "Nb familles ayant refusées",
|
||||
},
|
||||
},
|
||||
},
|
||||
tribunalCorrectionnel: {
|
||||
label: "Tribunal Correctionnel",
|
||||
stats: {
|
||||
nbFamillesPassees: {
|
||||
label: "Nb familles passées",
|
||||
},
|
||||
nbFamillesProgrammees: {
|
||||
label: "Nb familles programmées",
|
||||
},
|
||||
nbFamillesRecidive: {
|
||||
label: "Nb familles recidive",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
intervalGendarmerieProcureur: {
|
||||
label: "Délai moyen entre Gendarmerie et Procureur",
|
||||
unit: " jours",
|
||||
},
|
||||
intervalProcureurTribunalCorrectionnel: {
|
||||
label: "Délai moyen entre Procureur et Tribunal Correctionnel",
|
||||
unit: " jours",
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
||||
export type StatsPenales = StatsType<typeof statsPenalesDesc>;
|
|
@ -0,0 +1,159 @@
|
|||
import { differenceInDays } from "date-fns";
|
||||
import {
|
||||
isCompositionPenale,
|
||||
isCRPC,
|
||||
isEvenementBefore,
|
||||
isEvtProcureur,
|
||||
isGendarmerie,
|
||||
} from "../../../data/EvenementFamille";
|
||||
import { Famille } from "../../../data/Famille";
|
||||
import { average } from "../../../utils/math/average";
|
||||
import { filterFamillesWithOneOfEvenements } from "../filterFamillesWithOneOfEvenements";
|
||||
import { filterFamillesWithOneOfEvenementsOfType } from "../filterFamillesWithOneOfEvenementsOfType";
|
||||
import { StatsPenales } from "./StatsPenales";
|
||||
|
||||
export function computeStatsPenales(familles: Famille[]): StatsPenales {
|
||||
const famillesMisesEnDemeure = filterFamillesWithOneOfEvenementsOfType(
|
||||
familles,
|
||||
"Mise en demeure de scolarisation"
|
||||
);
|
||||
const famillesAvecGendarmerie = filterFamillesWithOneOfEvenements(
|
||||
familles,
|
||||
isGendarmerie
|
||||
);
|
||||
const statsPenales: StatsPenales = {
|
||||
nbFamillesMisesEnDemeure: famillesMisesEnDemeure.length,
|
||||
nbFamillesAvecGendarmerie: famillesAvecGendarmerie.length,
|
||||
compositionPenales: computeCompositionPenales(familles),
|
||||
crpc: computeCrpc(familles),
|
||||
tribunalCorrectionnel: computeTribunalCorrectionnel(familles),
|
||||
intervalGendarmerieProcureur: computeIntervalGendarmerieProcureur(familles),
|
||||
intervalProcureurTribunalCorrectionnel:
|
||||
computeIntervalProcureurTribunalCorrectionnel(familles),
|
||||
};
|
||||
return statsPenales;
|
||||
}
|
||||
|
||||
function computeCrpc(familles: Famille[]): StatsPenales["crpc"] {
|
||||
const famillesConcernees = filterFamillesWithOneOfEvenements(familles, (e) =>
|
||||
isCRPC(e)
|
||||
);
|
||||
const acceptees = filterFamillesWithOneOfEvenementsOfType(
|
||||
familles,
|
||||
"Acceptation CRPC"
|
||||
);
|
||||
const refusees = filterFamillesWithOneOfEvenementsOfType(
|
||||
familles,
|
||||
"Refus CRPC"
|
||||
);
|
||||
|
||||
return {
|
||||
nbFamilles: famillesConcernees.length,
|
||||
acceptees: acceptees.length,
|
||||
refusees: refusees.length,
|
||||
};
|
||||
}
|
||||
|
||||
function computeCompositionPenales(
|
||||
familles: Famille[]
|
||||
): StatsPenales["compositionPenales"] {
|
||||
const famillesConcernees = filterFamillesWithOneOfEvenements(familles, (e) =>
|
||||
isCompositionPenale(e)
|
||||
);
|
||||
const acceptees = filterFamillesWithOneOfEvenementsOfType(
|
||||
familles,
|
||||
"Composition pénale acceptée"
|
||||
);
|
||||
const refusees = filterFamillesWithOneOfEvenementsOfType(
|
||||
familles,
|
||||
"Composition pénale refusée"
|
||||
);
|
||||
|
||||
return {
|
||||
nbFamilles: famillesConcernees.length,
|
||||
acceptees: acceptees.length,
|
||||
refusees: refusees.length,
|
||||
};
|
||||
}
|
||||
|
||||
function computeTribunalCorrectionnel(
|
||||
familles: Famille[]
|
||||
): StatsPenales["tribunalCorrectionnel"] {
|
||||
const now = new Date();
|
||||
const famillesPassees = filterFamillesWithOneOfEvenements(
|
||||
familles,
|
||||
(e) => e.Type === "Tribunal correctionnel" && isEvenementBefore(e, now)
|
||||
);
|
||||
const famillesProgrammees = filterFamillesWithOneOfEvenements(
|
||||
familles,
|
||||
(e) => e.Type === "Tribunal correctionnel" && !isEvenementBefore(e, now)
|
||||
);
|
||||
|
||||
const famillesRecidiveTribunal = familles.filter((f) => {
|
||||
return (
|
||||
f.Evenements.filter((e) => e.Type === "Tribunal correctionnel").length > 1
|
||||
);
|
||||
});
|
||||
|
||||
return {
|
||||
nbFamillesPassees: famillesPassees.length,
|
||||
nbFamillesProgrammees: famillesProgrammees.length,
|
||||
nbFamillesRecidive: famillesRecidiveTribunal.length,
|
||||
};
|
||||
}
|
||||
|
||||
function computeIntervalGendarmerieProcureur(familles: Famille[]): number {
|
||||
const intervals = familles.flatMap((f) => {
|
||||
const evtGendarmerie = f.Evenements.find((e) => isGendarmerie(e));
|
||||
const evtProcureur = f.Evenements.find((e) => isEvtProcureur(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 for ${f.Titre} (${f.notionId})`
|
||||
);
|
||||
return [];
|
||||
} else {
|
||||
return [intervalInDays];
|
||||
}
|
||||
});
|
||||
return average(intervals);
|
||||
}
|
||||
|
||||
function computeIntervalProcureurTribunalCorrectionnel(
|
||||
familles: Famille[]
|
||||
): number {
|
||||
const intervals = familles.flatMap((f) => {
|
||||
const evtProcureur = f.Evenements.find((e) => isEvtProcureur(e));
|
||||
const evtTribunal = f.Evenements.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);
|
||||
}
|
Loading…
Reference in New Issue