perf: remove actif filter, increase batchSize, exclude Y articles without sales

- Remove actif/suspendu filter that caused wrong stats (893€ CA, 249 units)
  by incorrectly excluding products with sales. The parallel pagination
  and bulk ranking fixes are sufficient to handle large suppliers.
- Increase getMensuelByArticles and getReferentielByArticles batchSize
  from 20 to 50, reducing sequential batch iterations by ~2.5x.
- Filter gamme Y products with zero 12-month sales from returned rows.
  Reduces grid size (e.g. S053: 14775→fewer rows) without affecting
  products that actually sold. Y products with sales are preserved.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
MichaelandClaude Sonnet 4.6 committed 2026-03-19 21:23:34 +01:00
1 parent be3a196744
commit 1cd3ade77e
2 files changed
+16 -20

No files matched your search

+14 -18
View File
@@ -26,26 +26,16 @@ export async function getProductRows(input: GetProductRowsInput): Promise<Produc
try {
// ─── Phase 1 : Articles du fournisseur ───────────────────────────────
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;
const articles = await getArticlesByFournisseur(codeFournisseur);
console.log(`[getProductRows] ${articles.length} articles for ${codeFournisseur}`);
// ─── Phase 2 : Mensuel + Commandes (en parallèle) ────────────────────
const { dateDebut, dateFin } = buildLast12MonthsRange();
const [mensuelMap, referentielMap, commandesMap, rankingResult] = await Promise.all([
getMensuelByArticles(activeArticles, dateDebut, dateFin),
getReferentielByArticles(activeArticles),
getMensuelByArticles(articles, dateDebut, dateFin),
getReferentielByArticles(articles),
getCommandesByFournisseur(codeFournisseur),
getRankingByArticles(activeArticles, codeFournisseur),
getRankingByArticles(articles, codeFournisseur),
]);
const { rankings: rankingMap, totalRankedProducts } = rankingResult;
console.log(`[getProductRows] mensuel data for ${mensuelMap.size}/${articles.length} articles`);
@@ -268,9 +258,15 @@ export async function getProductRows(input: GetProductRowsInput): Promise<Produc
console.error("[getProductRows] Snapshot restore error:", snapErr);
}
// ─── Phase 7 : Score composite ────────────────────────────────────────
const rows = Array.from(productMap.values());
console.log(`[getProductRows] ${rows.length} produits, ${mensuelMap.size} avec données`);
// ─── Phase 8 : Filtrer les produits Y sans ventes ────────────────────
// Les produits en gamme Y sans aucune vente sur 12 mois sont exclus de la grille
// pour alléger le chargement. Exception : produits Y avec ventes conservés.
const allRows = Array.from(productMap.values());
const rows = allRows.filter(p =>
p.codeGamme !== "Y" || p.totalQuantite > 0
);
const excludedY = allRows.length - rows.length;
console.log(`[getProductRows] ${rows.length} produits (${excludedY} gamme Y sans ventes exclus), ${mensuelMap.size} avec données`);
return computeProductScores(rows);
} catch (error) {