feat: implement bulk PostgreSQL client to replace per-article HTTP API calls

This commit is contained in:
Michael committed 2026-04-03 11:21:38 +02:00
1 parent e90a567446
commit bd21f07c8e
2 files changed
+53 -29

No files matched your search

+6 -12
View File
@@ -1,4 +1,4 @@
import { pgGetHitParade, pgGetStockForCodeins } from "@/lib/pg-ff-client"; import { pgGetHitParade, HitParadeRow } from "@/lib/pg-ff-client";
import { HitParadeClient } from "./client"; import { HitParadeClient } from "./client";
export interface HitParadePivotRow { export interface HitParadePivotRow {
@@ -19,9 +19,7 @@ export interface HitParadePivotRow {
stockTotal: number; stockTotal: number;
} }
function pivotHitParade( function pivotHitParade(rows: HitParadeRow[]): HitParadePivotRow[] {
rows: Array<{ codein: string; libelle: string; fournisseur: string; site: string; qte_vendue: number; ca_ttc: number; marge: number }>
): HitParadePivotRow[] {
const map = new Map<string, HitParadePivotRow>(); const map = new Map<string, HitParadePivotRow>();
for (const row of rows) { for (const row of rows) {
@@ -33,7 +31,10 @@ function pivotHitParade(
qte292: 0, ca292: 0, marge292: 0, qte292: 0, ca292: 0, marge292: 0,
qte579: 0, ca579: 0, marge579: 0, qte579: 0, ca579: 0, marge579: 0,
qteTotal: 0, caTotal: 0, margeTotal: 0, qteTotal: 0, caTotal: 0, margeTotal: 0,
stock292: 0, stock579: 0, stockTotal: 0, // Stock comes from the SQL query directly (LEFT JOIN cube_stock)
stock292: row.stock292 ?? 0,
stock579: row.stock579 ?? 0,
stockTotal: row.stockTotal ?? 0,
}); });
} }
const entry = map.get(row.codein)!; const entry = map.get(row.codein)!;
@@ -75,13 +76,6 @@ export default async function HitParadePage(props: {
const rows = await pgGetHitParade(dateDebut, dateFin); const rows = await pgGetHitParade(dateDebut, dateFin);
const pivotted = pivotHitParade(rows); const pivotted = pivotHitParade(rows);
const codeins = pivotted.map(r => r.codein);
const stockMap = await pgGetStockForCodeins(codeins);
for (const row of pivotted) {
const s = stockMap.get(row.codein);
if (s) { row.stock292 = s.stock292; row.stock579 = s.stock579; row.stockTotal = s.stockTotal; }
}
return ( return (
<div className="min-h-screen bg-gray-50 p-6"> <div className="min-h-screen bg-gray-50 p-6">
<div className="mx-auto max-w-screen-2xl"> <div className="mx-auto max-w-screen-2xl">
+47 -17
View File
@@ -706,30 +706,60 @@ export interface HitParadeRow {
qte_vendue: number; qte_vendue: number;
ca_ttc: number; ca_ttc: number;
marge: number; marge: number;
stock292: number;
stock579: number;
stockTotal: number;
} }
/** /**
* Retourne les ventes produit sur une période, avec fournisseur, qté, CA TTC et marge par site. * Retourne les ventes produit sur une période, avec fournisseur, qté, CA TTC, marge et stock par site.
* Le stock est intégré via un LEFT JOIN — pas de requête séparée, pas de tableau de paramètres.
*/ */
export async function pgGetHitParade(dateDebut: string, dateFin: string): Promise<HitParadeRow[]> { export async function pgGetHitParade(dateDebut: string, dateFin: string): Promise<HitParadeRow[]> {
const result = await pgNoParallel(sql` const result = await pgNoParallel(sql`
WITH ventes AS (
SELECT
a.no_id AS art_no_id,
a.codein::text AS codein,
a.libelle1::text AS libelle,
COALESCE(fi.nom, af.code, 'Sans fournisseur')::text AS fournisseur,
m.site,
SUM(ABS(m.qtemvt))::float AS qte_vendue,
ABS(SUM(m.mntmvtttc))::float AS ca_ttc,
SUM(m.margemvt)::float AS marge
FROM mvtart m
JOIN articles a ON a.no_id = m.artnoid
LEFT JOIN artfou1 af ON af.art_no_id = a.no_id AND af.preference = 1
LEFT JOIN fouident fi ON fi.code = af.code
WHERE m.datmvt BETWEEN ${dateDebut}::date AND ${dateFin}::date
AND m.site IN ('292', '579')
AND m.genremvt = 3
GROUP BY a.no_id, a.codein, a.libelle1, fi.nom, af.code, m.site
),
stock_agg AS (
SELECT
cs.artnoid,
SUM(CASE WHEN cs.site = '292' THEN cs.stockdispo ELSE 0 END)::float AS stock292,
SUM(CASE WHEN cs.site = '579' THEN cs.stockdispo ELSE 0 END)::float AS stock579,
SUM(cs.stockdispo)::float AS stockTotal
FROM cube_stock cs
WHERE cs.artnoid IN (SELECT DISTINCT art_no_id FROM ventes)
GROUP BY cs.artnoid
)
SELECT SELECT
a.codein::text AS codein, v.codein,
a.libelle1::text AS libelle, v.libelle,
COALESCE(fi.nom, af.code, 'Sans fournisseur')::text AS fournisseur, v.fournisseur,
m.site, v.site,
SUM(ABS(m.qtemvt))::float AS qte_vendue, v.qte_vendue,
ABS(SUM(m.mntmvtttc))::float AS ca_ttc, v.ca_ttc,
SUM(m.margemvt)::float AS marge v.marge,
FROM mvtart m COALESCE(s.stock292, 0) AS stock292,
JOIN articles a ON a.no_id = m.artnoid COALESCE(s.stock579, 0) AS stock579,
LEFT JOIN artfou1 af ON af.art_no_id = a.no_id AND af.preference = 1 COALESCE(s.stockTotal, 0) AS "stockTotal"
LEFT JOIN fouident fi ON fi.code = af.code FROM ventes v
WHERE m.datmvt BETWEEN ${dateDebut}::date AND ${dateFin}::date LEFT JOIN stock_agg s ON s.artnoid = v.art_no_id
AND m.site IN ('292', '579') ORDER BY v.ca_ttc DESC
AND m.genremvt = 3
GROUP BY a.codein, a.libelle1, fi.nom, af.code, m.site
ORDER BY ca_ttc DESC
`); `);
console.log(`[pg-ff] HitParade: ${result.rows.length} lignes pour ${dateDebut}→${dateFin}`); console.log(`[pg-ff] HitParade: ${result.rows.length} lignes pour ${dateDebut}→${dateFin}`);