fix: utiliser FOUPORT2.SEUIL comme source principale du franco fournisseur
FOUCAD ne couvre que 53/153 fournisseurs actifs (commande auto uniquement). FOUPORT2.SEUIL est la source officielle de l'ERP et couvre 108 fournisseurs. 4 fournisseurs dans COMMANDE_AUTO_QTEPROPO n'avaient pas de franco visible (IMDIFA, MYCANDYSHOP, PTIT CLOWN, PUCKATOR BV). - Sync : ajout de FOUPORT et FOUPORT2 dans le pipeline de synchronisation - API : franco = COALESCE(fouport2.seuil, foucad.franco) dans les deux routes - Schema PG : création des tables fouport et fouport2 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
b4a9331fa8
commit
c75fd5c56d
3 files changed
+99
-12
No files matched your search
@@ -461,6 +461,27 @@ CREATE TABLE IF NOT EXISTS foucad (
|
|||||||
suividatemodif TIMESTAMP
|
suividatemodif TIMESTAMP
|
||||||
);
|
);
|
||||||
|
|
||||||
|
-- Conditions de port fournisseur (source officielle du franco)
|
||||||
|
CREATE TABLE IF NOT EXISTS fouport (
|
||||||
|
no_id NUMERIC(20,0) PRIMARY KEY,
|
||||||
|
code TEXT,
|
||||||
|
sit_code TEXT,
|
||||||
|
suividatecreation TIMESTAMP,
|
||||||
|
suividatemodif TIMESTAMP
|
||||||
|
);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_fouport_code ON fouport (code);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS fouport2 (
|
||||||
|
fou_no_id NUMERIC(20,0),
|
||||||
|
no_id NUMERIC(20,0) PRIMARY KEY,
|
||||||
|
seuil NUMERIC(12,2),
|
||||||
|
mode SMALLINT,
|
||||||
|
valeur NUMERIC(12,2),
|
||||||
|
suividatecreation TIMESTAMP,
|
||||||
|
suividatemodif TIMESTAMP
|
||||||
|
);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_fouport2_fou_no_id ON fouport2 (fou_no_id);
|
||||||
|
|
||||||
-- ============================================================
|
-- ============================================================
|
||||||
-- Publicités (FBENTPUB + ECOULEMENT + ECOULEMENT_DETAIL SQL Server)
|
-- Publicités (FBENTPUB + ECOULEMENT + ECOULEMENT_DETAIL SQL Server)
|
||||||
-- ============================================================
|
-- ============================================================
|
||||||
|
|||||||
@@ -14,27 +14,31 @@ router.get('/', async (req, res) => {
|
|||||||
q.codesite AS site,
|
q.codesite AS site,
|
||||||
q.fou_code AS codefou,
|
q.fou_code AS codefou,
|
||||||
fi.nom AS nom_fou,
|
fi.nom AS nom_fou,
|
||||||
fc.franco AS franco_ht,
|
COALESCE(fp2.seuil, fc.franco) AS franco_ht,
|
||||||
COUNT(q.art_no_id) AS nb_articles,
|
COUNT(q.art_no_id) AS nb_articles,
|
||||||
SUM(q.qtepropo) AS qte_totale,
|
SUM(q.qtepropo) AS qte_totale,
|
||||||
ROUND(SUM(q.qtepropo * cp.pa), 2) AS montant_propo_ht,
|
ROUND(SUM(q.qtepropo * cp.pa), 2) AS montant_propo_ht,
|
||||||
CASE
|
CASE
|
||||||
WHEN fc.franco IS NULL OR fc.franco = 0 THEN 'N/A'
|
WHEN COALESCE(fp2.seuil, fc.franco) IS NULL OR COALESCE(fp2.seuil, fc.franco) = 0 THEN 'N/A'
|
||||||
WHEN SUM(q.qtepropo * cp.pa) >= fc.franco THEN 'OUI'
|
WHEN SUM(q.qtepropo * cp.pa) >= COALESCE(fp2.seuil, fc.franco) THEN 'OUI'
|
||||||
ELSE 'NON'
|
ELSE 'NON'
|
||||||
END AS franco_atteint,
|
END AS franco_atteint,
|
||||||
CASE
|
CASE
|
||||||
WHEN fc.franco IS NULL OR fc.franco = 0 THEN NULL
|
WHEN COALESCE(fp2.seuil, fc.franco) IS NULL OR COALESCE(fp2.seuil, fc.franco) = 0 THEN NULL
|
||||||
ELSE ROUND(fc.franco - SUM(q.qtepropo * cp.pa), 2)
|
ELSE ROUND(COALESCE(fp2.seuil, fc.franco) - SUM(q.qtepropo * cp.pa), 2)
|
||||||
END AS ecart_franco
|
END AS ecart_franco
|
||||||
FROM commande_auto_qtepropo q
|
FROM commande_auto_qtepropo q
|
||||||
LEFT JOIN fouident fi ON fi.code = q.fou_code
|
LEFT JOIN fouident fi ON fi.code = q.fou_code
|
||||||
LEFT JOIN foucad fc ON fc.foucode = q.fou_code
|
LEFT JOIN foucad fc ON fc.foucode = q.fou_code
|
||||||
|
LEFT JOIN fouport fp ON fp.code = q.fou_code
|
||||||
|
LEFT JOIN (
|
||||||
|
SELECT fou_no_id, MAX(seuil) AS seuil FROM fouport2 GROUP BY fou_no_id
|
||||||
|
) fp2 ON fp2.fou_no_id = fp.no_id
|
||||||
LEFT JOIN cube_pa cp ON cp.artnoid = q.art_no_id
|
LEFT JOIN cube_pa cp ON cp.artnoid = q.art_no_id
|
||||||
WHERE q.qtepropo > 0
|
WHERE q.qtepropo > 0
|
||||||
AND ($1 = '' OR q.codesite LIKE $1)
|
AND ($1 = '' OR q.codesite LIKE $1)
|
||||||
AND ($2 = '' OR q.fou_code ILIKE $2)
|
AND ($2 = '' OR q.fou_code ILIKE $2)
|
||||||
GROUP BY q.codesite, q.fou_code, fi.nom, fc.franco
|
GROUP BY q.codesite, q.fou_code, fi.nom, fc.franco, fp2.seuil
|
||||||
ORDER BY q.codesite, montant_propo_ht DESC
|
ORDER BY q.codesite, montant_propo_ht DESC
|
||||||
`, [`%${site}%`, `%${codefou}%`]);
|
`, [`%${site}%`, `%${codefou}%`]);
|
||||||
|
|
||||||
@@ -58,27 +62,31 @@ router.get('/:codefou', async (req, res) => {
|
|||||||
q.codesite AS site,
|
q.codesite AS site,
|
||||||
q.fou_code AS codefou,
|
q.fou_code AS codefou,
|
||||||
fi.nom AS nom_fou,
|
fi.nom AS nom_fou,
|
||||||
fc.franco AS franco_ht,
|
COALESCE(fp2.seuil, fc.franco) AS franco_ht,
|
||||||
COUNT(q.art_no_id) AS nb_articles,
|
COUNT(q.art_no_id) AS nb_articles,
|
||||||
SUM(q.qtepropo) AS qte_totale,
|
SUM(q.qtepropo) AS qte_totale,
|
||||||
ROUND(SUM(q.qtepropo * cp.pa), 2) AS montant_propo_ht,
|
ROUND(SUM(q.qtepropo * cp.pa), 2) AS montant_propo_ht,
|
||||||
CASE
|
CASE
|
||||||
WHEN fc.franco IS NULL OR fc.franco = 0 THEN 'N/A'
|
WHEN COALESCE(fp2.seuil, fc.franco) IS NULL OR COALESCE(fp2.seuil, fc.franco) = 0 THEN 'N/A'
|
||||||
WHEN SUM(q.qtepropo * cp.pa) >= fc.franco THEN 'OUI'
|
WHEN SUM(q.qtepropo * cp.pa) >= COALESCE(fp2.seuil, fc.franco) THEN 'OUI'
|
||||||
ELSE 'NON'
|
ELSE 'NON'
|
||||||
END AS franco_atteint,
|
END AS franco_atteint,
|
||||||
CASE
|
CASE
|
||||||
WHEN fc.franco IS NULL OR fc.franco = 0 THEN NULL
|
WHEN COALESCE(fp2.seuil, fc.franco) IS NULL OR COALESCE(fp2.seuil, fc.franco) = 0 THEN NULL
|
||||||
ELSE ROUND(fc.franco - SUM(q.qtepropo * cp.pa), 2)
|
ELSE ROUND(COALESCE(fp2.seuil, fc.franco) - SUM(q.qtepropo * cp.pa), 2)
|
||||||
END AS ecart_franco
|
END AS ecart_franco
|
||||||
FROM commande_auto_qtepropo q
|
FROM commande_auto_qtepropo q
|
||||||
LEFT JOIN fouident fi ON fi.code = q.fou_code
|
LEFT JOIN fouident fi ON fi.code = q.fou_code
|
||||||
LEFT JOIN foucad fc ON fc.foucode = q.fou_code
|
LEFT JOIN foucad fc ON fc.foucode = q.fou_code
|
||||||
|
LEFT JOIN fouport fp ON fp.code = q.fou_code
|
||||||
|
LEFT JOIN (
|
||||||
|
SELECT fou_no_id, MAX(seuil) AS seuil FROM fouport2 GROUP BY fou_no_id
|
||||||
|
) fp2 ON fp2.fou_no_id = fp.no_id
|
||||||
LEFT JOIN cube_pa cp ON cp.artnoid = q.art_no_id
|
LEFT JOIN cube_pa cp ON cp.artnoid = q.art_no_id
|
||||||
WHERE q.qtepropo > 0
|
WHERE q.qtepropo > 0
|
||||||
AND q.fou_code ILIKE $1
|
AND q.fou_code ILIKE $1
|
||||||
AND ($2 = '' OR q.codesite LIKE $2)
|
AND ($2 = '' OR q.codesite LIKE $2)
|
||||||
GROUP BY q.codesite, q.fou_code, fi.nom, fc.franco
|
GROUP BY q.codesite, q.fou_code, fi.nom, fc.franco, fp2.seuil
|
||||||
ORDER BY q.codesite
|
ORDER BY q.codesite
|
||||||
`, [codefou, `%${site}%`]);
|
`, [codefou, `%${site}%`]);
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,14 @@ const FOUCAD_COLS = [
|
|||||||
'montantcdeauto','datecdeauto','suividatecreation','suividatemodif',
|
'montantcdeauto','datecdeauto','suividatecreation','suividatemodif',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const FOUPORT_COLS = [
|
||||||
|
'no_id','code','sit_code','suividatecreation','suividatemodif',
|
||||||
|
];
|
||||||
|
|
||||||
|
const FOUPORT2_COLS = [
|
||||||
|
'fou_no_id','no_id','seuil','mode','valeur','suividatecreation','suividatemodif',
|
||||||
|
];
|
||||||
|
|
||||||
const PLAN_REAPPRO_COLS = [
|
const PLAN_REAPPRO_COLS = [
|
||||||
'id','magasin','codein','bu_no_id','stockmag','encours_palette_mag',
|
'id','magasin','codein','bu_no_id','stockmag','encours_palette_mag',
|
||||||
'attente_prepa_mag','colis_rea','colis_ajout_web','stock_dispo',
|
'attente_prepa_mag','colis_rea','colis_ajout_web','stock_dispo',
|
||||||
@@ -171,6 +179,56 @@ async function syncAppro(force) {
|
|||||||
console.error(`[foucad] ERREUR: ${err.message}`);
|
console.error(`[foucad] ERREUR: ${err.message}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// === FOUPORT (full refresh — conditions de port par fournisseur) ===
|
||||||
|
try {
|
||||||
|
const ms = await getMssql();
|
||||||
|
const res = await ms.request().query(`
|
||||||
|
SELECT NO_ID, CODE, SIT_CODE, SUIVIDATECREATION, SUIVIDATEMODIF
|
||||||
|
FROM FOUPORT
|
||||||
|
`);
|
||||||
|
|
||||||
|
const rows = res.recordset.map(r => ({
|
||||||
|
no_id: r.NO_ID,
|
||||||
|
code: r.CODE,
|
||||||
|
sit_code: r.SIT_CODE ?? null,
|
||||||
|
suividatecreation: r.SUIVIDATECREATION,
|
||||||
|
suividatemodif: r.SUIVIDATEMODIF,
|
||||||
|
}));
|
||||||
|
|
||||||
|
const count = await fullRefresh(pg, 'fouport', rows, FOUPORT_COLS);
|
||||||
|
await logSync(pg, 'fouport', count, 'ok');
|
||||||
|
console.log(`[fouport] ${count} lignes`);
|
||||||
|
} catch (err) {
|
||||||
|
await logSync(pg, 'fouport', 0, 'error', err.message);
|
||||||
|
console.error(`[fouport] ERREUR: ${err.message}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// === FOUPORT2 (full refresh — seuils de franco par fournisseur) ===
|
||||||
|
try {
|
||||||
|
const ms = await getMssql();
|
||||||
|
const res = await ms.request().query(`
|
||||||
|
SELECT FOU_NO_ID, NO_ID, SEUIL, MODE, VALEUR, SUIVIDATECREATION, SUIVIDATEMODIF
|
||||||
|
FROM FOUPORT2
|
||||||
|
`);
|
||||||
|
|
||||||
|
const rows = res.recordset.map(r => ({
|
||||||
|
fou_no_id: r.FOU_NO_ID,
|
||||||
|
no_id: r.NO_ID,
|
||||||
|
seuil: r.SEUIL ?? null,
|
||||||
|
mode: r.MODE ?? null,
|
||||||
|
valeur: r.VALEUR ?? null,
|
||||||
|
suividatecreation: r.SUIVIDATECREATION,
|
||||||
|
suividatemodif: r.SUIVIDATEMODIF,
|
||||||
|
}));
|
||||||
|
|
||||||
|
const count = await fullRefresh(pg, 'fouport2', rows, FOUPORT2_COLS);
|
||||||
|
await logSync(pg, 'fouport2', count, 'ok');
|
||||||
|
console.log(`[fouport2] ${count} lignes`);
|
||||||
|
} catch (err) {
|
||||||
|
await logSync(pg, 'fouport2', 0, 'error', err.message);
|
||||||
|
console.error(`[fouport2] ERREUR: ${err.message}`);
|
||||||
|
}
|
||||||
|
|
||||||
// === PLAN_REAPPRO (full refresh — état courant) ===
|
// === PLAN_REAPPRO (full refresh — état courant) ===
|
||||||
try {
|
try {
|
||||||
const ms = await getMssql();
|
const ms = await getMssql();
|
||||||
|
|||||||
Reference in new issue
Block a user