remove proc pénale
parent
21f50efb5a
commit
b4d1a7edad
|
@ -16,5 +16,4 @@
|
||||||
dist
|
dist
|
||||||
test-coverage
|
test-coverage
|
||||||
node_modules
|
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 {
|
export function isEvenementBefore(evt: EvenementFamille, date: Date): boolean {
|
||||||
if (evt.Date === null) {
|
if (evt.Date === null) {
|
||||||
|
// Assume lack of date are oldest events
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return evt.Date < date;
|
return evt.Date < date;
|
||||||
|
@ -101,3 +102,18 @@ export function isValidEvenementFamille(str: string | null): boolean {
|
||||||
Object.prototype.hasOwnProperty.call(categorieEvenement, str)
|
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;
|
Integration: Date | null;
|
||||||
ContexteEntree: ContexteEntreeDC;
|
ContexteEntree: ContexteEntreeDC;
|
||||||
Sortie: Date | null;
|
Sortie: Date | null;
|
||||||
|
// sorted by date asc
|
||||||
Evenements: EvenementFamille[];
|
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", () => {
|
describe("formatValue", () => {
|
||||||
test("format with default options", () => {
|
test("format with default options", () => {
|
||||||
expect(formatValue(42.42, { notionPropName: "whatever" })).toBe("42,4");
|
expect(formatValue(42.42, {})).toBe("42,4");
|
||||||
expect(formatValue(42, { notionPropName: "whatever" })).toBe("42");
|
expect(formatValue(42, {})).toBe("42");
|
||||||
});
|
});
|
||||||
test("format with valueMaxFractioDigits: 2", () => {
|
test("format with valueMaxFractioDigits: 2", () => {
|
||||||
expect(
|
expect(
|
||||||
formatValue(42.4242, {
|
formatValue(42.4242, {
|
||||||
notionPropName: "whatever",
|
|
||||||
valueMaxFractioDigits: 2,
|
valueMaxFractioDigits: 2,
|
||||||
})
|
})
|
||||||
).toBe("42,42");
|
).toBe("42,42");
|
||||||
expect(
|
expect(
|
||||||
formatValue(42, {
|
formatValue(42, {
|
||||||
notionPropName: "whatever",
|
|
||||||
valueMaxFractioDigits: 2,
|
valueMaxFractioDigits: 2,
|
||||||
})
|
})
|
||||||
).toBe("42");
|
).toBe("42");
|
||||||
|
@ -24,7 +22,6 @@ describe("formatValue", () => {
|
||||||
test("format with unit", () => {
|
test("format with unit", () => {
|
||||||
expect(
|
expect(
|
||||||
formatValue(42, {
|
formatValue(42, {
|
||||||
notionPropName: "whatever",
|
|
||||||
unit: "%",
|
unit: "%",
|
||||||
})
|
})
|
||||||
).toBe("42%");
|
).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", {
|
const valueStr = value.toLocaleString("fr-FR", {
|
||||||
useGrouping: false,
|
useGrouping: false,
|
||||||
maximumFractionDigits:
|
maximumFractionDigits:
|
|
@ -1,5 +1,5 @@
|
||||||
import { ValueWithEvol } from "../../../statistiques/ELStats";
|
import { StatPublishOptions } from "../notion/publish/v1/statPublishOptions";
|
||||||
import { StatPublishOptions } from "../../statPublishOptions";
|
import { ValueWithEvol } from "../statistiques/v1/ELStats";
|
||||||
import { formatValue } from "./formatValue";
|
import { formatValue } from "./formatValue";
|
||||||
|
|
||||||
export function formatValueWithEvol(
|
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 { writeFileSync } from "fs";
|
||||||
import { checkDataConsistency } from "./data/checkDataConsistency";
|
import { checkDataConsistency } from "./data/checkDataConsistency";
|
||||||
import { fetchFamiliesWithEventsFromNotion } from "./notion/fetch/fetchFamiliesWithEventsFromNotion";
|
import { fetchFamiliesWithEventsFromNotion } from "./notion/fetch/fetchFamiliesWithEventsFromNotion";
|
||||||
import { publishStatisticsToNotion } from "./notion/publish/publishStatisticsToNotion";
|
import { publishStatisticsToNotion } from "./notion/publish/v1/publishStatisticsToNotion";
|
||||||
import { computeELStats } from "./statistiques/computeELStats";
|
import { publishStatsToPage } from "./notion/publish/v2/publishStatsToPage";
|
||||||
import { computeStatsParAnciennete } from "./statistiques/computeEvenementsParAnciennete";
|
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 = {
|
type ProcessOptions = {
|
||||||
dryRun: boolean;
|
dryRun: boolean;
|
||||||
|
@ -65,13 +68,26 @@ function buildProcessOptions(): ProcessOptions {
|
||||||
"./el-stats-par-anciennete.json",
|
"./el-stats-par-anciennete.json",
|
||||||
JSON.stringify(statsParAnciennete, null, " ")
|
JSON.stringify(statsParAnciennete, null, " ")
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const statsV2 = computeStatsPenales(familles);
|
||||||
|
|
||||||
if (options.dryRun) {
|
if (options.dryRun) {
|
||||||
console.log(
|
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 {
|
} else {
|
||||||
console.log("Publishing statistics...");
|
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 = (
|
const eventPages = (
|
||||||
await queryAllDbResults(notionClient, {
|
await queryAllDbResults(notionClient, {
|
||||||
database_id: familEventsDbId,
|
database_id: familEventsDbId,
|
||||||
|
sorts: [
|
||||||
|
{property: "Date",
|
||||||
|
direction: "ascending"
|
||||||
|
}
|
||||||
|
]
|
||||||
})
|
})
|
||||||
).filter(isFullPage);
|
).filter(isFullPage);
|
||||||
const familyPages = (
|
const familyPages = (
|
||||||
|
|
|
@ -3,17 +3,17 @@ import {
|
||||||
PageObjectResponse,
|
PageObjectResponse,
|
||||||
UpdateDatabaseParameters,
|
UpdateDatabaseParameters,
|
||||||
} from "@notionhq/client/build/src/api-endpoints";
|
} from "@notionhq/client/build/src/api-endpoints";
|
||||||
|
import { formatValueWithEvol } from "../../../format/formatValueWithEvol";
|
||||||
import {
|
import {
|
||||||
ELStatsPeriod,
|
ELStatsPeriod,
|
||||||
PeriodStatsValues,
|
PeriodStatsValues,
|
||||||
ValueWithEvol,
|
ValueWithEvol,
|
||||||
} from "../../statistiques/ELStats";
|
} from "../../../statistiques/v1/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 { StatPublishOptions, statPublishOptions } from "./statPublishOptions";
|
||||||
import { formatValueWithEvol } from "./format/formatValueWithEvol";
|
|
||||||
|
|
||||||
const periodeDbPropertyName = "Période";
|
const periodeDbPropertyName = "Période";
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { Client, isFullBlock } from "@notionhq/client";
|
import { Client, isFullBlock } from "@notionhq/client";
|
||||||
import { ELStats } from "../../statistiques/ELStats";
|
import { ELStats } from "../../../statistiques/v1/ELStats";
|
||||||
import { listAllChildrenBlocks } from "../utils/listAllChildrenBlocks";
|
import { listAllChildrenBlocks } from "../../utils/listAllChildrenBlocks";
|
||||||
import { richTextToPlainText } from "../utils/text/richTextToPlainText";
|
import { richTextToPlainText } from "../../utils/text/richTextToPlainText";
|
||||||
import { publishPeriodStats } from "./publishPeriodStats";
|
import { publishPeriodStats } from "./publishPeriodStats";
|
||||||
import { publishStatsActuelles } from "./publishStatsActuelles";
|
import { publishStatsActuelles } from "./publishStatsActuelles";
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
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 { ELStatsAtDate } from "../../statistiques/ELStats";
|
import { formatValue } from "../../../format/formatValue";
|
||||||
import { StatPublishOptions, statPublishOptions } from "../statPublishOptions";
|
import { ELStatsAtDate } from "../../../statistiques/v1/ELStats";
|
||||||
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";
|
||||||
import { formatValue } from "./format/formatValue";
|
|
||||||
import { currentStatsHeading, statsPageId } from "./publishStatisticsToNotion";
|
import { currentStatsHeading, statsPageId } from "./publishStatisticsToNotion";
|
||||||
|
import { StatPublishOptions, statPublishOptions } from "./statPublishOptions";
|
||||||
|
|
||||||
export async function publishStatsActuelles(
|
export async function publishStatsActuelles(
|
||||||
notionClient: Client,
|
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(
|
export function statPublishOptions(
|
||||||
statJsPropName: AllStatsPropNames
|
statJsPropName: AllStatsPropNames
|
||||||
|
@ -185,8 +187,5 @@ const statPropsPublishOptions: {
|
||||||
};
|
};
|
||||||
export type StatPublishOptions = {
|
export type StatPublishOptions = {
|
||||||
notionPropName: string;
|
notionPropName: string;
|
||||||
unit?: string;
|
} & ValueFormatOptions &
|
||||||
valueMaxFractioDigits?: number;
|
EvolFormatOptions;
|
||||||
evolMaxFractioDigits?: number;
|
|
||||||
evolPctMaxFractioDigits?: number;
|
|
||||||
};
|
|
|
@ -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 { Famille } from "../../data/Famille";
|
||||||
import { IdentifiedPeriod } from "../period/IdentifiedPeriod";
|
import { IdentifiedPeriod } from "../../period/IdentifiedPeriod";
|
||||||
import { Period } from "../period/Period";
|
import { Period } from "../../period/Period";
|
||||||
import {
|
import {
|
||||||
ELStatsOverPeriod,
|
ELStatsOverPeriod,
|
||||||
ELStatsPeriod,
|
ELStatsPeriod,
|
|
@ -1,7 +1,7 @@
|
||||||
import { Famille } from "../data/Famille";
|
import { Famille } from "../../data/Famille";
|
||||||
import { ELStats } from "./ELStats";
|
|
||||||
import { computeELPeriodStats } from "./computeELPeriodStats";
|
import { computeELPeriodStats } from "./computeELPeriodStats";
|
||||||
import { computeELStatsAtDate } from "./computeELStatsAtDate";
|
import { computeELStatsAtDate } from "./computeELStatsAtDate";
|
||||||
|
import { ELStats } from "./ELStats";
|
||||||
import { generateELMonths } from "./generateELMonths";
|
import { generateELMonths } from "./generateELMonths";
|
||||||
import { generateELYears } from "./generateELYears";
|
import { generateELYears } from "./generateELYears";
|
||||||
|
|
|
@ -4,17 +4,17 @@ import {
|
||||||
isEvenementBefore,
|
isEvenementBefore,
|
||||||
isProcedureCivile,
|
isProcedureCivile,
|
||||||
isProcedurePenale,
|
isProcedurePenale,
|
||||||
} from "../data/EvenementFamille";
|
} from "../../data/EvenementFamille";
|
||||||
import {
|
import {
|
||||||
Famille,
|
Famille,
|
||||||
dureeResistanceInDays,
|
dureeResistanceInDays,
|
||||||
isExResistant,
|
isExResistant,
|
||||||
isResistant,
|
isResistant,
|
||||||
} from "../data/Famille";
|
} from "../../data/Famille";
|
||||||
import { average } from "../utils/math/average";
|
import { average } from "../../utils/math/average";
|
||||||
import { median } from "../utils/math/median";
|
import { median } from "../../utils/math/median";
|
||||||
import { percent } from "../utils/math/percent";
|
import { percent } from "../../utils/math/percent";
|
||||||
import { notNull } from "../utils/notNull";
|
import { notNull } from "../../utils/notNull";
|
||||||
import { ELStatsAtDate } from "./ELStats";
|
import { ELStatsAtDate } from "./ELStats";
|
||||||
import { computePourcentageEntreeApresMiseEnDemeure } from "./computePourcentageEntreeApresMiseEnDemeure";
|
import { computePourcentageEntreeApresMiseEnDemeure } from "./computePourcentageEntreeApresMiseEnDemeure";
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
import {
|
import {
|
||||||
isEvenementInPeriod,
|
isEvenementInPeriod,
|
||||||
isProcedurePenale,
|
isProcedurePenale,
|
||||||
} from "../data/EvenementFamille";
|
} from "../../data/EvenementFamille";
|
||||||
import {
|
import {
|
||||||
Famille,
|
Famille,
|
||||||
isResistantOverPeriod,
|
isResistantOverPeriod,
|
||||||
periodOfResistance,
|
periodOfResistance,
|
||||||
} from "../data/Famille";
|
} from "../../data/Famille";
|
||||||
import { Period } from "../period/Period";
|
import { Period } from "../../period/Period";
|
||||||
import { isPeriodContaining } from "../period/isPeriodContaining";
|
import { isPeriodContaining } from "../../period/isPeriodContaining";
|
||||||
import { ELStatsOverPeriod } from "./ELStats";
|
import { ELStatsOverPeriod } from "./ELStats";
|
||||||
import { computePourcentageEntreeApresMiseEnDemeure } from "./computePourcentageEntreeApresMiseEnDemeure";
|
import { computePourcentageEntreeApresMiseEnDemeure } from "./computePourcentageEntreeApresMiseEnDemeure";
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
import { isProcedureCivile, isProcedurePenale } from "../data/EvenementFamille";
|
import {
|
||||||
import { Famille } from "../data/Famille";
|
isProcedureCivile,
|
||||||
|
isProcedurePenale,
|
||||||
|
} from "../../data/EvenementFamille";
|
||||||
|
import { Famille } from "../../data/Famille";
|
||||||
import { computeFamillesWithEventsConditionInEarlyPeriod } from "./computeFamilleWithEventAfterDurationOfDC";
|
import { computeFamillesWithEventsConditionInEarlyPeriod } from "./computeFamilleWithEventAfterDurationOfDC";
|
||||||
|
|
||||||
export function computeStatsParAnciennete(familles: Famille[]) {
|
export function computeStatsParAnciennete(familles: Famille[]) {
|
|
@ -1,7 +1,10 @@
|
||||||
import { addMonths } from "date-fns";
|
import { addMonths } from "date-fns";
|
||||||
import { EvenementFamille, isEvenementBefore } from "../data/EvenementFamille";
|
import {
|
||||||
import { Famille } from "../data/Famille";
|
EvenementFamille,
|
||||||
import { percent } from "../utils/math/percent";
|
isEvenementBefore,
|
||||||
|
} from "../../data/EvenementFamille";
|
||||||
|
import { Famille } from "../../data/Famille";
|
||||||
|
import { percent } from "../../utils/math/percent";
|
||||||
|
|
||||||
type FamillesWithEventsConditionInEarlyPeriod = {
|
type FamillesWithEventsConditionInEarlyPeriod = {
|
||||||
[name: string]: {
|
[name: string]: {
|
|
@ -1,5 +1,5 @@
|
||||||
import { Famille } from "../data/Famille";
|
import { Famille } from "../../data/Famille";
|
||||||
import { percent } from "../utils/math/percent";
|
import { percent } from "../../utils/math/percent";
|
||||||
|
|
||||||
export function computePourcentageEntreeApresMiseEnDemeure(
|
export function computePourcentageEntreeApresMiseEnDemeure(
|
||||||
familles: Famille[]
|
familles: Famille[]
|
|
@ -1,6 +1,6 @@
|
||||||
import { getMonth, getYear, setMonth, setYear } from "date-fns";
|
import { getMonth, getYear, setMonth, setYear } from "date-fns";
|
||||||
import { IdentifiedPeriod } from "../period/IdentifiedPeriod";
|
import { IdentifiedPeriod } from "../../period/IdentifiedPeriod";
|
||||||
import { generateConsecutiveIdentifiedPeriods } from "../period/generateConsecutiveIdentifiedPeriods";
|
import { generateConsecutiveIdentifiedPeriods } from "../../period/generateConsecutiveIdentifiedPeriods";
|
||||||
|
|
||||||
export function generateELMonths(): IdentifiedPeriod[] {
|
export function generateELMonths(): IdentifiedPeriod[] {
|
||||||
const months = generateConsecutiveIdentifiedPeriods({
|
const months = generateConsecutiveIdentifiedPeriods({
|
|
@ -1,6 +1,6 @@
|
||||||
import { addYears } from "date-fns/fp";
|
import { addYears } from "date-fns/fp";
|
||||||
import { IdentifiedPeriod } from "../period/IdentifiedPeriod";
|
import { IdentifiedPeriod } from "../../period/IdentifiedPeriod";
|
||||||
import { generateConsecutiveIdentifiedPeriods } from "../period/generateConsecutiveIdentifiedPeriods";
|
import { generateConsecutiveIdentifiedPeriods } from "../../period/generateConsecutiveIdentifiedPeriods";
|
||||||
|
|
||||||
export function generateELYears(): IdentifiedPeriod[] {
|
export function generateELYears(): IdentifiedPeriod[] {
|
||||||
return generateConsecutiveIdentifiedPeriods({
|
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