@@ -452,27 +452,17 @@ public function edit(int $id): TemplateResponse
452452 return $ this ->configureCSP ($ response );
453453 }
454454
455- // Check if entry can be edited
456- // Allow editing if:
457- // 1. It's a manual entry (user created it themselves) - but not if already approved
458- // 2. It has pending approval status (correction request)
459- // 3. It's an automatic entry that is completed (not yet approved) - allow direct editing for convenience
460- // 4. The entry date is within the last 2 weeks (14 days) - for data integrity and compliance
461- // Do NOT allow editing if entry is already approved (approvedBy is set) or older than 2 weeks
462- $ isApproved = $ entry ->getApprovedBy () !== null ;
463- $ entryDate = $ entry ->getStartTime ();
464- $ editCutoff = new \DateTime ();
465- $ editCutoff ->modify ('- ' . Constants::EDIT_WINDOW_DAYS . ' days ' );
466- $ editCutoff ->setTime (0 , 0 , 0 );
467- $ isWithinEditWindow = $ entryDate && $ entryDate >= $ editCutoff ;
468-
469- $ canEdit = !$ isApproved && $ isWithinEditWindow && (
470- $ entry ->getIsManualEntry ()
471- || $ entry ->getStatus () === TimeEntry::STATUS_PENDING_APPROVAL
472- || ($ entry ->getStatus () === TimeEntry::STATUS_COMPLETED && !$ entry ->getIsManualEntry ())
473- );
455+ // Check if entry can be edited (logic lives in TimeEntry::canEdit to stay DRY)
456+ $ canEdit = $ entry ->canEdit (Constants::EDIT_WINDOW_DAYS );
474457
475458 if (!$ canEdit ) {
459+ $ isApproved = $ entry ->getApprovedBy () !== null ;
460+ $ entryDate = $ entry ->getStartTime ();
461+ $ editCutoff = new \DateTime ();
462+ $ editCutoff ->modify ('- ' . Constants::EDIT_WINDOW_DAYS . ' days ' );
463+ $ editCutoff ->setTime (0 , 0 , 0 );
464+ $ isWithinEditWindow = $ entryDate && $ entryDate >= $ editCutoff ;
465+
476466 $ errorMessage = $ isApproved
477467 ? $ this ->l10n ->t ('Cannot edit this time entry. Please use "Request Correction" for approved entries. ' )
478468 : (!$ isWithinEditWindow
@@ -781,27 +771,17 @@ public function update(int $id, ?string $date = null, ?float $hours = null, ?str
781771 return $ mc0 ;
782772 }
783773
784- // Check if entry can be edited
785- // Allow editing if:
786- // 1. It's a manual entry (user created it themselves) - but not if already approved
787- // 2. It has pending approval status (correction request)
788- // 3. It's an automatic entry that is completed (not yet approved) - allow direct editing for convenience
789- // 4. The entry date is within the last 2 weeks (14 days) - for data integrity and compliance
790- // Do NOT allow editing if entry is already approved (approvedBy is set) or older than 2 weeks
791- $ isApproved = $ entry ->getApprovedBy () !== null ;
792- $ entryDate = $ entry ->getStartTime ();
793- $ editCutoff = new \DateTime ();
794- $ editCutoff ->modify ('- ' . Constants::EDIT_WINDOW_DAYS . ' days ' );
795- $ editCutoff ->setTime (0 , 0 , 0 );
796- $ isWithinEditWindow = $ entryDate && $ entryDate >= $ editCutoff ;
797-
798- $ canEdit = !$ isApproved && $ isWithinEditWindow && (
799- $ entry ->getIsManualEntry ()
800- || $ entry ->getStatus () === TimeEntry::STATUS_PENDING_APPROVAL
801- || ($ entry ->getStatus () === TimeEntry::STATUS_COMPLETED && !$ entry ->getIsManualEntry ())
802- );
774+ // Check if entry can be edited (logic lives in TimeEntry::canEdit to stay DRY)
775+ $ canEdit = $ entry ->canEdit (Constants::EDIT_WINDOW_DAYS );
803776
804777 if (!$ canEdit ) {
778+ $ isApproved = $ entry ->getApprovedBy () !== null ;
779+ $ entryDate = $ entry ->getStartTime ();
780+ $ editCutoff = new \DateTime ();
781+ $ editCutoff ->modify ('- ' . Constants::EDIT_WINDOW_DAYS . ' days ' );
782+ $ editCutoff ->setTime (0 , 0 , 0 );
783+ $ isWithinEditWindow = $ entryDate && $ entryDate >= $ editCutoff ;
784+
805785 $ errorMessage = $ isApproved
806786 ? $ this ->l10n ->t ('Cannot edit this time entry. Please use "Request Correction" for approved entries. ' )
807787 : (!$ isWithinEditWindow
@@ -1047,6 +1027,16 @@ public function update(int $id, ?string $date = null, ?float $hours = null, ?str
10471027 $ entry ->setProjectCheckProjectId ($ project_check_project_id );
10481028 }
10491029
1030+ // Finalise paused entries: when the user supplies an end_time, the entry
1031+ // is no longer orphaned – promote it to completed so all downstream logic
1032+ // (compliance checks, reports, approval flow) treats it correctly.
1033+ if ($ entry ->getStatus () === TimeEntry::STATUS_PAUSED && $ entry ->getEndTime () !== null ) {
1034+ $ entry ->setStatus (TimeEntry::STATUS_COMPLETED );
1035+ if (!$ entry ->getEndedReason ()) {
1036+ $ entry ->setEndedReason (TimeEntry::ENDED_REASON_MANUAL_CLOCK_OUT );
1037+ }
1038+ }
1039+
10501040 // Check rest period compliance before saving (ArbZG §5)
10511041 if ($ entry ->getStartTime ()) {
10521042 $ restPeriodCheck = $ this ->complianceService ->checkRestPeriodForStartTime ($ userId , $ entry ->getStartTime (), $ id );
@@ -1224,8 +1214,8 @@ public function getDeletionImpact(int $id): JSONResponse
12241214 ], Http::STATUS_FORBIDDEN );
12251215 }
12261216
1227- // Check if entry can be deleted
1228- $ canDelete = $ entry ->getIsManualEntry ();
1217+ // Check if entry can be deleted (manual entries + orphaned paused entries)
1218+ $ canDelete = $ entry ->canDelete ();
12291219 $ impact = [
12301220 'canDelete ' => $ canDelete ,
12311221 'isManualEntry ' => $ entry ->getIsManualEntry (),
@@ -1577,8 +1567,8 @@ public function delete(int $id): JSONResponse
15771567 return $ mcDel ;
15781568 }
15791569
1580- // Check if entry can be deleted (only manual entries)
1581- if (!$ entry ->getIsManualEntry ()) {
1570+ // Check if entry can be deleted (manual entries + orphaned paused entries)
1571+ if (!$ entry ->canDelete ()) {
15821572 return new JSONResponse ([
15831573 'success ' => false ,
15841574 'error ' => $ this ->l10n ->t ('Cannot delete automatic time entries ' )
0 commit comments