diff --git a/src/components/AdminRoute.jsx b/src/components/AdminRoute.jsx index 8015120..5ea4444 100644 --- a/src/components/AdminRoute.jsx +++ b/src/components/AdminRoute.jsx @@ -9,7 +9,7 @@ export default function AdminRoute({ children }) { return (
-

Loading...

+

Wird geladen …

) } diff --git a/src/components/finance/TaxCard.jsx b/src/components/finance/TaxCard.jsx index d997767..debd7e8 100644 --- a/src/components/finance/TaxCard.jsx +++ b/src/components/finance/TaxCard.jsx @@ -5,6 +5,7 @@ import { taxView } from '../../lib/financeView' * Block 4: „Steuer“. Rücklage (Betrag und woraus sie sich ergibt), Kleinunternehmer-Zähler gegen die Grenzen, * Vorjahr (nur wenn eingetragen), Gewerbesteuer-Hinweis (nur wenn nötig) und die nächste ESt-Vorauszahlung * (nur wenn eingestellt). Ist der Zähler unbekannt (Stripe nicht erreichbar), steht das als Text da, nie eine 0. + * Am Ende steht immer der Hinweis „Orientierungswert, ersetzt keine Steuerberatung.“ */ export default function TaxCard({ steuer }) { const v = taxView(steuer) @@ -44,6 +45,8 @@ export default function TaxCard({ steuer }) {
am {v.prepayment.dateText}
)} + +

{v.noteText}

) diff --git a/src/lib/financeView.js b/src/lib/financeView.js index 4775d23..f1f08f3 100644 --- a/src/lib/financeView.js +++ b/src/lib/financeView.js @@ -292,10 +292,13 @@ const KLEIN_LIMIT_CENTS = 2_500_000 const KLEIN_HARD_LIMIT_CENTS = 10_000_000 const GEWERBE_ALLOWANCE_CENTS = 2_450_000 +/** Dauerhafter Hinweis unter den Steuerwerten: die Zahlen sind Näherungen. */ +export const TAX_NOTE = 'Orientierungswert, ersetzt keine Steuerberatung.' + /** * Texte der Steuerkarte aus `steuer`: * { reserve: { amountText, basisText }, small: { known, counterText, shareText, limitText, hardText, previousText }, - * gewerbeText, prepayment: { dateText, amountText } | null }. + * gewerbeText, prepayment: { dateText, amountText } | null, noteText }. * Ist der Kleinunternehmer-Zähler null (Stripe nicht erreichbar), steht „unbekannt“ statt einer Zahl. */ export function taxView(steuer) { @@ -331,7 +334,7 @@ export function taxView(steuer) { counterText: known ? `${euro(k.jahrCents)} von ${euroWhole(limit)}${year !== null ? ` (${year})` : ''}` : 'unbekannt (Stripe nicht erreichbar)', shareText: known && isNum(k.anteilFolgejahr) - ? `${percentDe(k.anteilFolgejahr * 100, 1)} % der ${euroWhole(limit).replace(' €', '-€')}-Grenze` + ? `${percentDe(k.anteilFolgejahr * 100, 1)} % der Grenze von ${euroWhole(limit)}` : null, limitText: `Über ${euroWhole(limit)} im Jahr${year !== null ? ` ${year}` : ''}: ab ${ year !== null ? year + 1 : 'dem Folgejahr' @@ -344,6 +347,7 @@ export function taxView(steuer) { ? `Der Gewinn${year !== null ? ` ${year}` : ''} liegt über dem Gewerbesteuer-Freibetrag von ${euroWhole(GEWERBE_ALLOWANCE_CENTS)} (natürliche Personen und Personengesellschaften, § 11 GewStG). Auf den übersteigenden Gewerbeertrag kann Gewerbesteuer anfallen.` : null, prepayment, + noteText: TAX_NOTE, } } diff --git a/tests/unit/adminRoute.test.mjs b/tests/unit/adminRoute.test.mjs new file mode 100644 index 0000000..b2f1be8 --- /dev/null +++ b/tests/unit/adminRoute.test.mjs @@ -0,0 +1,14 @@ +import test from 'node:test' +import assert from 'node:assert/strict' +import { readFileSync } from 'node:fs' +import path from 'node:path' +import { fileURLToPath } from 'node:url' + +const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..') +const source = readFileSync(path.join(root, 'src/components/AdminRoute.jsx'), 'utf8') + +// AdminRoute braucht React und den Auth-Kontext (nicht unter Node ladbar): der Ladetext wird am Quelltext geprüft +test('AdminRoute: Ladetext auf Deutsch, kein englisches „Loading...“', () => { + assert.match(source, /

Wird geladen …<\/p>/) + assert.doesNotMatch(source, /Loading/) +}) diff --git a/tests/unit/financeView.test.mjs b/tests/unit/financeView.test.mjs index 6d03fa2..2b2ef61 100644 --- a/tests/unit/financeView.test.mjs +++ b/tests/unit/financeView.test.mjs @@ -20,6 +20,7 @@ const { forecastRows, forecastNotes, taxView, + TAX_NOTE, aboView, productLabel, aboStatus, @@ -453,17 +454,25 @@ test('taxView: Kleinunternehmer-Zähler „ von 25.000 € (2026)“ und const v = taxView(steuer()) assert.equal(v.small.known, true) assert.equal(v.small.counterText, '80,00 € von 25.000 € (2026)') - assert.equal(v.small.shareText, '0,3 % der 25.000-€-Grenze') + assert.equal(v.small.shareText, '0,3 % der Grenze von 25.000 €') assert.equal(v.small.limitText, 'Über 25.000 € im Jahr 2026: ab 2027 keine Kleinunternehmerregelung.') assert.equal( v.small.hardText, 'Grenze 100.000 €: Ab dem Umsatz, der diese Grenze übersteigt, gilt schon im laufenden Jahr die Regelbesteuerung (Umsatzsteuer).' ) assert.equal(v.small.previousText, null) - assert.equal(taxView(steuer({}, { anteilFolgejahr: 0.704 })).small.shareText, '70,4 % der 25.000-€-Grenze') + assert.equal(taxView(steuer({}, { anteilFolgejahr: 0.704 })).small.shareText, '70,4 % der Grenze von 25.000 €') assert.equal(taxView(steuer({}, { jahrCents: 0, anteilFolgejahr: 0 })).small.counterText, '0,00 € von 25.000 € (2026)') }) +test('taxView: Orientierungshinweis steht immer dabei, Anteil ohne „-€-Grenze“', () => { + assert.equal(TAX_NOTE, 'Orientierungswert, ersetzt keine Steuerberatung.') + assert.equal(taxView(steuer()).noteText, TAX_NOTE) + assert.equal(taxView(null).noteText, TAX_NOTE) + assert.equal(taxView(steuer({}, { jahrCents: null, anteilFolgejahr: null })).noteText, TAX_NOTE) + for (const t of [taxView(steuer()), taxView(steuer({}, { anteilFolgejahr: 1.2 }))]) assert.doesNotMatch(t.small.shareText, /-€-Grenze/) +}) + test('taxView: Stripe nicht erreichbar -> unbekannt statt 0', () => { const v = taxView(steuer({}, { jahrCents: null, anteilFolgejahr: null })) assert.equal(v.small.known, false) @@ -492,7 +501,7 @@ test('taxView: Vorjahr nur wenn gesetzt, über der Grenze mit Hinweis', () => { test('taxView: Grenzen kommen aus dem Server (Rückfall nur ohne Wert), Jahr fehlt -> Folgejahr', () => { const custom = taxView(steuer({ jahr: 2030 }, { grenzeFolgejahrCents: 3000000, grenzeHartCents: 12000000, anteilFolgejahr: 0.5, vorjahrCents: 3000001 })) assert.equal(custom.small.counterText, '80,00 € von 30.000 € (2030)') - assert.equal(custom.small.shareText, '50 % der 30.000-€-Grenze') + assert.equal(custom.small.shareText, '50 % der Grenze von 30.000 €') assert.equal(custom.small.limitText, 'Über 30.000 € im Jahr 2030: ab 2031 keine Kleinunternehmerregelung.') assert.match(custom.small.hardText, /^Grenze 120\.000 €: Ab dem Umsatz, der diese Grenze übersteigt, gilt schon im laufenden Jahr die Regelbesteuerung \(Umsatzsteuer\)\.$/) assert.equal(custom.small.previousText, 'Vorjahr: 30.000,01 € (über 30.000 €: im laufenden Jahr keine Kleinunternehmerregelung)')