Commit Graph
150 Commits
Author SHA1 Message Date
Claude eeaae09282 feat(produits): page de recherche produit + fiche 360° local/réseau
Nouvelle page /produits : recherche par libellé ou par code centrale, puis
fiche complète d'un produit — identité, prix, stock par magasin, ventes sur
12 mois glissants, et l'intégralité des métriques réseau Qlik.

Jusqu'ici les données produit n'étaient accessibles que par fournisseur
(la Grille) ou par classement (Hit Parade) : aucune route n'acceptait un
codein. Les données réseau Qlik n'étaient visibles que dans six colonnes
de la grille d'arbitrage.

Deux analyses ajoutées :
- comparatif local vs réseau, ramené au magasin moyen (indice de
  performance sur les quantités, seule base commune fiable — le CA local
  est TTC et la base du CA Qlik n'est pas documentée, donc indicatif) ;
- opportunités de la même famille : références que le réseau vend bien et
  que nous vendons peu, écart calculé par magasin.

Détail mensuel réseau enrichi : le cube Qlik renvoyait déjà CA, nb de
magasins, CA/magasin et marge % par (article, mois) mais seule la quantité
était conservée. Ces mesures sont désormais stockées dans une nouvelle
colonne metrics_by_month, sans requête Qlik supplémentaire. qte_by_month
reste inchangée — la colonne « Tendance / Réseau » de la Grille en dépend.

L'extraction Qlik peut désormais cibler un seul code centrale
(/api/qlik/sync?codeCentrale=…), ouverte à tout utilisateur connecté et
plafonnée à 3 extractions simultanées ; le mode fournisseur reste
réservé aux admins.

Refactor sans changement de comportement : les helpers de mois, le calcul
de tendance et les graphes SVG quittent heatmap-grid.tsx pour des modules
partagés, et le polling des jobs Qlik devient le hook useQlikSyncJob,
réutilisé par la Grille et par la fiche.

Les calculs de ventes reprennent le SQL canonique de la Grille (genremvt=3
avec quantités niées pour déduire les retours, stock de fin de mois pris
sur le dernier mouvement, report sur les mois sans mouvement), afin que
les chiffres des deux pages soient identiques par construction.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XR8cMbsdjXWChX8seL9NCP
2026-07-27 14:26:08 +00:00
Claude 99097b6eca fix(qlik): dérive les mois N-1 depuis Quantité COMP (vrais 12 mois)
Le cube [Article Code, Mois] ne renvoie que les mois de l'année N (les
mesures 'N' sont nulles ailleurs → lignes supprimées). Le code cherchait
des lignes d'année N-1 qui n'existent pas, donc 'Quantité COMP' n'était
jamais exploitée → seulement ~7 mois affichés.

'Quantité COMP' étant le comparable N-1, à la ligne Mois=YYYYMM elle donne
la quantité du MÊME mois l'année précédente. On dérive donc deux points
par ligne : YYYY-MM (Quantité N) et (YYYY-1)-MM (Quantité COMP) → 12 mois
sans ligne supplémentaire ni requête en plus.

UI : l'en-tête du modal affiche le nombre RÉEL de mois disponibles au lieu
de '12 derniers mois' en dur.
2026-07-25 21:31:15 +00:00
Claude 2af7c42b2b fix(grille): tooltip tendance (régression 12 mois) + lots Qlik plus petits (OOM)
- Corrige le tooltip erroné 'X% (4 derniers mois vs 4 précédents)' →
  'Tendance X% sur 12 mois (régression)'. Le calcul est déjà une
  régression linéaire sur 12 mois ; seul le texte était resté l'ancien.
- Réduit la taille des lots du cube [Article Code, Mois] (800→300, replis
  150/75) pour alléger la mémoire moteur Qlik et limiter les 'Out of
  memory / File corrupted' (3002) observés sur le sync.
2026-07-24 07:41:41 +00:00
Claude 5b5e69eed1 feat(grille): modal en courbe unique + retrait Quantité COMP (2025)
- Modal : les 12 barres remplacées par UNE seule courbe SVG des ventes
  réseau mensuelles (points + quantités affichées + axe des mois).
- Sync : retrait de la mesure 'Quantité COMP' (année N-1) — trop lent à
  récupérer. Retour au cube [Article Code, Mois] à 5 mesures (Quantité N).
  Le détail mensuel couvre donc les mois de l'année en cours ; la tendance
  (régression) se calcule sur ces mois.
2026-07-23 20:40:24 +00:00
Claude 6d349e33b4 feat(grille): modal sur colonne Tendance + tendance par régression 12 mois + Quantité COMP
UI:
- La colonne Tendance (renommée 'Réseau · 12 m') ouvre le modal au clic
  (au lieu de la colonne Nb magasins, remise en simple affichage).
- Tendance calculée par RÉGRESSION LINÉAIRE (moindres carrés) sur les 12
  derniers mois : robuste au bruit, % = pente×durée/moyenne. Libellé
  Forte hausse/Hausse/Stable/Baisse/Forte baisse (seuils ±8% / ±25%).

Sync:
- Ajout de la mesure 'Quantité COMP' (année N-1) au cube [Article Code,
  Mois] → 12 mois glissants : mois de l'année N via Quantité N, mois de
  l'année N-1 via Quantité COMP. Cube 8 colonnes, PAGEM 1200 (<10000
  cellules). Total réseau reste en année N (non gonflé).
  Configurable : QLIK_MEAS_QTE_COMP_ID.
2026-07-23 19:53:20 +00:00
Claude 71563500a0 feat(grille): tendance réseau (sparkline) + modal ventes réseau par mois
Le sync Qlik calculait déjà les ventes réseau mois par mois mais les
sommait en un total. On conserve désormais le détail mensuel.

- Sync : accumulation additive qteByMonth { code: { 'YYYY-MM': qté } }
  in-page (chemins rapide + par lots), rattachée au métrique réseau.
  Reset propre en cas de repli code 15. Total inchangé.
- Stockage : colonne jsonb qte_by_month sur qlik_network_metrics
  (schema + db-init ALTER), upsert + lecture.
- ProductRow.qteReseauByMonth propagé jusqu'à la grille.
- UI grille :
  · colonne '% Présence réseau' remplacée par 'Tendance réseau' :
    sparkline 12 mois teintée + flèche + variation % (moyenne 4 derniers
    mois vs 4 précédents), triable ;
  · cellule 'Nb magasins' rendue cliquable → modal des ventes réseau
    mois par mois (barres, 12 derniers mois).

Nécessite un nouveau Sync Qlik pour peupler le détail mensuel (les
données déjà en cache n'ont que le total → modal 'pas encore de détail').
2026-07-22 14:17:57 +00:00
Claude 2e25bbc5b3 feat(grille): bouton "Rafraîchir" pour forcer le rechargement serveur
Ajoute un bouton dans l'en-tête de la Grille qui force le rechargement
des données depuis le serveur en ignorant le cache mémoire de 10 min
(via le paramètre URL _refresh → refresh=1 → forceRefresh). Utile pour
remonter immédiatement l'état serveur courant, notamment la colonne INIT.
Spinner pendant le chargement, désactivé si un chargement est en cours.
2026-07-21 21:11:28 +00:00
R0m1k3 32f9a27563 Fix Qlik network column sorting 2026-06-22 12:12:48 +00:00
R0m1k3 850852912f fix(qlik): track async sync job status 2026-06-21 19:08:04 +00:00
MichaelandClaude Opus 4.8 de8a435c14 fix(qlik): batch SelectValues to avoid Engine abort + drop couv stock metric
Large supplier (4816 codes) triggered Qlik Engine "Request aborted"
(code 15): a single SelectValues over all codes forced the hypercube to
calculate too many rows at once. Now select in 1200-code batches and
accumulate, keeping each calc small. 1417 codes worked before, 4816 did
not - chunking scales to any supplier.

Also remove the "Couverture de stock" network column end-to-end (grid,
types, Qlik clients, cache, schema, db-init), shifting the marge measure
index from 6 to 5 and the hypercube width from 7 to 6.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 10:55:03 +02:00
MichaelandClaude Opus 4.8 8cc95cb387 fix(grid): align Sync Qlik button with summary-bar actions
The button was a two-line flex-col (button + date below), making it
taller than the single-line Export button next to it, so its button sat
visibly higher in the items-center row. Lay it out inline instead: the
"MAJ Qlik" date sits to the left (hidden under lg, kept in the tooltip),
the button keeps the 36px btn-action height and now aligns with siblings.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 09:41:28 +02:00
MichaelandClaude Opus 4.8 5f364f7d52 feat(grid): refine grid page chrome (refined dense-pro, theme kept)
Redesign the grid page shell while preserving the Slate/teal Apple theme:
- header reworked into a branded bar: teal accent marker + uppercase
  eyebrow + supplier name as the hero, with "Magasin" and "Références"
  metric pills
- loading/error state shown as a teal (or error-red) accent chip
- "Valider" save button restyled with the brand gradient + soft shadow
- grid container radius/shadow aligned to the apple-card system

No change to table cell logic or the network columns.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 09:38:14 +02:00
MichaelandClaude Opus 4.8 524faf4a7a feat(qlik): drop network rupture% metric and the "Sans vente 6 mois" grid tab
Stock Rupture % N saturated at 100% for high-presence products (degenerate
at the article x network grain), so remove it end to end: config id,
NetworkMetric, hypercube (width 8->7), cache, schema, enrich and grid
column. db-init drops the column on existing DBs.

Also remove the "Sans vente 6 mois" tab from the grid page: the grid now
renders directly without the tab switcher; delete the NoSalesTab component.
(The separate Stock negatif page keeps its own sans-vente tabs.)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 09:32:03 +02:00
MichaelandClaude Opus 4.8 bd9bc78f4c feat(qlik): extract 4 decision metrics (CA/mag, couverture, marge%, rupture%)
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>
2026-06-21 08:34:54 +02:00
MichaelandClaude Opus 4.8 0b9846f55d fix(qlik): auto-refresh grid after sync without manual reload
Restore the _refresh searchParam bump so grid-client refetches
/api/grid/rows with refresh=1 (forceRefresh, bypassing the 10-min
getProductRows cache) and re-renders the network columns from the
store. Also call router.refresh() to update the server-rendered
MAJ Qlik timestamp on the button.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 08:23:34 +02:00
MichaelandClaude Opus 4.8 aee968d30f feat(grid): replace ranking/AI/score with Qlik network data
Remove ranking, AI analysis (routes + ai-copilot module), and score-engine
from the grid. Add Qlik Sense network metrics (CA, Qte, nb magasins per
product) joined by code centrale (articles.artcentrale).

- qlik-client.ts: NTLM + ticket SSO auth, QIX hypercube extraction (master items)
- qlik-network-cache.ts + qlik_network_metrics table (db-init): cache layer
- POST /api/qlik/sync?fournisseur=: per-supplier sync into cache
- SyncQlikButton: per-supplier sync, grid reload, last-update date display
- get-product-rows Phase 8: enrich rows with cached network metrics
- heatmap-grid: CA reseau / Qte reseau / Magasins (/270) / % presence columns
- discovery: app 9872ee6e, master items CA N / Quantite N / Magasin Ventes Nb N
- deps: httpntlm, ws

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 22:52:39 +02:00
Michael cd7b87aef8 feat: date de derniere entree en stock par magasin dans le tooltip des badges 2026-05-26 15:57:16 +02:00
Michael 1b5c260813 feat(grid): add premium semi-blocking glassmorphism loading overlay with real-time stream progression 2026-05-26 14:00:16 +02:00
Michael d75102fb18 perf(grid): optimize state store with O(1) row indexing and debounced summary calculations 2026-05-26 13:53:51 +02:00
Michael e6f40d3d81 feat(grid): implement product streaming with JSON chunks for grid client 2026-05-26 13:31:26 +02:00
MichaelandClaude Sonnet 4.6 dc16beeda4 feat: add no-sales-6-months tab to stock management page
Adds a second tab "Sans vente 6 mois" on the grid page listing all
products with no sale in the last 6 months, sorted by oldest last
sale first. Resolves merge conflicts from upstream refactor.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 12:49:13 +02:00
Michael 6492f93bf4 feat: add NoSalesTab component to display products without sales in the last 6 months 2026-04-14 12:45:21 +02:00
Michael a2c4a065dd feat: add ExportDropdown component with Excel and PDF export functionality for grid data 2026-04-10 13:25:19 +02:00
MichaelandClaude Sonnet 4.6 6b26676836 feat: flag products whose last registered supplier differs from current view
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>
2026-04-03 11:55:42 +02:00
MichaelandClaude Sonnet 4.6 6ef23de317 feat: restrict AI analysis to admin role only
- FloatingSummaryBar: hide BulkAiAnalyzer button for non-admins
- AiInsightBlock: hide individual Analyser button for non-admins
- Both use useSession() to check role === "admin"

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 11:43:48 +02:00
MichaelandClaude Sonnet 4.6 bbb04a4d2a fix: immediate AI loading feedback + auto-fallback for deprecated model
- BulkAiAnalyzer: set isAnalyzing=true immediately on click (before
  context fetch), so the spinner appears instantly instead of after
  1-2 seconds of silence
- analyze/route.ts: if configured model returns 400/404 (e.g., deprecated
  google/gemini-flash-1.5), automatically retry with google/gemini-2.0-flash-001
- batch-analyze/route.ts: same fallback logic

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 11:34:14 +02:00
MichaelandClaude Sonnet 4.6 2aa9cbecaa revert: restore grid to pre-infinite-scroll state
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>
2026-04-03 11:26:13 +02:00
Michael b39e010903 feat: implement infinite grid loading with server-side pagination and client-side integration 2026-04-02 18:39:29 +02:00
Michael 4dfdcc1144 feat: implement infinite scrolling and background data loading for the product grid component 2026-04-02 17:47:10 +02:00
Michael f70249555e feat: implement high-performance virtualized heatmap grid with granular Zustand state management 2026-04-02 17:36:42 +02:00
Michael 88a3121c92 feat: implement grid state management, data fetching, and infinite scroll infrastructure 2026-04-02 17:22:41 +02:00
Michael 2893114fca feat: implement infinite grid pagination with server-side data fetching and custom hook 2026-04-02 17:17:32 +02:00
Michael 7e4b370267 feat: implement PostgreSQL client for bulk data retrieval to replace per-article HTTP requests and configure Claude permissions 2026-04-02 16:31:11 +02:00
MichaelandClaude Sonnet 4.6 ead53db496 feat: restrict gamme/export/exports-page to admin; fix create user button style
- Non-admin users see gamme as read-only badge (no select)
- Export button hidden for non-admin in grid
- Save drafts button hidden for non-admin
- Exports page hidden in sidebar for non-admin
- Create user button: explicit blue style (was unreadable with apple-btn-primary)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 13:29:52 +02:00
Michael 8ecba594cf feat: introduce virtualized heatmap grid component with dynamic monthly data and optimized cell rendering. 2026-03-23 16:20:17 +01:00
Michael ffa257fda1 feat: Implement product heatmap grid with comprehensive data aggregation and PostgreSQL client for product rows. 2026-03-23 16:09:09 +01:00
Michael bba6fe05e8 feat: implement client-side grid orchestrator and core heatmap table component. 2026-03-23 14:13:39 +01:00
Michael 53b85381fa feat: add server-side API for fetching and processing comprehensive product data for the grid. 2026-03-23 14:00:27 +01:00
Michael 99954fb001 feat: Add AI Copilot Zustand store for managing and persisting product insights. 2026-03-23 13:34:36 +01:00
Michael 86df5d6f29 feat: introduce BulkAiAnalyzer component for bulk product classification and AI context profiling. 2026-03-23 12:43:02 +01:00
Michael e391550a30 feat: Introduce product assortment grid client and direct PostgreSQL data access for FF Nancy. 2026-03-20 14:25:30 +01:00
MichaelandClaude Sonnet 4.6 a16ec24cd7 perf+fix: parallelize article pagination, filter inactive articles, add gamme Y
Performance fixes for large suppliers (14k+ articles):
- fetchAllPages now fetches page 1, reads total count from response,
  then fetches remaining pages in parallel (10 at a time) instead of
  sequentially. Falls back to sequential if no count in response.
- getProductRows filters out suspended/inactive articles before calling
  getMensuelByArticles and getReferentielByArticles, reducing API calls
  from N_total to N_active (e.g. 14775→~2500 for S053).
- getRankingByArticles receives only active articles for bulk fetch.
- FfArticle now exposes actif and suspendu fields.

Gamme Y support:
- GammeSelect: add Y option with violet color
- GridFilterBar: add Y filter button with violet color
- BulkActionToolbar: add Y bulk assignment button

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-19 20:23:38 +01:00
MichaelandClaude Opus 4.6 414bf6133d fix: correct snapshot save to detect all gamme changes (drafts + validated)
handleSnapshot was only looking at active draftChanges to build the
snapshot. After validation (Valider), drafts are cleared but changes
are applied to row.codeGamme via applyDraftsToRows. This caused
handleSnapshot (Camera/Export) to save an empty snapshot that
overwrote the real one, losing all gamme changes on page reload.

Now handleSnapshot compares (draftChanges[codein] ?? row.codeGamme)
vs row.codeGammeInit to detect ALL changes, whether drafted or
already validated. Uses codeGammeInit as "before" reference (API
value, never modified).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-19 17:13:49 +01:00
Michael 01d2dc8b34 feat: add BulkAiAnalyzer component for automatic product classification and AI context profiling. 2026-03-19 15:52:48 +01:00
Michael aa69637f98 feat: Introduce bulk AI analyzer component to pre-classify products and prepare data for AI analysis, including context profiling. 2026-03-19 13:19:49 +01:00
Michael a4528c6d14 feat: Add HeatmapGrid component for visualizing product data with TanStack Table, virtualization, and performance optimizations. 2026-03-19 13:02:16 +01:00
Michael 8b7d81b20c feat: implement product grid with comprehensive product data fetching, processing, and heatmap display. 2026-03-19 12:41:03 +01:00
Michael d8a9329075 feat: Introduce AI Copilot feature with product analysis engine, state management, and UI components for insights. 2026-03-19 07:53:56 +01:00
Michael 95795ce7e3 feat: Introduce AI analysis engine for product A/Z recommendations based on detailed business rules. 2026-03-18 22:15:14 +01:00
Michael aa02d019bd feat: Implement AI Copilot for product analysis and add comprehensive product grid data fetching. 2026-03-18 21:25:53 +01:00