From b556a459bb7410757f747105c697871941a23a09 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 7 Oct 2026 15:17:29 +0000 Subject: [PATCH] Kontrolle: Rechnungsdialog weist auf die fehlende Steuernummer hin MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Nicht sperrender Hinweis (§ 34a UStDV), solange financeSettings.steuernummer leer ist; die Einstellungen werden einmal geladen, bei einem Ladefehler erscheint kein Hinweis. Co-Authored-By: Claude Sonnet 5.5 --- src/components/auftraege/RechnungDialog.jsx | 8 ++++++++ src/hooks/useRechnungDaten.js | 18 +++++++++++++++++- src/lib/rechnungDialogView.js | 8 ++++++++ tests/unit/rechnungDialogView.test.mjs | 16 ++++++++++++++++ 4 files changed, 49 insertions(+), 1 deletion(-) diff --git a/src/components/auftraege/RechnungDialog.jsx b/src/components/auftraege/RechnungDialog.jsx index bed3f7c..d02bd79 100644 --- a/src/components/auftraege/RechnungDialog.jsx +++ b/src/components/auftraege/RechnungDialog.jsx @@ -10,6 +10,7 @@ import { useCustomers } from '../../hooks/useCustomers' import { useScrollIntoView } from '../../hooks/useScrollIntoView' import { useKundenTickets, + useEinstellungen, useProjektkontoDetail, useProjektkonten, useRechnungVorschau, @@ -39,6 +40,7 @@ import { standardArt, standardAuftrag, startProjekt, + steuernummerHinweis, ticketOptionen, wirksamesProjekt, zahlungszielVorschlag, @@ -114,6 +116,7 @@ function RechnungFormular({ onClose, onCreated, projektId, auftraegeAktiv, onSho const kunde = kundeDoc && canInvoice(kundeDoc).ok ? kundeDoc : null const blockiert = Boolean(kundeDoc) && !kunde + const einstellungen = useEinstellungen() const konten = useProjektkonten(kunde?.$id) const projekt = wirksamesProjekt(state.projektId, konten.data?.konten) const aktiv = konten.data ? Boolean(konten.data.auftraegeAktiv) : Boolean(auftraegeAktiv) @@ -458,6 +461,11 @@ function RechnungFormular({ onClose, onCreated, projektId, auftraegeAktiv, onSho

Bitte einen Kunden aus der Liste wählen. Nur feste Kunden mit E-Mail-Adresse erscheinen dort.

)} {!festerKunde && kunde && kunde.email &&

Die Rechnung geht an {kunde.email}.

} + {steuernummerHinweis(einstellungen) && ( +

+ {steuernummerHinweis(einstellungen)} +

+ )} {kunde && gate.warn && ( { + let aktuell = true + getSettings().then( + (d) => aktuell && setEinstellungen(d?.einstellungen ?? null), + () => aktuell && setEinstellungen(null) + ) + return () => { + aktuell = false + } + }, []) + return einstellungen +} + /** Projektkonten eines Kunden: { auftraegeAktiv, kunde, konten, ohneProjekt, stripeOk }. */ export function useProjektkonten(kundeId) { return useGeladen(() => getProjektkonten(kundeId), kundeId, 'Die Projekte konnten nicht geladen werden.') diff --git a/src/lib/rechnungDialogView.js b/src/lib/rechnungDialogView.js index 7964cf0..771f736 100644 --- a/src/lib/rechnungDialogView.js +++ b/src/lib/rechnungDialogView.js @@ -3,6 +3,7 @@ // Arbeitsblätter (Auswahl, Summen, Umwandlung aus Appwrite-Dokumenten) und die Ticketliste für „Weiteres Ticket hinzunehmen“. import { euro, dateDe, ymdBerlin } from './financeFormat' import { INVOICE_LIMITS } from './financeView' +import { steuernummerFehlt } from './kundenFelder' import { worksheetMinutes } from './support' import { germanDateToIso } from './ticketForm' import { ticketsText } from './projektkontoView' @@ -17,6 +18,13 @@ export const ART_OPTION_LABEL = { export const AB_HINWEIS = 'Anzahlung und Schlussrechnung brauchen eine Auftragsbestätigung.' export const ENTWURF_HINWEIS = 'Zu dieser Auftragsbestätigung gibt es noch einen Entwurf. Erst senden oder löschen.' export const OHNE_PROJEKT = 'Ohne Projekt' +export const STEUERNUMMER_RECHNUNG_HINWEIS = + 'Die Steuernummer fehlt noch – sie gehört auf jede Rechnung (§ 34a UStDV). Eintragen unter Finanzen → Einstellungen.' + +/** Hinweis im Rechnungsdialog, solange die Steuernummer fehlt; ohne Einstellungen (lädt, Ladefehler) kein Hinweis. */ +export function steuernummerHinweis(einstellungen) { + return steuernummerFehlt(einstellungen) ? STEUERNUMMER_RECHNUNG_HINWEIS : '' +} const GUELTIG = ['versendet', 'bestaetigt'] const FINALISIERT = ['offen', 'ueberfaellig', 'bezahlt', 'uneinbringlich'] diff --git a/tests/unit/rechnungDialogView.test.mjs b/tests/unit/rechnungDialogView.test.mjs index 076d96e..98aa954 100644 --- a/tests/unit/rechnungDialogView.test.mjs +++ b/tests/unit/rechnungDialogView.test.mjs @@ -8,6 +8,7 @@ const { gueltigeFestpreisAbs, aufwandAuftrag, abLabel, berechnetFuerAuftrag, hatEntwurfZurAuftrag, artOptionen, standardArt, standardAuftrag, anzahlungStandard, ausgewaehlteIds, blaetterSumme, blattAusAppwrite, ticketOptionen, zahlungszielVorschlag, + STEUERNUMMER_RECHNUNG_HINWEIS, steuernummerHinweis, } = await loadModule('src/lib/rechnungDialogView.js') const ab = (over = {}) => ({ @@ -232,3 +233,18 @@ test('zahlungszielVorschlag: Anzahlung und Schluss übernehmen das Zahlungsziel assert.equal(zahlungszielVorschlag({ art: 'frei', ab: dreissig }), '14') assert.equal(zahlungszielVorschlag({ art: '', auftraege: [aufwand] }), '14') }) + +test('steuernummerHinweis: nicht sperrender Hinweis, solange die Steuernummer in den Einstellungen leer ist', () => { + assert.equal( + STEUERNUMMER_RECHNUNG_HINWEIS, + 'Die Steuernummer fehlt noch – sie gehört auf jede Rechnung (§ 34a UStDV). Eintragen unter Finanzen → Einstellungen.' + ) + for (const leer of [{}, { steuernummer: '' }, { steuernummer: ' ' }, { steuernummer: null }]) { + assert.equal(steuernummerHinweis(leer), STEUERNUMMER_RECHNUNG_HINWEIS) + } + assert.equal(steuernummerHinweis({ steuernummer: '12/345/67890' }), '') + // noch nicht geladen (undefined) und Ladefehler (null) behaupten nichts + assert.equal(steuernummerHinweis(undefined), '') + assert.equal(steuernummerHinweis(null), '') + assert.equal(steuernummerHinweis([]), '') +})