fix: Sortierung Personalkosten + Umlaute DB + Summenzeilen
- Gründer immer sort_order 1+2, dann nach start_date - Beide Gründer exakt gleiches Gehalt (7.000 EUR/Mo ab Jan 2027) - Alle Pos-Namen durchnummeriert (Pos 3 bis Pos 35) Umlaute in DB-Labels (Liquidität, GuV, Betriebliche): Umsatzerloese→Umsatzerlöse, UEBERSCHUSS→ÜBERSCHUSS, Koerperschaftsteuer→Körperschaftsteuer, etc. Engine-Labels synchron aktualisiert. Summenzeile (SUMME) als tfoot für: Personalkosten, Materialaufwand, Betriebliche Aufwendungen, Investitionen, Sonstige Erträge Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -229,10 +229,10 @@ export default function FinanzplanSlide({ lang }: FinanzplanSlideProps) {
|
||||
{rows.map(row => {
|
||||
const values = getValues(row)
|
||||
const label = getLabel(row)
|
||||
const isSumRow = row.is_sum_row || label.includes('GESAMT') || label.includes('Summe') || label.includes('UEBERSCHUSS') || label.includes('LIQUIDITAET')
|
||||
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')
|
||||
const isEditable = row.is_editable
|
||||
// Balance rows show Dec value, flow rows show annual sum
|
||||
const isBalanceRow = label.includes('Kontostand') || label === 'LIQUIDITAET'
|
||||
const isBalanceRow = label.includes('Kontostand') || label === 'LIQUIDITÄT' || label === 'LIQUIDITAET'
|
||||
|
||||
let annual = 0
|
||||
if (isBalanceRow) {
|
||||
@@ -283,6 +283,47 @@ export default function FinanzplanSlide({ lang }: FinanzplanSlideProps) {
|
||||
)
|
||||
})}
|
||||
</tbody>
|
||||
{/* Summenzeile für relevante Sheets */}
|
||||
{['personalkosten', 'materialaufwand', 'betriebliche', 'investitionen', 'sonst_ertraege'].includes(activeSheet) && rows.length > 0 && (() => {
|
||||
// Berechne Summe über alle Zeilen die keine Summenzeilen sind
|
||||
const sumValues: Record<string, number> = {}
|
||||
let sumAnnual = 0
|
||||
const nonSumRows = rows.filter(r => {
|
||||
const l = getLabel(r)
|
||||
return !(r.is_sum_row || l.includes('GESAMT') || l.includes('Summe') || l.includes('Gesamtkosten'))
|
||||
})
|
||||
for (let idx = 0; idx < 12; idx++) {
|
||||
const mKey = `m${monthStart + idx}`
|
||||
let colSum = 0
|
||||
for (const row of nonSumRows) {
|
||||
const v = getValues(row)
|
||||
colSum += v[mKey] || 0
|
||||
}
|
||||
sumValues[mKey] = colSum
|
||||
sumAnnual += colSum
|
||||
}
|
||||
return (
|
||||
<tfoot>
|
||||
<tr className="border-t-2 border-white/20 bg-white/[0.05]">
|
||||
<td className="py-1.5 px-2 sticky left-0 bg-slate-900/90 backdrop-blur font-bold text-white/80 text-xs">
|
||||
{de ? 'SUMME' : 'TOTAL'}
|
||||
</td>
|
||||
<td className={`text-right py-1.5 px-2 font-bold text-xs ${sumAnnual < 0 ? 'text-red-400' : 'text-white/80'}`}>
|
||||
{formatCell(sumAnnual)}
|
||||
</td>
|
||||
{Array.from({ length: 12 }, (_, idx) => {
|
||||
const mKey = `m${monthStart + idx}`
|
||||
const v = sumValues[mKey] || 0
|
||||
return (
|
||||
<td key={idx} className={`text-right py-1.5 px-1.5 font-bold text-xs ${v < 0 ? 'text-red-400' : v > 0 ? 'text-white/70' : 'text-white/15'}`}>
|
||||
{formatCell(v)}
|
||||
</td>
|
||||
)
|
||||
})}
|
||||
</tr>
|
||||
</tfoot>
|
||||
)
|
||||
})()}
|
||||
</table>
|
||||
)}
|
||||
</GlassCard>
|
||||
|
||||
@@ -262,7 +262,7 @@ export async function computeFinanzplan(pool: Pool, scenarioId: string): Promise
|
||||
const findLiq = (label: string) => liquid.find(r => r.row_label === label)
|
||||
|
||||
// Computed rows
|
||||
const liqUmsatz = findLiq('Umsatzerloese')
|
||||
const liqUmsatz = findLiq('Umsatzerlöse')
|
||||
if (liqUmsatz) {
|
||||
await pool.query('UPDATE fp_liquiditaet SET values = $1 WHERE id = $2', [JSON.stringify(totalRevenue), liqUmsatz.id])
|
||||
liqUmsatz.values = totalRevenue
|
||||
@@ -292,19 +292,19 @@ export async function computeFinanzplan(pool: Pool, scenarioId: string): Promise
|
||||
// WICHTIG: Überschuss = nur operativer Cashflow (ohne Kapitaleinzahlungen)
|
||||
const sumEin = findLiq('Summe EINZAHLUNGEN')
|
||||
const sumAus = findLiq('Summe AUSZAHLUNGEN')
|
||||
const uebVorInv = findLiq('UEBERSCHUSS VOR INVESTITIONEN')
|
||||
const uebVorEnt = findLiq('UEBERSCHUSS VOR ENTNAHMEN')
|
||||
const ueberschuss = findLiq('UEBERSCHUSS')
|
||||
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('LIQUIDITAET')
|
||||
const liquiditaet = findLiq('LIQUIDITÄT')
|
||||
|
||||
// Operative Einzahlungen (OHNE Eigenkapital und Fremdkapital)
|
||||
const einzahlungenOperativ = ['Umsatzerloese', 'Sonst. betriebl. Ertraege', 'Anzahlungen']
|
||||
const einzahlungenOperativ = ['Umsatzerlöse', 'Sonst. betriebl. Erträge', 'Anzahlungen']
|
||||
// Finanzierung (separat)
|
||||
const finanzierung = ['Neuer Eigenkapitalzugang', 'Erhaltenes Fremdkapital']
|
||||
// Operative Auszahlungen (OHNE Kreditrückzahlungen)
|
||||
const auszahlungenOperativ = ['Materialaufwand', 'Personalkosten', 'Sonstige Kosten', 'Umsatzsteuer', 'Gewerbesteuer', 'Koerperschaftsteuer']
|
||||
const finanzAuszahlungen = ['Kreditrueckzahlungen']
|
||||
const auszahlungenOperativ = ['Materialaufwand', 'Personalkosten', 'Sonstige Kosten', 'Umsatzsteuer', 'Gewerbesteuer', 'Körperschaftsteuer']
|
||||
const finanzAuszahlungen = ['Kreditrückzahlungen']
|
||||
|
||||
// Summe EINZAHLUNGEN = nur operativ (für die Zeile "Summe Einzahlungen")
|
||||
if (sumEin) {
|
||||
@@ -345,7 +345,7 @@ export async function computeFinanzplan(pool: Pool, scenarioId: string): Promise
|
||||
}
|
||||
|
||||
// ÜBERSCHUSS = Überschuss vor Entnahmen - Entnahmen (immer noch rein operativ)
|
||||
const entnahmen = findLiq('Kapitalentnahmen/Ausschuettungen')
|
||||
const entnahmen = findLiq('Kapitalentnahmen/Ausschüttungen')
|
||||
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))
|
||||
@@ -392,10 +392,10 @@ export async function computeFinanzplan(pool: Pool, scenarioId: string): Promise
|
||||
|
||||
// Write GuV rows
|
||||
const guvUpdates: { label: string; values: AnnualValues }[] = [
|
||||
{ label: 'Umsatzerloese', values: umsatzAnnual },
|
||||
{ label: 'Umsatzerlöse', values: umsatzAnnual },
|
||||
{ label: 'Gesamtleistung', values: umsatzAnnual },
|
||||
{ label: 'Summe Materialaufwand', values: materialAnnual },
|
||||
{ label: 'Loehne und Gehaelter', values: personalBruttoAnnual },
|
||||
{ label: 'Löhne und Gehälter', values: personalBruttoAnnual },
|
||||
{ label: 'Soziale Abgaben', values: personalSozialAnnual },
|
||||
{ label: 'Summe Personalaufwand', values: personalAnnual },
|
||||
{ label: 'Abschreibungen', values: afaAnnual },
|
||||
@@ -468,14 +468,14 @@ export async function computeFinanzplan(pool: Pool, scenarioId: string): Promise
|
||||
}
|
||||
|
||||
await pool.query('UPDATE fp_guv SET values = $1 WHERE scenario_id = $2 AND row_label = $3', [JSON.stringify(gewerbesteuer), scenarioId, 'Gewerbesteuer'])
|
||||
await pool.query('UPDATE fp_guv SET values = $1 WHERE scenario_id = $2 AND row_label = $3', [JSON.stringify(koerperschaftsteuer), scenarioId, 'Koerperschaftssteuer'])
|
||||
await pool.query('UPDATE fp_guv SET values = $1 WHERE scenario_id = $2 AND row_label = $3', [JSON.stringify(koerperschaftsteuer), scenarioId, 'Körperschaftssteuer'])
|
||||
await pool.query('UPDATE fp_guv SET values = $1 WHERE scenario_id = $2 AND row_label = $3', [JSON.stringify(steuernGesamt), scenarioId, 'Steuern gesamt'])
|
||||
await pool.query('UPDATE fp_guv SET values = $1 WHERE scenario_id = $2 AND row_label = $3', [JSON.stringify(ergebnisNachSteuern), scenarioId, 'Ergebnis nach Steuern'])
|
||||
await pool.query('UPDATE fp_guv SET values = $1 WHERE scenario_id = $2 AND row_label = $3', [JSON.stringify(ergebnisNachSteuern), scenarioId, 'Jahresueberschuss'])
|
||||
await pool.query('UPDATE fp_guv SET values = $1 WHERE scenario_id = $2 AND row_label = $3', [JSON.stringify(ergebnisNachSteuern), scenarioId, 'Jahresüberschuss'])
|
||||
|
||||
// Steuern auch in Liquidität eintragen (monatlich = 1/12 des Jahresbetrags)
|
||||
const liqGewSt = findLiq('Gewerbesteuer')
|
||||
const liqKSt = findLiq('Koerperschaftsteuer')
|
||||
const liqKSt = findLiq('Körperschaftsteuer')
|
||||
if (liqGewSt) {
|
||||
const v = emptyMonthly()
|
||||
for (let y = 2026; y <= 2030; y++) {
|
||||
|
||||
Reference in New Issue
Block a user