mirror of
https://github.com/R0m1k3/CollectFlow.git
synced 2026-10-16 19:59:30 +02:00
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:
1 parent
02a10caa4b
commit
aee968d30f
34 files changed
+1043
-2925
No files matched your search
@@ -0,0 +1,62 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { auth } from "@/lib/auth";
|
||||
import { fetchNetworkMetrics } from "@/lib/qlik-client";
|
||||
import { upsertNetworkMetrics } from "@/lib/qlik-network-cache";
|
||||
import { pgGetArticlesByFournisseur } from "@/lib/pg-ff-client";
|
||||
|
||||
// Synchro potentiellement longue (extraction hypercube paginee).
|
||||
export const maxDuration = 300;
|
||||
|
||||
/**
|
||||
* POST /api/qlik/sync?fournisseur=XXX
|
||||
* Tire de Qlik les metriques reseau des articles du fournisseur (par code centrale)
|
||||
* et met a jour le cache local. Admin uniquement.
|
||||
*/
|
||||
export async function POST(req: NextRequest) {
|
||||
const session = await auth();
|
||||
if (!session || (session.user as { role?: string } | undefined)?.role !== "admin") {
|
||||
return NextResponse.json({ error: "Unauthorized" }, { status: 403 });
|
||||
}
|
||||
|
||||
const fournisseur = req.nextUrl.searchParams.get("fournisseur");
|
||||
if (!fournisseur) {
|
||||
return NextResponse.json({ error: "Param 'fournisseur' requis" }, { status: 400 });
|
||||
}
|
||||
|
||||
try {
|
||||
// Codes centraux des articles de ce fournisseur
|
||||
const articles = await pgGetArticlesByFournisseur(fournisseur);
|
||||
const codes = [
|
||||
...new Set(
|
||||
articles
|
||||
.map((a) => (a.codeCentrale ? String(a.codeCentrale).trim() : ""))
|
||||
.filter(Boolean),
|
||||
),
|
||||
];
|
||||
if (codes.length === 0) {
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
fournisseur,
|
||||
fetched: 0,
|
||||
upserted: 0,
|
||||
message: "Aucun article avec code centrale pour ce fournisseur",
|
||||
fetchedAt: new Date().toISOString(),
|
||||
});
|
||||
}
|
||||
|
||||
const metrics = await fetchNetworkMetrics(codes);
|
||||
const count = await upsertNetworkMetrics([...metrics.values()]);
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
fournisseur,
|
||||
requested: codes.length,
|
||||
fetched: metrics.size,
|
||||
upserted: count,
|
||||
fetchedAt: new Date().toISOString(),
|
||||
});
|
||||
} catch (e) {
|
||||
const msg = e instanceof Error ? e.message : String(e);
|
||||
console.error("[api/qlik/sync]", msg);
|
||||
return NextResponse.json({ success: false, error: msg }, { status: 500 });
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user