Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
adc8d357c9 | ||
|
|
950539472f | ||
|
|
e01048fe3b | ||
|
|
c5b0896bb4 |
No files matched your search
+13
-1
@@ -171,7 +171,19 @@ async function syncAppro(force) {
|
||||
suividatemodif: r.SUIVIDATEMODIF,
|
||||
}));
|
||||
|
||||
const count = await fullRefresh(pg, 'foucad', rows, FOUCAD_COLS);
|
||||
// foucode est PK côté PostgreSQL mais la source FOUCAD peut renvoyer
|
||||
// plusieurs lignes par FOUCODE → on déduplique en gardant la plus récente
|
||||
// (suividatemodif), sinon l'INSERT viole foucad_pkey.
|
||||
const byCode = new Map();
|
||||
for (const row of rows) {
|
||||
const prev = byCode.get(row.foucode);
|
||||
if (!prev || (row.suividatemodif ?? 0) >= (prev.suividatemodif ?? 0)) {
|
||||
byCode.set(row.foucode, row);
|
||||
}
|
||||
}
|
||||
const dedupRows = [...byCode.values()];
|
||||
|
||||
const count = await fullRefresh(pg, 'foucad', dedupRows, FOUCAD_COLS);
|
||||
await logSync(pg, 'foucad', count, 'ok');
|
||||
console.log(`[foucad] ${count} lignes`);
|
||||
} catch (err) {
|
||||
|
||||
+73
-1
@@ -11,6 +11,48 @@ const STOCK_COLS = [
|
||||
const PA_COLS = ['artnoid','pa'];
|
||||
const PV_COLS = ['artnoid','site','pv'];
|
||||
|
||||
// ARTFOU2.PRIXACHAT empile l'historique des prix d'un fournisseur sous forme
|
||||
// "[01/01/1901,0.990:16/05/2018,1.010]". Le dernier couple porte le prix courant
|
||||
// et la date à laquelle il a été appliqué.
|
||||
function lastPriceChange(s) {
|
||||
if (!s) return null;
|
||||
const body = String(s).trim().replace(/^\[/, '').replace(/\]$/, '');
|
||||
if (!body) return null;
|
||||
const pairs = body.split(':');
|
||||
const [d, p] = pairs[pairs.length - 1].split(',');
|
||||
const m = d && d.match(/^(\d{2})\/(\d{2})\/(\d{4})$/);
|
||||
const price = parseFloat(p);
|
||||
if (!m || Number.isNaN(price)) return null;
|
||||
return { date: Date.UTC(+m[3], +m[2] - 1, +m[1]), price };
|
||||
}
|
||||
|
||||
// Pour chaque artnoid en doublon, retrouve le prix dont le changement est le plus
|
||||
// récent. Égalité de date de prix → on départage sur SUIVIDATEMODIF de la ligne.
|
||||
async function resolveDuplicatePa(ms, artnoids) {
|
||||
const ids = artnoids.map(Number).filter(Number.isFinite);
|
||||
if (!ids.length) return new Map();
|
||||
|
||||
const res = await ms.request().query(`
|
||||
SELECT f1.ART_NO_ID, f2.PRIXACHAT, f2.SUIVIDATEMODIF
|
||||
FROM ARTFOU1 f1
|
||||
JOIN ARTFOU2 f2 ON f2.IDARTFOU1 = f1.NO_ID
|
||||
WHERE f1.ART_NO_ID IN (${ids.join(',')})
|
||||
`);
|
||||
|
||||
const best = new Map();
|
||||
for (const r of res.recordset) {
|
||||
const lp = lastPriceChange(r.PRIXACHAT);
|
||||
if (!lp) continue;
|
||||
const key = String(r.ART_NO_ID);
|
||||
const modif = r.SUIVIDATEMODIF ? new Date(r.SUIVIDATEMODIF).getTime() : 0;
|
||||
const prev = best.get(key);
|
||||
if (!prev || lp.date > prev.date || (lp.date === prev.date && modif > prev.modif)) {
|
||||
best.set(key, { date: lp.date, price: lp.price, modif });
|
||||
}
|
||||
}
|
||||
return best;
|
||||
}
|
||||
|
||||
async function syncStock(force) {
|
||||
const ms = await getMssql();
|
||||
const pg = getPg();
|
||||
@@ -57,7 +99,37 @@ async function syncStock(force) {
|
||||
// === Cube_PA (full refresh) ===
|
||||
try {
|
||||
const res = await ms.request().query(`SELECT ArtNoId, PA FROM Cube_PA`);
|
||||
const rows = res.recordset.map(r => ({ artnoid: r.ArtNoId, pa: r.PA }));
|
||||
const raw = res.recordset.map(r => ({ artnoid: r.ArtNoId, pa: r.PA }));
|
||||
|
||||
// artnoid est PK côté PostgreSQL, mais le cube peut sortir deux lignes pour
|
||||
// un article livré par deux fournisseurs → l'INSERT violerait cube_pa_pkey.
|
||||
const groups = new Map();
|
||||
for (const r of raw) {
|
||||
const key = String(r.artnoid);
|
||||
const g = groups.get(key);
|
||||
if (g) g.push(r); else groups.set(key, [r]);
|
||||
}
|
||||
const dupIds = [...groups].filter(([, g]) => g.length > 1).map(([id]) => id);
|
||||
|
||||
let rows = raw;
|
||||
if (dupIds.length) {
|
||||
const best = await resolveDuplicatePa(ms, dupIds);
|
||||
rows = [];
|
||||
for (const [key, g] of groups) {
|
||||
if (g.length === 1) { rows.push(g[0]); continue; }
|
||||
const b = best.get(key);
|
||||
let chosen = b && g.find(x => Math.abs(parseFloat(x.pa) - b.price) < 0.005);
|
||||
if (!chosen) {
|
||||
// Pas de prix fournisseur exploitable : on retient le PA le plus élevé,
|
||||
// qui sous-estime la marge plutôt que de l'inventer.
|
||||
chosen = g.reduce((a, x) => (parseFloat(x.pa) > parseFloat(a.pa) ? x : a));
|
||||
console.warn(`[cube_pa] artnoid ${key} non résolu → PA le plus élevé retenu (${chosen.pa})`);
|
||||
}
|
||||
rows.push(chosen);
|
||||
}
|
||||
console.log(`[cube_pa] ${dupIds.length} artnoid dédupliqués`);
|
||||
}
|
||||
|
||||
const count = await fullRefresh(pg, 'cube_pa', rows, PA_COLS);
|
||||
await logSync(pg, 'cube_pa', count, 'ok');
|
||||
console.log(`[cube_pa] ${count} lignes refresh`);
|
||||
|
||||
Reference in new issue
Block a user