feat(accounting): tax window shows all costs (incoming invoices + expenses) alongside revenue

Einnahmen-Ausgaben view for the Milchbüchlein/simple-accounting case:
- taxReportService.getTaxReport now returns a cost side (loadCosts:
  incoming invoices + internal expenses, company- or event-booked,
  schema-guarded) plus a summary (income / costs / result, VAT payable)
- declined/duplicate costs excluded; re-billed costs kept (matching
  re-bill revenue is counted, so the net is correct)
- CSV + PDF exports gain a Costs section and an income/costs/result
  summary; pdf-i18n keys added for all 6 locales (fr/nl/pt/ru machine —
  flag for native review)
- frontend tax page renders the summary card, a costs table (company
  vs event), and a 'verify with Treuhänder' disclaimer
- tax-report tests cover the cost aggregation + zeroed summary when the
  accounting tables are absent; adminCrmAuth test enables the accounting
  master flag the route now requires

fr/nl/pt/ru strings are machine-generated and need native review.
This commit is contained in:
Luca
2026-06-11 21:09:13 +02:00
parent 2e8e4a0f86
commit 545ef334f4
9 changed files with 701 additions and 16 deletions
@@ -72,7 +72,9 @@ describe('admin CRM routes — auth + permission gate', () => {
// of permissions, so for happy-path tests we flip every CRM flag
// on. Negative tests (no-token, bad-signature) hit adminAuth
// first and never reach the flag check, so they're unaffected.
const crmFlags = ['quotes', 'bills', 'contracts', 'hoursLogging', 'calendar', 'taxReport', 'clients'];
// `accounting` is the master flag the tax-report route now requires
// (tax export moved out of CRM into Accounting, independent of bills).
const crmFlags = ['quotes', 'bills', 'contracts', 'hoursLogging', 'calendar', 'taxReport', 'clients', 'accounting'];
for (const key of crmFlags) {
// eslint-disable-next-line no-await-in-loop
await db('feature_flags').where({ key }).update({ value: 1 });