Kontrolle: Rechnungsdialog weist auf die fehlende Steuernummer hin
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 <noreply@anthropic.com>
This commit is contained in:
1 parent
dec7bea7d2
commit
b556a459bb
4 files changed
+49
-1
No files matched your search
@@ -10,6 +10,7 @@ import { useCustomers } from '../../hooks/useCustomers'
|
|||||||
import { useScrollIntoView } from '../../hooks/useScrollIntoView'
|
import { useScrollIntoView } from '../../hooks/useScrollIntoView'
|
||||||
import {
|
import {
|
||||||
useKundenTickets,
|
useKundenTickets,
|
||||||
|
useEinstellungen,
|
||||||
useProjektkontoDetail,
|
useProjektkontoDetail,
|
||||||
useProjektkonten,
|
useProjektkonten,
|
||||||
useRechnungVorschau,
|
useRechnungVorschau,
|
||||||
@@ -39,6 +40,7 @@ import {
|
|||||||
standardArt,
|
standardArt,
|
||||||
standardAuftrag,
|
standardAuftrag,
|
||||||
startProjekt,
|
startProjekt,
|
||||||
|
steuernummerHinweis,
|
||||||
ticketOptionen,
|
ticketOptionen,
|
||||||
wirksamesProjekt,
|
wirksamesProjekt,
|
||||||
zahlungszielVorschlag,
|
zahlungszielVorschlag,
|
||||||
@@ -114,6 +116,7 @@ function RechnungFormular({ onClose, onCreated, projektId, auftraegeAktiv, onSho
|
|||||||
const kunde = kundeDoc && canInvoice(kundeDoc).ok ? kundeDoc : null
|
const kunde = kundeDoc && canInvoice(kundeDoc).ok ? kundeDoc : null
|
||||||
const blockiert = Boolean(kundeDoc) && !kunde
|
const blockiert = Boolean(kundeDoc) && !kunde
|
||||||
|
|
||||||
|
const einstellungen = useEinstellungen()
|
||||||
const konten = useProjektkonten(kunde?.$id)
|
const konten = useProjektkonten(kunde?.$id)
|
||||||
const projekt = wirksamesProjekt(state.projektId, konten.data?.konten)
|
const projekt = wirksamesProjekt(state.projektId, konten.data?.konten)
|
||||||
const aktiv = konten.data ? Boolean(konten.data.auftraegeAktiv) : Boolean(auftraegeAktiv)
|
const aktiv = konten.data ? Boolean(konten.data.auftraegeAktiv) : Boolean(auftraegeAktiv)
|
||||||
@@ -458,6 +461,11 @@ function RechnungFormular({ onClose, onCreated, projektId, auftraegeAktiv, onSho
|
|||||||
<p className="rd-hint">Bitte einen Kunden aus der Liste wählen. Nur feste Kunden mit E-Mail-Adresse erscheinen dort.</p>
|
<p className="rd-hint">Bitte einen Kunden aus der Liste wählen. Nur feste Kunden mit E-Mail-Adresse erscheinen dort.</p>
|
||||||
)}
|
)}
|
||||||
{!festerKunde && kunde && kunde.email && <p className="rd-hint">Die Rechnung geht an {kunde.email}.</p>}
|
{!festerKunde && kunde && kunde.email && <p className="rd-hint">Die Rechnung geht an {kunde.email}.</p>}
|
||||||
|
{steuernummerHinweis(einstellungen) && (
|
||||||
|
<p className="msg warn" role="status">
|
||||||
|
{steuernummerHinweis(einstellungen)}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
{kunde && gate.warn && (
|
{kunde && gate.warn && (
|
||||||
<AddressWarning
|
<AddressWarning
|
||||||
customer={kunde}
|
customer={kunde}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// Hooks des Rechnungsdialogs: Projektliste, Projektkonto, Vorschau, Tickets des Kunden und Arbeitsblätter weiterer Tickets.
|
// Hooks des Rechnungsdialogs: Projektliste, Projektkonto, Vorschau, Tickets des Kunden und Arbeitsblätter weiterer Tickets.
|
||||||
// Überall zählt nur die jüngste Antwort; nach dem Ausbau eines Hooks zählt keine mehr.
|
// Überall zählt nur die jüngste Antwort; nach dem Ausbau eines Hooks zählt keine mehr.
|
||||||
import { useCallback, useEffect, useRef, useState } from 'react'
|
import { useCallback, useEffect, useRef, useState } from 'react'
|
||||||
import { getProjektkonten, getProjektkonto, previewInvoice } from '../lib/financeApi'
|
import { getProjektkonten, getProjektkonto, getSettings, previewInvoice } from '../lib/financeApi'
|
||||||
import { getAbgerechnet } from '../lib/teamApi'
|
import { getAbgerechnet } from '../lib/teamApi'
|
||||||
import { listKundenTickets, listTicketBlaetter } from '../lib/rechnungDialogApi'
|
import { listKundenTickets, listTicketBlaetter } from '../lib/rechnungDialogApi'
|
||||||
import { blattAusAppwrite } from '../lib/rechnungDialogView'
|
import { blattAusAppwrite } from '../lib/rechnungDialogView'
|
||||||
@@ -61,6 +61,22 @@ function useGeladen(laden, schluessel, fallbackError) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Finanzeinstellungen, einmal geladen: undefined = lädt, null = nicht ladbar, sonst das Objekt `einstellungen`. */
|
||||||
|
export function useEinstellungen() {
|
||||||
|
const [einstellungen, setEinstellungen] = useState(undefined)
|
||||||
|
useEffect(() => {
|
||||||
|
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 }. */
|
/** Projektkonten eines Kunden: { auftraegeAktiv, kunde, konten, ohneProjekt, stripeOk }. */
|
||||||
export function useProjektkonten(kundeId) {
|
export function useProjektkonten(kundeId) {
|
||||||
return useGeladen(() => getProjektkonten(kundeId), kundeId, 'Die Projekte konnten nicht geladen werden.')
|
return useGeladen(() => getProjektkonten(kundeId), kundeId, 'Die Projekte konnten nicht geladen werden.')
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
// Arbeitsblätter (Auswahl, Summen, Umwandlung aus Appwrite-Dokumenten) und die Ticketliste für „Weiteres Ticket hinzunehmen“.
|
// Arbeitsblätter (Auswahl, Summen, Umwandlung aus Appwrite-Dokumenten) und die Ticketliste für „Weiteres Ticket hinzunehmen“.
|
||||||
import { euro, dateDe, ymdBerlin } from './financeFormat'
|
import { euro, dateDe, ymdBerlin } from './financeFormat'
|
||||||
import { INVOICE_LIMITS } from './financeView'
|
import { INVOICE_LIMITS } from './financeView'
|
||||||
|
import { steuernummerFehlt } from './kundenFelder'
|
||||||
import { worksheetMinutes } from './support'
|
import { worksheetMinutes } from './support'
|
||||||
import { germanDateToIso } from './ticketForm'
|
import { germanDateToIso } from './ticketForm'
|
||||||
import { ticketsText } from './projektkontoView'
|
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 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 ENTWURF_HINWEIS = 'Zu dieser Auftragsbestätigung gibt es noch einen Entwurf. Erst senden oder löschen.'
|
||||||
export const OHNE_PROJEKT = 'Ohne Projekt'
|
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 GUELTIG = ['versendet', 'bestaetigt']
|
||||||
const FINALISIERT = ['offen', 'ueberfaellig', 'bezahlt', 'uneinbringlich']
|
const FINALISIERT = ['offen', 'ueberfaellig', 'bezahlt', 'uneinbringlich']
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ const {
|
|||||||
gueltigeFestpreisAbs, aufwandAuftrag, abLabel, berechnetFuerAuftrag, hatEntwurfZurAuftrag,
|
gueltigeFestpreisAbs, aufwandAuftrag, abLabel, berechnetFuerAuftrag, hatEntwurfZurAuftrag,
|
||||||
artOptionen, standardArt, standardAuftrag, anzahlungStandard,
|
artOptionen, standardArt, standardAuftrag, anzahlungStandard,
|
||||||
ausgewaehlteIds, blaetterSumme, blattAusAppwrite, ticketOptionen, zahlungszielVorschlag,
|
ausgewaehlteIds, blaetterSumme, blattAusAppwrite, ticketOptionen, zahlungszielVorschlag,
|
||||||
|
STEUERNUMMER_RECHNUNG_HINWEIS, steuernummerHinweis,
|
||||||
} = await loadModule('src/lib/rechnungDialogView.js')
|
} = await loadModule('src/lib/rechnungDialogView.js')
|
||||||
|
|
||||||
const ab = (over = {}) => ({
|
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: 'frei', ab: dreissig }), '14')
|
||||||
assert.equal(zahlungszielVorschlag({ art: '', auftraege: [aufwand] }), '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([]), '')
|
||||||
|
})
|
||||||
Reference in new issue
Block a user