fix: améliore la gestion des données manquante

This commit is contained in:
Sébastien Arod 2025-06-16 10:29:41 +02:00
parent 998714105b
commit 456cb3279d
17 changed files with 65 additions and 28 deletions

View file

@ -1,9 +1,13 @@
import { StatsValue } from "../statistiques/v2/desc/StatsDesc";
import { ValueFormatOptions } from "./ValueFormatOptions"; import { ValueFormatOptions } from "./ValueFormatOptions";
export function formatValue( export function formatValue(
value: number, value: StatsValue,
valueFormatOptions: ValueFormatOptions valueFormatOptions: ValueFormatOptions
) { ) {
if (value === undefined) {
return "Pas de données";
}
const valueStr = value.toLocaleString("fr-FR", { const valueStr = value.toLocaleString("fr-FR", {
useGrouping: false, useGrouping: false,
maximumFractionDigits: maximumFractionDigits:

View file

@ -1,7 +1,7 @@
import { formatValue } from "../../../format/formatValue"; import { formatValue } from "../../../format/formatValue";
import { ValueFormatOptions } from "../../../format/ValueFormatOptions"; import { ValueFormatOptions } from "../../../format/ValueFormatOptions";
import { StatsData } from "../../../statistiques/v2/desc/StatsDesc"; import { StatsData, StatsValue } from "../../../statistiques/v2/desc/StatsDesc";
import { chunk, isNumber } from "lodash"; import { chunk, isObject } from "lodash";
import { BlockObjectRequest } from "@notionhq/client/build/src/api-endpoints"; import { BlockObjectRequest } from "@notionhq/client/build/src/api-endpoints";
export function createSingleValueStatListItemBlock( export function createSingleValueStatListItemBlock(
@ -9,7 +9,7 @@ export function createSingleValueStatListItemBlock(
formatOptions: ValueFormatOptions, formatOptions: ValueFormatOptions,
data: StatsData data: StatsData
): BlockObjectRequest { ): BlockObjectRequest {
if (isNumber(data)) { if (!isObject(data)) {
return bulletedListNumberData(label, data, formatOptions); return bulletedListNumberData(label, data, formatOptions);
} else if (data.relatedPageIds.length === 0) { } else if (data.relatedPageIds.length === 0) {
return bulletedListNumberData(label, data.value, formatOptions); return bulletedListNumberData(label, data.value, formatOptions);
@ -50,7 +50,7 @@ export function createSingleValueStatListItemBlock(
function bulletedListNumberData( function bulletedListNumberData(
label: string, label: string,
data: number, data: StatsValue,
formatOptions: ValueFormatOptions formatOptions: ValueFormatOptions
): BlockObjectRequest { ): BlockObjectRequest {
return { return {

View file

@ -65,7 +65,11 @@ export function isMultiValueStatDesc(x: StatDesc): x is MultiValueStatDesc {
return "type" in x && x.type === "multi"; return "type" in x && x.type === "multi";
} }
export type StatsData = number | { value: number; relatedPageIds: string[] }; export type StatsValue = number | undefined;
export type StatsData =
| StatsValue
| { value: StatsValue; relatedPageIds: string[] };
export type StatType<T extends StatDesc> = T extends StatGroupListDesc export type StatType<T extends StatDesc> = T extends StatGroupListDesc
? Record< ? Record<

View file

@ -4,8 +4,8 @@ import {
isExResistant, isExResistant,
isResistant, isResistant,
} from "../../../data/Famille"; } from "../../../data/Famille";
import { average } from "../../../utils/math/average"; import { average } from "../math/average";
import { median } from "../../../utils/math/median"; import { median } from "../math/median";
import { StatsGenerales } from "./StatsGenerales"; import { StatsGenerales } from "./StatsGenerales";
import _, { countBy, uniq } from "lodash"; import _, { countBy, uniq } from "lodash";
import { isIntegrationEnCours } from "../../../data/StatutFamille"; import { isIntegrationEnCours } from "../../../data/StatutFamille";

View file

@ -0,0 +1,7 @@
import { StatsValue } from "../desc/StatsDesc";
export function average(values: number[]): StatsValue {
if (values.length === 0) return undefined;
return values.reduce((a, b) => a + b) / values.length;
}

View file

@ -0,0 +1,7 @@
import { StatsValue } from "../desc/StatsDesc";
export function max(values: number[]): StatsValue {
if (values.length === 0) return undefined;
return Math.max(...values);
}

View file

@ -1,5 +1,7 @@
export function median(values: number[]): number { import { StatsValue } from "../desc/StatsDesc";
if (values.length === 0) return NaN;
export function median(values: number[]): StatsValue {
if (values.length === 0) return undefined;
const sorted = [...values].sort((a, b) => a - b); const sorted = [...values].sort((a, b) => a - b);

View file

@ -0,0 +1,7 @@
import { StatsValue } from "../desc/StatsDesc";
export function min(values: number[]): StatsValue {
if (values.length === 0) return undefined;
return Math.min(...values);
}

View file

@ -0,0 +1,8 @@
import { StatsValue } from "../desc/StatsDesc";
export function percent(value: StatsValue, total: StatsValue): StatsValue {
if (value === undefined || total === undefined) {
return undefined;
}
return (100 * value) / total;
}

View file

@ -3,6 +3,8 @@ import { Famille } from "../../../data/Famille";
import { NamedStatsType } from "../desc/StatsDesc"; import { NamedStatsType } from "../desc/StatsDesc";
import { statsAmendesDesc } from "./StatsPenales"; import { statsAmendesDesc } from "./StatsPenales";
import { isEvtProcedurePenale } from "../../../data/EvenementFamille"; import { isEvtProcedurePenale } from "../../../data/EvenementFamille";
import { max } from "../math/max";
import { min } from "../math/min";
export function computeStatsAmendes( export function computeStatsAmendes(
familles: Famille[] familles: Famille[]
@ -38,10 +40,10 @@ export function computeStatsAmendes(
.map((a) => a.Montant); .map((a) => a.Montant);
const stats = { const stats = {
amendeMinAvecSursi: Math.min(...montantsAvecSursi), amendeMinAvecSursi: min(montantsAvecSursi),
amendeMaxAvecSursi: Math.max(...montantsAvecSursi), amendeMaxAvecSursi: max(montantsAvecSursi),
amendeMinFerme: Math.min(...montantsFerme), amendeMinFerme: min(montantsFerme),
amendeMaxFerme: Math.max(...montantsFerme), amendeMaxFerme: max(montantsFerme),
}; };
return [evtType, stats]; return [evtType, stats];
}) })

View file

@ -23,7 +23,7 @@ import {
} from "./computeFamilleAvecInfosProceduresPenales"; } from "./computeFamilleAvecInfosProceduresPenales";
import { computeIntervalMedGendarmerieOuProcureur } from "./intervals/computeIntervalMedGendarmerieOuProcureur"; import { computeIntervalMedGendarmerieOuProcureur } from "./intervals/computeIntervalMedGendarmerieOuProcureur";
import { groupBy } from "lodash"; import { groupBy } from "lodash";
import { percent } from "../../../utils/math/percent"; import { percent } from "../math/percent";
import { isEvtTypeProcedurePenaleHorsGendarmerie } from "../../../data/TypeEvenementsPenal"; import { isEvtTypeProcedurePenaleHorsGendarmerie } from "../../../data/TypeEvenementsPenal";
import { computeStatsAmendes } from "./computeStatsAmendes"; import { computeStatsAmendes } from "./computeStatsAmendes";

View file

@ -4,10 +4,11 @@ import {
FamilleAvecInfosProceduresPenales, FamilleAvecInfosProceduresPenales,
InfosProcedurePenale, InfosProcedurePenale,
} from "../computeFamilleAvecInfosProceduresPenales"; } from "../computeFamilleAvecInfosProceduresPenales";
import { StatsValue } from "../../desc/StatsDesc";
export function computeIntervalGendarmerieProcureur( export function computeIntervalGendarmerieProcureur(
familles: FamilleAvecInfosProceduresPenales[] familles: FamilleAvecInfosProceduresPenales[]
): number { ): StatsValue {
return computeIntervalProcedurePenale( return computeIntervalProcedurePenale(
familles, familles,
(procPenal: InfosProcedurePenale): number | undefined => { (procPenal: InfosProcedurePenale): number | undefined => {

View file

@ -5,10 +5,11 @@ import {
} from "../computeFamilleAvecInfosProceduresPenales"; } from "../computeFamilleAvecInfosProceduresPenales";
import { computeIntervalProcedurePenale } from "./computeIntervalProcedurePenale"; import { computeIntervalProcedurePenale } from "./computeIntervalProcedurePenale";
import { min } from "lodash"; import { min } from "lodash";
import { StatsValue } from "../../desc/StatsDesc";
export function computeIntervalMedGendarmerieOuProcureur( export function computeIntervalMedGendarmerieOuProcureur(
familles: FamilleAvecInfoProceduresPenales[] familles: FamilleAvecInfoProceduresPenales[]
): number { ): StatsValue {
return computeIntervalProcedurePenale( return computeIntervalProcedurePenale(
familles, familles,
(procPenal: InfosProcedurePenale): number | undefined => { (procPenal: InfosProcedurePenale): number | undefined => {

View file

@ -1,5 +1,6 @@
import { Famille } from "../../../../data/Famille"; import { Famille } from "../../../../data/Famille";
import { average } from "../../../../utils/math/average"; import { StatsValue } from "../../desc/StatsDesc";
import { average } from "../../math/average";
import { import {
FamilleAvecInfosProceduresPenales as FamilleAvecInfoProceduresPenales, FamilleAvecInfosProceduresPenales as FamilleAvecInfoProceduresPenales,
InfosProcedurePenale, InfosProcedurePenale,
@ -13,7 +14,7 @@ export function computeIntervalProcedurePenale(
famille: Famille famille: Famille
) => number | undefined, ) => number | undefined,
intervalName: string intervalName: string
): number { ): StatsValue {
const intervals: number[] = famillesAvecInfoProceduresPenales.flatMap((f) => { const intervals: number[] = famillesAvecInfoProceduresPenales.flatMap((f) => {
return f.proceduresPenales return f.proceduresPenales
.map((pp) => { .map((pp) => {

View file

@ -4,10 +4,11 @@ import {
FamilleAvecInfosProceduresPenales, FamilleAvecInfosProceduresPenales,
InfosProcedurePenale, InfosProcedurePenale,
} from "../computeFamilleAvecInfosProceduresPenales"; } from "../computeFamilleAvecInfosProceduresPenales";
import { StatsValue } from "../../desc/StatsDesc";
export function computeIntervalProcureurTribunalCorrectionnel( export function computeIntervalProcureurTribunalCorrectionnel(
familles: FamilleAvecInfosProceduresPenales[] familles: FamilleAvecInfosProceduresPenales[]
): number { ): StatsValue {
return computeIntervalProcedurePenale( return computeIntervalProcedurePenale(
familles, familles,
(procPenal: InfosProcedurePenale): number | undefined => { (procPenal: InfosProcedurePenale): number | undefined => {

View file

@ -1,5 +0,0 @@
export function average(values: number[]): number {
if (values.length === 0) return NaN;
return values.reduce((a, b) => a + b) / values.length;
}

View file

@ -1,3 +0,0 @@
export function percent(value: number, total: number): number {
return (100 * value) / total;
}