54f0919b73
Build pitch-deck / build-push-deploy (push) Successful in 2m0s
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / test-go-consent (push) Successful in 47s
CI / test-python-voice (push) Successful in 35s
CI / test-bqas (push) Successful in 32s
- Add ROW_LABEL_MAP (DE→EN) covering GuV, Liquidität, Kunden, Betriebliche Aufwendungen rows - Add FORMULA_TOOLTIPS_EN with English tooltip text for all formula-driven rows - Add MONTH_LABELS_EN (Mrz→Mar, Mai→May, Okt→Oct) - LabelWithTooltip now accepts `de` flag, translates display text and tooltip accordingly - Month column headers switch between DE/EN month abbreviations - Falls back to original German label for any row not in the map Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
161 lines
6.1 KiB
TypeScript
161 lines
6.1 KiB
TypeScript
// FinanzplanSlide helpers — extracted from FinanzplanSlide.tsx
|
||
|
||
export interface SheetMeta {
|
||
name: string
|
||
label_de: string
|
||
label_en: string
|
||
rows: number
|
||
}
|
||
|
||
export interface SheetRow {
|
||
id: number
|
||
row_label?: string
|
||
person_name?: string
|
||
item_name?: string
|
||
category?: string
|
||
section?: string
|
||
is_editable?: boolean
|
||
is_sum_row?: boolean
|
||
values?: Record<string, number>
|
||
values_total?: Record<string, number>
|
||
values_brutto?: Record<string, number>
|
||
brutto_monthly?: number
|
||
position?: string
|
||
start_date?: string
|
||
purchase_amount?: number
|
||
[key: string]: unknown
|
||
}
|
||
|
||
export interface FpScenario {
|
||
id: string
|
||
name: string
|
||
is_default: boolean
|
||
}
|
||
|
||
export const MONTH_LABELS = [
|
||
'Jan', 'Feb', 'Mrz', 'Apr', 'Mai', 'Jun',
|
||
'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez',
|
||
]
|
||
|
||
export const MONTH_LABELS_EN = [
|
||
'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
|
||
'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec',
|
||
]
|
||
|
||
export function getLabel(row: SheetRow): string {
|
||
return row.row_label || row.person_name || row.item_name || '—'
|
||
}
|
||
|
||
// German → English row label translations
|
||
export const ROW_LABEL_MAP: Record<string, string> = {
|
||
// GuV / P&L
|
||
'Umsatzerlöse': 'Revenue',
|
||
'Materialaufwand': 'Cost of Materials',
|
||
'Material-/Wareneinsatz': 'Materials / COGS',
|
||
'Fremdleistungen': 'External Services',
|
||
'Rohertrag': 'Gross Profit',
|
||
'Rohergebnis': 'Gross Result',
|
||
'Gesamtleistung': 'Total Output',
|
||
'Personalkosten': 'Personnel Costs',
|
||
'Abschreibungen': 'Depreciation',
|
||
'Betriebliche Aufwendungen': 'Operating Expenses',
|
||
'Sonstige betriebliche Aufwendungen': 'Other Operating Expenses',
|
||
'EBIT': 'EBIT',
|
||
'Betriebsergebnis': 'Operating Result',
|
||
'Zinsergebnis': 'Net Interest',
|
||
'Zinsaufwand': 'Interest Expense',
|
||
'Zinsertrag': 'Interest Income',
|
||
'Ergebnis vor Steuern': 'Earnings Before Tax',
|
||
'EBT': 'EBT',
|
||
'Gewerbesteuer': 'Trade Tax',
|
||
'Körperschaftsteuer': 'Corporate Tax',
|
||
'Steuern gesamt': 'Total Taxes',
|
||
'Steuern': 'Taxes',
|
||
'Jahresüberschuss': 'Net Income',
|
||
'Jahresfehlbetrag': 'Net Loss',
|
||
'Ergebnis nach Steuern': 'Net Result',
|
||
// Liquidität
|
||
'Einzahlungen': 'Cash Inflows',
|
||
'Summe Einzahlungen': 'Total Inflows',
|
||
'Auszahlungen': 'Cash Outflows',
|
||
'Summe Auszahlungen': 'Total Outflows',
|
||
'Überschuss/Fehlbetrag': 'Surplus / Deficit',
|
||
'ÜBERSCHUSS': 'SURPLUS',
|
||
'FEHLBETRAG': 'DEFICIT',
|
||
'ÜBERSCHUSS/FEHLBETRAG': 'SURPLUS / DEFICIT',
|
||
'Kontostand': 'Account Balance',
|
||
'Kontostand (Anfang)': 'Opening Balance',
|
||
'Kontostand (Ende)': 'Closing Balance',
|
||
'LIQUIDITÄT': 'LIQUIDITY',
|
||
'LIQUIDITAET': 'LIQUIDITY',
|
||
'Kredittilgung': 'Loan Repayment',
|
||
'Zins- und Tilgungszahlung': 'Interest & Principal',
|
||
'Investitionen': 'Investments',
|
||
'Sonstige Erträge': 'Other Income',
|
||
// Kunden
|
||
'Neukunden': 'New Customers',
|
||
'Bestandskunden': 'Existing Customers',
|
||
'Bestandskunden gesamt': 'Total Existing Customers',
|
||
'Anzahl Kunden': 'Customer Count',
|
||
'GESAMT': 'TOTAL',
|
||
'GESAMTUMSATZ': 'TOTAL REVENUE',
|
||
// Betriebliche Aufwendungen
|
||
'Fort-/Weiterbildungskosten (F)': 'Training & Development (F)',
|
||
'Fahrzeugkosten (F)': 'Vehicle Costs (F)',
|
||
'KFZ-Steuern (F)': 'Vehicle Tax (F)',
|
||
'KFZ-Versicherung (F)': 'Vehicle Insurance (F)',
|
||
'Reisekosten (F)': 'Travel Expenses (F)',
|
||
'Bewirtungskosten (F)': 'Entertainment Costs (F)',
|
||
'Internet/Mobilfunk (F)': 'Internet / Mobile (F)',
|
||
'Cloud-Hosting (SysEleven/Hetzner)': 'Cloud Hosting (SysEleven/Hetzner)',
|
||
'Berufsgenossenschaft (F)': 'Employers\' Liability Insurance (F)',
|
||
'Allgemeine Marketingkosten (F)': 'General Marketing Costs (F)',
|
||
'Gewerbesteuer (F)': 'Trade Tax (F)',
|
||
'Summe sonstige Aufwendungen': 'Total Other Expenses',
|
||
'SUMME Betriebliche Aufwendungen': 'TOTAL Operating Expenses',
|
||
'SUMME': 'TOTAL',
|
||
'Summe': 'Total',
|
||
}
|
||
|
||
export const FORMULA_TOOLTIPS: Record<string, string> = {
|
||
'Fort-/Weiterbildungskosten (F)': 'Mitarbeiter (ohne Gründer) × 300 EUR/Mon',
|
||
'Fahrzeugkosten (F)': 'Mitarbeiter (ohne Gründer) × 200 EUR/Mon',
|
||
'KFZ-Steuern (F)': 'Mitarbeiter (ohne Gründer) × 25 EUR/Mon',
|
||
'KFZ-Versicherung (F)': 'Mitarbeiter (ohne Gründer) × 150 EUR/Mon',
|
||
'Reisekosten (F)': 'Headcount gesamt × 75 EUR/Mon',
|
||
'Bewirtungskosten (F)': 'Bestandskunden × 50 EUR/Mon',
|
||
'Internet/Mobilfunk (F)': 'Headcount gesamt × 50 EUR/Mon',
|
||
'Cloud-Hosting (SysEleven/Hetzner)': '1.500 EUR Basis + (Kunden - 10) × 100 EUR (erste 10 inkl.)',
|
||
'Berufsgenossenschaft (F)': '0,5% der Brutto-Lohnsumme (VBG IT/Büro)',
|
||
'Allgemeine Marketingkosten (F)': '8% vom Umsatz (2026-2028), 10% ab 2029',
|
||
'Gewerbesteuer (F)': '12,25% vom Gewinn (Messzahl 3,5% × Hebesatz 350%, nur bei Gewinn)',
|
||
'Personalkosten': 'Summe aus Tab Personalkosten',
|
||
'Abschreibungen': 'Summe AfA aus Tab Investitionen',
|
||
}
|
||
|
||
export const FORMULA_TOOLTIPS_EN: Record<string, string> = {
|
||
'Fort-/Weiterbildungskosten (F)': 'Employees (excl. founders) × €300/month',
|
||
'Fahrzeugkosten (F)': 'Employees (excl. founders) × €200/month',
|
||
'KFZ-Steuern (F)': 'Employees (excl. founders) × €25/month',
|
||
'KFZ-Versicherung (F)': 'Employees (excl. founders) × €150/month',
|
||
'Reisekosten (F)': 'Total headcount × €75/month',
|
||
'Bewirtungskosten (F)': 'Existing customers × €50/month',
|
||
'Internet/Mobilfunk (F)': 'Total headcount × €50/month',
|
||
'Cloud-Hosting (SysEleven/Hetzner)': '€1,500 base + (customers − 10) × €100 (first 10 included)',
|
||
'Berufsgenossenschaft (F)': '0.5% of gross payroll (VBG IT/Office)',
|
||
'Allgemeine Marketingkosten (F)': '8% of revenue (2026–2028), 10% from 2029',
|
||
'Gewerbesteuer (F)': '12.25% of profit (rate 3.5% × multiplier 350%, only when profitable)',
|
||
'Personalkosten': 'Sum from Personnel Costs tab',
|
||
'Abschreibungen': 'Sum of depreciation from Investments tab',
|
||
}
|
||
|
||
export function getValues(row: SheetRow): Record<string, number> {
|
||
return row.values || row.values_total || row.values_brutto || (row as Record<string, unknown>).values_invest as Record<string, number> || {}
|
||
}
|
||
|
||
export function formatCell(v: number | undefined): string {
|
||
if (v === undefined || v === null) return ''
|
||
if (v === 0) return '—'
|
||
return Math.round(v).toLocaleString('de-DE', { maximumFractionDigits: 0 })
|
||
}
|