1. Home
  2. HRM
  3. Leaves
  4. Leaves Approval & Permissions

Leaves Approval & Permissions

What This Page Covers

This page is the permission rulebook for the Leaves module — exactly who can approve, reject, cancel, edit, or mark unnotified any given leave row, and under what row state each of those actions is allowed. It is the page the Daai client uses as its source of truth (see the matrix in leave-permissions.service.ts), so what you read here is what the UI actually enforces row-by-row.

📍 Screen: HRM > Leaves — every action button (HOD ▾, Manager ▾, Cancel, Unnotified) on each leave row is governed by the rules below. The same rules apply when the same actions appear inside the Leave aside (View / Edit drawer).

👥 The Three Approver Roles

RoleHow it’s identifiedScope
Reporting ManagerThe user listed as the leave applicant’s Reporting Manager on the employee record. The leave row carries this person as reportingManager.Manager-side approve / reject for leaves of their direct team only — the user must match the row’s reporting-manager field.
Department Head (HOD)The user listed as Head of the applicant’s department. The leave row carries this person as departmentHead.HOD-side approve / reject for leaves inside their department only — the user must match the row’s HOD field.
Override UserAny role granted the Leave Override permission under User Management > Roles > Leaves. Typically reserved for HR / Admin.Can step in and act on any row in the company — Override bypasses both the HOD and the Manager identity checks and unlocks the late-stage cancel / edit / unnotified actions.

💡 Tip — two distinct permissions: The Leaves module exposes two separate permissions in Roles: Leave Approval (lets the user act in their own HOD / Manager role) and Leave Override (lets the user act on anyone’s row, regardless of identity). Most line managers only need Leave Approval; only HR / Admin should hold Leave Override.

✅ The Two-Step Approval Rule

Each leave row carries two independent approval flags — an HOD side and a Manager side — plus an overall status that is derived from them:

HOD sideManager sideOverall statusSalary effect
PendingPendingPendingTreated as not-yet-approved; not deducted as paid leave until both sides approve.
ApprovedPendingPendingStill pending — both sides must approve.
PendingApprovedPendingStill pending — both sides must approve.
ApprovedApprovedApprovedConsumes the paid balance for the chosen leave type (or splits Paid + Unpaid if balance is short).
RejectedanyRejectedOne rejection fails the whole request, regardless of the other side.
anyRejectedRejectedOne rejection fails the whole request, regardless of the other side.

📌 Key rule: the overall leave is granted only when both Manager and HOD approve. A single rejection on either side fails the request immediately — the salary engine then treats those days as Rejected (i.e. as absent), not as approved leave.

The HOD ▾ and Manager ▾ chips on the leaves grid are independent — clicking one updates only its own side; the other side stays unchanged until that approver acts. Override Users see both chips active and can substitute for either side when the natural approver is unreachable.

🔐 Per-Action Capability Matrix

The table below is the canonical capability matrix the UI enforces on every row. Permission means a role flag (set under User Management > Roles > Leaves); Row state is what the row itself must be in for the button to enable.

ActionPermission requiredIdentity checkRow state must be
Approve / Reject (HOD side)Leave Approval or Leave OverrideIf only Leave Approval: user must be the row’s departmentHead. If Leave Override: identity check is skipped.HOD side = Pending, overall not Rejected, not cancelled
Approve / Reject (Manager side)Leave Approval or Leave OverrideIf only Leave Approval: user must be the row’s reportingManager. If Leave Override: identity check is skipped.Manager side = Pending, overall not Rejected, not cancelled
Cancel LeaveLeave Approval or Leave OverrideNone — anyone holding either permission can cancel an Approved leave.Overall = Approved, not already cancelled
Mark as UnnotifiedLeave Approval or Leave OverrideNone — anyone holding either permission can mark a Rejected absence as Unnotified.Overall = Rejected, not already marked Unnotified, not cancelled
Edit Leave (after submit)Leave OverrideNone — Override unlocks Edit for any row.Any state except cancelled (cancelled rows are read-only)
See HOD / Manager / Cancel / Unnotified action columnsLeave Approval or Leave Override
Resolve Attendance × Leave MismatchesLeave OverrideReconciliation toggle is hidden for users without Leave Override

⚠️ Why the row-state guard matters: the buttons stay disabled rather than vanishing when a row is in the wrong state — e.g. you cannot Cancel a Pending leave, and you cannot mark a still-Approved leave as Unnotified. This prevents a single click from undoing days that the salary engine has already paid out.

⚙️ Special Cases the Override User Handles

Four scenarios cannot be fixed by the natural approver and require the Leave Override permission:

ScenarioWhat you doWhat the system does
Approved leave but employee actually worked that dayOpen the row → Cancel Leave (or use the Reconciliation grid).The leave is cancelled, the row is logged as cancelled in Change Log, and the deducted paid balance is restored.
Leave was rejected but employee was still absentOpen the row → Mark Unnotified.The day is flagged as Unnotified Leave in the change log and is treated as unpaid at salary generation, regardless of paid-leave balance.
Fewer or more days were actually taken than approvedOpen the row → Edit → adjust From / End dates (and Half Period if applicable).Less Leave Taken: the unused days are added back to the balance. More Leave Taken: the extra days are validated against remaining balance — they are pushed into Paid if balance allows, otherwise auto-split into Paid + Unpaid.
Paid leave applied beyond available balanceNo special action — applied / approved as a normal leave.The system auto-splits the date range: the days within balance become Paid; the remaining days become Unpaid. The Total Paid / Total Unpaid fields on the form show this split before approval.

📌 Reconciliation grid shortcut: All four override scenarios above are also reachable from HRM > Leaves > Reconciliation as one-click actions per day. Leaves created from the Reconciliation grid are auto-approved (HOD + Manager approval skipped), so use that view only after you have verified the day’s attendance evidence.

🛠️ Behind the Scenes — API Casing

When the UI sends an approve or reject action, the third URL segment is the role the user is acting as — and it must be lowercase:

  • GET leave/approve/:leave_id/:approved_by/:approving_as
  • GET leave/reject/:leave_id/:rejected_by/:rejecting_as

The server compares :approving_as / :rejecting_as with strict equality against lowercase "hod" and "manager". Mixed-case strings (e.g. "HOD", "Manager") silently bypass both branches — no status fields update, and the row stays Pending even though the API call returns 200.

⚠️ If you build automation: always send hod or manager in lowercase when scripting against the leave approve / reject endpoints. The Daai UI does this for you automatically; manual integrations need to mirror that contract.

📝 Audit Trail — Every Action is Permanent

  • Every state change — apply, approve, reject, cancel, edit, mark unnotified, reconciliation action — is appended to the Change Log tab inside the leave aside, with the user, timestamp, and the before / after values.
  • Change-log entries are written at the moment of Save (not on every keystroke), so the timeline mirrors actual user actions.
  • Change-log entries are permanent; they cannot be edited or deleted, even by an Override User. This is the audit guarantee for compliance reporting.
  • The Salary engine reads the latest leave state at salary-generation time — so any approve / cancel / unnotified flip you make before running salary will be reflected in that month’s payroll. Flips made after salary generation only affect the next cycle.

📊 Quick Reference — “Who Can Do What”

ActionEmployee (self)Reporting ManagerHODOverride User
Apply Leave✅ Yes (own)✅ Yes (own + team, if Create perm)✅ Yes (own + dept, if Create perm)✅ Yes (anyone)
View Leave Row✅ Own only✅ Team (Read All)✅ Department (Read All)✅ All
Approve / Reject — Manager side❌ No✅ Yes (own team)❌ No (unless also Override)✅ Yes (any row)
Approve / Reject — HOD side❌ No❌ No (unless also Override)✅ Yes (own dept)✅ Yes (any row)
Cancel Approved Leave❌ No✅ Yes (with Leave Approval)✅ Yes (with Leave Approval)✅ Yes
Mark Rejected Leave as Unnotified❌ No✅ Yes (with Leave Approval)✅ Yes (with Leave Approval)✅ Yes
Edit Leave (after submit / approval)❌ No❌ No❌ No✅ Yes
Resolve Attendance × Leave Mismatches❌ No❌ No❌ No✅ Yes

💡 Tip — always update before payroll: Run any pending approve / cancel / mark-unnotified work before the Salary Generation Date. The salary engine reads leave status as it stands at generation time; cleaning up afterwards needs a salary regenerate to flow into payslips.

⚠️ Warning — restrict Leave Override: Misusing Override can quietly cancel approved leaves, change paid-vs-unpaid splits, and shift salary deductions across employees. Grant Leave Override only to authorised HR / Admin roles, and audit the Change Log periodically.

How can we help?