HRM Enhanced Documentation

Complete Master Reference (Original + Enhancements)

HRM Master Reference — ERD & Process Flows

This document unifies the entire Alkareem HRM Module. It combines the original schemas and flows from Employee Onboarding, Attendance Setup, and Payroll, integrated with the critical enhancements required for a complete, robust system based on FQMS analysis.

🟢 NEW (ENHANCEMENT) 🔵 UPDATED CONFIG/FLOW ⚪ ORIGINAL

1. Core Employee Management ERD

erDiagram
    %% ORIGINAL ENTITIES %%
    employees {
        int id PK
        string name
        string code UK
        string son_of
        date dob
        string cnic UK "Soft-delete safe"
        enum gender
        enum marital_status
        enum blood_group
        string religion
        string image_path
        string biometric_id UK "Mapping for device logs"
        enum onboarding_status "docs_pending,policy_pending,active"
        boolean is_active
        timestamp deleted_at "nullable — for rehire support"
    }

    employee_employment {
        int id PK
        int employee_id FK
        int branch_id FK
        int designation_id FK
        int department_id FK
        date joining_date
        date valid_till "Contract expiry"
        decimal salary
        int payment_account_id FK
        int salary_expense_account_id FK
        enum status "draft,active,expired,terminated"
        string location "If diff from branch"
        decimal credit_limit
        string contract_file_path
    }

    employee_contacts {
        int id PK
        int employee_id FK
        string email UK
        string mobile_number
        text current_address
        text permanent_address
        string emergency_contact_name
        string emergency_contact_relation
        string emergency_contact_phone
    }

    employee_academics {
        int id PK
        int employee_id FK
        string degree_title
        string institute_name
        year passing_year
        string grade_or_cgpa
    }

    employee_references {
        int id PK
        int employee_id FK
        string reference_type
        string name
        string relation
        string address
        string designation
        string phone
        string email
    }

    employee_cheque_infos {
        int id PK
        int employee_id FK
        date transaction_date
        string account_number
        string cheque_number
        string cheque_date
        decimal amount
        string cheque_location
        text notes
    }

    employee_guarantors {
        int id PK
        int employee_id FK
        string name
        string son_of
        string relation
        string cnic
        string phone
        string residence_phone
        string occupation
        string city
        string business_address
        string business_phone
        string since_living "Time at address"
        string since_working "Time at job"
        string employer_name
        string attachment_path
    }

    employee_job_histories {
        int id PK
        int employee_id FK
        string company_name
        string designation
        date start_date
        date end_date
        int salary
        string reason_for_leaving
    }

    employee_job_changes {
        int id PK
        int employee_id FK
        enum change_type "Transfer, Promotion, Demotion, Salary_Increment"
        date effective_date
        int previous_branch_id FK
        int new_branch_id FK
        int previous_designation_id FK
        int new_designation_id FK
        decimal previous_salary
        decimal new_salary
        string change_reason
        int approved_by FK
    }

    %% NEW & UPDATED SETUP ENTITIES %%
    designations {
        int id PK
        int branch_id FK "nullable for Global"
        string designation_name UK
        string designation_code UK
        text description "nullable"
        boolean is_active
    }

    departments {
        int id PK
        int branch_id FK "nullable for Global"
        string department_name UK
        string department_code UK
        text description "nullable"
        boolean is_active
    }

    employee_family_members {
        int id PK
        int employee_id FK
        string name
        enum relation
        date dob
        string cnic
        boolean is_nominee
        decimal nominee_percentage
    }

    employee_internal_relations {
        int id PK
        int employee_id FK
        int related_employee_id FK
        string relation_type
    }

    employee_attachments {
        int id PK
        int employee_id FK
        enum attachable_type "cnic,cheque,edu_cert,exp_letter,etc"
        int attachable_id "nullable FK"
        string file_path
    }

    employee_exits {
        int id PK
        int employee_id FK
        enum exit_type "resigned,terminated,contract_ended,absconded,deceased"
        date resignation_date "Date intent was submitted"
        date notice_date
        int notice_period_days
        date last_working_date
        string reason
        enum clearance_status "pending,in_progress,cleared"
        decimal encashment_days "Unused leave payout"
        decimal encashment_amount
        decimal final_settlement_amount
        int salary_calculation_id FK "Nullable (Final Settlement Payroll Run)"
        int manager_approved_by FK
        enum status "pending, approved, rejected, completed"
    }

    employee_rejoinings {
        int id PK
        int employee_id FK
        int exit_id FK
        date rejoining_date
        int new_branch_id FK
        int new_designation_id FK
        decimal new_salary
        string rejoining_reason
    }

    allowance_deductions {
        int id PK
        int branch_id FK "nullable for Global"
        string name
        string type "Allowance, Deduction"
        text description
    }

    employee_allowance_deductions {
        int id PK
        int employee_id FK
        int allowance_deduction_id FK
        decimal amount
        date effective_from
        date effective_to "nullable"
        text description
    }

    operations {
        int id PK
        string name
        boolean is_active
    }

    employee_operations {
        int id PK
        int employee_id FK
        int operation_id FK
    }

    holidays {
        int id PK
        int branch_id FK "nullable for Global"
        string name
        date holiday_date
        boolean is_fixed
    }

    departments ||--o{ employee_employment : "defines"
    designations ||--o{ employee_employment : "defines"
    employees ||--o{ employee_employment : "has"
    
    employees ||--o{ employee_contacts : "has"
    employees ||--o{ employee_academics : "holds"
    employees ||--o{ employee_references : "provides"
    employees ||--o{ employee_guarantors : "has"
    employees ||--o{ employee_cheque_infos : "has"
    employees ||--o{ employee_job_histories : "has"
    employees ||--o{ employee_job_changes : "history"
    employees ||--o{ employee_family_members : "has"
    employees ||--o{ employee_internal_relations : "is"
    employees ||--o{ employee_attachments : "owns"
    
    employees ||--o{ employee_exits : "exits via"
    employees ||--o{ employee_rejoinings : "rejoins via"
    employees ||--o{ employee_allowance_deductions : "has custom components"
    allowance_deductions ||--o{ employee_allowance_deductions : "defines"
    employees ||--o{ employee_operations : "assigned to"
    operations ||--o{ employee_operations : "is assigned"
    holidays }o--|| employees : "applies to (branch-wise)"
            

Employee Lifecycle Flows

flowchart TD
    subgraph "Onboarding Process"
        A1((Hiring Decision)) --> A2["Create Draft employees record\nonboarding_status=docs_pending"]
        A2 --> A3["Create Draft employee_employment record\nSets initial Branch, Department, Designation, Salary"]
        
        A3 --> A6["Document Collection\nCNIC, Guarantors, References"]
        A6 --> A7["Configure Custom Allowances, Deductions & Assign Operations\n(employee_allowance_deductions & employee_operations)"]
        A7 --> A8["Upload to employee_attachments"]
        A8 --> A9["HR Activates employees & employee_employment"]
    end

    subgraph "Job Change (Transfer/Promotion)"
        C1["HR Initiates Job Change"] --> C2["Create employee_job_changes\nSet change_type & effective_date"]
        C2 --> C3["Update employee_employment\nwith new designation/branch/salary"]
        C3 --> C4["Generate Official Letter"]
    end
    
    subgraph "Unified Employee Exit"
        E1(("Resignation/Fire")) --> E2["Create employee_exits\nRecord reason & dates"]
        E2 --> E3["Clearance Checklist & Final Settlement"]
        E3 --> E4["Update employee_employment -> 'terminated'\nemployees.is_active = false"]
    end
            

2. The Master Policy Engine (Attendance & Payroll) FQMS HYBRID ARCHITECTURE

This section defines the centralized 4-tab Policy Engine driven by Designations, and how the Attendance and Payroll processors consume it.

erDiagram
    %% CORE POLICY ENGINE %%
    employees {
        int id PK
    }
    designations {
        int id PK
    }

    payroll_policy {
        int id PK
        string policy_name "e.g., Manager Policy v2"
        int designation_id FK "Anchor for the whole engine (Unique)"
        date effective_date
        date valid_to "nullable"
        boolean is_active
    }

    payroll_policy_branches {
        int id PK
        int payroll_policy_id FK
        int branch_id FK "Multi-branch deployment"
    }

    salary_policies {
        int id PK
        int payroll_policy_id FK
        string salary_type "fixed_basic, target_based_basic, no_basic"
        string target_not_ach_logic "percentage, amount"
        decimal target_not_ach_value
        string sales_level "individual, branch"
        decimal marketing_inc_percent
        decimal inquiry_inc_percent
        decimal recovery_inc_percent
        decimal cash_sale_inc_percent
        decimal recovery_close_percent
        decimal fine_collected_percent
        boolean require_ac_age_for_recovery_inc "For R. Inc. A/C age must >"
        int recovery_ac_age_limit
        boolean start_inc_from_ac_age_limit "Start Incentive from A/C age limit"
    }

    attendance_policies {
        int id PK
        int payroll_policy_id FK
        int paid_holidays_in_month
        int paid_half_days_in_month
        boolean allow_consec_holidays
        boolean deduct_all_on_exceed_limit
        decimal temp_advance_percent
        decimal fixed_advance_amount
        int in_grace_time_mins
        int out_grace_time_mins
        time shift_from_time
        time shift_to_time
        boolean is_sun
        boolean is_mon
        boolean is_tue
        boolean is_wed
        boolean is_thu
        boolean is_fri
        boolean is_sat
        boolean strict_holiday_pay "Sandwich rule"
        boolean crosses_midnight "Night Shifts"
        boolean enable_overtime
        decimal overtime_rate_multiplier "e.g. 1.5x"
        int min_overtime_minutes "Threshold to trigger OT"
    }

    policy_leave_rules {
        int id PK
        int attendance_policy_id FK
        int leave_type_id FK
        decimal total_days_annually "e.g. 18"
        decimal accrued_per_month "e.g. 1.5 (if missing, given as Lump Sum)"
    }

    policy_fine_rules {
        int id PK
        int attendance_policy_id FK
        int minutes_late
        decimal fine_value
        string fine_type "Gross, Basic"
    }



    target_incentive {
        int id PK
        int payroll_policy_id FK
        int operation_id FK
        enum sale_type "Installment, Cash"
        enum target_type "Auto, Manual"
        enum target_level "Branch, Individual"
        decimal target_amount
        decimal incentive_value
        enum incentive_type "Percentage, Amount"
        enum inc_plan "Straight, Slab"
        decimal target_not_achieved_penalty
    }

    product_incentive {
        int id PK
        int payroll_policy_id FK
        int operation_id FK
        enum sale_type "Cash, Installment"
        enum type "Model, Category"
        string item_code
        decimal percent
    }

    operations {
        int id PK
        string name "e.g., Marketing, Recovery, CRC, Verification"
        boolean is_active
    }

    leave_types {
        int id PK
        int branch_id FK "nullable for Global"
        string name
        boolean is_paid
    }

    %% RELATIONSHIPS: POLICY TREE %%
    designations ||--o{ payroll_policy : "owns"
    payroll_policy ||--o{ payroll_policy_branches : "deployed in"
    
    payroll_policy ||--|| salary_policies : "Tab 1"
    payroll_policy ||--|| attendance_policies : "Tab 2"
    payroll_policy ||--o{ target_incentive : "Tab 3"
    payroll_policy ||--o{ product_incentive : "Tab 4"
    
    attendance_policies ||--o{ policy_leave_rules : "has"
    attendance_policies ||--o{ policy_fine_rules : "has"

    leave_types ||--|{ policy_leave_rules : "defines"
    operations ||--o{ target_incentive : "defines comm for"
    operations ||--o{ product_incentive : "defines comm for"
    
    employees ||--o{ employee_operations : "assigned to"
    operations ||--o{ employee_operations : "is assigned"

    %% ATTENDANCE DATA %%
    attendance_punches {
        int id PK
        int employee_id FK
        date punch_date "Optimization/Night Shift"
        datetime punch_time
        enum punch_type "in, out"
        string device_id
    }

    attendance_corrections {
        int id PK
        int branch_id FK "Tracking which HR branch processed it"
        int employee_id FK
        date correction_date
        string original_status
        string corrected_status
        string reason
        int approved_by FK
        enum status "pending, approved, rejected"
    }

    daily_attendances {
        int id PK
        int employee_id FK
        date attendance_date
        time first_in_time
        time last_out_time
        enum status "Present, Absent, Leave, Late, Half-Day"
        int total_work_minutes
        int overtime_minutes "OT Tracking"
    }

    monthly_attendance_summaries {
        int id PK
        int employee_id FK
        year year
        int month
        int total_present_days
        int total_late_days
        int total_leave_days
        int total_overtime_minutes
    }

    employee_leaves {
        int id PK
        int employee_id FK
        int leave_type_id FK
        date start_date
        date end_date
        boolean is_half_day
        enum session "AM, PM"
        enum status "pending, approved, rejected"
        int approved_by FK
    }

    employee_leave_balances {
        int id PK
        int employee_id FK
        int leave_type_id FK
        int year
        decimal allocated_days
        decimal used_days
        decimal expired_days "Wiped at Year-End"
        decimal carried_forward_days "From previous year"
    }

    SALARY_CALCULATIONS {
        int id PK
        int employee_id FK
        int branch_id FK
        int payroll_policy_id FK "Snapshot"
        int month
        int year
        int working_days_in_month
        int present_days
        int absent_days
        int half_days
        int late_minutes
        decimal basic_salary "Base Pay"
        decimal total_incentives "Marketing + Product + CRC"
        decimal total_allowances "House, Fuel, etc"
        decimal attendance_fines
        decimal advance_recovered
        decimal extra_deductions
        decimal overtime_amount "Summary Field"
        decimal gross_salary
        decimal net_salary
        boolean is_final_settlement
        int exit_id FK "nullable"
        enum status "draft, approved, paid"
        date paid_date
        enum payment_mode "Bank, Cash, Cheque"
        int approved_by FK
        int paid_by FK
    }

    SALARY_COMPONENTS {
        int id PK
        int calculation_id FK
        enum component_type "earning, deduction"
        string label
        decimal amount
        string source_type "e.g., Advance, FineRule, Incentive"
        int source_id "FK to source table"
    }

    employee_payslips {
        int id PK
        int salary_calculation_id FK "Base Calculation"
        string payslip_number
        date generated_date
        string pdf_path
        boolean is_emailed
    }

    INCENTIVE_CALCULATIONS {
        int id PK
        int salary_calculation_id FK
        int incentive_rule_id FK "FK to target/product_incentive"
        decimal target_amount
        decimal achieved_amount
        decimal payout_amount
    }

    employee_advances {
        int id PK
        int employee_id FK
        int advance_type_id FK
        enum request_type "Advance, Loan (Legal/Tax distinction)"
        decimal amount_requested
        decimal installment_amount "Calculated if mode=installment"
        int installments_count "Total months"
        string recovery_mode "installment, one_time"
        date recovery_start_date
        enum status "pending, approved, rejected, paid"
        int approved_by FK
        boolean is_settled
    }

    employee_advance_repayments {
        int id PK
        int advance_id FK "FK to employee_advances"
        int salary_calculation_id FK "Nullable (If deducted via payroll)"
        decimal amount
        date repayment_date
        int installment_number
        enum payment_method "salary, cash, bank"
        string reference_number "e.g., Cheque No, Bank Txn ID"
        text notes
    }

    advance_types {
        int id PK
        int branch_id FK "nullable for Global"
        string name
        boolean is_active
    }

    allowance_deductions {
        int id PK
        int branch_id FK "nullable for Global"
        string name
        string type "Allowance, Deduction"
        text description
    }

    employee_allowance_deductions {
        int id PK
        int employee_id FK
        int allowance_deduction_id FK
        decimal amount
        date effective_from
        date effective_to "nullable"
        text description
    }

    employee_operations {
        int id PK
        int employee_id FK
        int operation_id FK
    }

    payroll_locks {
        int id PK
        int branch_id FK "nullable for Global"
        int month
        int year
        boolean is_locked "If true, blocks all attendance & payroll edits"
    }

    %% RELATIONSHIPS: LOG DATA %%    
    employees ||--o{ attendance_punches : "punches"
    employees ||--o{ daily_attendances : "has"
    employees ||--o{ monthly_attendance_summaries : "has"
    employees ||--o{ employee_leaves : "requests"
    leave_types ||--o{ employee_leaves : "type"
    leave_types ||--o{ employee_leave_balances : "type"
    employees ||--o{ employee_leave_balances : "has"
    
    advance_types ||--o{ employee_advances : "categorizes"
    employees ||--o{ employee_advances : "requests"
    employee_advances ||--o{ employee_advance_repayments : "has ledger"
    employees ||--o{ employee_allowance_deductions : "has custom"
    allowance_deductions ||--o{ employee_allowance_deductions : "defines"
    
    SALARY_CALCULATIONS ||--o{ SALARY_COMPONENTS : "has details"
    SALARY_CALCULATIONS ||--o{ INCENTIVE_CALCULATIONS : "has audit trail"
    SALARY_CALCULATIONS ||--o{ employee_payslips : "generates"

    employees ||--o{ employee_operations : "assigned to"
    operations ||--o{ employee_operations : "is assigned"
            

A. Daily Attendance Automation (Powered by Master Policy)

flowchart TD
    subgraph "System Nightly Job"
        S_START((Midnight Trigger)) --> S1["For each Active Employee"]
        S1 --> S1a["Find Employee's designation_id\nFetch active attendance_policies (Tab 2)"]
        S1a --> S2{"Check policy_weekly_holidays\nIs today a weekend?"}
        S2 -- Yes --> S_END1["Mark Status: 'Weekend'"]
        S2 -- No --> S2b{"Check holidays table\nIs today a fixed holiday?"}
        S2b -- Yes --> S_END1b["Mark Status: 'Holiday'"]
        S2b -- No --> S2c{"Check attendance_corrections\n(Status: 'Approved')"}
        S2c -- Found --> S_END1c["Overwrite Status with Correction\n(e.g., Absent -> Present)"]
        S2c -- Not Found --> S3{"Check employee_leaves"}
        
        S3 -- On Leave --> S_END2["Mark Status: 'On Leave'"]
        S3 -- No Leave --> S4["Fetch attendance_punches for punch_date"]
        
        S4 --> S5{Punches Found?}
        S5 -- No --> S_END3["Mark 'Absent'"]
        S5 -- Yes --> S6["Calculate First In / Last Out\nApply shift_from_time and grace_times"]
        
        S6 --> S7["Determine Status (Present, Late, Early Exit)"]
        S7 --> S8["Create/Update daily_attendances"]
    end
                

B. Monthly Payroll Engine (Powered by Master Policy)

flowchart TD
    subgraph "Phase 1: Guard Check & Base Calculation"
        G1((Trigger Payroll Run)) --> G2["Locate Employee's active History for Month\nCheck for Transfers/Designation Changes"]
        G2 --> G2b{"Any Changes Mid-Month?"}
        
        G2b -- No --> G_STD["Load payroll_policy (where current date between eff & valid_to)\nAND employee.branch_id IN (payroll_policy_branches)"]
        G2b -- Yes --> G_SEG["Split Month into Segments\nFetch mapped policy for each segment\n(Matches Segment Designation + Segment Branch)"]
        
        G_STD & G_SEG --> G3["Load child tabs for active segments\nSnapshot policy_id into calculation record"]
        G3 --> S1{"salary_type?"}
        S1 -- "fixed_basic" --> S3["Calculate pro-rated basic using proration_method\n(Sum of all segments)"]
        S1 -- "target_based_basic" --> S4["Check Sales Modules against target_not_ach_value"]
        S3 & S4 --> S5["Store basic_salary in SALARY_CALCULATIONS"]
    end

    subgraph "Phase 2 & 3: Performance, Allowances & Deductions"
        S5 --> I_OP["Fetch employee_operations for employee"]
        I_OP --> I1["Query External Modules (Sales/Recovery) for assigned operation volume"]
        I1 --> I2["Match volume against salary_policies & incentive rules"]
        I2 --> I2b["Create INCENTIVE_CALCULATIONS audit record\n(Rule, Target, Achieved, Payout)"]
        
        I2b --> AL1["Fetch employee_allowance_deductions\nWhere effective_from <= Month\nAND (effective_to IS NULL OR >= Month)"]
        AL1 --> AL2{"Type?"}
        AL2 -- "Allowance" --> AL3["Create Earning Component\nSum -> total_allowances"]
        AL2 -- "Deduction" --> AL4["Create Deduction Component\nSum -> extra_deductions"]

        AL3 & AL4 --> I3["Create SALARY_COMPONENTS for Incentives"]
        
        I3 --> D1["Fetch Late Minutes\nApply policy_fine_rules"]
        D1 --> D2["Check employee_advances\n(Extract Installment/Recovery)"]
        D2 --> D3["Create SALARY_COMPONENTS for Fines & Advances"]
    end

    subgraph "Phase 4: Net Pay & Approval"
        D3 --> F1["Net Pay = (Basic + Incentives + Allowances) - (Fines + Advances + Extra)"]
        F1 --> F1b{"Is this a FINAL Settlement?"}
        F1b -- Yes --> F1c["Calculate Leave Encashment\nAdd to SALARY_COMPONENTS"]
        F1b -- No --> F2
        F1c --> F2["Finalize SALARY_CALCULATIONS record"]
        F2 --> F3["HR/Manager Review & Approve (Status='approved')"]
        F3 --> F5["Finance Disburses (Status='paid')"]
    end

    subgraph "Manual / Full Advance Recovery"
        M1((Direct Payment)) --> M2["Employee pays via Cash/Bank"]
        M2 --> M3["Insert record into employee_advance_repayments"]
        M3 --> M4["Check Total Sum of Repayments against amount_requested"]
        M4 -- "If Fully Paid" --> M6["Mark employee_advances.is_settled = true\nSet status='paid'"]
    end
                

3. Strategic Operation Flows (Integration & Payout)

A. Biometric Machine Log Integration

flowchart TD
    B1((Biometric Device)) -- "Punches Captured" --> B2["Raw Data (CSV/TXT/API)"]
    B2 --> B3["Internal Import Service\n(Parses Employee Code + Timestamp)"]
    B3 --> B4["Bulk Insert into attendance_punches"]
    B4 --> B5["Nightly Job triggers at Midnight\nto process punches into Daily Attendance"]
                

B. Salary Disbursement & Payout Flow

flowchart TD
    P1((Calculation Approved)) --> P2["Generate Bank Transfer Sheet\n(Filter: status='approved' & branch_id)"]
    P2 --> P3["Finance Final Review"]
    P3 --> P4{"Disbursement Method?"}
    P4 -- "Bank" --> P5["Upload to Bank Portal\nMark Calculation as 'paid'"]
    P4 -- "Cash" --> P6["Disburse via Cashier\nMark Calculation as 'paid'"]
                

C. Bulk Attendance CSV Upload Flow (Offline/Weekly Sync)

flowchart TD
    U1((Manual Sync Needed)) --> U2["HR selects Branch & Target Month"]
    U2 --> U3["Upload CSV File\n(biometric_id, timestamp, type)"]
    
    subgraph "Phase 1: Validation & Bulk Ingest"
        U3 --> V1["Validate biometric_id against employees table"]
        V1 --> V2["Parse Timestamps & Remove Duplicates"]
        V2 --> V3["Bulk Insert into attendance_punches\n(Set punch_date for each record)"]
    end
    
    subgraph "Phase 2: Manual Processing"
        V3 --> P1["Trigger 'Process Range' for selected Month"]
        P1 --> P2["Loop through each Date in Range"]
        P2 --> P3["Run 'Detailed Punch Logic' for each Employee"]
        P3 --> P4["Update daily_attendances\n(Status, Late Mins, etc.)"]
    end
    
    P4 --> U_END((Month Processed Successfully))
            

5. Edge Case Processing & Business Rules

Segmented Payroll Logic

To solve the "Headache" of mid-month transfers or joining/exits, the system uses Time Segmentation:

  • The Rule: The month is split into segments based on employee_job_histories or employee_job_changes.
  • Who Pays? The Current / Final Branch of the month where the employee is active on the Payroll Lock Date (typically 25th-30th) pays the full salary.
  • Which Policy? Each segment uses its own policy. If Segment A was in Branch 1 (Designation X) and Segment B is in Branch 2 (Designation Y), the basic salary and commissions are calculated separately for each date range and summed up.

Proration Formulas

Strict Working Days Proration

Basic * (Attended + Paid Holidays) / Total Monthly Working Days

The system strictly calculates salary based only on days actually presented or officially paid. Unattended days automatically resolve to zero pay without needing separate fine deductions for the basic calculation.

Attendance Regularization (Corrections)

Handles missed punches or system errors with a full audit trail:

  • The Flow: Request Created -> Reason Provided -> Manager/HR Approval.
  • The Effect: Once 'Approved', the Nightly Job ignores machine data and uses the correction status for daily_attendances.
  • Audit: `original_status` is preserved in the attendance_corrections table for compliance.

Leave Encashment Logic

Calculated during Final Settlement/Exit:

Payout = (Basic Salary / 30) * Unused Balance * Encash_Factor%

Where Encash_Factor% is defined in the policy (e.g., 50% or 100% of the balance is paid as cash).

Biometric Integration Mapping

To bridge the gap between hardware and software, the system follows this mapping protocol:

Machine User ID (e.g. 125)

employees.biometric_id

The Bridge

ERP Employee Code (e.g. EMP-001)

Advanced Edge Cases & Resolutions

1. Night Shift Transitions

Issue: Spans two calendar dates.
Resolution: If POLICY_WORK_SCHEDULES.crosses_midnight is true, any OUT punch occurring before to_time + out_grace on Day 2 is hard-attributed back to Day 1's punch_date.

2. Continuous Absence (Sandwich Rule)

Issue: Holiday falls between unapproved absences.
Resolution: If strict_holiday_pay is true, the system checks the working day before & after a holiday. If BOTH are 'Absent', the holiday is marked as 'Absent' (unpaid). If on approved leave, the sandwich rule is bypassed.

3. Mid-Month Policy Revision

Issue: HR changes a policy mid-month without a transfer.
Resolution: Policies are version-locked. HR creates a new version with an effective_date. The Engine treats this exactly like a Job Transfer, triggering time-segmented calculation automatically.

4. Multi-Device Conflicts

Issue: Employee clocks in on Device A and B at same time.
Resolution: The Bulk Sync script deduplicates globally by biometric_id. Any punch within a 5-minute window of another punch for the same ID is discarded, regardless of device_id.

5. Advance Recovery vs Zero Pay

Issue: Installment due, but net pay is negative/zero.
Resolution: Installment deductions are capped at Net Salary (post-fines). Unrecovered amounts automatically carry forward, extending the schedule until is_settled=true.

6. Overlapping Leave Guard

Issue: Employee requests leave over existing leave.
Resolution: Hard validation layer. employee_leaves throws a unique constraint exception if the requested start/end dates intersect with any 'approved' or 'pending' request for that user.

7. Same-Month Rejoining

Issue: Exit on 15th, Rejoin on 20th.
Resolution: Handled natively by Segmented Logic. The exit closes job_histories. The rejoin opens a new one. The days in between (16-19) are dead zones resulting in 0 pay for that segment.

8. Incentive Target Resolution

Issue: Branch hits target, Individual does not.
Resolution: Incentives are Cumulative. The system generates an Earnings component for the Branch hitting the target, passing the reward to everyone, but skips the Individual component for the underperformer.

9. Leave Accrual Engine (Earned vs Lump Sum)

Issue: Annual leaves typically build up monthly (e.g. 1.5 days/mo), but Casual leaves are granted upfront.
Resolution: policy_leave_rules uses accrued_per_month. If NULL, the full `total_days_annually` is allocated as a Lump Sum on Jan 1st. If 1.5, a separate Monthly Background Job automatically queries active employees on that policy and increments their employee_leave_balances by 1.5 on the 1st of every month.

10. Overtime Conversion Formula

Issue: Need to securely translate OT minutes into a monetary figure.
Resolution: The Payroll engine dynamically sums total_overtime_minutes from the monthly summary. Payout = (total_overtime_minutes / 60) * (Basic Salary / Expected Monthly Hours) * overtime_rate_multiplier. This is stored directly in SALARY_CALCULATIONS.overtime_amount.

11. Strict Allowance Proration

Issue: Mid-month joiners receiving full monthly fixed allowances.
Resolution: Fixed Allowances are prorated exactly like the Basic Salary. The engine uses the strict Working Days method applied only over the intersection of the employee's active effective_from & effective_to dates and the current payout month.

12. Year-End Leave Expiry Job

Issue: Unused non-carry-forward leaves accumulating infinitely.
Resolution: A scheduled background job sweeps employee_leave_balances on the final day of the policy cycle. Formula: expired_days = allocated_days - used_days - carried_forward_days. The active balance is then zeroed out to prevent infinite accumulation or incorrect encashment.

13. Immutable Payroll Locks

Issue: HR approving attendance corrections after salaries are paid.
Resolution: The moment a salary calculation reaches status='approved', the system generates a record in the payroll_locks table for that branch/month. This acts as a hard guard: any subsequent Attendance Corrections or Policy changes for that period are instantly rejected by the system.

14. Cross-Branch Policy Conflicts (Latest-Active Rule)

Issue: Overlapping active policies for the same designation mapped to the same branch.
Resolution: The system permits multiple policies to co-exist for the same branch and designation. To resolve conflicts, the Payroll Engine dynamically selects the latest active policy by ordering by effective_date DESC, safely ignoring older overlapping policies at runtime.

4. Master Logic & Issue Index

Category Key Logic / Issue Status Location
Core HR Unified Branch/Dept/Designation Hierarchy COMPLETED Section 1 ERD
Core HR Onboarding Lifecycle (Draft -> Active) COMPLETED Section 1 Flow
Operations Operation Assignment to Employees COMPLETED Section 1 ERD
Policy Engine 4-Tab Policy Anchor (Salary, Attend, Target, Product) COMPLETED Section 2 ERD
Policy Engine Designation-Based Policy Inheritance COMPLETED Section 2 ERD
Policy Engine Multi-Branch Policy Mapping (Pivot Table) COMPLETED Section 2 ERD / Flow 1
Attendance Biometric Punch Integration Flow COMPLETED Section 3 Flow
Attendance Leave Accrual Engine (Earned vs Lump Sum) COMPLETED Section 2 ERD / Sec 5
Attendance Fixed/Gazetted Holiday Management COMPLETED Section 1/2 ERD
Payroll Volume-Based Operational Commissions COMPLETED Section 2 Flow
Payroll Custom Allowances & Deductions COMPLETED Section 2 ERD/Flow
Advances Automated Installment Recovery Logic COMPLETED Section 2 ERD/Flow
Attendance Overtime Calculation (Threshold & Multiplier) COMPLETED Section 2 ERD
Attendance Half-Day Leave & AM/PM Session Support COMPLETED Section 2 ERD
Attendance Annual Leave Roll-Over (Carry Forward) COMPLETED Section 2 ERD
Advances Loan vs Advance Distinction (Legal/Tax) COMPLETED Section 2 ERD
Finance Payslip PDF Generation & Tracking COMPLETED Section 2 ERD
Finance Date-Bound Fixed Allowances Engine COMPLETED Section 2 & 3
Finance Audit Redundancy Pruning (Final Schema) COMPLETED Section 1 ERD
Approvals Immutable Payroll Locks COMPLETED Section 2 ERD / Sec 5
Attendance Year-End Leave Expiry Job COMPLETED Section 5
Payroll Overtime Conversion Formula COMPLETED Section 5
Payroll Allowance Proration Engine COMPLETED Section 5
Approvals Approval Stage for Leaves, Exits, Advances, Salary COMPLETED All ERDs/Flows
Finance Salary Disbursement via Payout Accounts COMPLETED Section 3 Flow
Production Mid-Month Transfer & Segmented Payroll COMPLETED Section 2/5 Flow
Production Biometric Mapping (Device UserID to ERP) COMPLETED Section 1/5 ERD
Audit/Legal Attendance Regularization & Correction Trail COMPLETED Section 2/5 Flow
Audit/Legal Policy Versioning (valid_to) & Snapshotting COMPLETED Section 2 ERD/Flow
Audit/Legal Detailed Salary Audit (Days/Mins/Policy Ref) COMPLETED Section 2 ERD
Audit/Legal Automated Leave Encashment on Exit COMPLETED Section 1/5 Flow
Operations Bulk Attendance Upload Flow (Manual/Offline) COMPLETED Section 3-C Flow