diff --git a/backend/src/routes/adminLedger.js b/backend/src/routes/adminLedger.js index f279750a..8b05d28e 100644 --- a/backend/src/routes/adminLedger.js +++ b/backend/src/routes/adminLedger.js @@ -6,9 +6,9 @@ * /mappings GET/PATCH category→account + default-account/VAT settings * /export GET Treuhänder collective-journal CSV (generic|banana|bexio) * - * Gated by the `accounting` master flag; export additionally requires the - * `taxReport` sub-flag (it's the export umbrella). Uses the `accounting.*` - * permissions. Output is a GUIDELINE — the UI carries the Treuhänder caveat. + * Gated by the `accounting` master flag (all routes, incl. /export). Uses the + * `accounting.*` permissions. Output is a GUIDELINE — the UI carries the + * Treuhänder caveat. */ const express = require('express'); const { body, param, query } = require('express-validator'); @@ -32,7 +32,6 @@ function requireFlag(key, code) { }; } const requireAccounting = requireFlag('accounting', 'ACCOUNTING_DISABLED'); -const requireTaxReport = requireFlag('taxReport', 'TAX_REPORT_DISABLED'); router.use(adminAuth); router.use(requireAccounting); @@ -107,7 +106,10 @@ router.patch('/mappings/settings', requirePermission('accounting.manage'), handl })); // ── Treuhänder export ──────────────────────────────────────────────── -router.get('/export', requireTaxReport, requirePermission('bills.view'), +// Gated by the router-level `accounting` flag only — the export lives on the +// Tax page now but is an accounting-layer feature (needs the chart-of-accounts +// mapping), so it no longer requires the `taxReport` sub-flag. +router.get('/export', requirePermission('bills.view'), [query('from').matches(/^\d{4}-\d{2}-\d{2}$/), query('to').matches(/^\d{4}-\d{2}-\d{2}$/), query('currency').matches(/^[A-Za-z]{3}$/), query('format').optional().isIn(ledgerService.EXPORT_FORMATS)], handleAsync(async (req, res) => { diff --git a/frontend/src/i18n/locales/de.json b/frontend/src/i18n/locales/de.json index 1e14f722..1513ed0c 100644 --- a/frontend/src/i18n/locales/de.json +++ b/frontend/src/i18n/locales/de.json @@ -3938,8 +3938,13 @@ }, "exportPdf": "PDF exportieren", "ledgerExport": "Treuhänder-Export", - "ledgerExportHint": "Doppelte Buchung für Ihren Treuhänder, abgebildet über Ihren Kontenplan.", + "ledgerExportHint": "Doppelte Buchungssätze für Ihren Treuhänder, abgebildet über Ihren Kontenplan.", "ledgerExportConfigure": "Einrichten →", + "export": { + "reportTitle": "Bericht", + "reportHint": "Lesbare Liste — für Ihre Unterlagen.", + "journalTitle": "Buchungsjournal" + }, "exportCsv": "CSV exportieren", "exportFailed": "Export fehlgeschlagen. Bitte erneut versuchen.", "errorTitle": "Steuerliste konnte nicht geladen werden", diff --git a/frontend/src/i18n/locales/en.json b/frontend/src/i18n/locales/en.json index a75e69aa..8c025724 100644 --- a/frontend/src/i18n/locales/en.json +++ b/frontend/src/i18n/locales/en.json @@ -3937,9 +3937,14 @@ "currency": "Currency" }, "exportPdf": "Export PDF", - "ledgerExport": "Treuhänder export", - "ledgerExportHint": "Double-entry journal for your accountant, mapped via your Chart of accounts.", + "ledgerExport": "Accountant export", + "ledgerExportHint": "Double-entry postings for your accountant, mapped via your Chart of accounts.", "ledgerExportConfigure": "Configure →", + "export": { + "reportTitle": "Report", + "reportHint": "Readable list — for your own records.", + "journalTitle": "Accounting journal" + }, "exportCsv": "Export CSV", "exportFailed": "Export failed. Please try again.", "errorTitle": "Could not load tax report", diff --git a/frontend/src/pages/admin/clients/TaxReportPage.tsx b/frontend/src/pages/admin/clients/TaxReportPage.tsx index 3cc80480..6e15dd5e 100644 --- a/frontend/src/pages/admin/clients/TaxReportPage.tsx +++ b/frontend/src/pages/admin/clients/TaxReportPage.tsx @@ -28,6 +28,7 @@ const selectClassName = 'w-full rounded-md border border-neutral-300 dark:border-neutral-600 bg-white dark:bg-neutral-800 px-3 py-2 text-sm text-neutral-900 dark:text-neutral-100 focus:outline-none focus:ring-2 focus:ring-primary-500'; import { taxReportService, type TaxReportParams } from '../../../services/taxReport.service'; import { ledgerService, type ExportFormat } from '../../../services/ledger.service'; +import { useFeatureFlags } from '../../../contexts/FeatureFlagsContext'; import { useLocalizedDate } from '../../../hooks/useLocalizedDate'; import { toast } from 'react-toastify'; @@ -93,6 +94,7 @@ function triggerBrowserDownload(url: string, filename: string) { export const TaxReportPage: React.FC = () => { const { t, i18n } = useTranslation(); + const { flags } = useFeatureFlags(); const { format: fmtDate } = useLocalizedDate(); const [preset, setPreset] = useState('thisYear'); const initialPeriod = useMemo(() => periodForPreset('thisYear'), []); @@ -294,58 +296,82 @@ export const TaxReportPage: React.FC = () => { -
-
- - + {/* Export area — two clearly-separated groups so it's obvious + what each file is and who it's for: the human-readable Report + (PDF/CSV) and the accounting Journal (for the Treuhänder). The + Journal group only shows when the accounting layer is on, since + it needs the Chart-of-accounts mapping. */} +
+ {/* Group 1 — Report (for you) */} +
+
+
+ {t('taxReport.export.reportTitle', 'Report')} +
+
+ {t('taxReport.export.reportHint', 'Readable list — for your own records.')} +
+
+
+ + +
- {/* Treuhänder collective-journal export — moved here from its own - tab; reuses the same period/currency. Format = target tool. */} -
- - -
-

- {t('taxReport.ledgerExportHint', 'Double-entry journal for your accountant, mapped via your Chart of accounts.')}{' '} - - {t('taxReport.ledgerExportConfigure', 'Configure →')} - -

+ {/* Group 2 — Accounting journal (for your accountant) */} + {flags.accounting && ( +
+
+
+ {t('taxReport.export.journalTitle', 'Accounting journal')} +
+
+ {t('taxReport.ledgerExportHint', 'Double-entry postings for your accountant, mapped via your Chart of accounts.')}{' '} + + {t('taxReport.ledgerExportConfigure', 'Configure →')} + +
+
+
+ + +
+
+ )}