feat: Steuerberechnung in GuV — KSt + GewSt + Verlustvortrag
Stockach 78333, Hebesatz 350%: - Gewerbesteuer: 3,5% × 3,5 = 12,25% - Körperschaftsteuer: 15% + 5,5% Soli = 15,825% - Gesamt: ~28,08% auf den Gewinn Verlustvortrag: - Verluste werden kumuliert und mit künftigen Gewinnen verrechnet - Bis 1 Mio EUR: 100% verrechenbar - Über 1 Mio EUR: nur 60% (Mindestbesteuerung) GuV-Zeilen: Gewerbesteuer, Körperschaftsteuer, Steuern gesamt, Ergebnis nach Steuern, Jahresüberschuss Liquidität: Steuern als monatliche Auszahlungen (1/12 des Jahres) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -409,15 +409,103 @@ export async function computeFinanzplan(pool: Pool, scenarioId: string): Promise
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// EBIT
|
// EBIT (Betriebsergebnis)
|
||||||
const ebit: AnnualValues = {}
|
const ebit: AnnualValues = {}
|
||||||
for (let y = 2026; y <= 2030; y++) {
|
for (let y = 2026; y <= 2030; y++) {
|
||||||
const k = `y${y}`
|
const k = `y${y}`
|
||||||
ebit[k] = (umsatzAnnual[k] || 0) - (materialAnnual[k] || 0) - (personalAnnual[k] || 0) - (afaAnnual[k] || 0) - (sonstigeAnnual[k] || 0)
|
ebit[k] = Math.round((umsatzAnnual[k] || 0) - (materialAnnual[k] || 0) - (personalAnnual[k] || 0) - (afaAnnual[k] || 0) - (sonstigeAnnual[k] || 0))
|
||||||
}
|
}
|
||||||
await pool.query('UPDATE fp_guv SET values = $1 WHERE scenario_id = $2 AND row_label = $3', [JSON.stringify(ebit), scenarioId, 'EBIT'])
|
await pool.query('UPDATE fp_guv SET values = $1 WHERE scenario_id = $2 AND row_label = $3', [JSON.stringify(ebit), scenarioId, 'EBIT'])
|
||||||
await pool.query('UPDATE fp_guv SET values = $1 WHERE scenario_id = $2 AND row_label = $3', [JSON.stringify(ebit), scenarioId, 'Ergebnis nach Steuern'])
|
|
||||||
await pool.query('UPDATE fp_guv SET values = $1 WHERE scenario_id = $2 AND row_label = $3', [JSON.stringify(ebit), scenarioId, 'Jahresueberschuss'])
|
// Steuerberechnung (nur auf Gewinne, mit Verlustvortrag)
|
||||||
|
// Stockach 78333: Hebesatz 350%
|
||||||
|
// Gewerbesteuer = 3,5% × 3,5 = 12,25%
|
||||||
|
// Körperschaftsteuer = 15% + 5,5% Soli = 15,825%
|
||||||
|
// Gesamt: ~28,075%
|
||||||
|
const GEWERBESTEUER_RATE = 0.035 * 3.5 // 12,25%
|
||||||
|
const KOERPERSCHAFTSTEUER_RATE = 0.15 * 1.055 // 15,825% (inkl. Soli)
|
||||||
|
|
||||||
|
const gewerbesteuer: AnnualValues = {}
|
||||||
|
const koerperschaftsteuer: AnnualValues = {}
|
||||||
|
const steuernGesamt: AnnualValues = {}
|
||||||
|
const ergebnisNachSteuern: AnnualValues = {}
|
||||||
|
let verlustvortrag = 0 // kumulierter Verlustvortrag
|
||||||
|
|
||||||
|
for (let y = 2026; y <= 2030; y++) {
|
||||||
|
const k = `y${y}`
|
||||||
|
const gewinn = ebit[k] || 0
|
||||||
|
|
||||||
|
if (gewinn <= 0) {
|
||||||
|
// Verlust: keine Steuern, Verlustvortrag aufbauen
|
||||||
|
verlustvortrag += Math.abs(gewinn)
|
||||||
|
gewerbesteuer[k] = 0
|
||||||
|
koerperschaftsteuer[k] = 0
|
||||||
|
steuernGesamt[k] = 0
|
||||||
|
ergebnisNachSteuern[k] = Math.round(gewinn)
|
||||||
|
} else {
|
||||||
|
// Gewinn: Verlustvortrag verrechnen
|
||||||
|
// Bis 1 Mio EUR: 100% verrechenbar
|
||||||
|
// Über 1 Mio EUR: nur 60% verrechenbar (Mindestbesteuerung)
|
||||||
|
let verrechenbar = 0
|
||||||
|
if (verlustvortrag > 0) {
|
||||||
|
if (gewinn <= 1000000) {
|
||||||
|
verrechenbar = Math.min(verlustvortrag, gewinn)
|
||||||
|
} else {
|
||||||
|
verrechenbar = Math.min(verlustvortrag, 1000000 + (gewinn - 1000000) * 0.6)
|
||||||
|
}
|
||||||
|
verlustvortrag -= verrechenbar
|
||||||
|
}
|
||||||
|
|
||||||
|
const zuVersteuern = Math.max(0, gewinn - verrechenbar)
|
||||||
|
const gst = Math.round(zuVersteuern * GEWERBESTEUER_RATE)
|
||||||
|
const kst = Math.round(zuVersteuern * KOERPERSCHAFTSTEUER_RATE)
|
||||||
|
|
||||||
|
gewerbesteuer[k] = gst
|
||||||
|
koerperschaftsteuer[k] = kst
|
||||||
|
steuernGesamt[k] = gst + kst
|
||||||
|
ergebnisNachSteuern[k] = Math.round(gewinn - gst - kst)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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(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'])
|
||||||
|
|
||||||
|
// Steuern auch in Liquidität eintragen (monatlich = 1/12 des Jahresbetrags)
|
||||||
|
const liqGewSt = findLiq('Gewerbesteuer')
|
||||||
|
const liqKSt = findLiq('Koerperschaftsteuer')
|
||||||
|
if (liqGewSt) {
|
||||||
|
const v = emptyMonthly()
|
||||||
|
for (let y = 2026; y <= 2030; y++) {
|
||||||
|
const jahresBetrag = gewerbesteuer[`y${y}`] || 0
|
||||||
|
if (jahresBetrag > 0) {
|
||||||
|
const monatlich = Math.round(jahresBetrag / 12)
|
||||||
|
const startM = (y - 2026) * 12 + 1
|
||||||
|
for (let m = startM; m <= startM + 11 && m <= MONTHS; m++) {
|
||||||
|
v[`m${m}`] = monatlich
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await pool.query('UPDATE fp_liquiditaet SET values = $1 WHERE id = $2', [JSON.stringify(v), liqGewSt.id])
|
||||||
|
liqGewSt.values = v
|
||||||
|
}
|
||||||
|
if (liqKSt) {
|
||||||
|
const v = emptyMonthly()
|
||||||
|
for (let y = 2026; y <= 2030; y++) {
|
||||||
|
const jahresBetrag = koerperschaftsteuer[`y${y}`] || 0
|
||||||
|
if (jahresBetrag > 0) {
|
||||||
|
const monatlich = Math.round(jahresBetrag / 12)
|
||||||
|
const startM = (y - 2026) * 12 + 1
|
||||||
|
for (let m = startM; m <= startM + 11 && m <= MONTHS; m++) {
|
||||||
|
v[`m${m}`] = monatlich
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await pool.query('UPDATE fp_liquiditaet SET values = $1 WHERE id = $2', [JSON.stringify(v), liqKSt.id])
|
||||||
|
liqKSt.values = v
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
personalkosten: { total_brutto: totalBrutto, total_sozial: totalSozial, total: totalPersonal, positions: personal, headcount },
|
personalkosten: { total_brutto: totalBrutto, total_sozial: totalSozial, total: totalPersonal, positions: personal, headcount },
|
||||||
|
|||||||
Reference in New Issue
Block a user