// 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 };