Gutschrift: Beleg-Upload auch fuer Sachwerte + kein Unterschriftsblock bei Geld

- Beleg-Upload jetzt fuer beide Arten: bei Geld die Ueberweisungs-
  bestaetigung, bei Sachwert das unterschriebene Dokument. ReceiptControls
  in der Liste fuer Geld UND Sachwert (Label je nach Typ). Endpoint war
  schon typ-agnostisch.
- PDF-Unterschriftsblock nur noch bei Sachwert - eine Ueberweisung wird
  nicht unterschrieben (Beleg = hochgeladene Ueberweisungsbestaetigung).
  Bei Geld entfaellt der Unterschrift/Ort-Block; im Formular sind Ort +
  'Unterschrift am' bei Geld ausgeblendet.

Verifiziert: beide PDFs erzeugen sauber (je 1 Seite).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-12 09:26:35 +02:00
co-authored by Claude Opus 4.8
parent 5e606df49e
commit 0078654465
3 changed files with 60 additions and 38 deletions
@@ -280,22 +280,25 @@ function CreditNoteFormModal({
value={form.creditDate}
onChange={(e) => set('creditDate', e.target.value)}
/>
<Input
label="Ort (Unterschrift)"
value={form.place}
onChange={(e) => set('place', e.target.value)}
placeholder="z.B. Oldenburg"
/>
{/* Ort/Unterschrift nur bei Sachwert Überweisung wird nicht unterschrieben. */}
{isSachwert && (
<Input
label="Ort (Unterschrift)"
value={form.place}
onChange={(e) => set('place', e.target.value)}
placeholder="z.B. Oldenburg"
/>
)}
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<Input
label="Unterschrift am (optional)"
type="date"
value={form.signedAt}
onChange={(e) => set('signedAt', e.target.value)}
/>
{form.type === 'SACHWERT' && (
{isSachwert && (
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<Input
label="Unterschrift am (optional)"
type="date"
value={form.signedAt}
onChange={(e) => set('signedAt', e.target.value)}
/>
<label className="flex items-center gap-2 text-sm mt-7">
<input
type="checkbox"
@@ -305,8 +308,8 @@ function CreditNoteFormModal({
/>
Ware erhalten (Empfang bestätigt)
</label>
)}
</div>
</div>
)}
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">Notiz (optional)</label>
@@ -318,9 +321,11 @@ function CreditNoteFormModal({
/>
</div>
{form.type === 'GELD' && !editing && (
{!editing && (
<p className="text-xs text-gray-500">
Der Überweisungsbeleg kann nach dem Speichern in der Liste hochgeladen werden.
{isSachwert
? 'Das unterschriebene Dokument kann nach dem Speichern in der Liste hochgeladen werden.'
: 'Der Überweisungsbeleg kann nach dem Speichern in der Liste hochgeladen werden.'}
</p>
)}
@@ -336,7 +341,7 @@ function CreditNoteFormModal({
}
// ---------- Beleg-Upload (nur GELD) ----------
function ReceiptControls({ cn, canEdit, onChanged }: { cn: CreditNote; canEdit: boolean; onChanged: () => void }) {
function ReceiptControls({ cn, canEdit, onChanged, label = 'Beleg' }: { cn: CreditNote; canEdit: boolean; onChanged: () => void; label?: string }) {
const fileRef = useRef<HTMLInputElement>(null);
const uploadMutation = useMutation({
mutationFn: (file: File) => creditNoteApi.uploadReceipt(cn.id, file),
@@ -353,17 +358,17 @@ function ReceiptControls({ cn, canEdit, onChanged }: { cn: CreditNote; canEdit:
return (
<span className="inline-flex items-center gap-2 text-xs">
<a href={fileUrl(cn.receiptPath, { inline: true })} target="_blank" rel="noopener noreferrer" className="text-blue-600 hover:underline inline-flex items-center gap-1">
<Eye className="w-3.5 h-3.5" /> Beleg
<Eye className="w-3.5 h-3.5" /> {label}
</a>
{canEdit && (
<button onClick={() => removeMutation.mutate()} className="text-gray-400 hover:text-red-600" title="Beleg entfernen">
<button onClick={() => removeMutation.mutate()} className="text-gray-400 hover:text-red-600" title={`${label} entfernen`}>
<X className="w-3.5 h-3.5" />
</button>
)}
</span>
);
}
if (!canEdit) return <span className="text-xs text-gray-400">kein Beleg</span>;
if (!canEdit) return <span className="text-xs text-gray-400">kein {label}</span>;
return (
<>
<input
@@ -378,7 +383,7 @@ function ReceiptControls({ cn, canEdit, onChanged }: { cn: CreditNote; canEdit:
disabled={uploadMutation.isPending}
className="inline-flex items-center gap-1 text-xs text-blue-600 hover:text-blue-800"
>
<Upload className="w-3.5 h-3.5" /> {uploadMutation.isPending ? 'lädt …' : 'Beleg'}
<Upload className="w-3.5 h-3.5" /> {uploadMutation.isPending ? 'lädt …' : label}
</button>
</>
);
@@ -497,11 +502,14 @@ export default function CreditNotesSection({ contractId, canEdit }: { contractId
<div className="text-xs text-gray-500 mt-0.5">an Bankkonto: <span className="font-mono">{card.iban}</span> ({card.accountHolder})</div>
) : null;
})()}
{cn.type === 'GELD' && (
<div className="mt-1">
<ReceiptControls cn={cn} canEdit={canEdit} onChanged={refresh} />
</div>
)}
<div className="mt-1">
<ReceiptControls
cn={cn}
canEdit={canEdit}
onChanged={refresh}
label={cn.type === 'GELD' ? 'Überweisungsbeleg' : 'Unterschr. Dokument'}
/>
</div>
</div>
{canEdit && (
<div className="flex items-center gap-1">