Adds CA par Magasin, Couverture stock Qte, Marge % and Stock Rupture %
network measures to the Qlik hypercube extraction (in-page Playwright ws
+ legacy server ws), persists them in qlik_network_metrics, joins them in
getProductRows and renders 4 new grid columns with buy-signal coloring
(low coverage / high margin = green; high rupture = rose).
- qlik-client: config IDs (env-overridable, master GUIDs of app 9872ee6e),
NetworkMetric fields, hypercube width 4->8, page height 2500->1250
- qlik-playwright: same 4 measures in the in-page hypercube + row mapping
- schema + db-init: 4 numeric columns (ALTER ADD COLUMN IF NOT EXISTS for
existing DBs)
- cache + grid types + enrich: plumb the new fields end to end
Note: percent measures stored as raw Qlik ratio; UI renders x100 when |v|<=1.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Instead of unreliable preference=1, use artfou1.no_id DESC (most recently
added artfou1 entry) to identify the last supplier for each product.
Shows an amber warning icon in the Désignation column when the last
supplier ≠ current supplier view, with tooltip showing who to attribute
the sales to.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Remove infinite grid loading, useInfiniteGrid hook, and server-side
pagination API route. Revert grid components to the simpler version
that avoids 2MB+ cache failures from unstable_cache.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The ranking bulk endpoint is capped at 500 by the API server, making
it useless for full supplier matching. Per-article ranking (codein filter)
works correctly and is now called only for articles WITH sales data.
getProductRows restructured:
- Phase 2A: mensuel + commandes in parallel (all articles)
- Phase 2B: referentiel + ranking in parallel, only for articlesWithData
(articles that appear in mensuelMap)
For a 45060-article supplier with 5446 with sales:
- Referentiel: 45060 → 5446 calls (88% reduction)
- Ranking: 45060 → 5446 calls (88% reduction)
totalRankedProducts fetched from GET /api/ranking?limit=500 count.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Remove actif/suspendu filter that caused wrong stats (893€ CA, 249 units)
by incorrectly excluding products with sales. The parallel pagination
and bulk ranking fixes are sufficient to handle large suppliers.
- Increase getMensuelByArticles and getReferentielByArticles batchSize
from 20 to 50, reducing sequential batch iterations by ~2.5x.
- Filter gamme Y products with zero 12-month sales from returned rows.
Reduces grid size (e.g. S053: 14775→fewer rows) without affecting
products that actually sold. Y products with sales are preserved.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
getRankingByArticles now uses GET /api/ranking?foucentrale=<code>
to fetch all rankings for a supplier in a single request instead of
making one request per article. For a 500-article supplier this goes
from ~500 HTTP calls to 2 (count + bulk), eliminating the timeout
that caused the client-side crash on large suppliers.
Falls back to per-article requests if no codeFournisseur is provided
or if the bulk endpoint fails.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replaces raw sql ANY() template (which had array type issues) with
proper Drizzle inArray(), deduplicating by codein in JS.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The old fournisseur code stored in ventesProduits may differ from the
new API codefou (e.g. "AUXENCE" vs "A025"), causing zero results.
Querying by codein = ANY(...) finds the classification data regardless
of how the supplier was previously keyed.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
api-ff-client.ts:
- FfArticle: add reference (ref_fou_principale) and gtin fields
- getArticlesByFournisseur: map ref_fou_principale → reference, gtin → gtin
get-product-rows.ts:
- ProductRow seeded with reference and gtin from API articles
- Phase 6: read codeGamme, codeGammeInit, code3, libelle3 from ventesProduits
(read-only, DISTINCT ON codein ordered by updated_at DESC)
- Phase 7 snapshot still overrides DB gammes when a snapshot exists
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replaces bulk mouvements pagination + per-article stock N+1 with a single
batched call to the new mensuel endpoint (confirmed working via diag).
api-ff-client.ts:
- Remove getStockByFournisseur (no longer needed)
- Add FfMensuelEntry/Ventes/Receptions interfaces
- Add getMensuelByArticles(articles, dateDebut, dateFin, batchSize=20)
→ Map<codein, FfMensuelEntry[]> using no_id as API identifier
get-product-rows.ts:
- Phase 2: getMensuelByArticles + getCommandesByFournisseur in parallel
- Phase 5: aggregate mois×site entries → sales12m, stock12m, workingStores
- qte_vendue / ca_ht are negative → Math.abs()
- stock carry-forward for months with no data
- pa from prmp_fin_mois
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>