feat(pitch-deck): formula engine + tooltips for betriebliche Aufwendungen
All checks were successful
Build pitch-deck / build-push-deploy (push) Successful in 1m27s
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 36s
CI / test-python-voice (push) Successful in 36s
CI / test-bqas (push) Successful in 34s

Engine formulas added:
- Berufsgenossenschaft (F): 2.77% of total brutto payroll (VBG IT rate)
- Internet/Mobilfunk (F): Headcount × 50 EUR/Mon
- Allgemeine Marketingkosten (F): 10% of monthly revenue

UI: Hover tooltips on all (F) and computed rows showing the formula.
SUMME matcher updated for renamed "SUMME Betriebliche Aufwendungen".

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-04-18 14:15:16 +02:00
parent 9bb689b7e6
commit dc36e59d17
2 changed files with 53 additions and 2 deletions

View File

@@ -51,6 +51,34 @@ function getLabel(row: SheetRow): string {
return row.row_label || row.person_name || row.item_name || '—'
}
const FORMULA_TOOLTIPS: Record<string, string> = {
'Fort-/Weiterbildungskosten (F)': 'Mitarbeiter (ohne Gründer) × 500 EUR/Mon',
'Fahrzeugkosten (F)': 'Mitarbeiter (ohne Gründer) × 400 EUR/Mon',
'KFZ-Steuern (F)': 'Mitarbeiter (ohne Gründer) × 50 EUR/Mon',
'KFZ-Versicherung (F)': 'Mitarbeiter (ohne Gründer) × 500 EUR/Mon',
'Reisekosten (F)': 'Headcount gesamt × 100 EUR/Mon',
'Bewirtungskosten (F)': 'Enterprise-Kunden × 200 EUR/Mon',
'Internet/Mobilfunk (F)': 'Headcount gesamt × 50 EUR/Mon',
'Serverkosten Cloud (F)': 'Bestandskunden × 100 EUR + 500 EUR Basis',
'Berufsgenossenschaft (F)': '2,77% der Brutto-Lohnsumme (VBG IT)',
'Allgemeine Marketingkosten (F)': '10% vom Monatsumsatz',
'Personalkosten': 'Summe aus Tab Personalkosten',
'Abschreibungen': 'Summe AfA aus Tab Investitionen',
}
function LabelWithTooltip({ label }: { label: string }) {
const tooltip = FORMULA_TOOLTIPS[label]
if (!tooltip) return <span>{label}</span>
return (
<span className="group relative cursor-help">
{label}
<span className="invisible group-hover:visible absolute left-0 top-full mt-1 z-50 bg-slate-800 border border-white/10 text-[9px] text-white/70 px-2 py-1 rounded shadow-lg whitespace-nowrap">
{tooltip}
</span>
</span>
)
}
function getValues(row: SheetRow): Record<string, number> {
return row.values || row.values_total || row.values_brutto || {}
}
@@ -394,7 +422,7 @@ export default function FinanzplanSlide({ lang, investorId, preferredScenarioId
return (
<tr key={row.id} className={`border-b border-white/[0.03] ${isSumRow ? 'bg-white/[0.03]' : ''} hover:bg-white/[0.02]`}>
<td className={`py-1.5 px-2 sticky left-0 bg-slate-900/90 backdrop-blur ${isSumRow ? 'font-bold text-white/80' : 'text-white/60'}`}>
{label}
<LabelWithTooltip label={label} />
</td>
{[2026, 2027, 2028, 2029, 2030].map(y => {
const v = values[`y${y}`] || 0
@@ -453,7 +481,7 @@ export default function FinanzplanSlide({ lang, investorId, preferredScenarioId
<td className={`py-1 px-2 sticky left-0 bg-slate-900/90 backdrop-blur ${isSumRow ? 'font-bold text-white/80' : 'text-white/60'}`}>
<div className="flex items-center gap-1">
{isEditable && <span className="w-1 h-1 rounded-full bg-indigo-400 flex-shrink-0" />}
<span className="truncate">{label}</span>
<span className="truncate"><LabelWithTooltip label={label} /></span>
{row.position && <span className="text-white/50 ml-1">({row.position})</span>}
{row.section && <span className="text-white/50 ml-1">[{row.section}]</span>}
</div>