diff --git a/pitch-deck/components/slides/MilestonesSlide.tsx b/pitch-deck/components/slides/MilestonesSlide.tsx index c167d38..77332d1 100644 --- a/pitch-deck/components/slides/MilestonesSlide.tsx +++ b/pitch-deck/components/slides/MilestonesSlide.tsx @@ -147,7 +147,7 @@ const THEMES = { }, } -type Theme = typeof THEMES.dark +type Theme = typeof THEMES.dark | typeof THEMES.light // ── Data ────────────────────────────────────────────────────────────────────── const TODAY_POSITION = 0.56 diff --git a/pitch-deck/lib/finanzplan/engine.ts b/pitch-deck/lib/finanzplan/engine.ts index 721559b..e3299ae 100644 --- a/pitch-deck/lib/finanzplan/engine.ts +++ b/pitch-deck/lib/finanzplan/engine.ts @@ -413,57 +413,42 @@ export async function computeFinanzplan(pool: Pool, scenarioId: string): Promise liqInvest.values = totalInvest } - // Compute sums and rolling balance - // WICHTIG: Überschuss = nur operativer Cashflow (ohne Kapitaleinzahlungen) - const sumEin = findLiq('Summe EINZAHLUNGEN') - const sumAus = findLiq('Summe AUSZAHLUNGEN') - const uebVorInv = findLiq('ÜBERSCHUSS VOR INVESTITIONEN') - const uebVorEnt = findLiq('ÜBERSCHUSS VOR ENTNAHMEN') - const ueberschuss = findLiq('ÜBERSCHUSS') - const kontostand = findLiq('Kontostand zu Beginn des Monats') - const liquiditaet = findLiq('LIQUIDITÄT') + // Compute sums and rolling balance — dynamic row_type-based (handles any label conventions) + const findLiqMatch = (options: string[]) => liquid.find(r => options.includes(r.row_label)) + const sumEin = findLiqMatch(['Summe ERTRÄGE', 'Summe EINZAHLUNGEN']) + const sumAus = findLiqMatch(['Summe AUSZAHLUNGEN']) + const uebVorInv = findLiqMatch(['ÜBERSCHUSS VOR INVESTITIONEN', 'UEBERSCHUSS VOR INVESTITIONEN']) + const uebVorEnt = findLiqMatch(['ÜBERSCHUSS VOR ENTNAHMEN', 'UEBERSCHUSS VOR ENTNAHMEN']) + const ueberschuss = findLiqMatch(['ÜBERSCHUSS', 'UEBERSCHUSS']) + // Kontostand: label varies per scenario (with/without parentheses) + const kontostand = liquid.find(r => r.row_type === 'kontostand' && !r.row_label.includes('LIQUIDIT')) + const liquiditaet = liquid.find(r => r.row_type === 'kontostand' && r.row_label.includes('LIQUIDIT')) - // Dynamically categorize rows by row_type instead of hardcoded labels - // Operative Einzahlungen (OHNE Eigenkapital, Fremdkapital, Stammkapital, Wandeldarlehen) - const einzahlungenOperativ = ['Umsatzerlöse', 'Sonst. betriebl. Erträge', 'Anzahlungen'] - // Finanzierung: match any row with these keywords (handles renamed labels) - const finanzierungRows = liquid.filter(r => - r.row_type === 'einzahlung' && - !einzahlungenOperativ.includes(r.row_label) && - !r.row_label.includes('Summe') - ) - // Operative Auszahlungen - const auszahlungenOperativ = ['Materialaufwand', 'Personalkosten', 'Sonstige Kosten', 'Umsatzsteuer', 'Gewerbesteuer', 'Körperschaftsteuer'] - // Finanz-Auszahlungen: any auszahlung not in operativ list - const finanzAuszahlungRows = liquid.filter(r => - r.row_type === 'auszahlung' && - !auszahlungenOperativ.includes(r.row_label) && - !r.row_label.includes('Summe') - ) - - // Summe EINZAHLUNGEN = nur operativ (für die Zeile "Summe Einzahlungen") + // Summe ERTRÄGE = ALL einzahlungen (dynamic — works regardless of how many rows exist) if (sumEin) { const s = emptyMonthly() - for (const label of einzahlungenOperativ) { - const row = findLiq(label) - if (row) for (let m = 1; m <= MONTHS; m++) s[`m${m}`] += Math.round(row.values[`m${m}`] || 0) + for (const row of liquid) { + if (row.row_type === 'einzahlung' && row.id !== sumEin.id) { + for (let m = 1; m <= MONTHS; m++) s[`m${m}`] += Math.round(row.values[`m${m}`] || 0) + } } await pool.query('UPDATE fp_liquiditaet SET values = $1 WHERE id = $2', [JSON.stringify(s), sumEin.id]) sumEin.values = s } - // Summe AUSZAHLUNGEN = nur operativ + // Summe AUSZAHLUNGEN = ALL auszahlungen (dynamic) if (sumAus) { const s = emptyMonthly() - for (const label of auszahlungenOperativ) { - const row = findLiq(label) - if (row) for (let m = 1; m <= MONTHS; m++) s[`m${m}`] += Math.round(row.values[`m${m}`] || 0) + for (const row of liquid) { + if (row.row_type === 'auszahlung' && row.id !== sumAus.id) { + for (let m = 1; m <= MONTHS; m++) s[`m${m}`] += Math.round(row.values[`m${m}`] || 0) + } } await pool.query('UPDATE fp_liquiditaet SET values = $1 WHERE id = $2', [JSON.stringify(s), sumAus.id]) sumAus.values = s } - // OPERATIVER ÜBERSCHUSS VOR INVESTITIONEN = operative Einzahlungen - operative Auszahlungen + // ÜBERSCHUSS VOR INVESTITIONEN = Summe ERTRÄGE - Summe AUSZAHLUNGEN (total cashflow) if (uebVorInv && sumEin && sumAus) { const s = emptyMonthly() for (let m = 1; m <= MONTHS; m++) s[`m${m}`] = Math.round((sumEin.values[`m${m}`] || 0) - (sumAus.values[`m${m}`] || 0)) @@ -471,7 +456,7 @@ export async function computeFinanzplan(pool: Pool, scenarioId: string): Promise uebVorInv.values = s } - // ÜBERSCHUSS VOR ENTNAHMEN = Operativer Überschuss - Investitionen + // ÜBERSCHUSS VOR ENTNAHMEN = ÜBERSCHUSS VOR INVESTITIONEN - Investitionen if (uebVorEnt && uebVorInv && liqInvest) { const s = emptyMonthly() for (let m = 1; m <= MONTHS; m++) s[`m${m}`] = Math.round((uebVorInv.values[`m${m}`] || 0) - (liqInvest.values[`m${m}`] || 0)) @@ -479,8 +464,8 @@ export async function computeFinanzplan(pool: Pool, scenarioId: string): Promise uebVorEnt.values = s } - // ÜBERSCHUSS = Überschuss vor Entnahmen - Entnahmen (immer noch rein operativ) - const entnahmen = findLiq('Kapitalentnahmen/Ausschüttungen') + // ÜBERSCHUSS = ÜBERSCHUSS VOR ENTNAHMEN - Kapitalentnahmen + const entnahmen = findLiqMatch(['Kapitalentnahmen/Ausschüttungen', 'Kapitalentnahmen/Ausschuettungen']) if (ueberschuss && uebVorEnt && entnahmen) { const s = emptyMonthly() for (let m = 1; m <= MONTHS; m++) s[`m${m}`] = Math.round((uebVorEnt.values[`m${m}`] || 0) - (entnahmen.values[`m${m}`] || 0)) @@ -488,24 +473,14 @@ export async function computeFinanzplan(pool: Pool, scenarioId: string): Promise ueberschuss.values = s } - // Rolling Kontostand: Vormonat + Operativer Überschuss + Finanzierung - // Finanzierung = Eigenkapital + Fremdkapital - Kreditrückzahlungen + // Rolling balance: LIQUIDITÄT[m] = LIQUIDITÄT[m-1] + ÜBERSCHUSS[m] + // ÜBERSCHUSS now includes ALL cash flows (operative + financing + repayments) if (kontostand && liquiditaet && ueberschuss) { - // Berechne monatliche Finanzierungs-Cashflows - const finCF = emptyMonthly() - for (const row of finanzierungRows) { - for (let m = 1; m <= MONTHS; m++) finCF[`m${m}`] += Math.round(row.values[`m${m}`] || 0) - } - for (const row of finanzAuszahlungRows) { - for (let m = 1; m <= MONTHS; m++) finCF[`m${m}`] -= Math.round(row.values[`m${m}`] || 0) - } - const ks = emptyMonthly() const lq = emptyMonthly() for (let m = 1; m <= MONTHS; m++) { ks[`m${m}`] = m === 1 ? 0 : Math.round(lq[`m${m - 1}`]) - // LIQUIDITÄT = Kontostand + Operativer Überschuss + Finanzierung - lq[`m${m}`] = Math.round(ks[`m${m}`] + (ueberschuss.values[`m${m}`] || 0) + (finCF[`m${m}`] || 0)) + lq[`m${m}`] = Math.round(ks[`m${m}`] + (ueberschuss.values[`m${m}`] || 0)) } await pool.query('UPDATE fp_liquiditaet SET values = $1 WHERE id = $2', [JSON.stringify(ks), kontostand.id]) await pool.query('UPDATE fp_liquiditaet SET values = $1 WHERE id = $2', [JSON.stringify(lq), liquiditaet.id])