fix(pitch-deck): betriebliche accordion header-first, umsatz labels, annual display
All checks were successful
Build pitch-deck / build-push-deploy (push) Successful in 1m25s
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 37s
CI / test-python-voice (push) Successful in 33s
CI / test-bqas (push) Successful in 36s

- Betriebliche: category header (sum_row) now renders BEFORE detail rows
- Umsatzerlöse: renamed to Preis/Monat, Anzahl Kunden, Umsatz per tier
- Engine: tier matching via parentheses extraction (handles renamed labels)
- Annual column: quantity=Dec value, price=Dec value (not cumulated)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-04-22 09:11:21 +02:00
parent d0bbfbb744
commit 4265f5175a
4 changed files with 61 additions and 25 deletions

View File

@@ -879,18 +879,29 @@ export default function FinanzplanSlide({ lang, investorId, preferredScenarioId,
return { ...row, values: computed, values_total: computed }
})
// For betriebliche: reorder so category header (sum_row) comes BEFORE detail rows
if (activeSheet === 'betriebliche') {
const grouped: SheetRow[] = []
const cats = new Map<string, { header: SheetRow | null; details: SheetRow[] }>()
// Collect by category
for (const row of computedRows) {
const cat = row.category as string || ''
if (!cats.has(cat)) cats.set(cat, { header: null, details: [] })
const g = cats.get(cat)!
if (row.is_sum_row) g.header = row
else g.details.push(row)
}
// Output: header first, then details (if open)
for (const [cat, g] of cats) {
if (g.header) grouped.push(g.header)
if (openCats.has(cat) || cat === 'summe' || cat === 'personal' || cat === 'abschreibungen') {
grouped.push(...g.details)
}
}
return grouped
}
return computedRows
})().filter(row => {
// For betriebliche: hide detail rows if their category is collapsed
if (activeSheet !== 'betriebliche') return true
const cat = row.category as string || ''
const label = getLabel(row)
// Always show: sum rows, Personalkosten, Abschreibungen, category="summe"
if (row.is_sum_row || cat === 'summe' || cat === 'personal' || cat === 'abschreibungen') return true
if (label === 'Personalkosten' || label === 'Abschreibungen') return true
// Detail rows: only show if category is open
return openCats.has(cat)
}).map(row => {
})().map(row => {
const values = getValues(row)
const label = getLabel(row)
const isSumRow = row.is_sum_row || label.includes('GESAMT') || label.includes('Summe') || label.includes('ÜBERSCHUSS') || label.includes('LIQUIDITÄT') || label.includes('UEBERSCHUSS') || label.includes('LIQUIDITAET')
@@ -901,9 +912,12 @@ export default function FinanzplanSlide({ lang, investorId, preferredScenarioId,
const isCatHeader = activeSheet === 'betriebliche' && row.is_sum_row && cat !== 'summe' && cat !== 'personal' && cat !== 'abschreibungen'
const isCatOpen = openCats.has(cat)
// Balance rows show Dec value, flow rows show annual sum
const section = (row as Record<string, unknown>).section as string || ''
const isBalanceRow = label.includes('Kontostand') || label === 'LIQUIDITÄT' || label === 'LIQUIDITAET'
|| label.includes('Bestandskunden') || (activeSheet === 'kunden' && row.row_label === 'Bestandskunden')
const isUnitPrice = (row as Record<string, unknown>).section === 'unit_cost' || (row as Record<string, unknown>).section === 'einkauf' || label.includes('Einkaufspreis')
|| label.includes('Anzahl Kunden') || section === 'quantity'
const isUnitPrice = section === 'unit_cost' || section === 'einkauf' || label.includes('Einkaufspreis')
|| section === 'price' || label.includes('Preis/Monat')
let annual = 0
if (isUnitPrice) {