Gutschrift: nur mit Empfaengeradresse anlegbar (Rechnung > Liefer)
Eine Gutschrift/ein Lieferschein braucht eine Empfaengeradresse aufs Dokument. Rechnungsadresse hat Vorrang, sonst Lieferadresse. Ist keine von beiden hinterlegt -> Anlegen blockiert. - Frontend: Klick auf 'Gutschrift anlegen' prueft defaults.hasRecipient- Address; wenn false -> Modal-OK-Meldung statt Formular. - Backend Defense-in-Depth: createCreditNote wirft 400, wenn weder billingAddressId noch addressId gesetzt. getCreditNoteDefaults liefert hasRecipientAddress. Verifiziert: ohne Adresse -> hasRecipientAddress false + create 400; mit Adresse -> ok. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -393,6 +393,7 @@ function ReceiptControls({ cn, canEdit, onChanged, label = 'Beleg' }: { cn: Cred
|
||||
export default function CreditNotesSection({ contractId, canEdit }: { contractId: number; canEdit: boolean }) {
|
||||
const queryClient = useQueryClient();
|
||||
const [showForm, setShowForm] = useState(false);
|
||||
const [showNoAddress, setShowNoAddress] = useState(false);
|
||||
const [editing, setEditing] = useState<CreditNote | null>(null);
|
||||
|
||||
const { data: listRes } = useQuery({
|
||||
@@ -425,7 +426,15 @@ export default function CreditNotesSection({ contractId, canEdit }: { contractId
|
||||
onError: (err: Error) => toast.error(err.message || 'PDF fehlgeschlagen'),
|
||||
});
|
||||
|
||||
const openCreate = () => { setEditing(null); setShowForm(true); };
|
||||
const openCreate = () => {
|
||||
// Ohne Empfängeradresse (Rechnungs- ODER Lieferadresse) kein Beleg möglich.
|
||||
if (defaults && !defaults.hasRecipientAddress) {
|
||||
setShowNoAddress(true);
|
||||
return;
|
||||
}
|
||||
setEditing(null);
|
||||
setShowForm(true);
|
||||
};
|
||||
const openEdit = (cn: CreditNote) => { setEditing(cn); setShowForm(true); };
|
||||
|
||||
const totalGross = creditNotes.reduce((sum, cn) => sum + (cn.amountGross || 0), 0);
|
||||
@@ -548,6 +557,21 @@ export default function CreditNotesSection({ contractId, canEdit }: { contractId
|
||||
onSaved={() => { setShowForm(false); refresh(); }}
|
||||
/>
|
||||
)}
|
||||
|
||||
{showNoAddress && (
|
||||
<Modal isOpen onClose={() => setShowNoAddress(false)} title="Keine Adresse hinterlegt" size="sm">
|
||||
<div className="space-y-4">
|
||||
<p className="text-sm text-gray-700">
|
||||
Für diesen Vertrag ist weder eine Rechnungs- noch eine Lieferadresse hinterlegt.
|
||||
Ohne Empfängeradresse kann keine Gutschrift/kein Lieferschein erstellt werden.
|
||||
Bitte ordne dem Vertrag zuerst eine Adresse zu.
|
||||
</p>
|
||||
<div className="flex justify-end">
|
||||
<Button onClick={() => setShowNoAddress(false)}>OK</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -105,6 +105,7 @@ export interface CreditNoteDefaults {
|
||||
nextNumber: string;
|
||||
bankCards: CreditNotePayoutBankCard[];
|
||||
contractBankCardId: number | null;
|
||||
hasRecipientAddress: boolean;
|
||||
}
|
||||
|
||||
export interface CreditNoteNumberRange {
|
||||
|
||||
Reference in New Issue
Block a user