diff --git a/backend/src/services/contractStatusScheduler.service.ts b/backend/src/services/contractStatusScheduler.service.ts index 89305f49..145ab625 100644 --- a/backend/src/services/contractStatusScheduler.service.ts +++ b/backend/src/services/contractStatusScheduler.service.ts @@ -144,7 +144,14 @@ export async function withContractDocumentLock( * Wird nach einem ContractDocument-Upload aufgerufen. Wenn der Typ eine * Lieferbestätigung ist: * - Contract.status von DRAFT auf ACTIVE setzen (falls DRAFT) - * - Contract.startDate auf deliveryDate (oder heute) setzen, falls noch leer + * - Contract.startDate auf das Lieferdatum setzen: + * * Explizit eingegebenes deliveryDate → IMMER als Vertragsbeginn + * übernehmen, auch wenn schon ein Datum gesetzt war. Die + * Lieferbestätigung ist das maßgebliche tatsächliche Startdatum + * und korrigiert ein evtl. vorher geschätztes Beginndatum. + * * Kein deliveryDate angegeben → Fallback "heute", aber NUR wenn + * startDate noch leer ist. Ein bestehendes (echtes) Datum darf + * nicht versehentlich mit "heute" überschrieben werden. * * Schreibweise "Lieferbestätigung" stammt aus dem Frontend-Dropdown * (SaveAttachmentModal / ContractDetail). Vergleich case-insensitive + @@ -165,13 +172,12 @@ export async function maybeActivateOnDeliveryConfirmation( }); if (!contract) return; - // deliveryDate parsen, Fallback auf heute + // Explizit eingegebenes Lieferdatum parsen (null = keins angegeben). let parsedDate: Date | null = null; if (deliveryDate) { const parsed = new Date(deliveryDate); if (!isNaN(parsed.getTime())) parsedDate = parsed; } - const effectiveDate = parsedDate || new Date(); const updateData: Record = {}; const changes: Record = {}; @@ -181,9 +187,21 @@ export async function maybeActivateOnDeliveryConfirmation( changes.status = { vorher: 'DRAFT', nachher: 'ACTIVE' }; } - if (!contract.startDate) { - updateData.startDate = effectiveDate; - changes.startDate = { vorher: null, nachher: effectiveDate.toISOString().split('T')[0] }; + const asDay = (d: Date | null | undefined) => + d ? new Date(d).toISOString().split('T')[0] : null; + + if (parsedDate) { + // Explizites Lieferdatum: als Vertragsbeginn übernehmen, auch überschreibend. + // No-op vermeiden, wenn der Tag schon exakt passt. + if (asDay(contract.startDate) !== asDay(parsedDate)) { + updateData.startDate = parsedDate; + changes.startDate = { vorher: asDay(contract.startDate), nachher: asDay(parsedDate) }; + } + } else if (!contract.startDate) { + // Kein Datum angegeben → Fallback heute, nur bei leerem Startdatum. + const today = new Date(); + updateData.startDate = today; + changes.startDate = { vorher: null, nachher: asDay(today) }; } if (Object.keys(updateData).length === 0) return; diff --git a/docs/todo.md b/docs/todo.md index 7b8eebe1..3e08e8a8 100644 --- a/docs/todo.md +++ b/docs/todo.md @@ -97,6 +97,19 @@ isolierte Instanz (keine Multi-Tenancy im Code), Provisioning + Abrechnung ## ✅ Erledigt +- [x] **🐞 Lieferbestätigung: eingegebenes Datum ändert Vertragsbeginn nicht** + - Beim Upload einer Lieferbestätigung mit Datum wurde `startDate` nur + gesetzt, wenn es noch LEER war (`if (!contract.startDate)`). Hatte + der Vertrag schon ein (geschätztes) Beginndatum, blieb es trotz + eingetragenem Lieferdatum stehen. + - Fix in `maybeActivateOnDeliveryConfirmation`: ein explizit + eingegebenes Lieferdatum überschreibt den Vertragsbeginn jetzt IMMER + (die Lieferbestätigung ist das maßgebliche tatsächliche Startdatum). + Der Fallback „heute" (kein Datum eingegeben) füllt weiterhin nur ein + leeres Feld, um ein echtes Datum nicht versehentlich zu überschreiben. + No-op + Audit-Log unverändert. Frontend schickte das Datum bereits + mit und lädt den Vertrag nach Upload neu – kein FE-Change nötig. + - [x] **🎂 Anstehende Geburtstage auch im Dashboard** - Die Geburtstags-Sektion gab es bisher nur im Vertrags-Cockpit. Jetzt 1:1 auch auf dem Dashboard (nur Mitarbeiter/Admin,