diff --git a/sync/server.js b/sync/server.js
index 7123abf..c22643e 100644
--- a/sync/server.js
+++ b/sync/server.js
@@ -61,7 +61,7 @@ app.get('/api/status', async (req, res) => {
try {
const pg = getPg();
const { rows } = await pg.query(
- `SELECT table_name, last_sync, rows_synced, status, error_message
+ `SELECT table_name, last_sync, rows_synced, status, error_msg
FROM sync_log ORDER BY table_name`
);
res.json({
@@ -238,7 +238,7 @@ function renderStatus(data){
\${t.table_name} |
\${fmtDate(t.last_sync)} |
\${t.rows_synced ?? '—'} |
- \${t.status ?? '—'}\${t.error_message?' — '+t.error_message:''} |
+ \${t.status ?? '—'}\${t.error_msg?' — '+t.error_msg:''} |
\`).join('');
}
diff --git a/sync/tables/articles.js b/sync/tables/articles.js
index c5b5944..6f98b3e 100644
--- a/sync/tables/articles.js
+++ b/sync/tables/articles.js
@@ -1,5 +1,5 @@
const { getMssql, getPg } = require('../db');
-const { batchUpsert, getLastSync, logSync } = require('../utils');
+const { batchUpsert, getLastSync, logSync, safeStr, safeBit } = require('../utils');
const ARTICLES_COLS = [
'no_id','codein','libelle1','libelle2','lib_ticket',
@@ -32,15 +32,15 @@ async function syncArticles(force) {
const rows = res.recordset.map(r => ({
no_id: r.NO_ID,
- codein: r.CODEIN,
- libelle1: r.LIBELLE1,
- libelle2: r.LIBELLE2,
- lib_ticket: r.LIB_TICKET,
- tax_code: r.TAX_CODE,
- ach_code: r.ACH_CODE,
- utilisable: r.UTILISABLE,
- actif: r.ACTIF,
- suspendu: r.SUSPENDU,
+ codein: safeStr(r.CODEIN),
+ libelle1: safeStr(r.LIBELLE1),
+ libelle2: safeStr(r.LIBELLE2),
+ lib_ticket: safeStr(r.LIB_TICKET),
+ tax_code: safeStr(r.TAX_CODE),
+ ach_code: safeStr(r.ACH_CODE),
+ utilisable: safeStr(r.UTILISABLE),
+ actif: safeStr(r.ACTIF),
+ suspendu: safeStr(r.SUSPENDU),
suividatecreation: r.SUIVIDATECREATION,
suividatemodif: r.SUIVIDATEMODIF,
nom_no_id: r.NOM_NO_ID,
@@ -102,9 +102,9 @@ async function syncArticles(force) {
`SELECT IDARTICLE, GTIN, PREFERENTIEL FROM ART_GTIN`
);
const rows = res.recordset.map(r => ({
- idarticle: r.IDARTICLE,
- gtin: r.GTIN,
- preferentiel: r.PREFERENTIEL,
+ idarticle: r.IDARTICLE,
+ gtin: safeStr(r.GTIN),
+ preferentiel: safeBit(r.PREFERENTIEL),
}));
const count = await batchUpsert(pg, 'art_gtin', rows, ['idarticle','gtin'], GTIN_COLS);
await logSync(pg, 'art_gtin', count, 'ok');
diff --git a/sync/tables/fournisseurs.js b/sync/tables/fournisseurs.js
index 8d47753..ac01131 100644
--- a/sync/tables/fournisseurs.js
+++ b/sync/tables/fournisseurs.js
@@ -1,5 +1,5 @@
const { getMssql, getPg } = require('../db');
-const { batchUpsert, fullRefresh, getLastSync, logSync } = require('../utils');
+const { batchUpsert, fullRefresh, getLastSync, logSync, safeDecimal } = require('../utils');
const ARTFOU1_COLS = [
'no_id','art_no_id','code','reference','ean13','itf',
@@ -58,8 +58,8 @@ async function syncFournisseurs(force) {
);
const rows = res.recordset.map(r => ({
idartfou1: r.IDARTFOU1,
- prixachat: r.PRIXACHAT,
- remise_promotion: r.REMISE_PROMOTION,
+ prixachat: safeDecimal(r.PRIXACHAT),
+ remise_promotion: safeDecimal(r.REMISE_PROMOTION),
}));
const count = await batchUpsert(pg, 'artfou2', rows, ['idartfou1'], ARTFOU2_COLS);
await logSync(pg, 'artfou2', count, 'ok');
diff --git a/sync/tables/stock.js b/sync/tables/stock.js
index 0183f77..2da8a96 100644
--- a/sync/tables/stock.js
+++ b/sync/tables/stock.js
@@ -1,5 +1,5 @@
const { getMssql, getPg } = require('../db');
-const { fullRefresh, batchUpsert, logSync } = require('../utils');
+const { fullRefresh, batchUpsert, logSync, safeNum, safeInt, safeStr } = require('../utils');
const STOCK_COLS = [
'artnoid','site','qte','prmp','valstock','pv',
@@ -27,23 +27,23 @@ async function syncStock(force) {
`);
const rows = res.recordset.map(r => ({
- artnoid: r.ArtNoId,
- site: r.Site,
- qte: r.QTE,
- prmp: r.Prmp,
- valstock: r.ValStock,
- pv: r.PV,
- stockdispo: r.StockDispo,
- stockmort: r.StockMort,
- stockcolis: r.StockColis,
- dernierevente: r.DerniereVente,
- dernierereception: r.DerniereReception,
- premierevente: r.PremiereVente,
- nbjoursdernierMouvement: r.NbJoursDernierMouvement,
- nbjoursdernierevente: r.NbJoursDerniereVente,
- nbjoursdernierrereception: r.NbJoursDerniereReception,
- interditachat: r.InterditAchat,
- codefou: r.CODEFOU,
+ artnoid: r.ArtNoId,
+ site: safeStr(r.Site),
+ qte: safeNum(r.QTE),
+ prmp: safeNum(r.Prmp),
+ valstock: safeNum(r.ValStock),
+ pv: safeNum(r.PV),
+ stockdispo: safeNum(r.StockDispo),
+ stockmort: safeNum(r.StockMort),
+ stockcolis: safeNum(r.StockColis),
+ dernierevente: r.DerniereVente,
+ dernierereception: r.DerniereReception,
+ premierevente: r.PremiereVente,
+ nbjoursdernierMouvement: safeInt(r.NbJoursDernierMouvement),
+ nbjoursdernierevente: safeInt(r.NbJoursDerniereVente),
+ nbjoursdernierrereception: safeInt(r.NbJoursDerniereReception),
+ interditachat: safeStr(r.InterditAchat),
+ codefou: safeStr(r.CODEFOU),
}));
const count = await fullRefresh(pg, 'cube_stock', rows, STOCK_COLS);
diff --git a/sync/utils.js b/sync/utils.js
index c4a9197..867d0a9 100644
--- a/sync/utils.js
+++ b/sync/utils.js
@@ -88,4 +88,50 @@ async function logSync(pg, tableName, rowsSynced, status, errorMsg = null) {
`, [tableName, rowsSynced, status, errorMsg]);
}
-module.exports = { batchUpsert, fullRefresh, getLastSync, logSync };
+// ── Helpers de conversion SQL Server → PostgreSQL ───────────
+
+/** Nettoie une chaîne : supprime null bytes (0x00), retourne null si vide */
+function safeStr(v) {
+ if (v == null) return null;
+ return String(v).replace(/\0/g, '') || null;
+}
+
+/** Convertit en nombre, retourne null si NaN ou non numérique */
+function safeNum(v) {
+ if (v == null) return null;
+ if (typeof v === 'number') return isNaN(v) ? null : v;
+ const n = parseFloat(String(v).replace(/[^0-9.\-]/g, ''));
+ return isNaN(n) ? null : n;
+}
+
+/** Convertit en entier, retourne null si NaN */
+function safeInt(v) {
+ if (v == null) return null;
+ if (typeof v === 'number') return Math.round(v);
+ const n = parseInt(v, 10);
+ return isNaN(n) ? null : n;
+}
+
+/** Convertit un BIT SQL Server (true/false) en SMALLINT (1/0) */
+function safeBit(v) {
+ if (v == null) return null;
+ return v ? 1 : 0;
+}
+
+/**
+ * Convertit une valeur DECIMAL/MONEY qui peut être retournée par mssql
+ * sous forme d'objet, tableau, ou string "[date,valeur]".
+ */
+function safeDecimal(v) {
+ if (v == null) return null;
+ if (typeof v === 'number') return isNaN(v) ? null : v;
+ if (Array.isArray(v)) {
+ const last = v[v.length - 1];
+ return typeof last === 'number' ? last : safeNum(last);
+ }
+ // ex: "[01/01/1901,163.000]" → 163
+ const m = String(v).match(/([\d]+\.?[\d]*)[\]]*$/);
+ return m ? parseFloat(m[1]) : null;
+}
+
+module.exports = { batchUpsert, fullRefresh, getLastSync, logSync, safeStr, safeNum, safeInt, safeBit, safeDecimal };