mirror of
https://framagit.org/enfance-libre/statistiques
synced 2025-12-07 13:33:46 +00:00
chore: remove stats v1
This commit is contained in:
parent
f8109fe524
commit
b35a479c49
12 changed files with 45 additions and 612 deletions
|
|
@ -1,9 +1,7 @@
|
||||||
import { Client } from "@notionhq/client";
|
import { Client } from "@notionhq/client";
|
||||||
import { writeFileSync } from "fs";
|
import { writeFileSync } from "fs";
|
||||||
import { fetchFamiliesWithEventsFromNotion } from "./notion/fetch/fetchFamiliesWithEventsFromNotion";
|
import { fetchFamiliesWithEventsFromNotion } from "./notion/fetch/fetchFamiliesWithEventsFromNotion";
|
||||||
import { publishStatisticsToNotion } from "./notion/publish/v1/publishStatisticsToNotion";
|
|
||||||
import { publishStatsToPage } from "./notion/publish/v2/publishStatsToPage";
|
import { publishStatsToPage } from "./notion/publish/v2/publishStatsToPage";
|
||||||
import { computeELStats } from "./statistiques/v1/computeELStats";
|
|
||||||
import { computeStatsPenales } from "./statistiques/v2/penales/computeStatsPenales";
|
import { computeStatsPenales } from "./statistiques/v2/penales/computeStatsPenales";
|
||||||
import { statsPenalesDesc } from "./statistiques/v2/penales/StatsPenales";
|
import { statsPenalesDesc } from "./statistiques/v2/penales/StatsPenales";
|
||||||
import { computeStatsGenerales } from "./statistiques/v2/generales/computeStatsGenerales";
|
import { computeStatsGenerales } from "./statistiques/v2/generales/computeStatsGenerales";
|
||||||
|
|
@ -20,6 +18,7 @@ import { typeEvenementsProcedurePenale } from "./data/TypeEvenementsPenal";
|
||||||
import { nettoyerDonneesFamilles } from "./data/nettoyage/familles/preparerDonneesFamilles";
|
import { nettoyerDonneesFamilles } from "./data/nettoyage/familles/preparerDonneesFamilles";
|
||||||
import { statsAutresDesc } from "./statistiques/v2/autres/StatsAutres";
|
import { statsAutresDesc } from "./statistiques/v2/autres/StatsAutres";
|
||||||
import { computeStatsAutres } from "./statistiques/v2/autres/computeStatsAutres";
|
import { computeStatsAutres } from "./statistiques/v2/autres/computeStatsAutres";
|
||||||
|
import { updateUpdateDate as updateRootPageUpdateDate } from "./notion/publish/updateUpdateDate";
|
||||||
|
|
||||||
type ProcessOptions = {
|
type ProcessOptions = {
|
||||||
dryRun: boolean;
|
dryRun: boolean;
|
||||||
|
|
@ -105,10 +104,7 @@ function buildProcessOptions(): ProcessOptions {
|
||||||
const currentDate = new Date(Date.now());
|
const currentDate = new Date(Date.now());
|
||||||
|
|
||||||
console.log("Calcul des statistiques...");
|
console.log("Calcul des statistiques...");
|
||||||
const elStats = computeELStats(familles, currentDate);
|
|
||||||
|
|
||||||
const statsGenerales = computeStatsGenerales(familles);
|
const statsGenerales = computeStatsGenerales(familles);
|
||||||
|
|
||||||
const statsPenales = computeStatsPenales(familles);
|
const statsPenales = computeStatsPenales(familles);
|
||||||
const statsSociales = computeStatsSociales(familles);
|
const statsSociales = computeStatsSociales(familles);
|
||||||
const statsAutres = computeStatsAutres(familles);
|
const statsAutres = computeStatsAutres(familles);
|
||||||
|
|
@ -127,7 +123,6 @@ function buildProcessOptions(): ProcessOptions {
|
||||||
console.log(
|
console.log(
|
||||||
"Dry run => Pas de publication. Les stats sont écrite localement dans el-stats-xxx"
|
"Dry run => Pas de publication. Les stats sont écrite localement dans el-stats-xxx"
|
||||||
);
|
);
|
||||||
writeFileSync("./el-stats-v1.json", JSON.stringify(elStats, null, " "));
|
|
||||||
|
|
||||||
writeFileSync(
|
writeFileSync(
|
||||||
"./el-stats-v2.json",
|
"./el-stats-v2.json",
|
||||||
|
|
@ -145,7 +140,7 @@ function buildProcessOptions(): ProcessOptions {
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
console.log("Publishing statistics...");
|
console.log("Publishing statistics...");
|
||||||
await publishStatisticsToNotion(elStats, currentDate, notionClient);
|
await updateRootPageUpdateDate(notionClient, currentDate);
|
||||||
|
|
||||||
const header = `Notes:
|
const header = `Notes:
|
||||||
- Dernière mise à jour le ${formatDate(currentDate, "dd/MM/yyyy à HH:mm")}
|
- Dernière mise à jour le ${formatDate(currentDate, "dd/MM/yyyy à HH:mm")}
|
||||||
|
|
|
||||||
43
src/notion/publish/updateUpdateDate.ts
Normal file
43
src/notion/publish/updateUpdateDate.ts
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
import { Client, isFullBlock } from "@notionhq/client";
|
||||||
|
import { listAllChildrenBlocks } from "../utils/listAllChildrenBlocks";
|
||||||
|
import { richTextToPlainText } from "../utils/text/richTextToPlainText";
|
||||||
|
|
||||||
|
export const statsRootPageId = "2b91cd90e3694e96bb196d69aeca59b1";
|
||||||
|
|
||||||
|
export async function updateUpdateDate(notionClient: Client, updateDate: Date) {
|
||||||
|
const childrenBlocks = (
|
||||||
|
await listAllChildrenBlocks(notionClient, {
|
||||||
|
block_id: statsRootPageId,
|
||||||
|
})
|
||||||
|
).filter(isFullBlock);
|
||||||
|
|
||||||
|
const blockTextPrefix = "Dernière mise à jour des statistiques : ";
|
||||||
|
const block = childrenBlocks.find(
|
||||||
|
(b) => b.type === "paragraph" &&
|
||||||
|
richTextToPlainText(b.paragraph.rich_text).startsWith(blockTextPrefix)
|
||||||
|
);
|
||||||
|
if (!block) {
|
||||||
|
console.log(`Could not find block starting with "${blockTextPrefix}"`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await notionClient.blocks.update({
|
||||||
|
block_id: block?.id,
|
||||||
|
paragraph: {
|
||||||
|
rich_text: [
|
||||||
|
{
|
||||||
|
text: {
|
||||||
|
content: blockTextPrefix,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
mention: {
|
||||||
|
date: {
|
||||||
|
start: updateDate.toISOString(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
@ -1,179 +0,0 @@
|
||||||
import { Client, isFullPage } from "@notionhq/client";
|
|
||||||
import {
|
|
||||||
PageObjectResponse,
|
|
||||||
UpdateDatabaseParameters,
|
|
||||||
} from "@notionhq/client/build/src/api-endpoints";
|
|
||||||
import { formatValueWithEvol } from "../../../format/formatValueWithEvol";
|
|
||||||
import {
|
|
||||||
ELStatsPeriod,
|
|
||||||
PeriodStatsValues,
|
|
||||||
ValueWithEvol,
|
|
||||||
} 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";
|
|
||||||
|
|
||||||
export async function publishPeriodStats(
|
|
||||||
notionClient: Client,
|
|
||||||
periodStatsDbId: string,
|
|
||||||
statsPeriods: ELStatsPeriod[]
|
|
||||||
) {
|
|
||||||
if (statsPeriods.length > 0) {
|
|
||||||
await updateDbProps(notionClient, periodStatsDbId, statsPeriods[0].stats);
|
|
||||||
}
|
|
||||||
const periodRows = (
|
|
||||||
await queryAllDbResults(notionClient, {
|
|
||||||
database_id: periodStatsDbId,
|
|
||||||
})
|
|
||||||
).filter(isFullPage);
|
|
||||||
|
|
||||||
const indexedPeriodRows: { [period: string]: PageObjectResponse } =
|
|
||||||
Object.fromEntries(
|
|
||||||
periodRows.map((r) => [
|
|
||||||
titlePropertyToText(r.properties, periodeDbPropertyName),
|
|
||||||
r,
|
|
||||||
])
|
|
||||||
);
|
|
||||||
|
|
||||||
const indexedPeriodStats = Object.fromEntries(
|
|
||||||
statsPeriods.map((stat) => [stat.periodId, stat])
|
|
||||||
);
|
|
||||||
|
|
||||||
const rowIdsToDelete = Object.entries(indexedPeriodRows)
|
|
||||||
.filter(
|
|
||||||
([periodId]) =>
|
|
||||||
!Object.prototype.hasOwnProperty.call(indexedPeriodStats, periodId)
|
|
||||||
)
|
|
||||||
.map(([, row]) => row.id);
|
|
||||||
|
|
||||||
const periodIdsToUpdate = Object.entries(indexedPeriodRows)
|
|
||||||
.filter(([periodId]) =>
|
|
||||||
Object.prototype.hasOwnProperty.call(indexedPeriodStats, periodId)
|
|
||||||
)
|
|
||||||
.map(([periodId]) => periodId);
|
|
||||||
|
|
||||||
const periodIdsToCreate = Object.entries(indexedPeriodStats)
|
|
||||||
.filter(
|
|
||||||
([periodId]) =>
|
|
||||||
!Object.prototype.hasOwnProperty.call(indexedPeriodRows, periodId)
|
|
||||||
)
|
|
||||||
.map(([periodId]) => periodId);
|
|
||||||
|
|
||||||
// Delete rows to delte
|
|
||||||
await removeBlocks(notionClient, rowIdsToDelete);
|
|
||||||
|
|
||||||
// Create rows to create
|
|
||||||
for (const periodId of periodIdsToCreate) {
|
|
||||||
const periodStats = indexedPeriodStats[periodId];
|
|
||||||
await notionClient.pages.create({
|
|
||||||
parent: {
|
|
||||||
database_id: periodStatsDbId,
|
|
||||||
},
|
|
||||||
properties: buildRowPropertiesForUpsert(periodId, periodStats.stats),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update rows
|
|
||||||
for (const periodId of periodIdsToUpdate) {
|
|
||||||
const periodStats = indexedPeriodStats[periodId];
|
|
||||||
const row = indexedPeriodRows[periodId];
|
|
||||||
await notionClient.pages.update({
|
|
||||||
page_id: row.id,
|
|
||||||
properties: buildRowPropertiesForUpsert(periodId, periodStats.stats),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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(
|
|
||||||
periodId: string,
|
|
||||||
stats: PeriodStatsValues<ValueWithEvol>
|
|
||||||
): CreatePageProperties {
|
|
||||||
const statsNotionProps: CreatePageProperties = Object.fromEntries(
|
|
||||||
(Object.keys(stats) as Array<keyof PeriodStatsValues<ValueWithEvol>>).map(
|
|
||||||
(jsProp) => {
|
|
||||||
const value: ValueWithEvol = stats[jsProp];
|
|
||||||
const publishOptions = statPublishOptions(jsProp);
|
|
||||||
return [
|
|
||||||
publishOptions.notionPropName,
|
|
||||||
valueWithEvolProp(value, publishOptions),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
return {
|
|
||||||
[periodeDbPropertyName]: {
|
|
||||||
title: [
|
|
||||||
{
|
|
||||||
text: {
|
|
||||||
content: periodId,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
...statsNotionProps,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function valueWithEvolProp(
|
|
||||||
n: ValueWithEvol,
|
|
||||||
publishOptions: StatPublishOptions
|
|
||||||
) {
|
|
||||||
const formatted = formatValueWithEvol(n, publishOptions);
|
|
||||||
return {
|
|
||||||
rich_text: [
|
|
||||||
{
|
|
||||||
text: {
|
|
||||||
content: formatted,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
@ -1,63 +0,0 @@
|
||||||
import { Client, isFullBlock } from "@notionhq/client";
|
|
||||||
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";
|
|
||||||
|
|
||||||
export const statsPageId = "2b91cd90e3694e96bb196d69aeca59b1";
|
|
||||||
export const currentStatsHeading = "Statistiques v1";
|
|
||||||
|
|
||||||
const yearStatsDb = "4b19a72aa07840eab948525ea41878ee";
|
|
||||||
const monthStatsDb = "8418a8a4a7544f6a8c54e6003be7efe5";
|
|
||||||
export async function publishStatisticsToNotion(
|
|
||||||
stats: ELStats,
|
|
||||||
currentDate: Date,
|
|
||||||
notionClient: Client
|
|
||||||
) {
|
|
||||||
await updateUpdateDate(notionClient, currentDate);
|
|
||||||
await publishStatsActuelles(notionClient, stats.actuelles);
|
|
||||||
|
|
||||||
await publishPeriodStats(notionClient, yearStatsDb, stats.annees);
|
|
||||||
|
|
||||||
await publishPeriodStats(notionClient, monthStatsDb, stats.mois);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function updateUpdateDate(notionClient: Client, updateDate: Date) {
|
|
||||||
const childrenBlocks = (
|
|
||||||
await listAllChildrenBlocks(notionClient, {
|
|
||||||
block_id: statsPageId,
|
|
||||||
})
|
|
||||||
).filter(isFullBlock);
|
|
||||||
|
|
||||||
const blockTextPrefix = "Dernière mise à jour des statistiques : ";
|
|
||||||
const block = childrenBlocks.find(
|
|
||||||
(b) =>
|
|
||||||
b.type === "paragraph" &&
|
|
||||||
richTextToPlainText(b.paragraph.rich_text).startsWith(blockTextPrefix)
|
|
||||||
);
|
|
||||||
if (!block) {
|
|
||||||
console.log(`Could not find block starting with "${blockTextPrefix}"`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await notionClient.blocks.update({
|
|
||||||
block_id: block?.id,
|
|
||||||
paragraph: {
|
|
||||||
rich_text: [
|
|
||||||
{
|
|
||||||
text: {
|
|
||||||
content: blockTextPrefix,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
mention: {
|
|
||||||
date: {
|
|
||||||
start: updateDate.toISOString(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
@ -1,81 +0,0 @@
|
||||||
import { Client, isFullBlock } from "@notionhq/client";
|
|
||||||
import { BlockObjectRequest } from "@notionhq/client/build/src/api-endpoints";
|
|
||||||
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,
|
|
||||||
statsActuelles: ELStatsAtDate<number>
|
|
||||||
) {
|
|
||||||
const newBlocks = (
|
|
||||||
Object.keys(statsActuelles) as Array<keyof typeof statsActuelles>
|
|
||||||
).map((jsProp) => {
|
|
||||||
const value: number = statsActuelles[jsProp];
|
|
||||||
const publishOptions = statPublishOptions(jsProp);
|
|
||||||
return currentStatBlock(value, publishOptions);
|
|
||||||
});
|
|
||||||
await updateStatsActuellesBlocks(notionClient, newBlocks);
|
|
||||||
}
|
|
||||||
|
|
||||||
function currentStatBlock(
|
|
||||||
value: number,
|
|
||||||
publishOptions: StatPublishOptions
|
|
||||||
): BlockObjectRequest {
|
|
||||||
const formattedValue = formatValue(value, publishOptions);
|
|
||||||
|
|
||||||
const content = `${publishOptions.notionPropName} : ${formattedValue}`;
|
|
||||||
return {
|
|
||||||
paragraph: {
|
|
||||||
rich_text: [
|
|
||||||
{
|
|
||||||
text: {
|
|
||||||
content: content,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
async function updateStatsActuellesBlocks(
|
|
||||||
notionClient: Client,
|
|
||||||
blocks: BlockObjectRequest[]
|
|
||||||
) {
|
|
||||||
const childrenBlocks = (
|
|
||||||
await listAllChildrenBlocks(notionClient, {
|
|
||||||
block_id: statsPageId,
|
|
||||||
})
|
|
||||||
).filter(isFullBlock);
|
|
||||||
|
|
||||||
const currentStatsHeadingBlockIndex = childrenBlocks.findIndex(
|
|
||||||
(block) =>
|
|
||||||
block.type === "heading_1" &&
|
|
||||||
richTextToPlainText(block.heading_1.rich_text) === currentStatsHeading
|
|
||||||
);
|
|
||||||
const endOfCurrentStats = childrenBlocks.findIndex(
|
|
||||||
(block, index) =>
|
|
||||||
index > currentStatsHeadingBlockIndex && block.type === "heading_1"
|
|
||||||
);
|
|
||||||
if (currentStatsHeadingBlockIndex === -1 || endOfCurrentStats === -1) {
|
|
||||||
throw new Error("Cannot find expected headings in statistics page");
|
|
||||||
}
|
|
||||||
|
|
||||||
const currentStatsHeadingBlock =
|
|
||||||
childrenBlocks[currentStatsHeadingBlockIndex];
|
|
||||||
|
|
||||||
const blocksIdsToRemove = childrenBlocks
|
|
||||||
.slice(currentStatsHeadingBlockIndex + 1, endOfCurrentStats)
|
|
||||||
.map((b) => b.id);
|
|
||||||
await removeBlocks(notionClient, blocksIdsToRemove);
|
|
||||||
|
|
||||||
await notionClient.blocks.children.append({
|
|
||||||
block_id: statsPageId,
|
|
||||||
after: currentStatsHeadingBlock.id,
|
|
||||||
children: [...blocks],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
@ -1,33 +0,0 @@
|
||||||
import { EvolFormatOptions } from "../../../format/EvolFormatOptions";
|
|
||||||
import { ValueFormatOptions } from "../../../format/ValueFormatOptions";
|
|
||||||
import { AllStatsPropNames } from "../../../statistiques/v1/ELStats";
|
|
||||||
|
|
||||||
export function statPublishOptions(
|
|
||||||
statJsPropName: AllStatsPropNames
|
|
||||||
): StatPublishOptions {
|
|
||||||
return statPropsPublishOptions[statJsPropName];
|
|
||||||
}
|
|
||||||
const statPropsPublishOptions: {
|
|
||||||
[jsPropName in AllStatsPropNames]: StatPublishOptions;
|
|
||||||
} = {
|
|
||||||
// Autre
|
|
||||||
|
|
||||||
nbFamillesAvecContrôleFiscal: {
|
|
||||||
notionPropName: "Nb familles ayant eu un contrôle fiscal",
|
|
||||||
},
|
|
||||||
pourcentageFamillesAvecContrôleFiscal: {
|
|
||||||
notionPropName: "% familles ayant eu un contrôle fiscal",
|
|
||||||
unit: "%",
|
|
||||||
},
|
|
||||||
nbFamillesAvecContrôleURSSAF: {
|
|
||||||
notionPropName: "Nb familles ayant eu un contrôle URSAFF",
|
|
||||||
},
|
|
||||||
pourcentageFamillesAvecContrôleURSSAF: {
|
|
||||||
notionPropName: "% familles ayant eu un contrôle URSAFF",
|
|
||||||
unit: "%",
|
|
||||||
},
|
|
||||||
};
|
|
||||||
export type StatPublishOptions = {
|
|
||||||
notionPropName: string;
|
|
||||||
} & ValueFormatOptions &
|
|
||||||
EvolFormatOptions;
|
|
||||||
|
|
@ -1,29 +0,0 @@
|
||||||
export type ELStats = {
|
|
||||||
actuelles: ELStatsAtDate<number>;
|
|
||||||
annees: ELStatsPeriod[];
|
|
||||||
|
|
||||||
mois: ELStatsPeriod[];
|
|
||||||
};
|
|
||||||
|
|
||||||
export type ELStatsAtDate<V> = {
|
|
||||||
// Autre
|
|
||||||
nbFamillesAvecContrôleFiscal: V;
|
|
||||||
pourcentageFamillesAvecContrôleFiscal: V;
|
|
||||||
nbFamillesAvecContrôleURSSAF: V;
|
|
||||||
pourcentageFamillesAvecContrôleURSSAF: V;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type ELStatsPeriod = {
|
|
||||||
periodId: string;
|
|
||||||
stats: PeriodStatsValues<ValueWithEvol>;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type PeriodStatsValues<V> = ELStatsAtDate<V>;
|
|
||||||
|
|
||||||
export type ValueWithEvol = {
|
|
||||||
value: number;
|
|
||||||
evol: number;
|
|
||||||
evolPercent: number;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type AllStatsPropNames = keyof ELStatsAtDate<number>;
|
|
||||||
|
|
@ -1,74 +0,0 @@
|
||||||
import { Famille } from "../../data/Famille";
|
|
||||||
import { IdentifiedPeriod } from "../../period/IdentifiedPeriod";
|
|
||||||
import { Period } from "../../period/Period";
|
|
||||||
import { ELStatsPeriod, PeriodStatsValues, ValueWithEvol } from "./ELStats";
|
|
||||||
import { computeELStatsAtDate } from "./computeELStatsAtDate";
|
|
||||||
|
|
||||||
export function computeELPeriodStats(
|
|
||||||
familles: Famille[],
|
|
||||||
periods: IdentifiedPeriod[]
|
|
||||||
): ELStatsPeriod[] {
|
|
||||||
let previousPeriodStatNumberValues: PeriodStatsValues<number> | null = null;
|
|
||||||
return periods.map((period) => {
|
|
||||||
const periodStatNumberValues: PeriodStatsValues<number> =
|
|
||||||
computePeriodStatsNumberValues(familles, period);
|
|
||||||
|
|
||||||
// Compute evol
|
|
||||||
const statsWithEvol = computeStatsEvol(
|
|
||||||
periodStatNumberValues,
|
|
||||||
previousPeriodStatNumberValues
|
|
||||||
);
|
|
||||||
previousPeriodStatNumberValues = periodStatNumberValues;
|
|
||||||
const periodStats: ELStatsPeriod = {
|
|
||||||
periodId: period.id,
|
|
||||||
stats: statsWithEvol,
|
|
||||||
};
|
|
||||||
return periodStats;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function computePeriodStatsNumberValues(
|
|
||||||
familles: Famille[],
|
|
||||||
period: Period
|
|
||||||
): PeriodStatsValues<number> {
|
|
||||||
return computeELStatsAtDate(familles, period.end);
|
|
||||||
}
|
|
||||||
|
|
||||||
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(
|
|
||||||
value: number,
|
|
||||||
previous: number | undefined
|
|
||||||
): ValueWithEvol {
|
|
||||||
return {
|
|
||||||
value: value,
|
|
||||||
evol: evol(value, previous),
|
|
||||||
evolPercent: evolPercent(value, previous),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function evolPercent(current: number, previous: number | undefined): number {
|
|
||||||
if (previous === undefined) return NaN;
|
|
||||||
const evolValue = evol(current, previous);
|
|
||||||
if (evolValue === 0) return 0;
|
|
||||||
return (100 * evolValue) / previous;
|
|
||||||
}
|
|
||||||
|
|
||||||
function evol(current: number, previous: number | undefined): number {
|
|
||||||
if (previous === undefined) return NaN;
|
|
||||||
return current - previous;
|
|
||||||
}
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
import { Famille } from "../../data/Famille";
|
|
||||||
import { computeELPeriodStats } from "./computeELPeriodStats";
|
|
||||||
import { computeELStatsAtDate } from "./computeELStatsAtDate";
|
|
||||||
import { ELStats } from "./ELStats";
|
|
||||||
import { generateELMonths } from "../../period/generateELMonths";
|
|
||||||
import { generateELYears } from "../../period/generateELYears";
|
|
||||||
|
|
||||||
export function computeELStats(
|
|
||||||
families: Famille[],
|
|
||||||
currentDate: Date
|
|
||||||
): ELStats {
|
|
||||||
const actuelles = computeELStatsAtDate(families, currentDate);
|
|
||||||
|
|
||||||
const yearsStats = computeELPeriodStats(families, generateELYears());
|
|
||||||
|
|
||||||
const monthsStats = computeELPeriodStats(families, generateELMonths());
|
|
||||||
|
|
||||||
return {
|
|
||||||
actuelles: actuelles,
|
|
||||||
annees: yearsStats,
|
|
||||||
mois: monthsStats,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
@ -1,35 +0,0 @@
|
||||||
import { Famille, isExResistant, isResistant } from "../../data/Famille";
|
|
||||||
import { percent } from "../../utils/math/percent";
|
|
||||||
import { ELStatsAtDate } from "./ELStats";
|
|
||||||
|
|
||||||
export function computeELStatsAtDate(
|
|
||||||
familles: Famille[],
|
|
||||||
asOfDate: Date
|
|
||||||
): ELStatsAtDate<number> {
|
|
||||||
const familleResistantesOrEx = familles.filter(
|
|
||||||
(famille) =>
|
|
||||||
isResistant(famille, asOfDate) || isExResistant(famille, asOfDate)
|
|
||||||
);
|
|
||||||
|
|
||||||
const famillesAvecContrôleFiscal = familleResistantesOrEx.filter((f) =>
|
|
||||||
f.EvenementsEL.find((e) => e.Type === "Contrôle fiscal")
|
|
||||||
);
|
|
||||||
|
|
||||||
const famillesAvecContrôleURSAFF = familleResistantesOrEx.filter((f) =>
|
|
||||||
f.EvenementsEL.find((e) => e.Type === "Contrôle URSSAF")
|
|
||||||
);
|
|
||||||
const elStats: ELStatsAtDate<number> = {
|
|
||||||
// Autre
|
|
||||||
nbFamillesAvecContrôleFiscal: famillesAvecContrôleFiscal.length,
|
|
||||||
pourcentageFamillesAvecContrôleFiscal: percent(
|
|
||||||
famillesAvecContrôleFiscal.length,
|
|
||||||
familleResistantesOrEx.length
|
|
||||||
),
|
|
||||||
nbFamillesAvecContrôleURSSAF: famillesAvecContrôleURSAFF.length,
|
|
||||||
pourcentageFamillesAvecContrôleURSSAF: percent(
|
|
||||||
famillesAvecContrôleURSAFF.length,
|
|
||||||
familleResistantesOrEx.length
|
|
||||||
),
|
|
||||||
};
|
|
||||||
return elStats;
|
|
||||||
}
|
|
||||||
|
|
@ -1,71 +0,0 @@
|
||||||
import { addMonths } from "date-fns";
|
|
||||||
import {
|
|
||||||
EvenementFamille,
|
|
||||||
isEvenementBefore,
|
|
||||||
} from "../../data/EvenementFamille";
|
|
||||||
import { Famille } from "../../data/Famille";
|
|
||||||
import { percent } from "../../utils/math/percent";
|
|
||||||
import { statutExResistant, statutResistant } from "../../data/StatutFamille";
|
|
||||||
|
|
||||||
type FamillesWithEventsConditionInEarlyPeriod = {
|
|
||||||
[name: string]: {
|
|
||||||
nbFamillesWithAtLeastDuration: number;
|
|
||||||
nbFamillesWithEventPredicate: number;
|
|
||||||
percentage: number;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export const computeFamillesWithEventsConditionInEarlyPeriod = (
|
|
||||||
familles: Famille[],
|
|
||||||
eventsPredicate: (events: EvenementFamille[]) => boolean,
|
|
||||||
durations: {
|
|
||||||
[name: string]: number;
|
|
||||||
} = {
|
|
||||||
"0 mois": 0,
|
|
||||||
"3 mois": 3,
|
|
||||||
"6 mois": 6,
|
|
||||||
"12 mois": 12,
|
|
||||||
"24 mois": 24,
|
|
||||||
}
|
|
||||||
): FamillesWithEventsConditionInEarlyPeriod => {
|
|
||||||
const evalDate = new Date(Date.now());
|
|
||||||
return Object.fromEntries(
|
|
||||||
Object.entries(durations).map(([name, months]) => {
|
|
||||||
const famillesWithAtLeastDurationOfDc = familles
|
|
||||||
.filter(
|
|
||||||
(f) => f.Statut === statutResistant || f.Statut === statutExResistant
|
|
||||||
)
|
|
||||||
.filter(
|
|
||||||
(f) =>
|
|
||||||
dcStartDate(f) !== null &&
|
|
||||||
addMonths(dcStartDate(f)!, months) < evalDate
|
|
||||||
);
|
|
||||||
|
|
||||||
const famillesWithEventPredicate = famillesWithAtLeastDurationOfDc.filter(
|
|
||||||
(f) => {
|
|
||||||
const dcDate = dcStartDate(f)!;
|
|
||||||
const dcPeriodEnd = addMonths(dcDate, months);
|
|
||||||
const eventsBeforeDate = f.EvenementsEL.filter((e) =>
|
|
||||||
isEvenementBefore(e, dcPeriodEnd)
|
|
||||||
);
|
|
||||||
return eventsPredicate(eventsBeforeDate);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
return [
|
|
||||||
name,
|
|
||||||
{
|
|
||||||
nbFamillesWithAtLeastDuration: famillesWithAtLeastDurationOfDc.length,
|
|
||||||
nbFamillesWithEventPredicate: famillesWithEventPredicate.length,
|
|
||||||
percentage: percent(
|
|
||||||
famillesWithEventPredicate.length,
|
|
||||||
famillesWithAtLeastDurationOfDc.length
|
|
||||||
),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
})
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const dcStartDate = (famille: Famille): Date | null => {
|
|
||||||
return famille.Integration;
|
|
||||||
};
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
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;
|
|
||||||
}
|
|
||||||
Loading…
Add table
Reference in a new issue