'use strict'; const express = require('express'); const router = express.Router(); const { verifyToken } = require('../middleware/auth'); const { getPool } = require('../services/sqlPool'); const store = () => require('../services/balanceSheetStore'); // ── Bootstrap on first require ──────────────────────────────────────────────── store().bootstrap().catch(e => console.error('[BalanceSheet] bootstrap error:', e)); // GET /api/balance-sheet/config router.get('/config', verifyToken, async (req, res) => { try { const cfg = await store().getConfig(); res.json({ success: true, data: cfg, items: store().BS_ITEMS }); } catch (err) { res.status(500).json({ success: false, message: err.message }); } }); // POST /api/balance-sheet/config body: { group_key, acct_codes[], fixed_value, notes } router.post('/config', verifyToken, async (req, res) => { try { const { group_key, acct_codes, opening_acct_codes, fixed_value, notes } = req.body; if (!group_key) return res.status(400).json({ success: false, message: 'group_key required' }); await store().saveConfig(group_key, acct_codes, opening_acct_codes, fixed_value, notes); res.json({ success: true }); } catch (err) { res.status(500).json({ success: false, message: err.message }); } }); // GET /api/balance-sheet/data?asOf=YYYY-MM-DD&from=YYYY-MM-DD&to=YYYY-MM-DD router.get('/data', verifyToken, async (req, res) => { try { const { asOf, from, to, snapshotId, netProfitOverride } = req.query; if (!asOf) return res.status(400).json({ success: false, message: 'asOf date required' }); if (!from || !to) return res.status(400).json({ success: false, message: 'from and to required for P&L data' }); const s = store(); const pool = await getPool(); const cfg = await s.getConfig(); const [netProfit, closingStock, totalProvisions] = await Promise.all([ netProfitOverride != null && netProfitOverride !== '' ? Promise.resolve(parseFloat(netProfitOverride)) : snapshotId ? s.fetchNetProfitFromSnapshot(pool, snapshotId) : s.fetchNetProfit(pool, from, to), s.fetchClosingStock(pool, from, to), s.fetchTotalProvisions(pool, from, to), ]); const values = {}; let reservesDebug = null; await Promise.all( s.BS_ITEMS.map(async item => { const c = cfg[item.key] || {}; let val = 0; if (item.src === 'fixed') { val = c.fixed_value != null ? c.fixed_value * 100000 : 0; } else if (item.src === 'pl_net') { val = netProfit; } else if (item.src === 'closing_stock') { val = closingStock; } else if (item.src === 'provisions') { const ledger = await s.fetchGroupBalance(pool, c.acct_codes || [], null, asOf); val = -ledger + totalProvisions; } else if (item.src === 'reserves_formula') { const rd = await s.fetchReservesSurplusDebug( pool, c.acct_codes || [], c.opening_acct_codes || [], from, to, asOf ); val = rd.result; reservesDebug = rd; } else { val = await s.fetchGroupBalance(pool, c.acct_codes || [], null, asOf); } values[item.key] = val; }) ); res.json({ success: true, asOf, from, to, values, meta: { net_profit: netProfit, closing_stock: closingStock, total_provisions: totalProvisions }, reserves_debug: reservesDebug, }); } catch (err) { res.status(500).json({ success: false, message: err.message }); } }); // GET /api/balance-sheet/snapshot-profit?id= — compute net profit from snapshot period router.get('/snapshot-profit', verifyToken, async (req, res) => { try { const { id } = req.query; if (!id) return res.status(400).json({ success: false, message: 'id required' }); const pool = await getPool(); const s = store(); const net = await s.fetchNetProfitFromSnapshot(pool, id); res.json({ success: true, net_profit: net }); } catch (err) { res.status(500).json({ success: false, message: err.message }); } }); // GET /api/balance-sheet/snapshots — list available P&L snapshots router.get('/snapshots', verifyToken, async (req, res) => { try { const snaps = await require('../services/costingStore').getSnapshots(); res.json({ success: true, data: snaps }); } catch (err) { res.status(500).json({ success: false, message: err.message }); } }); // GET /api/balance-sheet/accounts?q= — search chart of accounts for configure panel router.get('/accounts', verifyToken, async (req, res) => { try { const { q } = req.query; const pool = await getPool(); const req2 = pool.request(); let where = `WHERE T0.GroupMask IN (1,2,3)`; if (q) { req2.input('q', `%${q}%`); where += ` AND (T0.AcctCode LIKE @q OR T0.AcctName LIKE @q)`; } const r = await req2.query(` SELECT TOP 100 T0.AcctCode, T0.AcctName, T0.GroupMask FROM OACT T0 ${where} ORDER BY T0.AcctCode `); res.json({ success: true, data: r.recordset }); } catch (err) { res.status(500).json({ success: false, message: err.message }); } }); module.exports = router;