This feature adds the ability to delete timesheet periods, time-off requests, leave types, and company holidays from the Workforce tab (web, desktop, and mobile). It addresses Issue #562.
| Entity | Who can delete | When |
|---|---|---|
| Timesheet period | Owner or admin | Only when status is draft or rejected |
| Time-off request | Owner or approver/admin | Only when status is draft, submitted, or cancelled |
| Leave type | Admin only | Only if no time-off request uses this leave type |
| Company holiday | Admin only | Always (no dependencies) |
Submitted, approved, closed, or rejected records that affect audit or reporting cannot be deleted.
- Timesheet periods: Each draft or rejected period has a Delete button (owner or admin).
- Time-off requests: Each draft, submitted, or cancelled request has a Delete button (owner or approver).
- Leave types: In the admin section, each leave type is listed with a Delete button. Delete is blocked with an error if the leave type has any time-off requests.
- Company holidays: Each holiday in the list has a Delete button (admin only).
All delete actions use POST forms with CSRF protection and redirect back to the dashboard after success or error.
Delete is exposed as HTTP DELETE:
| Endpoint | Scope | Notes |
|---|---|---|
DELETE /api/v1/timesheet-periods/{id} |
write:time_entries |
Owner or admin; period must be draft or rejected |
DELETE /api/v1/time-off/requests/{id} |
write:time_entries |
Owner or approver; request must be draft, submitted, or cancelled |
DELETE /api/v1/time-off/leave-types/{id} |
write:reports |
Admin only; returns 400 if leave type has requests |
DELETE /api/v1/time-off/holidays/{id} |
write:reports |
Admin only |
Success: 200 with JSON { "message": "..." }.
Failure: 400 with { "error": "..." } or 403 for permission errors.
- Timesheet periods: Delete button on each draft or rejected period; confirmation dialog then refresh.
- Time-off requests: Delete button on each draft, submitted, or cancelled request (own requests or when user can approve); confirmation then refresh.
See desktop/src/renderer/js/api/client.js (deleteTimesheetPeriod, deleteTimeOffRequest) and desktop/src/renderer/js/app.js (workforce render and handlers).
- Timesheet periods: Popup menu on each period includes Delete when status is draft or rejected.
- Time-off requests: Popup menu includes Delete when status is draft, submitted, or cancelled and the user is owner or approver.
See mobile/lib/data/api/api_client.dart and mobile/lib/presentation/screens/finance_workforce_screen.dart.
- Service:
app/services/workforce_governance_service.pydelete_period(period_id, actor_id)delete_leave_request(request_id, actor_id, actor_can_approve=False)delete_leave_type(leave_type_id)delete_holiday(holiday_id)
- Web routes:
app/routes/workforce.pyβ POST routes for each delete, CSRF and permissions. - API routes:
app/routes/api_v1.pyβ DELETE endpoints with token scopes and admin checks where required.
- Deleting a leave type that has time-off requests is prevented; the API and web UI return a clear error.
- Only draft or rejected periods can be deleted to keep audit history for submitted/approved/closed periods.
- Only draft, submitted, or cancelled time-off requests can be deleted; approved or rejected ones are kept for reporting.