Commit Graph
97 Commits
Author SHA1 Message Date
Claude d89d2b3232 Parametres : telechargement des journaux serveur complets
Une extraction Qlik produit plusieurs milliers de lignes de diagnostic.
Un terminal les tronque et n'en laisse que la fin, alors que
l'information decisive — carte du modele Qlik, champs date retenus,
choix des periodes — se trouve en TETE. Diagnostiquer sur la fin du log
revient a travailler a l'aveugle.

- src/lib/log-capture.ts : instrumente console.log/warn/error une fois,
  recopie chaque ligne horodatee dans les captures ouvertes, ecrit au fil
  de l'eau dans le repertoire temporaire (un job qui fait tomber le
  process laisse quand meme son journal). Bornes : 200 000 lignes,
  8 000 caracteres par ligne, 20 fichiers conserves.
- GET /api/logs : liste JSON ; GET /api/logs?id=<jobId> : le fichier
  complet en piece jointe. Admin uniquement.
- La sync Qlik ouvre la capture AVANT son premier log et la ferme dans un
  finally, avec le statut final — les deux modes (fournisseur et produit).
- Parametres : section « Journaux serveur », un bouton Telecharger par
  job, le plus recent en premier, badge « en cours » pour un job vivant.

Aucun secret ne transite dans ces journaux : l'extracteur ne journalise
que le NOM du cookie de session, jamais sa valeur ni le mot de passe.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DfqUihgixw4K1AmJhizWiu
2026-08-01 06:45:14 +00:00
Claude fa1b64cfa6 Qlik: selection par code fournisseur au lieu de 41 569 codes articles
Le code fournisseur FF de la base SQL/API existe aussi dans Qlik : une
seule valeur y designe le meme perimetre que les dizaines de milliers de
codes articles. Comme SelectValues sur « Article Code » coute 8 a 100 s
par appel et doit etre refait a chaque passe annuelle, la bascule
supprime la partie la plus couteuse de la sync.

- ETAPE 0 : selectionnerParFournisseur() avant choisirPeriode().
- Essaie QLIK_FIELD_CODE_FOURNISSEUR puis code_fournisseur, Fournisseur,
  fournisseur_code_centrale.
- Verifie la couverture reelle (Article Code visibles vs codes demandes)
  et n'accepte la bascule qu'au-dela de QLIK_SUPPLIER_MIN_COVERAGE
  (0.99 par defaut) ; sinon annule la selection et revient aux codes.
- Quand la bascule est retenue, plus aucun SelectValues sur Article Code
  (passes annuelles et agregation par expressions).
- La sync fournisseur transmet job.fournisseur ; la sync produit (un seul
  code centrale) reste inchangee.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DfqUihgixw4K1AmJhizWiu
2026-07-31 15:44:22 +00:00
Michael 4ef0e9fdeb fix Qlik rolling 12-month integrity 2026-07-31 10:28:29 +02:00
Claude c9ecb47cb1 fix(produits): recherche asynchrone — la requête était coupée par le reverse proxy
« Unexpected token '<', "<html> <h"... is not valid JSON » : ce n'était pas du
JSON parce que ce n'était pas l'application qui répondait. La recherche enchaîne
deux allers-retours Qlik (dont une extraction mensuelle) et dépassait le délai du
proxy, qui renvoyait sa page d'erreur HTML.

- L'API passe en asynchrone, sur le modèle déjà éprouvé de POST /api/qlik/sync :
  POST démarre un job et rend la main immédiatement, GET renvoie l'avancement
  puis le résultat. Le client interroge toutes les 2 s et affiche l'étape en
  cours (recherche des articles / extraction des ventes / rapprochement
  catalogue). Deux recherches simultanées au maximum.
- Le client ne présume plus que la réponse est du JSON : les statuts 504, 502,
  503, 401 et 403 sont traduits en message actionnable au lieu d'une erreur de
  parsing.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DfqUihgixw4K1AmJhizWiu
2026-07-30 04:57:17 +00:00
Claude 203c96f6c9 feat(produits): recherche Qlik d'abord + fiche réseau complète, tendance 12 mois glissants
Recherche produit
- La page /produits interroge désormais Qlik Sense EN PREMIER
  (src/lib/qlik-search.ts) : recherche globale Engine sur les champs article
  (code + libellé détectés dynamiquement via FieldList), sélection des valeurs
  trouvées, puis liste des Article Code correspondants.
- Les métriques réseau des articles trouvés sont extraites sur 12 mois
  glissants et mises en cache (qlik_network_metrics), puis rapprochées du
  catalogue FF Nancy par code centrale (pgGetProduitsByCodeCentrale).
- Repli propre sur la recherche catalogue local si Qlik est injoignable, signalé
  dans l'UI. Résultats mis en cache mémoire 10 min, requête dédupliquée.
- Nouvelle route GET /api/produits/search (runtime nodejs, 300 s) ; la liste est
  chargée côté client avec état de chargement, l'extraction Qlik prenant
  plusieurs secondes.

Informations affichées
- Résultats : magasins vendeurs (+ % du réseau), quantité réseau, quantité par
  magasin, prix moyen réseau, CA par magasin, marge %, sparkline de tendance,
  fournisseur, et présence ou non au catalogue Nancy.
- Fiche : carte « Performance réseau · 12 mois glissants » en tête (8 indicateurs
  + détail mensuel qté / magasins / qté par magasin / CA / prix moyen / marge %),
  puis carte « Fournisseur » dédiée, puis identité, stock, nos ventes 12 mois.
- La fiche s'ouvre aussi par code centrale (?cc=) pour les produits que le réseau
  travaille et que Nancy ne référence pas — le libellé et le fournisseur Qlik
  sont persistés dans le cache réseau pour ce cas.

Tendance réseau
- computeNetworkTrend reconstruit sa fenêtre depuis la date du jour : 12 mois
  complets, mois en cours EXCLU (il est partiel et écrasait la pente). Les mois
  absents du cache valent 0 ; ceux antérieurs à la première extraction réelle
  sont écartés au lieu d'être inventés à 0.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DfqUihgixw4K1AmJhizWiu
2026-07-29 05:04:34 +00:00
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 1633d5e407 fix(qlik-sync): message explicite quand le serveur Qlik est en OOM
Quand l'app Qlik ne peut pas se charger faute de RAM serveur (code 6
'Not enough memory to load file' / code 3002 'File corrupted' / 'Out of
memory'), le job affiche un message clair ('Serveur Qlik saturé…') au
lieu de l'erreur technique. Ce n'est pas un bug CollectFlow : le sync
échoue à l'ouverture de l'app, avant toute requête.
2026-07-24 08:11:58 +00:00
R0m1k3 abac5c5ee5 perf(qlik): optimize network sync extraction 2026-06-22 09:58:49 +00:00
R0m1k3 850852912f fix(qlik): track async sync job status 2026-06-21 19:08:04 +00:00
R0m1k3 6d27c7935d fix: align qlik grid extraction date range 2026-06-21 11:26:49 +00:00
MichaelandClaude Opus 4.8 d54c3ae520 feat(qlik): add step-by-step logging to sync extraction
Logs each stage (PG codes -> NTLM session -> chromium -> csrf token
-> in-page ws -> OpenDoc -> SelectValues -> cube size -> rows) so a
hanging sync reveals where it stalls. Forwards in-page browser console
to the node logger.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 08:14:12 +02:00
MichaelandClaude Opus 4.8 694b780160 feat(qlik): extract network data via Playwright (in-page ws)
The Qlik proxy refuses a raw server-side websocket (403, even internally), so
extraction now runs through headless Chromium (NTLM via httpCredentials, like
the hermes agent) and opens the Engine websocket in-page — same origin, which
the proxy accepts. Efficient: selects the supplier's article codes on the
"Article Code" field so the hypercube returns only those rows.

- qlik-playwright.ts: browser singleton, in-page hypercube extraction (paginated)
- /api/qlik/sync: use the Playwright extractor
- Dockerfile: install chromium + headless deps, PLAYWRIGHT_CHROMIUM_PATH, copy playwright-core
- deps: playwright-core (lockfiles synced)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 23:54:03 +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 e6f40d3d81 feat(grid): implement product streaming with JSON chunks for grid client 2026-05-26 13:31:26 +02:00
Michael bd8339b27d feat: add pg-ff-client to replace HTTP API calls with bulk PostgreSQL queries 2026-04-23 10:36:37 +02:00
Michael d955c17af2 feat: add probe for N/A suppliers to retrieve franco details in GET route 2026-04-13 15:47:14 +02:00
Michael 33ff92aec0 feat: add commandes-auto audit with franco_ht filtering to GET route 2026-04-13 15:43:37 +02:00
Michael 2cbf8a753a feat: add foucad sample retrieval and columns to franco diagnostic 2026-04-13 15:40:56 +02:00
Michael 457903a611 feat: add franco diagnostic and raw commandes-auto retrieval in GET route 2026-04-13 15:34:26 +02:00
Michael 8dd2394893 feat: implement admin AI chat route with SQL execution and database schema context 2026-04-10 16:03:00 +02:00
Michael 6e10364922 feat: implement admin AI chat API with SQL execution tools and database schema context 2026-04-10 15:44:59 +02:00
Michael 0c1d3c10bd feat: implement admin AI chat API with SQL execution and schema retrieval tools 2026-04-10 15:23:46 +02:00
Michael 4994d55ffc feat: implement admin AI chat route with SQL execution tools and multi-provider support 2026-04-10 15:16:34 +02:00
Michael ade120a9da feat: add settings page with database configuration, AI provider management, and FF API status tracking. 2026-04-10 15:05:51 +02:00
Michael d0ca0c3602 feat: implement database and AI provider configuration settings with Google GenAI integration 2026-04-10 15:00:47 +02:00
Michael 9f05eb9bc9 feat: implement admin AI chat API with SQL execution and database schema tools 2026-04-10 13:51:18 +02:00
Michael 6891aff668 feat: implement admin AI chat route with SQL execution and database schema access tools 2026-04-10 13:38:26 +02:00
Michael 63d89e5029 feat: add API endpoint to fetch and format OpenRouter models list 2026-04-10 13:35:54 +02:00
Michael d9859ff9e0 feat: add API route to fetch and format OpenRouter models with pricing data 2026-04-10 13:29:31 +02:00
Michael 78cdc608d0 feat: implement admin AI chat interface with model selection and real-time cost tracking 2026-04-10 13:23:35 +02:00
Michael 638c4b5f3b feat: implement direct PostgreSQL data access and API proxy for automated orders 2026-04-08 16:37:42 +02:00
Michael 70c425befb feat: implement sidebar navigation and automated order management module with PostgreSQL client integration 2026-04-08 15:53:59 +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 83d101ddc1 feat: add interactive client component for Hit Parade data visualization with sorting, filtering, and date range controls 2026-04-03 10:46:09 +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 2893114fca feat: implement infinite grid pagination with server-side data fetching and custom hook 2026-04-02 17:17:32 +02:00
MichaelandClaude Sonnet 4.6 8b3ed4c435 chore: improve diag to check mntmvtht vs mntmvtttc totals and artfou1.preference distribution
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 09:40:28 +02:00
MichaelandClaude Sonnet 4.6 63641e9de9 chore: add mvtart column diag to /api/diag, remove unused diag-mvtart
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 09:36:21 +02:00
MichaelandClaude Sonnet 4.6 3e4b320cbe chore: add diag-mvtart to inspect columns and CA totals
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 09:28:53 +02:00
MichaelandClaude Sonnet 4.6 bc76237f48 feat: sort analytics by name (fournisseur) or code asc (nomenclature); show code in nomenclature label; remove diag-fournisseurs endpoint
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 08:42:21 +02:00
Michael f0a360115f chore: inspect fouident table for correct supplier names 2026-03-31 17:32:54 +02:00
Michael 67b0c8c74f chore: inspect v_ca_fournisseur view structure 2026-03-31 13:52:22 +02:00
Michael 072479b30f chore: fix diag-fournisseurs to inspect real fouadr1 column structure 2026-03-31 13:44:19 +02:00
Michael 09f80b35cb chore: add diag-fournisseurs endpoint to investigate fouadr1 sit_code and naming 2026-03-31 13:40:08 +02:00
MichaelandClaude Sonnet 4.6 cfd3a7e601 chore: remove temporary diag-supplier investigation endpoint
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-31 12:08:15 +02:00
MichaelandClaude Sonnet 4.6 51adac0349 fix: attribute CA to supplier of last stock entry (dernière entrée en stock)
Previous approach (artfou1 DISTINCT ON no_id DESC) picked the most recent
artfou1 record, but artfou1 is a commercial reference table that may not
reflect actual current sourcing.

New approach: for each article, find the most recent reception movement
(genremvt IN (1,2)) in mvtart — this is the actual last delivery. Join
artfou1 to get the supplier code (ORDER BY datmvt DESC, af.no_id DESC to
break ties). This correctly attributes CA to whoever last physically
delivered the goods, not to a historical commercial reference.

Articles with no reception history are excluded (no INNER JOIN fallback
needed as all sold articles must have been received at least once).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-31 12:05:38 +02:00
MichaelandClaude Sonnet 4.6 3d77f6b879 chore: add diag-supplier endpoint for artfou1 supplier attribution investigation
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-31 11:08:23 +02:00
Michael 41a8b32aff feat: Add API route to export modified gammes data to an Excel file. 2026-03-19 15:28:16 +01:00