Finanzen: Steuerruecklage, Kleinunternehmer-Zaehler und Aufgabenliste
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
34dfe181e4
commit
7dbf2ce75f
4 files changed
+1039
No files matched your search
@@ -0,0 +1,86 @@
|
||||
/**
|
||||
* Steuer-Auswertung der Finanzen (rein, ohne I/O): Rücklage auf den Gewinn des laufenden Jahres, Zähler für die
|
||||
* Kleinunternehmer-Grenzen (§ 19 UStG) und die nächste Einkommensteuer-Vorauszahlung. Beträge sind ganze Cent;
|
||||
* "heute" kommt als Berliner Kalendertag von außen.
|
||||
*/
|
||||
import { daysBetween } from './dates.js'
|
||||
|
||||
const GRENZE_FOLGEJAHR_CENTS = 2_500_000 // 25.000 EUR: wer im Jahr darüber liegt, ist im Folgejahr kein Kleinunternehmer mehr
|
||||
const GRENZE_HART_CENTS = 10_000_000 // 100.000 EUR: darüber endet die Regelung sofort
|
||||
const GEWERBESTEUER_FREIBETRAG_CENTS = 2_450_000 // 24.500 EUR Gewinn bei Personengesellschaften
|
||||
const DEFAULT_RESERVE_PERCENT = 30 // wie DEFAULT_SETTINGS.taxReservePercent (settings.js, hier nicht importiert: Modul bleibt rein)
|
||||
const EST_MONTHS = [3, 6, 9, 12] // ESt-Vorauszahlung jeweils am 10.
|
||||
const EST_DAY = 10
|
||||
|
||||
const isCents = (n) => Number.isSafeInteger(n)
|
||||
const pad = (n) => String(n).padStart(2, '0')
|
||||
|
||||
/** Nächster ESt-Vorauszahlungstermin ab heute (heute zählt mit) als YYYY-MM-DD. */
|
||||
function nextEstDate(today) {
|
||||
const year = Number(today.slice(0, 4))
|
||||
for (const month of EST_MONTHS) {
|
||||
const date = `${String(year).padStart(4, '0')}-${pad(month)}-${pad(EST_DAY)}`
|
||||
if (date >= today) return date
|
||||
}
|
||||
return `${String(year + 1).padStart(4, '0')}-${pad(EST_MONTHS[0])}-${pad(EST_DAY)}`
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {object} args
|
||||
* @param {string} args.today Berliner Tag YYYY-MM-DD
|
||||
* @param {Array} [args.transactions] Bankbuchungen { status, bookingDate, amountCents (+ Eingang / - Ausgang), category }
|
||||
* @param {Array} [args.invoices] Stripe-Rechnungen (gemappt) { paidCents, paidDate }
|
||||
* @param {object} [args.settings] { taxReservePercent, previousYearRevenueCents, estPrepaymentCents }
|
||||
*
|
||||
* Einnahmen und Ausgaben: gebuchte Bankbuchungen (BOOK) des Kalenderjahres von today ohne Kategorie "privat".
|
||||
* Der Kleinunternehmer-Zähler nimmt statt der Bankeingänge die Zahltage der Stripe-Rechnungen plus Buchungen
|
||||
* "rechnung-extern"; Stripe-Auszahlungen und Rechnungsbuchungen zählen dort nicht (sonst doppelt).
|
||||
*/
|
||||
export function computeTax({ today, transactions = [], invoices = [], settings } = {}) {
|
||||
daysBetween(today, today) // wirft bei einem ungültigen Tag
|
||||
const jahr = Number(today.slice(0, 4))
|
||||
const prefix = `${today.slice(0, 4)}-`
|
||||
|
||||
let einnahmenCents = 0
|
||||
let ausgabenCents = 0
|
||||
let externCents = 0
|
||||
for (const tx of transactions || []) {
|
||||
if (!tx || tx.status !== 'BOOK' || typeof tx.bookingDate !== 'string' || !tx.bookingDate.startsWith(prefix)) continue
|
||||
if (!isCents(tx.amountCents) || tx.category === 'privat') continue
|
||||
if (tx.amountCents > 0) {
|
||||
einnahmenCents += tx.amountCents
|
||||
if (tx.category === 'rechnung-extern') externCents += tx.amountCents
|
||||
} else {
|
||||
ausgabenCents -= tx.amountCents
|
||||
}
|
||||
}
|
||||
|
||||
let stripeCents = 0
|
||||
for (const invoice of invoices || []) {
|
||||
if (!invoice || typeof invoice.paidDate !== 'string' || !invoice.paidDate.startsWith(prefix)) continue
|
||||
if (isCents(invoice.paidCents) && invoice.paidCents > 0) stripeCents += invoice.paidCents
|
||||
}
|
||||
|
||||
const gewinnCents = einnahmenCents - ausgabenCents
|
||||
const prozent = Number.isFinite(settings?.taxReservePercent) ? settings.taxReservePercent : DEFAULT_RESERVE_PERCENT
|
||||
const jahrCents = stripeCents + externCents
|
||||
|
||||
const prepayment = settings?.estPrepaymentCents
|
||||
return {
|
||||
jahr,
|
||||
einnahmenCents,
|
||||
ausgabenCents,
|
||||
gewinnCents,
|
||||
ruecklageCents: Math.round((Math.max(0, gewinnCents) * prozent) / 100),
|
||||
prozent,
|
||||
gewerbesteuerHinweis: gewinnCents > GEWERBESTEUER_FREIBETRAG_CENTS,
|
||||
kleinunternehmer: {
|
||||
jahrCents,
|
||||
vorjahrCents: isCents(settings?.previousYearRevenueCents) ? settings.previousYearRevenueCents : null,
|
||||
grenzeFolgejahrCents: GRENZE_FOLGEJAHR_CENTS,
|
||||
grenzeHartCents: GRENZE_HART_CENTS,
|
||||
anteilFolgejahr: jahrCents / GRENZE_FOLGEJAHR_CENTS,
|
||||
},
|
||||
naechsteVorauszahlung: isCents(prepayment) && prepayment > 0 ? { date: nextEstDate(today), amountCents: prepayment } : null,
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user