mirror of
https://github.com/R0m1k3/CollectFlow.git
synced 2026-10-21 05:58:10 +02:00
feat: implement direct PostgreSQL data access and API proxy for automated orders
This commit is contained in:
1 parent
70c425befb
commit
638c4b5f3b
2 files changed
+46
-70
No files matched your search
@@ -1,31 +1,29 @@
|
|||||||
import { NextResponse } from "next/server";
|
import { NextRequest, NextResponse } from "next/server";
|
||||||
import { pgGetCommandesAuto } from "@/lib/pg-ff-client";
|
|
||||||
|
const FF_API_BASE = process.env.FF_API_BASE_URL ?? "https://api.ffnancy.fr";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GET /api/commandes-auto
|
* GET /api/commandes-auto[?site=292&codefou=N009]
|
||||||
*
|
*
|
||||||
* Retourne la liste des fournisseurs en commande automatique,
|
* Proxy vers https://api.ffnancy.fr/api/commandes-auto
|
||||||
* groupés par site (292, 579), avec franco et écart franco.
|
* Transfère les query params site et codefou si présents.
|
||||||
*
|
|
||||||
* Réponse :
|
|
||||||
* [
|
|
||||||
* {
|
|
||||||
* site: "292",
|
|
||||||
* codefou: "FOU123",
|
|
||||||
* nomfou: "Nom Fournisseur",
|
|
||||||
* franco: 500,
|
|
||||||
* nb_articles: 12,
|
|
||||||
* montant_cde: 620.50,
|
|
||||||
* franco_atteint: true,
|
|
||||||
* ecart_franco: -120.50
|
|
||||||
* },
|
|
||||||
* ...
|
|
||||||
* ]
|
|
||||||
*/
|
*/
|
||||||
export async function GET() {
|
export async function GET(req: NextRequest) {
|
||||||
try {
|
try {
|
||||||
const rows = await pgGetCommandesAuto();
|
const { searchParams } = req.nextUrl;
|
||||||
return NextResponse.json(rows);
|
const params = new URLSearchParams();
|
||||||
|
if (searchParams.get("site")) params.set("site", searchParams.get("site")!);
|
||||||
|
if (searchParams.get("codefou")) params.set("codefou", searchParams.get("codefou")!);
|
||||||
|
|
||||||
|
const qs = params.toString();
|
||||||
|
const url = `${FF_API_BASE}/api/commandes-auto${qs ? `?${qs}` : ""}`;
|
||||||
|
|
||||||
|
const res = await fetch(url, { cache: "no-store" });
|
||||||
|
if (!res.ok) {
|
||||||
|
return NextResponse.json({ error: `API upstream HTTP ${res.status}` }, { status: res.status });
|
||||||
|
}
|
||||||
|
const data = await res.json();
|
||||||
|
return NextResponse.json(data);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("[api/commandes-auto]", e);
|
console.error("[api/commandes-auto]", e);
|
||||||
return NextResponse.json({ error: "Erreur serveur" }, { status: 500 });
|
return NextResponse.json({ error: "Erreur serveur" }, { status: 500 });
|
||||||
|
|||||||
+25
-47
@@ -936,56 +936,34 @@ export interface PgCommandeAutoRow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retourne la liste des fournisseurs ayant des articles en commande auto,
|
* Retourne la liste des fournisseurs en commande automatique via l'API Hostinger.
|
||||||
* groupés par site + fournisseur, avec le montant total (pcb × pa),
|
* GET https://api.ffnancy.fr/api/commandes-auto
|
||||||
* le franco du fournisseur et l'écart franco.
|
|
||||||
*
|
|
||||||
* Hypothèses sur le schéma FF Nancy :
|
|
||||||
* - artfou1.cdeauto : flag commande auto (boolean-like)
|
|
||||||
* - fouident.franco : franco de port (montant minimum de commande)
|
|
||||||
* - cube_pa.pa : prix d'achat
|
|
||||||
*/
|
*/
|
||||||
export async function pgGetCommandesAuto(): Promise<PgCommandeAutoRow[]> {
|
export async function pgGetCommandesAuto(): Promise<PgCommandeAutoRow[]> {
|
||||||
|
const FF_API_BASE = process.env.FF_API_BASE_URL ?? "https://api.ffnancy.fr";
|
||||||
try {
|
try {
|
||||||
const result = await pgNoParallel(sql`
|
const res = await fetch(`${FF_API_BASE}/api/commandes-auto`, { cache: "no-store" });
|
||||||
SELECT
|
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
||||||
cs.site,
|
const data = await res.json();
|
||||||
fi.code AS codefou,
|
// L'API peut retourner directement un tableau ou un objet wrappé
|
||||||
COALESCE(fi.nom, af.code) AS nomfou,
|
const rows: unknown[] = Array.isArray(data)
|
||||||
COALESCE(fi.franco::numeric, 0) AS franco,
|
? data
|
||||||
COUNT(DISTINCT a.codein) AS nb_articles,
|
: (data?.data ?? data?.items ?? data?.results ?? []);
|
||||||
ROUND(SUM(
|
console.log(`[pg-ff] pgGetCommandesAuto: ${rows.length} lignes (API Hostinger)`);
|
||||||
GREATEST(1, COALESCE(af.pcb, 1))::numeric
|
// Normalise chaque ligne vers PgCommandeAutoRow
|
||||||
* COALESCE(pa.pa, 0)::numeric
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
), 2) AS montant_cde,
|
return (rows as any[]).map((r): PgCommandeAutoRow => ({
|
||||||
CASE
|
site: String(r.site ?? r.Site ?? ""),
|
||||||
WHEN COALESCE(fi.franco::numeric, 0) = 0 THEN NULL
|
codefou: String(r.codefou ?? r.CodeFou ?? r.code ?? ""),
|
||||||
WHEN SUM(
|
nomfou: String(r.nomfou ?? r.NomFou ?? r.nom ?? ""),
|
||||||
GREATEST(1, COALESCE(af.pcb, 1))::numeric
|
franco: Number(r.franco ?? r.Franco ?? 0),
|
||||||
* COALESCE(pa.pa, 0)::numeric
|
nb_articles: Number(r.nb_articles ?? r.nbArticles ?? r.count ?? 0),
|
||||||
) >= COALESCE(fi.franco::numeric, 0) THEN true
|
montant_cde: Number(r.montant_cde ?? r.montantCde ?? r.montant ?? 0),
|
||||||
ELSE false
|
franco_atteint: r.franco_atteint != null
|
||||||
END AS franco_atteint,
|
? Boolean(r.franco_atteint)
|
||||||
ROUND(
|
: null,
|
||||||
COALESCE(fi.franco::numeric, 0) - SUM(
|
ecart_franco: Number(r.ecart_franco ?? r.ecartFranco ?? 0),
|
||||||
GREATEST(1, COALESCE(af.pcb, 1))::numeric
|
}));
|
||||||
* COALESCE(pa.pa, 0)::numeric
|
|
||||||
), 2
|
|
||||||
) AS ecart_franco
|
|
||||||
FROM artfou1 af
|
|
||||||
JOIN articles a ON a.no_id = af.art_no_id
|
|
||||||
JOIN fouident fi ON fi.code = af.code
|
|
||||||
JOIN cube_stock cs ON cs.artnoid = a.no_id
|
|
||||||
LEFT JOIN cube_pa pa ON pa.artnoid = a.no_id
|
|
||||||
WHERE af.cdeauto::text IN ('1', 'true', 't', 'yes', 'y', 'on')
|
|
||||||
AND cs.site IN ('292', '579')
|
|
||||||
AND (af.suspendu IS NULL OR af.suspendu::text NOT IN ('1', 'true', 't', 'yes', 'y', 'on'))
|
|
||||||
AND (a.suspendu IS NULL OR a.suspendu::text NOT IN ('1', 'true', 't', 'yes', 'y', 'on'))
|
|
||||||
GROUP BY cs.site, fi.code, fi.nom, af.code, fi.franco
|
|
||||||
ORDER BY cs.site, COALESCE(fi.nom, af.code)
|
|
||||||
`);
|
|
||||||
console.log(`[pg-ff] pgGetCommandesAuto: ${result.rows.length} lignes`);
|
|
||||||
return result.rows as unknown as PgCommandeAutoRow[];
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("[pg-ff] pgGetCommandesAuto error:", (e as Error).message?.slice(0, 300));
|
console.error("[pg-ff] pgGetCommandesAuto error:", (e as Error).message?.slice(0, 300));
|
||||||
return [];
|
return [];
|
||||||
|
|||||||
Reference in new issue
Block a user