# Leave Management — Technical Guide

How the **Leave** module works in the Office Management System: roles, quotas, partial review, half-day leave, special leave grants, attendance sync, API, and database setup.

> **Simple guide for staff:** [LEAVE_AND_ATTENDANCE_README.md](../LEAVE_AND_ATTENDANCE_README.md)  
> **Admin tasks:** [ADMIN_GUIDE.md](../ADMIN_GUIDE.md)  
> **Developer map:** [PROJECT_STRUCTURE.md](../PROJECT_STRUCTURE.md)

---

## Overview

Staff request time off with **title**, **reason**, **category** (sick or casual), **duration** (full day, date range, or half day), and optional **description**. Applications start as **pending** until **Super Admin** or **Manager** reviews them **per weekday**.

- **Super Admin** and **Manager** can approve/reject (including Manager reviewing own leave).
- **Super Admin cannot apply** for leave.
- **Managers, Team Leads, and Employees** can submit applications.
- **Approved** (or partially approved) days sync to **attendance** as `leave` or `half_day`.
- **Weekends are not counted** in leave day totals or quota.
- **Company holidays** are excluded from leave day counts (see `companyHolidayService.js`).
- **Special leave** (child birth, wedding, etc.) can be **granted by admin** without using sick/casual quota.

---

## Roles and permissions

| Role | Apply | View own | View all | Review | Grant special |
|------|-------|----------|----------|--------|---------------|
| **Super Admin** | No | — | Yes | Yes | Yes |
| **Manager** | Yes | Yes | Yes (org) | Yes (incl. own) | Yes |
| **Team Lead** | Yes | Yes | No | No | No |
| **Employee** | Yes | Yes | No | No | No |

Route guards (`src/routes/leaveRoutes.js`):

- `POST /api/leaves` — `manager`, `team_lead`, `employee`
- `PATCH /api/leaves/:id/review` — `super_admin`, `manager`
- `POST /api/leaves/grant-special` — `super_admin`, `manager`

---

## Categories and yearly quotas

| Category | Default limit | Notes |
|----------|---------------|--------|
| **Sick** | 12 days / year | Per employee (`users.sick_leave_quota`) |
| **Casual** | 12 days / year | Per employee (`users.casual_leave_quota`) |
| **Combined** | 24 days / year | Sick + casual together |
| **Special** | Admin-granted | Child birth, wedding — see `special_leave_categories.sql` |

### Day counting

- Only **weekdays** (Mon–Fri) count toward quota and attendance.
- **Company holidays** in range are skipped (not counted as leave days).
- Example: Fri–Mon leave = **2 days** (Fri + Mon), not 4.
- **Half day** = **0.5** from the chosen category quota.
- **Pending**, **approved**, and **partial** approved days count toward quota when validating new requests.
- **Rejected** days do not count.

---

## Application statuses

| Status | Meaning |
|--------|---------|
| **pending** | Awaiting Super Admin or Manager review |
| **approved** | Every requested weekday approved |
| **rejected** | Every requested weekday rejected |
| **partial** | Mix of approved and rejected weekdays |

Once fully reviewed, the application cannot be reviewed again (create a new request if dates change).

---

## Review workflow (per day)

1. Reviewer opens **Leaves** or **Pending leave approvals** → **Review** on a pending row.
2. Modal shows each **weekday** in the range with checkboxes.
3. **Approve all** / **Reject all** shortcuts available.
4. Optional **note to employee**, then **Submit review**.
5. Final status derived from day choices: all approved → `approved`; all rejected → `rejected`; mixed → `partial`.

Partial reviews update attendance **only for approved days**. Rejected days follow normal attendance rules (present/half/absent/holiday).

Push notifications are sent to the applicant on review (see `notificationService.js`).

---

## Special leave (admin grant)

Super Admin and Manager can grant special leave from the **Attendance** page (`ManageSpecialLeavePanel`):

- Categories: child birth, wedding, and other special types (`special_leave_categories.sql`)
- Creates an approved leave application and syncs attendance for the date range
- Does not consume sick/casual quota

API: `POST /api/leaves/grant-special`

---

## Attendance integration

| Situation | Attendance |
|-----------|------------|
| Approved full day | `leave`, 0h |
| Approved half day | `half_day` |
| Partial — approved day | `leave` or `half_day` |
| Partial — rejected day | Unchanged (may show absent if no check-in) |
| Pending | No automatic row |
| Rejected | No change |
| Weekend in range | Skipped (company holiday) |
| Company holiday in range | Skipped |

Service: `markAttendanceLeaveForRange()` in `src/services/leaveService.js`.

Calendars merge leave rows with real check-in sessions via `src/utils/attendanceEnrichment.js`.

---

## REST API

Base: `/api/leaves` (JWT required).

### `POST /api/leaves`

**Roles:** manager, team_lead, employee

```json
{
  "title": "Family function",
  "reason": "Travel",
  "leave_category": "casual",
  "duration_type": "full",
  "start_date": "2026-06-10",
  "end_date": "2026-06-12"
}
```

Half day: `"duration_type": "half"`, same start/end date.

### `GET /api/leaves`

- Non-admin: own applications only
- Super Admin / Manager: all; optional `?status=pending`

### `GET /api/leaves/stats?month=YYYY-MM`

Month and yearly quota stats for the requester (admin gets org totals).

### `PATCH /api/leaves/:id/review`

**Roles:** super_admin, manager

```json
{
  "approved_dates": ["2026-06-10", "2026-06-11"],
  "rejected_dates": ["2026-06-12"],
  "review_note": "Optional message"
}
```

Or use legacy `status: "approved" | "rejected"` for all-or-nothing review.

### `POST /api/leaves/grant-special`

**Roles:** super_admin, manager

Admin-granted special leave for an employee (see validators in `leaveValidators.js`).

---

## Database setup

Run in Supabase (see [backend README](./README.md) for full order):

| File | Purpose |
|------|---------|
| `sql/leaves.sql` | Base table |
| `sql/leave_category_migration.sql` | Sick/casual column |
| `sql/leave_quota_migration.sql` | Per-user quotas |
| `sql/leave_half_day_migration.sql` | Half-day support |
| `sql/leave_partial_review_migration.sql` | Per-day review + partial status |
| `sql/special_leave_categories.sql` | Special leave types |
| `sql/company_holidays.sql` | Company holidays (affects leave day counting) |
| `sql/attendance.sql` | Attendance sessions |

---

## Dashboard UI

| Page | Path |
|------|------|
| Leave applications | `/leaves` |
| Pending approvals | `/leaves/pending` |
| Leave calendar | `/leave-calendar` |
| Grant special leave (admin) | Attendance page → `ManageSpecialLeavePanel` |

Components:

| File | Purpose |
|------|---------|
| `src/pages/leaves/index.js` | Main leave hub |
| `src/pages/leaves/pending.js` | Pending queue |
| `src/components/leaves/LeaveReviewModal.js` | Per-day review modal |
| `src/components/attendance/ManageSpecialLeavePanel.js` | Admin special leave grant |
| `src/lib/leaveStats.js` | Quota calculations |
| `src/lib/leaveCalendar.js` | Calendar day status map |
| `src/hooks/useLeaveDeepLink.js` | Push notification → scroll to leave row |

---

## Source files

| Area | Path |
|------|------|
| Business logic | `src/services/leaveService.js` |
| Validation | `src/validators/leaveValidators.js` |
| Controllers | `src/controllers/leavesController.js` |
| Routes | `src/routes/leaveRoutes.js` |
| Company holidays | `src/services/companyHolidayService.js` |
| Frontend API | `Office-management-system-dashboard/src/services/leavesService.js` |

Full map: [PROJECT_STRUCTURE.md](../PROJECT_STRUCTURE.md)

---

## Troubleshooting

| Problem | Fix |
|---------|-----|
| Quota exceeded | Check pending + approved usage for the year |
| Missing `leave_category` | Run `leave_category_migration.sql` |
| Partial review not working | Run `leave_partial_review_migration.sql` |
| Special leave categories missing | Run `special_leave_categories.sql` |
| Manager cannot review | Confirm role is `manager`; route allows manager |
| Approved leave not on attendance | Confirm status is approved/partial; check weekday dates |
| Holiday days counted in leave | Run `company_holidays.sql`; verify holiday dates in DB |

---

*Matches OMS leave module: sick/casual quotas, half-day, per-day review, special leave grants, Manager + Super Admin approval, attendance sync.*
