fix(pitch-deck): fix Liquidität engine label mismatches + MilestonesSlide types
All checks were successful
Build pitch-deck / build-push-deploy (push) Successful in 1m38s
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 38s
CI / test-python-voice (push) Successful in 36s
CI / test-bqas (push) Successful in 33s
All checks were successful
Build pitch-deck / build-push-deploy (push) Successful in 1m38s
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 38s
CI / test-python-voice (push) Successful in 36s
CI / test-bqas (push) Successful in 33s
Engine now uses dynamic row_type-based summation instead of hardcoded label strings that differed between scenarios (e.g. 'Summe ERTRÄGE' vs 'Summe EINZAHLUNGEN'), fixing stale 9.2M value in Wandeldarlehen scenarios. Rolling balance now includes all financing cash flows via ÜBERSCHUSS chain. MilestonesSlide: widen Theme type to union so t.key comparisons compile. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -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])
|
||||
|
||||
Reference in New Issue
Block a user