Vertrag-Löschen: Kette bleibt intakt, Liste refresht

Zwei zusammenspielende Bugs:

1) Backend: deleteContract-Reihenfolge scheiterte am UNIQUE-
   Constraint auf Contract.previousContractId. Beim Middle-Delete
   (A → B → C, B löschen) hielt B im UPDATE-Moment noch selbst
   previousContractId=A – der Versuch, C ebenfalls auf A
   umzubiegen, warf MariaDB Duplicate-Entry, das UPDATE brach ab.

   Fix: Transaction, umgedrehte Reihenfolge – erst B löschen
   (DB-Cascade ON DELETE SET NULL räumt C.previousContractId ab,
   gibt A-Slot frei), dann C sauber auf A umbiegen.

2) Frontend: deleteMutation invalidierte weder Contract-Listen
   noch Kunden-Vertragsbaum und hatte keinen onError-Handler.
   Nach dem Delete wurde nach /contracts navigiert, dort zeigte
   der stale Cache noch den gelöschten Vertrag – Eindruck: „ganze
   Historie weg". Bei Bug 1 fehlgeschlagen brach das schweigend
   ab.

   Fix: queryClient.invalidateQueries für ['contracts'],
   ['contract-tree', customerId], ['customer', customerId] nach
   Erfolg. onError-Toast bei Fehler.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-07-17 20:52:02 +02:00
co-authored by Claude Opus 4.7
parent 66fb5092fe
commit d0611b740a
3 changed files with 71 additions and 14 deletions
@@ -1567,8 +1567,22 @@ export default function ContractDetail() {
const deleteMutation = useMutation({
mutationFn: () => contractApi.delete(contractId),
onSuccess: () => {
// Nach dem Löschen die zentralen Vertragslisten + den Kunden-
// Vertragsbaum invalidieren sonst zeigt die Liste danach den
// gerade gelöschten Vertrag noch an, während der ans /contracts
// navigierte User den Eindruck bekommt, der Vorgänger sei mitgelöscht
// worden (siehe Bug „Vertrag löscht ganze Historie").
queryClient.invalidateQueries({ queryKey: ['contracts'] });
if (contractCustomerId) {
queryClient.invalidateQueries({ queryKey: ['contract-tree', contractCustomerId] });
queryClient.invalidateQueries({ queryKey: ['customer', contractCustomerId] });
}
navigate('/contracts');
},
onError: (err) => {
const msg = err instanceof Error ? err.message : 'Unbekannter Fehler';
toast.error(`Löschen fehlgeschlagen: ${msg}`);
},
});
const followUpMutation = useMutation({