Kontrolle: Rechnungsdialog übernimmt das Zahlungsziel der gewählten AB

Bei Anzahlung, Schlussrechnung und Aufwand wird 'Zahlungsziel in Tagen' mit
auftrag.zahlungszielTage vorbelegt (sonst 14); eine Eingabe des Nutzers bleibt.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
ClaudeandClaude Sonnet 5.5 committed 2026-10-07 15:17:08 +00:00
1 parent b7b3e834f8
commit dec7bea7d2
5 files changed
+63 -3

No files matched your search

@@ -41,6 +41,7 @@ import {
startProjekt,
ticketOptionen,
wirksamesProjekt,
zahlungszielVorschlag,
} from '../../lib/rechnungDialogView'
import {
BEZEICHNUNG_MAX,
@@ -169,6 +170,12 @@ function RechnungFormular({ onClose, onCreated, projektId, auftraegeAktiv, onSho
const gate = invoiceSendGate(kunde, totalCents)
const darf = darfSpeichern(status) && busy === null && Boolean(kunde) && projekt !== null && art !== ''
// Das Zahlungsziel der gewählten AB (bzw. 14); der Reducer lässt eine Eingabe des Nutzers unberührt
const tageVorschlag = zahlungszielVorschlag({ art, ab, auftraege })
useEffect(() => {
dispatch({ type: 'tage-vorschlag', wert: tageVorschlag })
}, [tageVorschlag])
// --- Effekte auf die Vorschau -----------------------------------------------------------------------------
const vorschauZeitraum = status.state === 'bereit' ? vorschau.daten.leistungszeitraum || '' : null
useEffect(() => {
+6 -1
View File
@@ -24,6 +24,7 @@ export function anfangszustand({ projektId = null } = {}) {
zeitraum: '',
zeitraumGeaendert: false,
days: String(INVOICE_LIMITS.defaultDays),
tageGeaendert: false,
memo: '',
}
}
@@ -35,7 +36,7 @@ function neueUid(s) {
export function reduce(s, a) {
switch (a?.type) {
case 'projekt':
return { ...anfangszustand({ projektId: a.projektId }), days: s.days, memo: s.memo }
return { ...anfangszustand({ projektId: a.projektId }), days: s.days, tageGeaendert: s.tageGeaendert, memo: s.memo }
case 'art':
return {
...s,
@@ -84,6 +85,10 @@ export function reduce(s, a) {
if (s.zeitraumGeaendert || s.zeitraum === a.text) return s
return { ...s, zeitraum: a.text }
case 'tage':
return { ...s, days: a.wert, tageGeaendert: true }
case 'tage-vorschlag':
// das Zahlungsziel der gewählten AB; eine Eingabe des Nutzers überschreibt er nie
if (s.tageGeaendert || s.days === a.wert) return s
return { ...s, days: a.wert }
case 'notiz':
return { ...s, memo: a.wert }
+14
View File
@@ -2,6 +2,7 @@
// Aufgaben: Projektwahl, waehlbare Rechnungsarten, gültige Auftragsbestätigungen (AB), Vorgaben für Anzahlung und Standardart,
// 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 { worksheetMinutes } from './support'
import { germanDateToIso } from './ticketForm'
import { ticketsText } from './projektkontoView'
@@ -145,6 +146,19 @@ export function standardAuftrag(art, auftraege, rechnungen = []) {
return ''
}
/**
* Vorbelegung „Zahlungsziel in Tagen“: bei Anzahlung und Schlussrechnung das Ziel der gewählten AB, bei Aufwand das der
* jüngsten gültigen Aufwands-AB (`auftraege`), sonst 14. Nur ganze Zahlen von 0 bis 60 zählen. -> Text
*/
export function zahlungszielVorschlag({ art, ab = null, auftraege = [] } = {}) {
const standard = String(INVOICE_LIMITS.defaultDays)
let quelle = null
if (art === 'anzahlung' || art === 'schluss') quelle = ab
else if (art === 'aufwand') quelle = aufwandAuftrag(auftraege)
const tage = quelle?.zahlungszielTage
return Number.isSafeInteger(tage) && tage >= 0 && tage <= INVOICE_LIMITS.maxDays ? String(tage) : standard
}
/** Vorgabe der Anzahlung: Prozent aus dem Zahlungsplan, sonst 50. */
export function anzahlungStandard(auftrag) {
const plan = auftrag?.zahlungsplan