mirror of
https://github.com/R0m1k3/CollectFlow.git
synced 2026-10-11 17:26:32 +02:00
feat: Introduce getProductRows server action for fetching and processing comprehensive product data from PostgreSQL.
This commit is contained in:
1 parent
f94d7753b4
commit
70b49c5c56
2 files changed
+127
-8
No files matched your search
@@ -7,6 +7,7 @@ import {
|
||||
pgGetArticlesByFournisseur,
|
||||
pgGetMensuelByFournisseur,
|
||||
pgGetGammesByFournisseur,
|
||||
pgGetNomenclatureByFournisseur,
|
||||
pgGetStockByFournisseur,
|
||||
pgGetRankingByFournisseur,
|
||||
pgGetCommandesByFournisseur,
|
||||
@@ -35,6 +36,7 @@ export async function getProductRows(input: GetProductRowsInput): Promise<Produc
|
||||
articles,
|
||||
mensuelRows,
|
||||
gammeMap,
|
||||
nomMap,
|
||||
stockMap,
|
||||
rankingResult,
|
||||
commandesMap,
|
||||
@@ -42,6 +44,7 @@ export async function getProductRows(input: GetProductRowsInput): Promise<Produc
|
||||
pgGetArticlesByFournisseur(codeFournisseur).catch(e => { console.error("[getProductRows] pgGetArticlesByFournisseur ERROR:", e); return []; }),
|
||||
pgGetMensuelByFournisseur(codeFournisseur, dateDebut, dateFin).catch(e => { console.error("[getProductRows] pgGetMensuelByFournisseur ERROR:", e); return []; }),
|
||||
pgGetGammesByFournisseur(codeFournisseur).catch(e => { console.error("[getProductRows] pgGetGammesByFournisseur ERROR:", e); return new Map<string, string>(); }),
|
||||
pgGetNomenclatureByFournisseur(codeFournisseur).catch(e => { console.error("[getProductRows] pgGetNomenclatureByFournisseur ERROR:", e); return new Map(); }),
|
||||
pgGetStockByFournisseur(codeFournisseur).catch(e => { console.error("[getProductRows] pgGetStockByFournisseur ERROR:", e); return new Map<string, PgStockRow[]>(); }),
|
||||
pgGetRankingByFournisseur(codeFournisseur).catch(e => { console.error("[getProductRows] pgGetRankingByFournisseur ERROR:", e); return { rankings: new Map(), totalRankedProducts: 0 }; }),
|
||||
pgGetCommandesByFournisseur(codeFournisseur).catch(e => { console.error("[getProductRows] pgGetCommandesByFournisseur ERROR:", e); return new Map<string, number>(); }),
|
||||
@@ -174,6 +177,18 @@ export async function getProductRows(input: GetProductRowsInput): Promise<Produc
|
||||
product.codeGamme = gammeCode as GammeCode;
|
||||
}
|
||||
|
||||
// ─── Phase 6b : Nomenclature (famille / sous-famille) ────────────────
|
||||
for (const [codein, nom] of nomMap.entries()) {
|
||||
const product = productMap.get(codein);
|
||||
if (!product) continue;
|
||||
product.code3 = nom.code3 ?? "";
|
||||
product.libelle3 = nom.libelle3 ?? "";
|
||||
product.code2 = nom.code2 ?? "";
|
||||
product.libelleNiveau2 = nom.libelle2 ?? "";
|
||||
product.code1 = nom.code1 ?? "";
|
||||
product.libelleNiveau1 = nom.libelle1nom ?? "";
|
||||
}
|
||||
|
||||
// ─── Phase 7 : Stock temps réel (cube_stock) ─────────────────────────
|
||||
for (const [codein, stocks] of stockMap.entries()) {
|
||||
const product = productMap.get(codein);
|
||||
|
||||
+112
-8
@@ -93,12 +93,24 @@ export async function pgGetFournisseurs(search?: string): Promise<{ code: string
|
||||
* 1 seule requête SQL — remplace getArticlesByFournisseur() + per-article fetches.
|
||||
*/
|
||||
export async function pgGetArticlesByFournisseur(codefou: string): Promise<PgArticle[]> {
|
||||
// Diagnostic une seule fois : colonnes de la table articles
|
||||
const diagResult = await db.execute(sql`
|
||||
SELECT column_name FROM information_schema.columns
|
||||
WHERE table_name = 'articles' ORDER BY ordinal_position LIMIT 30
|
||||
`);
|
||||
console.log("[pg-ff] Colonnes articles:", (diagResult.rows as unknown as { column_name: string }[]).map(r => r.column_name).join(", "));
|
||||
// Diagnostic : colonnes articles + nomenclature pour résoudre les champs manquants
|
||||
const [artCols, nomCols] = await Promise.all([
|
||||
db.execute(sql`
|
||||
SELECT column_name FROM information_schema.columns
|
||||
WHERE table_name = 'articles' ORDER BY ordinal_position
|
||||
`),
|
||||
db.execute(sql`
|
||||
SELECT column_name FROM information_schema.columns
|
||||
WHERE table_name = 'nomenclature' ORDER BY ordinal_position
|
||||
`),
|
||||
]);
|
||||
const artColNames = (artCols.rows as unknown as { column_name: string }[]).map(r => r.column_name);
|
||||
console.log("[pg-ff] Colonnes articles:", artColNames.join(", "));
|
||||
console.log("[pg-ff] Colonnes nomenclature:", (nomCols.rows as unknown as { column_name: string }[]).map(r => r.column_name).join(", "));
|
||||
|
||||
// Détecte la colonne FK de articles → nomenclature
|
||||
const nomFkCol = artColNames.find(c => /nom.*no_id|nomno_id|nomenclature.*id|idnomenclature|nom_no_id/i.test(c));
|
||||
console.log("[pg-ff] FK articles→nomenclature détectée:", nomFkCol ?? "non trouvée — libelle3 sera vide");
|
||||
|
||||
const result = await db.execute(sql`
|
||||
SELECT
|
||||
@@ -130,7 +142,7 @@ export async function pgGetArticlesByFournisseur(codefou: string): Promise<PgArt
|
||||
`);
|
||||
|
||||
if (result.rows.length > 0) {
|
||||
console.log("[pg-ff] Sample article row keys:", Object.keys(result.rows[0] as object).join(", "));
|
||||
console.log("[pg-ff] Sample article row:", JSON.stringify(result.rows[0]));
|
||||
}
|
||||
|
||||
return (result.rows as unknown as PgArticle[]).filter(r => r.codein);
|
||||
@@ -246,7 +258,99 @@ export async function pgGetGammesByFournisseur(codefou: string): Promise<Map<str
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 4. Stock temps réel (cube_stock)
|
||||
// 4. Nomenclature (famille / sous-famille)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export interface PgNomRow {
|
||||
codein: string;
|
||||
code3: string; // code feuille (ex: "360504")
|
||||
libelle3: string; // libellé feuille
|
||||
code2?: string; // famille (4 chiffres)
|
||||
libelle2?: string;
|
||||
code1?: string; // secteur (2 chiffres)
|
||||
libelle1nom?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne la nomenclature (famille/sous-famille) pour chaque article du fournisseur.
|
||||
* Essaie de join articles → nomenclature via les colonnes FK les plus probables.
|
||||
*/
|
||||
export async function pgGetNomenclatureByFournisseur(codefou: string): Promise<Map<string, PgNomRow>> {
|
||||
// Découvrir les colonnes de nomenclature
|
||||
const nomCols = await db.execute(sql`
|
||||
SELECT column_name FROM information_schema.columns
|
||||
WHERE table_name = 'nomenclature' ORDER BY ordinal_position
|
||||
`);
|
||||
const nomColNames = (nomCols.rows as unknown as { column_name: string }[]).map(r => r.column_name);
|
||||
console.log("[pg-ff] Nomenclature colonnes:", nomColNames.join(", "));
|
||||
|
||||
// Essai 1 : articles a un champ nomno_id ou nom_no_id (FK vers nomenclature.no_id)
|
||||
// Essai 2 : articles a un champ nomcode (code texte direct comme "360504")
|
||||
// On tente les deux requêtes et on prend celle qui réussit
|
||||
try {
|
||||
const result = await db.execute(sql`
|
||||
SELECT
|
||||
a.codein,
|
||||
n3.no_id AS nom3_id,
|
||||
n3.code AS code3,
|
||||
n3.libelle AS libelle3,
|
||||
n2.code AS code2,
|
||||
n2.libelle AS libelle2,
|
||||
n1.code AS code1,
|
||||
n1.libelle AS libelle1nom
|
||||
FROM artfou1 af
|
||||
JOIN articles a ON a.no_id = af.art_no_id AND af.code = ${codefou}
|
||||
JOIN nomenclature n3 ON n3.no_id = a.nomno_id
|
||||
LEFT JOIN nomenclature n2 ON n2.no_id = n3.parent_no_id
|
||||
LEFT JOIN nomenclature n1 ON n1.no_id = n2.parent_no_id
|
||||
WHERE a.codein IS NOT NULL
|
||||
`);
|
||||
console.log(`[pg-ff] Nomenclature (via nomno_id): ${result.rows.length} articles`);
|
||||
if (result.rows.length > 0) console.log("[pg-ff] Sample nom row:", JSON.stringify(result.rows[0]));
|
||||
return buildNomMap(result.rows as unknown as PgNomRow[]);
|
||||
} catch (e1) {
|
||||
console.log("[pg-ff] Nomenclature essai 1 (nomno_id) échoué:", (e1 as Error).message?.slice(0, 120));
|
||||
}
|
||||
|
||||
// Essai 2 : articles a un champ nomcode (code texte, ex "360504")
|
||||
try {
|
||||
const result = await db.execute(sql`
|
||||
SELECT
|
||||
a.codein,
|
||||
n3.code AS code3,
|
||||
n3.libelle AS libelle3,
|
||||
n2.code AS code2,
|
||||
n2.libelle AS libelle2,
|
||||
n1.code AS code1,
|
||||
n1.libelle AS libelle1nom
|
||||
FROM artfou1 af
|
||||
JOIN articles a ON a.no_id = af.art_no_id AND af.code = ${codefou}
|
||||
JOIN nomenclature n3 ON n3.code = a.nomcode
|
||||
LEFT JOIN nomenclature n2 ON n2.no_id = n3.parent_no_id
|
||||
LEFT JOIN nomenclature n1 ON n1.no_id = n2.parent_no_id
|
||||
WHERE a.codein IS NOT NULL
|
||||
`);
|
||||
console.log(`[pg-ff] Nomenclature (via nomcode): ${result.rows.length} articles`);
|
||||
if (result.rows.length > 0) console.log("[pg-ff] Sample nom row:", JSON.stringify(result.rows[0]));
|
||||
return buildNomMap(result.rows as unknown as PgNomRow[]);
|
||||
} catch (e2) {
|
||||
console.log("[pg-ff] Nomenclature essai 2 (nomcode) échoué:", (e2 as Error).message?.slice(0, 120));
|
||||
}
|
||||
|
||||
console.warn("[pg-ff] Nomenclature : impossible de résoudre le join articles→nomenclature. Vérifiez les logs.");
|
||||
return new Map();
|
||||
}
|
||||
|
||||
function buildNomMap(rows: PgNomRow[]): Map<string, PgNomRow> {
|
||||
const map = new Map<string, PgNomRow>();
|
||||
for (const r of rows) {
|
||||
if (r.codein) map.set(r.codein, r);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 5. Stock temps réel (cube_stock)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
|
||||
Reference in new issue
Block a user