59 lines
2.2 KiB
JavaScript
59 lines
2.2 KiB
JavaScript
// 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 };
|