@@ -0,0 +1,58 @@
|
||||
// services/sales/db.js
|
||||
// Thin helpers over the portal's own app DB (services/appSqlPool.js) for the
|
||||
// Sales Order module (replacement for the old msale/MySQL portal). Every
|
||||
// Sales table lives in the APP database (ZSO_* prefix) — never the SAP DB.
|
||||
'use strict';
|
||||
const sql = require('mssql');
|
||||
const { getPool } = require('../appSqlPool');
|
||||
|
||||
// Bind `?` placeholders positionally (same convention as appSqlPool.query),
|
||||
// but with explicit types for numbers so decimals don't round-trip as FLOAT
|
||||
// surprises and big ints don't overflow INT.
|
||||
function bind(req, text, params) {
|
||||
let i = 0;
|
||||
return text.replace(/\?/g, () => {
|
||||
const name = `p${i}`;
|
||||
const v = params[i];
|
||||
if (v === undefined || v === null) req.input(name, sql.NVarChar, null);
|
||||
else if (typeof v === 'number') req.input(name, Number.isInteger(v) && Math.abs(v) < 2147483647 ? sql.Int : sql.Decimal(19, 4), v);
|
||||
else if (typeof v === 'boolean') req.input(name, sql.Bit, v ? 1 : 0);
|
||||
else if (v instanceof Date) req.input(name, sql.DateTime2, v);
|
||||
else req.input(name, sql.NVarChar(sql.MAX), String(v));
|
||||
i++;
|
||||
return `@${name}`;
|
||||
});
|
||||
}
|
||||
|
||||
async function query(text, params = [], runner = null) {
|
||||
const r = runner ? runner.request() : (await getPool()).request();
|
||||
const res = await r.query(bind(r, text, params));
|
||||
return res.recordset || [];
|
||||
}
|
||||
|
||||
async function one(text, params = [], runner = null) {
|
||||
const rows = await query(text, params, runner);
|
||||
return rows[0] || null;
|
||||
}
|
||||
|
||||
// Run fn(tx) inside a SQL transaction; fn receives a runner usable as the
|
||||
// 3rd arg of query()/one(). Rolls back on any throw.
|
||||
async function tx(fn) {
|
||||
const pool = await getPool();
|
||||
const t = new sql.Transaction(pool);
|
||||
await t.begin();
|
||||
try {
|
||||
const out = await fn(t);
|
||||
await t.commit();
|
||||
return out;
|
||||
} catch (e) {
|
||||
try { await t.rollback(); } catch (_e) {}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
function json(v, fb) { if (v == null || v === '') return fb; try { return JSON.parse(v); } catch (_e) { return fb; } }
|
||||
function csv(v) { return String(v || '').split(',').map(s => s.trim()).filter(Boolean); }
|
||||
function round2(n) { return Math.round((Number(n) || 0) * 100) / 100; }
|
||||
|
||||
module.exports = { query, one, tx, json, csv, round2, sql };
|
||||
Reference in New Issue
Block a user