74 lines
2.3 KiB
TypeScript
74 lines
2.3 KiB
TypeScript
/**
|
|
* Calculs purs des tendances OPEX utilisées par les vignettes de catégories.
|
|
*
|
|
* Cette fonction ne dépend volontairement ni de React, ni des fichiers JSON
|
|
* historiques : la comparaison est toujours faite avec les montants réellement
|
|
* chargés pour l'exercice précédent.
|
|
*/
|
|
export type OpexCategoryLine = {
|
|
categorie: string | null | undefined;
|
|
montant: number;
|
|
};
|
|
|
|
export type OpexCategoryTrend = {
|
|
montantN1: number | null;
|
|
variationPct: number | null;
|
|
tendance: "hausse" | "baisse" | "stable" | "new";
|
|
};
|
|
|
|
/** Toute variation strictement inférieure à ce seuil est considérée stable. */
|
|
export const STABLE_VARIATION_THRESHOLD_PERCENT = 2;
|
|
|
|
function toCategoryTotals(lines: OpexCategoryLine[]): Record<string, number> {
|
|
return lines.reduce<Record<string, number>>((totals, line) => {
|
|
const category = line.categorie?.trim() || "Autre";
|
|
totals[category] = (totals[category] ?? 0) + line.montant;
|
|
return totals;
|
|
}, {});
|
|
}
|
|
|
|
/**
|
|
* Retourne les tendances par catégorie pour l'exercice courant.
|
|
*
|
|
* Les pourcentages sont arrondis à une décimale pour correspondre à l'affichage
|
|
* et éviter des différences entre le badge et les données fournies au composant.
|
|
*/
|
|
export function calculateCategoryTrends(
|
|
currentLines: OpexCategoryLine[],
|
|
previousLines: OpexCategoryLine[],
|
|
): Record<string, OpexCategoryTrend> {
|
|
const currentTotals = toCategoryTotals(currentLines);
|
|
const previousTotals = toCategoryTotals(previousLines);
|
|
|
|
return Object.fromEntries(
|
|
Object.entries(currentTotals).map(([category, currentAmount]) => {
|
|
const previousAmount = previousTotals[category] ?? 0;
|
|
|
|
if (previousAmount === 0) {
|
|
return [
|
|
category,
|
|
{
|
|
montantN1: null,
|
|
variationPct: null,
|
|
tendance: "new" as const,
|
|
},
|
|
];
|
|
}
|
|
|
|
const rawVariation = ((currentAmount - previousAmount) / previousAmount) * 100;
|
|
const variationPct = Math.round(rawVariation * 10) / 10;
|
|
const tendance =
|
|
Math.abs(variationPct) < STABLE_VARIATION_THRESHOLD_PERCENT
|
|
? "stable"
|
|
: variationPct > 0
|
|
? "hausse"
|
|
: "baisse";
|
|
|
|
return [
|
|
category,
|
|
{ montantN1: previousAmount, variationPct, tendance },
|
|
];
|
|
}),
|
|
);
|
|
}
|