diff --git a/src/features/grid/api/get-product-rows.ts b/src/features/grid/api/get-product-rows.ts index 725257f..376232c 100644 --- a/src/features/grid/api/get-product-rows.ts +++ b/src/features/grid/api/get-product-rows.ts @@ -47,10 +47,33 @@ export function invalidateGridRowsCache(codeFournisseur?: string) { gridRowsPending.clear(); } +/** + * Rafraîchit UNIQUEMENT la colonne INIT (codeGammeInit = gamme serveur courante) + * sur des lignes servies depuis le cache. La colonne Gamme (codeGamme) n'est pas + * touchée : elle conserve la valeur issue du snapshot. Ainsi l'état serveur (INIT) + * est toujours à jour à chaque chargement, même sur un hit du cache 10 min — et le + * marqueur "modifié" (Gamme ≠ INIT) se résorbe dès que le serveur rattrape la modif. + */ +async function refreshGammeInit(rows: ProductRow[], codeFournisseur: string): Promise { + try { + const gammeMap = await pgGetGammesByFournisseur(codeFournisseur); + if (gammeMap.size === 0) return; + for (const row of rows) { + const live = gammeMap.get(row.codein); + if (live !== undefined) row.codeGammeInit = live as GammeCode; + } + } catch (e) { + console.error("[getProductRows] refreshGammeInit error:", (e as Error).message?.slice(0, 200)); + } +} + export async function getProductRows(input: GetProductRowsInput): Promise { const cacheKey = gridRowsCacheKey(input); const cached = gridRowsCache.get(cacheKey); if (!input.forceRefresh && cached && Date.now() - cached.createdAt < GRID_ROWS_CACHE_TTL_MS) { + // La colonne INIT doit refléter l'état serveur à CHAQUE chargement, + // y compris sur un hit de cache (les données lourdes restent, elles, cachées). + await refreshGammeInit(cached.rows, input.codeFournisseur); return cached.rows; } @@ -314,6 +337,9 @@ async function buildProductRows(input: GetProductRowsInput): Promise 0 : mvtart contient des lignes genremvt=3 de quantité - * sans montant (corrections/régularisations, ex: codein 487673 site 579 — - * 38 affiché au lieu de 24 réels, CA exact). Une vente réelle a toujours un - * montant TTC non nul ; les endpoints officiels de l'API les excluent aussi. + * Cas vérifié (codein 487673, site 579, jan→juil 2026) : 31 ventes brutes, + * 7 retours clients → 24 net. L'ancien SUM(ABS(qtemvt)) affichait 38 (retours + * additionnés) ; SUM(-qtemvt) donne 24, identique à l'API mensuel officielle. */ export async function pgGetHitParade(dateDebut: string, dateFin: string): Promise { const result = await pgNoParallel(sql` @@ -789,8 +788,6 @@ export async function pgGetHitParade(dateDebut: string, dateFin: string): Promis WHERE m.datmvt BETWEEN ${dateDebut}::date AND ${dateFin}::date AND m.site IN ('292', '579') AND m.genremvt = 3 - AND m.mntmvtttc IS NOT NULL - AND m.mntmvtttc <> 0 AND a.codein IS NOT NULL GROUP BY TRIM(a.codein::text), m.site ), @@ -979,7 +976,7 @@ export async function pgGetStockNegatif(site?: string): Promise