/** * routes/reports.mjs — Reports (trial balance, etc.) */ export default function registerReports(app, pool) { // GET /api/ledger/trial-balance — Saldobalans app.get('/api/ledger/trial-balance', async (req, res) => { const tenant_id = req.headers['x-tenant-id'] || 'wavult-group'; const { period, period_from, period_to, fiscal_year } = req.query; if (!fiscal_year) return res.status(400).json({ ok: false, error: 'fiscal_year krävs' }); try { const conditions = ['e.tenant_id=$1', 'e.fiscal_year=$2', "e.status='posted'"]; const params = [tenant_id, parseInt(fiscal_year)]; let pidx = 3; if (period) { conditions.push(`e.period=$${pidx++}`); params.push(period); } else if (period_from && period_to) { conditions.push(`e.period>=$${pidx++}`); params.push(period_from); conditions.push(`e.period<=$${pidx++}`); params.push(period_to); } else if (period_from) { conditions.push(`e.period>=$${pidx++}`); params.push(period_from); } else if (period_to) { conditions.push(`e.period<=$${pidx++}`); params.push(period_to); } const { rows } = await pool.query( `SELECT l.account_number, MAX(l.account_name) AS account_name, COALESCE(SUM(l.debit), 0) AS total_debit, COALESCE(SUM(l.credit), 0) AS total_credit, COALESCE(SUM(l.debit), 0) - COALESCE(SUM(l.credit), 0) AS balance FROM ledger_journal_lines l JOIN ledger_journal_entries e ON e.id = l.entry_id WHERE ${conditions.join(' AND ')} GROUP BY l.account_number ORDER BY l.account_number`, params ); const totalDebit = rows.reduce((s,r) => s + parseFloat(r.total_debit), 0); const totalCredit = rows.reduce((s,r) => s + parseFloat(r.total_credit), 0); res.json({ ok: true, fiscal_year: parseInt(fiscal_year), period: period || 'all', accounts: rows, totals: { debit: totalDebit, credit: totalCredit, balanced: Math.abs(totalDebit - totalCredit) < 0.01 } }); } catch (e) { res.status(500).json({ ok: false, error: e.message }); } }); }