# HR Module — Business & Functional Documentation

## Overview

The HR module covers the complete employee lifecycle: hiring, master data maintenance, attendance tracking, leave and other request management, payroll processing, and end-of-service settlement. All data is scoped to a branch. Requests pass through a configurable multi-step approval workflow before taking effect.

---

## Setup Entities

Before entering any employee or transaction data, HR administrators configure a set of master tables that drive the rest of the module.

### Departments

Departments group employees by organisational unit (e.g. Finance, Engineering). Each department has a unique code and a translatable name stored in both Arabic and English. Departments can be activated or deactivated without deletion.

### Designations

Designations represent job titles or positions (e.g. Senior Accountant, HR Manager). Like departments, they carry a code, a translatable name, and an active flag.

### Grades

Grades define pay-band levels or seniority tiers. They are referenced on the employee record and can influence salary structure decisions.

### Contract Types

Contract types classify the legal form of employment (e.g. Full-Time Permanent, Fixed-Term, Part-Time). They are referenced when creating employee contracts and job offers.

### Leave Types

Leave types define the categories of leave employees may request (e.g. Annual Leave, Sick Leave, Emergency Leave). Each type carries a `payroll_affects` flag. When this flag is true, approved leave requests of this type cause a deduction from the employee's pay in the payroll run that covers the leave dates.

### Permission Types

Permission types categorise short-period absences or early departures that are tracked separately from full-day leave. They have the same code/name/active structure.

### Loan Types

Loan types categorise employee loans (e.g. Personal Loan, Emergency Loan). Like bonus and leave types, they carry a `payroll_affects` flag that controls whether approved loan installment amounts are pulled into payroll runs.

### Bonus Types

Bonus types categorise one-off bonus grants (e.g. Performance Bonus, Annual Bonus). The `payroll_affects` flag determines whether approved bonuses are included in payroll calculations.

### Penalty Types

Penalty types catalogue disciplinary deduction categories. They carry the same `payroll_affects` flag as other payroll-linked types.

### Earning Types

Earning types are generic allowance categories used when building a salary profile (e.g. Housing Allowance, Transportation Allowance). They are referenced by individual allowance lines on the salary profile.

### Deduction Types

Deduction types are generic recurring deduction categories used in salary profiles (e.g. Health Insurance, Social Insurance).

---

## Employee Master Data

### Creation

Creating an employee begins on the new-employee form. The administrator supplies the employee's personal details, assigns them to a branch, department, designation, and grade, and optionally links them to a candidate record from the recruitment pipeline. The system generates a unique employee code automatically. After saving, the administrator is redirected to the edit screen where all sub-sections (contracts, documents, salary profile, movements, status history) are managed.

### Employment Status

An employee's status can be: `active`, `inactive`, `suspended`, or `terminated`. Changing status creates an immutable status-history record capturing the previous status, the new status, the effective date, and the reason. Only employees with status `active` or `seconded` have `is_active = true`, which controls visibility in dropdowns and payroll eligibility.

### Contracts

Each employee can hold multiple contracts over time. A contract records the contract type, contract number, start date, end date, probation end date, signing date, and status (`draft`, `active`, `expired`, `terminated`). The `is_current` flag marks the operative contract. Contracts are added, edited, and deleted directly from the employee edit screen without leaving the page.

### Documents

Employee documents store identity papers, passports, certificates, medical records, contracts in physical form, and any other files. Each document record captures the document type, file path, expiry date where applicable, and upload metadata. Documents are managed inline on the employee edit screen.

### Salary Profile

Every employee has a current salary profile that defines their pay structure. The profile captures:

- Basic salary amount
- Payment method (bank transfer, cash, or cheque)
- Payroll cycle (monthly, weekly, or daily)
- Effective date range
- Cost centre assignment
- Payroll posting profile reference

Attached to the salary profile are:

- **Allowances** — recurring or one-time earnings added on top of basic salary. Each allowance can be calculated as a fixed amount or as a percentage of basic salary. An effective date range controls which payroll periods the allowance applies to.
- **Deductions** — recurring deductions subtracted from gross pay, with the same fixed/percentage/date-range structure.

Bank accounts are stored at the employee level (not the profile level) and are synced as part of the salary profile save.

When a salary profile is updated, the system upserts the current profile record, then replaces all allowance lines, deduction lines, and bank accounts in a single database transaction.

### Transfers

A transfer records a permanent movement of an employee between branches, departments, designations, or grades. When a transfer is saved, the service immediately updates the employee's own branch, department, designation, and grade fields to reflect the destination values. The transfer record preserves both the origin and destination values for historical reference.

### Secondments

A secondment records a temporary assignment of an employee to a different branch or department, with a start and end date. Unlike a transfer, it does not update the employee's own organisational assignment fields.

---

## Attendance

### Recording Attendance

Attendance records can be entered manually one at a time or imported in bulk from an Excel file or biometric device export. Each record captures:

- Employee and branch
- Attendance date
- Check-in and check-out timestamps
- Worked minutes (calculated from timestamps or entered directly)
- Status: `present`, `absent`, `late`, `early_leave`, or `partial_day`
- Source type: `manual`, `excel`, or `biometric`

When importing from Excel or biometric, the service performs an upsert keyed on employee ID and attendance date, meaning a second import for the same employee on the same day overwrites the earlier record.

### Import Batches

Each bulk import creates an import-batch record that tracks the source type, total rows, processed rows, successful rows, and failed rows. The batch transitions through statuses: `pending` → `processing` → `completed` (or `completed_with_errors` or `failed`). Individual row errors do not abort the entire batch.

### Overtime

Overtime records are entered against a specific employee and optionally linked to an attendance record for the same day. The record stores the overtime date, start time, end time, requested minutes (calculated from times), status (`pending`, `approved`, `rejected`), and source type.

### Absences

Absence records document unplanned absences independently of the attendance stream. Each record carries the absence date, absence type (`unexcused`, `excused`, `sick`, `leave`), status (`open`, `approved`, `rejected`), and an optional link to a corresponding attendance record.

---

## Leave Management

### Leave Types

Leave types are configured in Setup (described above). The key business consideration is the `payroll_affects` flag, which causes deductions for unapproved or unpaid leave categories to appear in payroll runs.

### Requesting Leave

A leave request records the employee, branch, leave type, start and end dates, and reason. If a half-day option is selected, the session (morning or afternoon) is also recorded. The system automatically calculates requested days from the date range (0.5 for a half-day). Supporting attachments may be uploaded.

On creation, an approval workflow is immediately initiated for the request. The workflow is resolved by matching on request type `leave` against the active workflow configuration.

### Approval

Leave requests pass through the configured multi-step approval process. Pending requests appear in the Approvals queue. Each step in the queue is processed by an approver acting in their designated role. Approving all steps marks the request as `approved`; rejecting any step marks it `rejected` and skips remaining steps. The leave request's own `status`, `current_approval_step`, `approved_at`, and `rejected_at` fields are kept in sync with the approval record.

### Balance

Leave balances are not computed as a separate entity; entitlement and consumption tracking is managed externally or through reporting on approved leave requests.

---

## Recruitment

The recruitment pipeline moves from an approved headcount need through to a signed job offer.

### Job Requests

A job request documents a department's need to hire for a specific designation. It captures the requesting branch, department, designation, and the number of positions to fill. Statuses are `draft`, `open`, `approved`, and `closed`. Job requests are the anchor to which candidates are linked.

### Candidates

A candidate represents an individual applicant. Candidates are linked to a job request, a branch, and a designation. Candidate status tracks their pipeline stage: `new`, `screening`, `interview`, `offered`, `accepted`, or `rejected`. Supporting documents (CV, certificates, ID copies) are stored as candidate document records. The `name` field is bilingual (Arabic and English). When a candidate is hired, an employee record can be created from the candidate record by referencing the `candidate_id` on the employee.

### Interviews

An interview is scheduled for a specific candidate and assigned to an interviewer (an admin user). Each interview records the scheduled date/time, interview type, status (`scheduled`, `completed`, `cancelled`), overall result (`pending`, `passed`, `failed`, `on_hold`), and recommendation status (`pending`, `recommended`, `rejected`).

Multiple evaluations can be recorded for a single interview, one per evaluator. Each evaluation captures the evaluator, a numeric score, comments, and an individual recommendation status.

### Job Offers

A job offer is issued to a candidate and references a contract type. It records the offer date, proposed salary, start date, and approval status (`pending`, `approved`, `rejected`). An accepted job offer triggers the creation of an employee record and potentially the first employment contract.

---

## Employee Requests

All request types below share the same approval workflow infrastructure. Each request is created with status `pending`, immediately triggers a workflow, and can carry file attachments. Approval or rejection is recorded on the shared approval log.

### Leave Request

Described in the Leave Management section above.

### Permission Request

A permission request covers short-period absences during working hours (e.g. a medical appointment). It records the employee, permission type, permission date, start time, end time, and the calculated requested minutes. Statuses: `pending`, `approved`, `rejected`, `cancelled`.

### Loan Request

A loan request records a request for a financial advance. It captures the employee, loan type, requested amount, number of installments, installment amount (calculated from amount / installments), deduction start date, and payroll status (`pending`, `processed`, `skipped`). When the loan type has `payroll_affects = true` and the deduction start date falls within a payroll period, the installment amount appears as a `loan` deduction in that period's payroll calculation.

### Bonus Request

A bonus request records a grant or request for a bonus payment. It captures the employee, bonus type, bonus date, amount, and calculation type (fixed or variable). When the bonus type has `payroll_affects = true` and the bonus date falls within a payroll period, the bonus amount appears as an earning in that period's payroll calculation. Statuses: `pending`, `approved`, `rejected`, `cancelled`. Also tracks a payroll status field.

### Data-Change Request

A data-change request allows an employee to formally request a correction to their personal master data. The form captures the specific field to be changed (name, email, phone, address, nationality, marital status, date of birth, national ID number, or passport number), the current value, and the requested new value. On approval, the change must be applied manually by an administrator.

### Complaint Request

A complaint request gives employees a formal channel to raise concerns. It captures a subject, description, and optionally marks the complaint as confidential. The status lifecycle is: `pending` → `approved` / `under_review` / `resolved` / `closed` / `rejected`. A response date is recorded when a response note is first added, and a close date is recorded when the status becomes `closed`.

### Resignation Request

A resignation request initiates the offboarding process. It records the employee, resignation date, reason, requested last working date, and the approved last working date once management confirms. A separate `settlement_status` field tracks the end-of-service settlement progress (`pending`, `processing`, `completed`).

---

## Request Workflow — Multi-Step Approval Configuration

### Configuring Workflows

Before requests can be approved, an administrator defines at least one workflow per request type. A workflow is bound to exactly one request type (leave, permission, loan, bonus, data_change, complaint, or resignation). Only one active workflow is used per request type.

Each workflow contains an ordered list of steps. Each step specifies:

- Sequence order (1, 2, 3, …)
- Approval type: `role` (any admin holding the specified role can act) or `manager` (the requester's direct manager at the specified level, e.g. level 1 = direct manager, level 2 = manager's manager)
- For role-type steps: the target role
- For manager-type steps: the manager level

### How Approval Works

When a request is created or edited (while still pending), the system looks up the active workflow for the request type. It creates an `Approval` record linked to the request and the workflow, then generates one `ApprovalStep` row per workflow step. The first step in sequence is set to `pending`; all subsequent steps are set to `waiting`.

An administrator with the `hr.request_approvals.action` permission visits the Approvals queue, selects a pending approval, and chooses to approve or reject, with optional notes.

On **approve**: the current pending step is marked `approved`. The service checks whether there is a next `waiting` step. If so, that step is advanced to `pending` and the approval's `current_sequence_order` is updated. If there is no next step, the approval is marked `approved`, `completed_at` is set, and the underlying request's `status` is updated to `approved` with an `approved_at` timestamp.

On **reject**: the current step is marked `rejected`, all remaining `waiting` steps are marked `skipped`, the approval is marked `rejected`, and the underlying request's `status` is updated to `rejected` with a `rejected_at` timestamp.

---

## Payroll

### Payroll Periods

A payroll period defines a calendar window for pay calculation. It carries a year, month, start date, end date, and payment date. Status: `open`, `processing`, or `closed`. Period code is generated as `PP-YYYYMM`. Multiple payroll runs can be linked to a single period.

### Payroll Runs

A payroll run represents one execution of payroll for a specific period and optionally a specific branch. Run types are `monthly` (full standard calculation) or `free_salary` (manually entered lines not derived from salary profiles). Status lifecycle: `draft` → `processed` → `approved` → `posted` → `paid`. A separate payment_status tracks whether individual salary payments have been made: `unpaid`, `partially_paid`, or `paid`.

### Salary Calculation

When a run is processed, the calculation engine:

1. Queries all active employees matching the run's branch filter who have a salary profile effective within the period dates.
2. For each employee, resolves the most current effective salary profile.
3. Builds a list of line items:
   - **Basic salary** — the flat amount from the profile.
   - **Allowances** — each active allowance line on the profile whose effective date range overlaps the period. Fixed allowances use their value directly; percentage allowances multiply the percentage against basic salary.
   - **Bonuses** — approved bonus requests with `payroll_affects = true`, whose bonus date falls within the period and whose payroll status is `pending` or null.
   - **Deductions** — each active deduction line on the profile, calculated as fixed or percentage.
   - **Loan installments** — approved loan requests with `payroll_affects = true` whose deduction start date is on or before the period end date and whose payroll status is `pending` or null.
   - **Leave deductions** — approved leave requests whose leave type has `payroll_affects = true`, overlapping the payroll period. Leave days within the period are calculated at a daily rate (basic salary divided by the number of days in the period). Half-day leaves count as 0.5 days.
4. Sums earnings and deductions. Net salary = basic salary + total earnings − total deductions.
5. Creates one `PayrollLine` per employee and one `PayrollLineItem` per line item component.

### Payroll Approval

After processing, the run awaits management approval. The Payroll Approvals section shows pending runs. An administrator can approve (status → `approved`, with approver and timestamp) or reject (status reverted to `draft`, approval fields cleared).

### Payroll Posting

Once approved, a payroll posting record is created for the run. The posting maps payroll totals to general-ledger accounts using the run's payroll posting profile. On the posting action, the service:

1. Sums gross amounts across all payroll lines.
2. Creates a journal entry in the general ledger, with lines for: basic salary (debit), allowances (debit), other earnings (debit), loan receivables (credit), other deductions (credit), and payroll payable (credit for net salary).
3. Posts the journal entry (validates that the fiscal period is open).
4. Marks the posting as `posted` and updates the payroll run status to `posted`.

### Salary Payments

Individual salary payments record the actual disbursement to each employee. A payment links to a payroll run and a specific payroll line. It captures the payment date, amount, payment method (bank transfer, cash, or cheque), and status (`pending`, `processing`, `paid`, `failed`). After each payment is created or updated, the system recalculates the parent run's aggregate payment status (`unpaid`, `partially_paid`, or `paid`). When all lines are paid, the run status advances to `paid`.

---

## End-of-Service Settlement

End-of-service settlement handles the final payment due to a departing employee.

A settlement record links to the employee, their branch, an optional resignation request, and a payroll posting profile. It captures:

- Last working date (defaulted from the approved resignation last working date if a resignation request is linked)
- Service years (calculated from hire date to last working date, in decimal years)
- Gross settlement amount
- Deduction amount
- Net amount (gross minus deductions)
- Settlement reason

Status lifecycle: `draft` → `approved` → `posted`.  
Payment status: `unpaid` → `processing` → `paid`.

When a settlement is created or updated, the linked resignation request's `settlement_status` is set to `processing`. When payment is confirmed, it is set to `completed`.

On posting, the service creates and posts a GL accrual entry (debit end-of-service expense account, credit deductions account if any deductions, credit payroll payable account for net amount). On payment confirmation, a second GL entry is posted (debit payroll payable, credit bank/cash account).

---

## Payroll Posting Profile

A payroll posting profile is a named map of GL account IDs used during payroll posting. Each profile carries account references for:

- Basic salary expense
- Allowance expense
- General earnings expense
- Deduction liability
- Loan receivable
- Payroll payable liability
- Bank/cash account
- End-of-service expense

Profiles are assigned at the payroll run level and optionally overridden at posting time. They can also be assigned to individual employee salary profiles so that employees charged to different cost centres can post to different accounts.

---

## Analytics Dashboard

The HR analytics dashboard aggregates key operational metrics into a single view. It shows headcount by status, recent hire and attrition counts, pending requests by type, payroll run summaries for recent periods, and attendance overviews. Data is read-only and drawn from multiple HR tables.
