diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 9079fe6f..95cd90cb 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -69,7 +69,6 @@ import { ClientsLayout } from './components/admin/ClientsLayout'; import { AccountingLayout, AccountingIndex } from './components/admin/AccountingLayout'; import { AccountingInboxPage } from './pages/admin/accounting/AccountingInboxPage'; import { ExpensesLedgerPage } from './pages/admin/accounting/ExpensesLedgerPage'; -import { ChartOfAccountsPage } from './pages/admin/accounting/ChartOfAccountsPage'; import { RequireFeature } from './components/admin/RequireFeature'; import { PageErrorBoundary, OfflineIndicator, SkipLink, DynamicFavicon, RobotsMetaTags, CMSContentBlock, Loading } from './components/common'; import { MaintenanceWrapper } from './components/MaintenanceWrapper'; @@ -291,9 +290,9 @@ function App() { the old path working for bookmarks. */} } /> - {/* Chart of accounts + VAT codes (Layer A) — gated by - the accounting master flag alongside the section. */} - } /> + {/* Chart of accounts (Layer A) moved into Settings → + Accounting; keep the old path working for bookmarks. */} + } /> } /> diff --git a/frontend/src/components/admin/AccountingLayout.tsx b/frontend/src/components/admin/AccountingLayout.tsx index 061a911a..0761337e 100644 --- a/frontend/src/components/admin/AccountingLayout.tsx +++ b/frontend/src/components/admin/AccountingLayout.tsx @@ -9,7 +9,7 @@ import React from 'react'; import { NavLink, Outlet, Navigate, useLocation, useNavigate } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; -import { Landmark, Calculator, Inbox, Wallet, BookOpen } from 'lucide-react'; +import { Landmark, Calculator, Inbox, Wallet } from 'lucide-react'; import type { LucideIcon } from 'lucide-react'; import { useFeatureFlags, type FeatureKey } from '../../contexts/FeatureFlagsContext'; @@ -52,13 +52,8 @@ export const AccountingLayout: React.FC = () => { icon: Calculator, featureFlag: 'taxReport', }, - { - key: 'ledger', - to: '/admin/accounting/ledger', - label: t('accounting.subnav.chartOfAccounts', 'Chart of accounts'), - icon: BookOpen, - featureFlag: 'accounting', - }, + // Chart of accounts moved to Settings → Accounting (all accounting config + // lives there now); this section keeps only the operational pages. // Future: Erfolgsrechnung (Layer B). ]; diff --git a/frontend/src/pages/admin/accounting/ChartOfAccountsPage.tsx b/frontend/src/components/admin/ChartOfAccountsManager.tsx similarity index 92% rename from frontend/src/pages/admin/accounting/ChartOfAccountsPage.tsx rename to frontend/src/components/admin/ChartOfAccountsManager.tsx index ed106900..562ee617 100644 --- a/frontend/src/pages/admin/accounting/ChartOfAccountsPage.tsx +++ b/frontend/src/components/admin/ChartOfAccountsManager.tsx @@ -1,23 +1,27 @@ /** - * Accounting → Chart of accounts (Layer A). + * Chart of accounts manager (Layer A) — embedded in Settings → Accounting. * * Full CRUD for the Swiss/LI KMU-Kontenrahmen accounts, plus the mappings the * Treuhänder export relies on: which account each expense category books to and - * the default/system accounts. VAT codes + their rate/treatment maps live in - * Settings → Accounting (VatCodesManager), so all VAT config sits in one place. + * the default/system accounts. Sits alongside VatCodesManager so all accounting + * configuration lives in one place. * * This data drives the export only — picpeak is not a double-entry ledger. + * + * NOTE: ledgerService.updateSettings is a PARTIAL merge, so this component saves + * ONLY the account keys (SETTING_ACCOUNT_KEYS); the VAT maps are owned by + * VatCodesManager. Scoping each patch keeps the two from reverting each other. */ import React, { useEffect, useMemo, useState } from 'react'; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { useTranslation } from 'react-i18next'; import { toast } from 'react-toastify'; import { X, Plus, Pencil, Trash2, AlertCircle } from 'lucide-react'; -import { Button, Card, CardContent, Input, Loading } from '../../../components/common'; +import { Button, Card, CardContent, Input, Loading } from '../common'; import { ledgerService, type LedgerAccount, type AccountType, type LedgerSettings, -} from '../../../services/ledger.service'; -import { categoryLabel } from '../../../services/accounting.service'; +} from '../../services/ledger.service'; +import { categoryLabel } from '../../services/accounting.service'; const ACCOUNT_TYPES: AccountType[] = ['asset', 'liability', 'equity', 'revenue', 'expense']; const labelCls = 'block text-xs font-medium text-neutral-700 dark:text-neutral-300 mb-1'; @@ -65,7 +69,7 @@ const AccountModal: React.FC<{ account?: LedgerAccount; onClose: () => void; onD ); }; -export const ChartOfAccountsPage: React.FC = () => { +export const ChartOfAccountsManager: React.FC = () => { const { t } = useTranslation(); const qc = useQueryClient(); const [accountModal, setAccountModal] = useState<{ account?: LedgerAccount } | null>(null); @@ -73,7 +77,7 @@ export const ChartOfAccountsPage: React.FC = () => { const { data: accounts, isLoading: la } = useQuery({ queryKey: ['ledger-accounts'], queryFn: () => ledgerService.listAccounts() }); const { data: mappings, isLoading: lm } = useQuery({ queryKey: ['ledger-mappings'], queryFn: () => ledgerService.getMappings() }); - // Local editable copy of the settings (default accounts + VAT maps). + // Local editable copy of the settings (default/system accounts only). const [settings, setSettings] = useState({}); useEffect(() => { if (mappings?.settings) setSettings(mappings.settings); }, [mappings?.settings]); @@ -91,9 +95,9 @@ export const ChartOfAccountsPage: React.FC = () => { onSuccess: () => { qc.invalidateQueries({ queryKey: ['ledger-mappings'] }); }, onError: (e: any) => toast.error(e?.response?.data?.error || e.message || 'Failed'), }); - // Save ONLY the account keys — the VAT maps now live in Settings → Accounting - // (VatCodesManager) and updateSettings is a partial merge, so scoping the - // patch here prevents a stale full-settings save from reverting the maps. + // Save ONLY the account keys — the VAT maps are owned by VatCodesManager and + // updateSettings is a partial merge, so scoping the patch here prevents a + // stale full-settings save from reverting the maps. const saveSettings = useMutation({ mutationFn: () => { const patch: Partial = {}; @@ -197,4 +201,4 @@ export const ChartOfAccountsPage: React.FC = () => { ); }; -export default ChartOfAccountsPage; +export default ChartOfAccountsManager; diff --git a/frontend/src/features/settings/tabs/AccountingTab.tsx b/frontend/src/features/settings/tabs/AccountingTab.tsx index 9b5abad7..90cb79d8 100644 --- a/frontend/src/features/settings/tabs/AccountingTab.tsx +++ b/frontend/src/features/settings/tabs/AccountingTab.tsx @@ -13,6 +13,7 @@ import { DecimalInput } from '../../../components/common/DecimalInput'; import { accountingService } from '../../../services/accounting.service'; import { sortedCountryOptions } from '../../../constants/countries'; import { VatCodesManager } from '../../../components/admin/VatCodesManager'; +import { ChartOfAccountsManager } from '../../../components/admin/ChartOfAccountsManager'; const labelCls = 'block text-sm font-medium text-neutral-700 dark:text-neutral-300 mb-1'; const inputCls = 'w-full max-w-xs rounded-md border border-neutral-300 dark:border-neutral-600 bg-white dark:bg-neutral-800 px-3 py-2 text-sm'; @@ -121,6 +122,16 @@ export const AccountingTab: React.FC = () => { {/* VAT codes + rate→code / treatment→code maps — relocated here from the Chart-of-accounts page so all VAT config lives in one place. */} + + {/* Chart of accounts (accounts + category/default-account mappings) — + moved off the /admin/accounting section so all accounting config is + here; the section keeps only the operational pages. */} +
+

+ {t('ledger.accounts.title', 'Chart of accounts')} +

+ +
); }; diff --git a/frontend/src/pages/admin/clients/TaxReportPage.tsx b/frontend/src/pages/admin/clients/TaxReportPage.tsx index ba1edfb3..4b162232 100644 --- a/frontend/src/pages/admin/clients/TaxReportPage.tsx +++ b/frontend/src/pages/admin/clients/TaxReportPage.tsx @@ -346,7 +346,7 @@ export const TaxReportPage: React.FC = () => {
{t('taxReport.ledgerExportHint', 'Double-entry postings for your accountant, mapped via your Chart of accounts.')}{' '} - + {t('taxReport.ledgerExportConfigure', 'Configure →')}