mirror of
https://github.com/R0m1k3/CollectFlow.git
synced 2026-10-14 18:58:17 +02:00
merge: piloter Période + garde-fou d'intégrité + sélection par dimension Mois
Fusion de deux lignes de travail parallèles sur main, complémentaires et non concurrentes :cd2e77eselectionnerFenetreViaDimensionMois() — sélectionne les 12 mois par qElemNumber sur la dimension maître Mois. C'est ce qui marche : les champs Date exposés sont dissociés des faits (100 % du total avant comme après), la dimension maître porte les vraies valeurs.4ef0e9fgarde-fou d'intégrité — refuse d'écrire le cache si la fenêtre n'est pas entièrement couverte. C'est pourquoi le cache est resté inchangé au lieu d'être corrompu.726fb84choisirPeriode() — le maillon manquant. Le dump des expressions donne la cause de fond : « Quantité N » = Sum({<Type_Cal={'N'}>} quantite) « Quantité COMP » = Sum({<Type_Cal={'$(vPeriod_comp)'}…>} quantite) Un pont de périodes duplique les lignes de faits ; Type_Cal marque la période analysée (N) ou de comparaison (COMP), et le champ Période (4 valeurs) décide de quelle période il s'agit. Sélectionner correctement les mois ne suffit donc pas : sous la période par défaut, « Quantité N » rend 0 sur tout mois hors période courante, même parfaitement sélectionné. Orchestration fusionnée : 1. choisirPeriode() essaie chaque valeur de Période et MESURE, sur un cube [Mois] × Quantité N, combien de mois de la fenêtre elle rend disponibles. Aucun libellé n'est deviné. 2. Si une période couvre les 12 mois → master measures (exactes sur toute la fenêtre). Sinon → agrégation directe des faits, en secours. 3. Dans les deux cas, la couverture des 12 mois est revérifiée avant persistance ; sinon l'extraction est refusée et le cache laissé intact. La tendance conserve la règle stricte de4ef0e9f(les 12 clés explicitement présentes, ou pas de tendance), qui écarte aussi le « +4100 % » calculé sur deux points pour un article vendu depuis mai. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DfqUihgixw4K1AmJhizWiu
This commit is contained in:
8 files changed
+389
-145
No files matched your search
@@ -60,14 +60,15 @@ export const TREND_COLOR: Record<NetworkTrend["direction"], string> = {
|
||||
* présent dans le cache est donc **ignoré** — sinon la pente est faussée par un
|
||||
* mois tronqué.
|
||||
*
|
||||
* Un mois **absent** du cache n'est PAS supposé nul : l'extraction ne couvre pas
|
||||
* toujours les 12 mois (les mesures Qlik « N » ne savent pas remonter au-delà de
|
||||
* l'année en cours). La sync écrit un zéro **explicite** sur chaque mois qu'elle
|
||||
* a réellement couvert sans vente ; la tendance ne retient donc que les mois
|
||||
* présents comme clés, et ignore purement et simplement les autres.
|
||||
* Une série n'est affichée que si les **12 clés sont explicitement présentes**.
|
||||
* L'extracteur Qlik écrit lui-même les mois sans faits à 0 après avoir validé
|
||||
* la fenêtre et l'égalité avec le total Qlik. Une ancienne extraction partielle
|
||||
* ne peut donc plus être présentée comme une tendance réelle.
|
||||
*
|
||||
* Sans cette distinction, un article vendu seulement depuis mai voyait sa
|
||||
* tendance calculée sur deux points — « +4 100 % · Forte hausse ».
|
||||
* Cette exigence du « tout ou rien » évite deux écueils observés en production :
|
||||
* une tendance calculée sur deux points (« +4 100 % · Forte hausse » pour un
|
||||
* article vendu depuis mai), et des mois non extraits comptés comme des mois
|
||||
* sans vente.
|
||||
*
|
||||
* Utilise tous les points (robuste au bruit d'un mois isolé). L'indicateur `pct` est la
|
||||
* variation modélisée sur la période (pente × durée) rapportée à la moyenne.
|
||||
@@ -79,16 +80,14 @@ export function computeNetworkTrend(
|
||||
): NetworkTrend {
|
||||
const empty: NetworkTrend = { values: [], labels: [], direction: "flat", pct: null, hasData: false };
|
||||
if (!qteByMonth) return empty;
|
||||
const presents = Object.keys(qteByMonth).sort(); // "YYYY-MM" trie chronologiquement
|
||||
if (presents.length === 0) return empty;
|
||||
const labels = buildRolling12QlikMonths(now);
|
||||
const complet = labels.every((label) =>
|
||||
Object.prototype.hasOwnProperty.call(qteByMonth, label) &&
|
||||
Number.isFinite(Number(qteByMonth[label])),
|
||||
);
|
||||
if (!complet) return empty;
|
||||
|
||||
const fenetre = buildRolling12QlikMonths(now);
|
||||
// Seuls les mois RÉELLEMENT extraits comptent : ceux que la sync n'a pas
|
||||
// couverts sont absents des clés et sont écartés, plutôt que comptés à zéro.
|
||||
const labels = fenetre.filter((m) => qteByMonth[m] != null);
|
||||
if (labels.length === 0) return empty;
|
||||
|
||||
const values = labels.map((l) => Number(qteByMonth[l]) || 0);
|
||||
const values = labels.map((l) => Number(qteByMonth[l]));
|
||||
const n = values.length;
|
||||
let pct: number | null = null;
|
||||
let direction: NetworkTrend["direction"] = "flat";
|
||||
|
||||
Reference in new issue
Block a user