diff --git a/backend/src/services/taxReportService.js b/backend/src/services/taxReportService.js index 66c9428b..cbbbd088 100644 --- a/backend/src/services/taxReportService.js +++ b/backend/src/services/taxReportService.js @@ -49,6 +49,7 @@ const REPORTABLE_STATUSES = ['sent', 'paid', 'overdue', 'pending_delivery', 'can // D.2 — `ensureInt` consolidated into utils/numericHelpers. const { ensureInt } = require('../utils/numericHelpers'); +const logger = require('../utils/logger'); function ensureRate(v) { if (v === null || v === undefined || v === '') return 0; @@ -449,10 +450,20 @@ async function getTaxReport({ from, to, currency, includeCosts = true } = {}) { const totalsByVatRate = Array.from(byRate.values()).sort((a, b) => a.vatRate - b.vatRate); // Cost side (Einnahmen-Ausgaben). Optional so legacy callers that - // only want the revenue listing can opt out. - const costs = includeCosts - ? await loadCosts({ from, to, cur }) - : { rows: [], totalNet: 0, totalVat: 0, totalGross: 0 }; + // only want the revenue listing can opt out. The cost side is + // SUPPLEMENTARY — if it fails (e.g. an accounting table/column missing + // on an older install) it must NOT take down the core revenue report. + // Degrade to empty costs + log the real error for diagnosis. + let costs = { rows: [], totalNet: 0, totalVat: 0, totalGross: 0 }; + let costsError = null; + if (includeCosts) { + try { + costs = await loadCosts({ from, to, cur }); + } catch (err) { + costsError = err.message; + logger.error?.(`taxReport: cost side failed (revenue still returned): ${err.message}`); + } + } // Summary: income vs cost vs result. Result = a simplified // Einnahmen-Ausgaben surplus (net basis); vatPayable = output VAT @@ -478,6 +489,7 @@ async function getTaxReport({ from, to, currency, includeCosts = true } = {}) { grandTotal, cancelledCount, costs, + costsError, summary, currency: cur, period: { from, to }, diff --git a/frontend/src/pages/admin/clients/TaxReportPage.tsx b/frontend/src/pages/admin/clients/TaxReportPage.tsx index 890980ba..afc788b1 100644 --- a/frontend/src/pages/admin/clients/TaxReportPage.tsx +++ b/frontend/src/pages/admin/clients/TaxReportPage.tsx @@ -358,6 +358,19 @@ export const TaxReportPage: React.FC = () => { )} + {/* Non-fatal: the revenue report loaded but the cost side errored. */} + {report?.costsError && ( + +
+ +
+

{t('taxReport.costsErrorTitle', 'Costs could not be loaded')}

+

{report.costsError}

+
+
+
+ )} + {/* Results */} {isLoading ? ( diff --git a/frontend/src/services/taxReport.service.ts b/frontend/src/services/taxReport.service.ts index 00c4c41a..8449e290 100644 --- a/frontend/src/services/taxReport.service.ts +++ b/frontend/src/services/taxReport.service.ts @@ -97,6 +97,8 @@ export interface TaxReport { /** Cost side (#4). Present when the accounting tables exist; empty * otherwise. */ costs: TaxReportCosts; + /** Non-fatal: set when the cost side failed to load (revenue still shown). */ + costsError?: string | null; /** Income/cost/result summary (#4). */ summary: TaxReportSummary; currency: string;