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>
This commit is contained in:
MichaelandClaude Opus 4.8 committed 2026-06-20 22:52:39 +02:00
1 parent 02a10caa4b
commit aee968d30f
34 files changed
+1043 -2925

No files matched your search

+10 -11
View File
@@ -73,8 +73,6 @@ export interface ProductRow {
totalCa: number;
totalMarge: number;
tauxMarge: number;
/** Score de performance hybride (0-100) */
score: number;
workingStores: string[];
/** Rotation normalisée : unités vendues / magasin / mois */
unitsPerStorePerMonth?: number;
@@ -86,7 +84,6 @@ export interface ProductRow {
isLastProduct?: boolean;
/** Top 30% CA du lot fournisseur */
isTop30Supplier?: boolean;
aiRecommendation?: string | null;
/** SQL Server internal ID — nécessaire pour /api/articles/:noid/mensuel */
noid?: number;
/** Données stock & approvisionnement (API FF Nancy) */
@@ -110,14 +107,16 @@ export interface ProductRow {
shareQty?: number;
/** Référentiels globaux */
totalFournisseurCa?: number;
/** Ranking réseau (classement global) */
rankingCa?: number;
rankingQte?: number;
/** Ranking magasin */
rankingMagCa?: number;
rankingMagQte?: number;
/** Nombre total de produits classés dans le réseau (produits avec ventes sur la période) */
totalRankedProducts?: number;
/** Code centrale (clé jointure Qlik, format 10000XXXXXX) */
codeCentrale?: string;
/** Données réseau Qlik (~270 magasins) */
caReseau?: number;
qteReseau?: number;
nbMagasinsReseau?: number;
/** Taux de présence réseau = nbMagasinsReseau / 270 */
tauxPresenceReseau?: number;
/** Fraîcheur des données réseau (ISO) */
networkFetchedAt?: string;
}
/** Summary bar totals for the currently visible/filtered rows */
+23
View File
@@ -0,0 +1,23 @@
declare module "httpntlm" {
interface NtlmOptions {
url: string;
username: string;
password: string;
domain?: string;
workstation?: string;
headers?: Record<string, string>;
rejectUnauthorized?: boolean;
[key: string]: unknown;
}
interface NtlmResponse {
statusCode: number;
headers: Record<string, unknown>;
body: string;
}
type Cb = (err: Error | null, res: NtlmResponse) => void;
const httpntlm: {
get(opts: NtlmOptions, cb: Cb): void;
post(opts: NtlmOptions, cb: Cb): void;
};
export default httpntlm;
}