/** * 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, } }