Neuer Vertragsstatus "Gekuendigt / bestaetigt" + Kuendigungs-Workflow

Bisheriges "Gekuendigt" (CANCELLED) umbenannt in "Gekuendigt / Bestaetigung
abwarten" und wird jetzt automatisch gesetzt, sobald ein Kuendigungsschreiben
hochgeladen wird. Neuer Status CANCELLED_CONFIRMED ("Gekuendigt / bestaetigt")
wird automatisch gesetzt, sobald ein Kuendigungsbestaetigungsdatum vorliegt
(Dokument fuellt das Datum oder manuell) + Vertragsende = Kuendigungsdatum.

Schema: Enum-Wert CANCELLED_CONFIRMED + Migration (idempotentes MODIFY COLUMN);
Daten-Migration hebt bestehende CANCELLED (alte Logik: nur bei Bestaetigung
gesetzt) auf CANCELLED_CONFIRMED.

Backend: neue Trigger maybeMarkAwaitingConfirmationOnLetter (Schreiben->CANCELLED)
im Upload-Handler; maybeCancelOnCancellationConfirmation setzt jetzt
CANCELLED_CONFIRMED (auch aus CANCELLED). Cockpit-Semantik mitgewandert
(Fristen-Skip/"beendet" fuer CANCELLED_CONFIRMED; Ladeliste + Kuendigungs-
bestaetigungs-Filter erweitert).

Frontend: Labels/Farben/Status-Erklaerungen + Status-Dropdown in ContractList,
ContractDetail, ContractForm, ContractDetailModal, CustomerDetail
(CANCELLED orange "abwarten", CANCELLED_CONFIRMED rot).

Verifiziert: tsc+build gruen; Schreiben->CANCELLED, Bestaetigung->
CANCELLED_CONFIRMED+Enddatum; Daten-Migration idempotent.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-08-13 18:14:34 +02:00
co-authored by Claude Opus 4.8
parent a5b8922dd0
commit fc3131059b
14 changed files with 150 additions and 33 deletions
@@ -21,7 +21,8 @@ const statusLabels: Record<ContractStatus, string> = {
DRAFT: 'Entwurf',
PENDING: 'Ausstehend',
ACTIVE: 'Aktiv',
CANCELLED: 'Gekündigt',
CANCELLED: 'Gekündigt / Bestätigung abwarten',
CANCELLED_CONFIRMED: 'Gekündigt / bestätigt',
EXPIRED: 'Abgelaufen',
DEACTIVATED: 'Deaktiviert',
ONGOING: 'Läuft weiter (unbestimmt)',
@@ -30,7 +31,8 @@ const statusLabels: Record<ContractStatus, string> = {
const statusVariants: Record<ContractStatus, 'success' | 'warning' | 'danger' | 'default'> = {
ACTIVE: 'success',
PENDING: 'warning',
CANCELLED: 'danger',
CANCELLED: 'warning',
CANCELLED_CONFIRMED: 'danger',
EXPIRED: 'danger',
DRAFT: 'default',
DEACTIVATED: 'default',
@@ -138,7 +138,8 @@ export default function AssignToContractModal({
px-2 py-0.5 text-xs rounded-full
${contract.status === 'ACTIVE' ? 'bg-green-100 text-green-800' :
contract.status === 'PENDING' ? 'bg-yellow-100 text-yellow-800' :
contract.status === 'CANCELLED' ? 'bg-red-100 text-red-800' :
contract.status === 'CANCELLED' ? 'bg-orange-100 text-orange-800' :
contract.status === 'CANCELLED_CONFIRMED' ? 'bg-red-100 text-red-800' :
'bg-gray-100 text-gray-800'}
`}>
{contract.status}