mirror of
https://github.com/R0m1k3/CollectFlow.git
synced 2026-10-11 17:26:32 +02:00
feat: Add Claude settings to allow specific Git and Next.js Bash commands.
This commit is contained in:
1 parent
dcebf74f31
commit
69c7d65482
3 files changed
+64
-17
No files matched your search
@@ -2,7 +2,8 @@
|
||||
"permissions": {
|
||||
"allow": [
|
||||
"Bash(git push:*)",
|
||||
"Bash(npx next:*)"
|
||||
"Bash(npx next:*)",
|
||||
"Bash(git status:*)"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -26,16 +26,26 @@ export async function getProductRows(input: GetProductRowsInput): Promise<Produc
|
||||
|
||||
try {
|
||||
// ─── Phase 1 : Articles du fournisseur ───────────────────────────────
|
||||
const articles = await getArticlesByFournisseur(codeFournisseur);
|
||||
console.log(`[getProductRows] ${articles.length} articles for ${codeFournisseur}`);
|
||||
const allArticles = await getArticlesByFournisseur(codeFournisseur);
|
||||
console.log(`[getProductRows] ${allArticles.length} articles for ${codeFournisseur}`);
|
||||
|
||||
// Filtrer les articles actifs et non-suspendus pour les appels coûteux (mensuel/referentiel)
|
||||
// Les articles inactifs/suspendus restent dans la grille mais sans données de vente
|
||||
const activeArticles = allArticles.filter(a => a.suspendu !== true && a.actif !== false);
|
||||
const suspendedCount = allArticles.length - activeArticles.length;
|
||||
if (suspendedCount > 0) {
|
||||
console.log(`[getProductRows] Filtrage: ${activeArticles.length} actifs, ${suspendedCount} suspendus/inactifs exclus des appels API`);
|
||||
}
|
||||
// On utilise allArticles pour la grille, activeArticles pour mensuel/referentiel
|
||||
const articles = allArticles;
|
||||
|
||||
// ─── Phase 2 : Mensuel + Commandes (en parallèle) ────────────────────
|
||||
const { dateDebut, dateFin } = buildLast12MonthsRange();
|
||||
const [mensuelMap, referentielMap, commandesMap, rankingResult] = await Promise.all([
|
||||
getMensuelByArticles(articles, dateDebut, dateFin),
|
||||
getReferentielByArticles(articles),
|
||||
getMensuelByArticles(activeArticles, dateDebut, dateFin),
|
||||
getReferentielByArticles(activeArticles),
|
||||
getCommandesByFournisseur(codeFournisseur),
|
||||
getRankingByArticles(articles, codeFournisseur),
|
||||
getRankingByArticles(activeArticles, codeFournisseur),
|
||||
]);
|
||||
const { rankings: rankingMap, totalRankedProducts } = rankingResult;
|
||||
console.log(`[getProductRows] mensuel data for ${mensuelMap.size}/${articles.length} articles`);
|
||||
|
||||
+47
-11
@@ -30,6 +30,8 @@ export interface FfArticle {
|
||||
noid?: number; // SQL Server internal ID (pour endpoint /mensuel)
|
||||
reference?: string; // référence fournisseur (ref_fou_principale)
|
||||
gtin?: string; // code-barres EAN/GTIN
|
||||
actif?: boolean; // article actif
|
||||
suspendu?: boolean; // article suspendu
|
||||
}
|
||||
|
||||
export interface FfMouvement {
|
||||
@@ -99,30 +101,62 @@ function extractList(data: unknown): any[] {
|
||||
|
||||
async function fetchAllPages<T>(
|
||||
buildUrl: (page: number) => string,
|
||||
_extractItems: (data: unknown) => T[], // conservé pour compatibilité, mais on utilise extractList
|
||||
_extractItems: (data: unknown) => T[],
|
||||
pageSize = 500
|
||||
): Promise<T[]> {
|
||||
const all: T[] = [];
|
||||
let page = 1;
|
||||
// Page 1 — récupère les items et tente d'obtenir le total pour paralléliser
|
||||
const url1 = buildUrl(1);
|
||||
console.log(`[api-ff] GET ${url1}`);
|
||||
const res1 = await fetch(url1, { cache: "no-store" });
|
||||
if (!res1.ok) {
|
||||
console.error(`[api-ff] HTTP ${res1.status} — ${url1}`);
|
||||
return [];
|
||||
}
|
||||
const data1 = await res1.json();
|
||||
const items1 = extractList(data1) as T[];
|
||||
console.log(`[api-ff] page 1: ${items1.length} items, keys: ${items1[0] ? Object.keys(items1[0] as object).join(",") : "empty"}`);
|
||||
|
||||
// Si la première page est incomplète, pas besoin de continuer
|
||||
if (items1.length < pageSize) return items1;
|
||||
|
||||
// Cherche un total dans la réponse pour paralléliser les pages suivantes
|
||||
const d1 = data1 as Record<string, unknown>;
|
||||
const total = Number(d1.count ?? d1.total ?? d1.nb_total ?? d1.totalCount ?? 0);
|
||||
|
||||
if (total > pageSize) {
|
||||
const totalPages = Math.ceil(total / pageSize);
|
||||
const remaining = Array.from({ length: totalPages - 1 }, (_, i) => i + 2);
|
||||
// Fetch en chunks de 10 pages en parallèle
|
||||
const all = [...items1];
|
||||
for (let i = 0; i < remaining.length; i += 10) {
|
||||
const chunk = remaining.slice(i, i + 10);
|
||||
const results = await Promise.all(chunk.map(async (p) => {
|
||||
const url = buildUrl(p);
|
||||
console.log(`[api-ff] GET ${url}`);
|
||||
const res = await fetch(url, { cache: "no-store" });
|
||||
if (!res.ok) return [] as T[];
|
||||
const data = await res.json();
|
||||
return extractList(data) as T[];
|
||||
}));
|
||||
for (const r of results) all.push(...r);
|
||||
}
|
||||
return all;
|
||||
}
|
||||
|
||||
// Fallback séquentiel (pas de total dans la réponse)
|
||||
const all = [...items1];
|
||||
let page = 2;
|
||||
while (true) {
|
||||
const url = buildUrl(page);
|
||||
console.log(`[api-ff] GET ${url}`);
|
||||
const res = await fetch(url, { cache: "no-store" });
|
||||
if (!res.ok) {
|
||||
console.error(`[api-ff] HTTP ${res.status} — ${url}`);
|
||||
break;
|
||||
}
|
||||
if (!res.ok) break;
|
||||
const data = await res.json();
|
||||
const items = extractList(data) as T[];
|
||||
if (page === 1) {
|
||||
console.log(`[api-ff] page 1: ${items.length} items, keys: ${items[0] ? Object.keys(items[0] as object).join(",") : "empty"}`);
|
||||
}
|
||||
all.push(...items);
|
||||
if (items.length < pageSize) break;
|
||||
page++;
|
||||
}
|
||||
|
||||
return all;
|
||||
}
|
||||
|
||||
@@ -214,6 +248,8 @@ export async function getArticlesByFournisseur(
|
||||
noid: r.no_id ?? r.noid ?? r.NoId,
|
||||
reference: r.ref_fou_principale ?? r.reference ?? r.ref_fournisseur ?? undefined,
|
||||
gtin: r.gtin ?? r.Gtin ?? r.ean ?? r.barcode ?? undefined,
|
||||
actif: r.actif != null ? Boolean(Number(r.actif)) : undefined,
|
||||
suspendu: r.suspendu != null ? Boolean(Number(r.suspendu)) : undefined,
|
||||
})).filter(a => a.codein);
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user