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_historiesoremployee_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_correctionstable 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:
employees.biometric_id
The Bridge
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 |