Skip to content

aliraxa29/overtime

Overtime Management for HRMS v15

CI License: MIT Python 3.10+ Frappe v15 PRs Welcome

A Frappe/HRMS v15 app that automatically calculates overtime hours from Employee Checkin records. Supports overnight shifts, Ramadan schedules with religion-based rules, configurable rounding, rate multipliers, and an approval workflow.


Table of Contents


Features

Feature Description
Auto-calculation Overtime calculated on Attendance submit via doc_events hook
Overnight shifts Full support for shifts crossing midnight (e.g. 23:30 → 07:30)
Ramadan mode Date-range activation with religion-based shift schedules
Shift rule scoring Weighted matching: period → religion category → shift type → department
Food/Suhoor breaks Configurable break deductions per shift rule
Grace period Late arrival / early departure tolerance (per shift rule)
Rounding Round Up, Round Down, or Round to Nearest (configurable interval)
Rate multipliers Separate rates for normal days vs holidays
Min/Max caps Minimum minutes threshold, maximum hours per day
Approval workflow Optional manager approval before overtime is finalized
Bulk operations Recalculate / bulk-submit overtime via API
Daily scheduler Fallback daily job to catch missed attendance events
Attendance sync Overtime hours and entry link written back to Attendance record

Installation

Prerequisites

  • Frappe v15
  • HRMS v15 (installed and configured with Shift Types and Employee Checkin)
  • Python 3.10+

Install

cd $PATH_TO_YOUR_BENCH

# Get the app
bench get-app $URL_OF_THIS_REPO --branch develop

# Install on your site
bench --site your-site.local install-app overtime

# Run migrations
bench --site your-site.local migrate

The after_install hook automatically:

  1. Creates custom fields on Employee and Attendance
  2. Creates default Overtime Settings
  3. Creates 7 default Overtime Shift Rules

Configuration

Overtime Settings

Navigate to Overtime Settings (single DocType) to configure global behavior.

Field Type Description
enabled Check Master switch — disables all overtime processing when off
overtime_based_on Select Shift Hours (scheduled vs actual) or Fixed Hours (fixed daily threshold)
minimum_overtime_minutes Int Minimum minutes before overtime counts (e.g. 15 = ignore <15min)
max_overtime_hours_per_day Float Daily cap (e.g. 4.0)
overtime_rounding Select No Rounding, Round Up, Round Down, Round to Nearest
rounding_interval_minutes Int Interval for rounding (e.g. 15 = round to 15-min blocks)
default_overtime_rate_multiplier Float Normal-day rate (e.g. 1.5x)
holiday_overtime_rate_multiplier Float Holiday rate (e.g. 2.0x)
require_approval Check If enabled, entries are created as Draft for manager approval
auto_create_overtime_entry Check Auto-create Overtime Entry on Attendance submit
ramadan_mode_enabled Check Enable Ramadan period shift rules
ramadan_start_date Date Ramadan period start
ramadan_end_date Date Ramadan period end

Overtime Shift Rules

Navigate to Overtime Shift Rule list to manage shift definitions.

Each rule defines:

Field Description
shift_name Display name (e.g. "Morning", "Night")
applicable_period Standard or Ramadan
employee_category All, Muslim, or Non-Muslim
check_in_time / check_out_time Scheduled shift start/end times
is_overnight_shift Check if shift crosses midnight
allow_late_early_exception Enable grace period
late_early_grace_minutes Grace minutes for late arrival / early departure
has_food_break Deduct a food/suhoor break from working hours
food_break_duration_minutes Break length in minutes
food_break_type Regular Break or Suhoor Break
food_break_included_in_shift If checked, break is deducted from scheduled hours
shift_type Optional — link to HRMS Shift Type for matching
department Optional — restrict rule to a department
overtime_eligible Allow overtime calculation for this rule

Custom Fields

Created automatically by after_install:

DocType Field Type Description
Employee religion_category Select Muslim / Non-Muslim
Attendance overtime_hours Float Auto-filled overtime hours
Attendance overtime_entry Link Link to Overtime Entry

How It Works

Calculation Flow

  1. Trigger: Attendance.on_submit fires hooks_handler.on_attendance_submit()
  2. Settings check: Load Overtime Settings; skip if disabled or auto-create is off
  3. Rule matching: get_applicable_shift_rule() finds the best-scoring rule for this attendance
  4. Checkin retrieval: Get Employee Checkin records linked to this Attendance (with fallback search)
  5. Duration calc: Compute actual working hours from first-IN to last-OUT checkin timestamps
  6. Scheduled hours: Calculate from shift rule's check_in/check_out times (handles overnight)
  7. Net overtime: actual_hours - scheduled_hours - food_break + grace_adjustment
  8. Rounding: Apply configured rounding method
  9. Caps: Enforce minimum_overtime_minutes and max_overtime_hours_per_day
  10. Rate: Apply default_overtime_rate_multiplier or holiday_overtime_rate_multiplier
  11. Create entry: Insert Overtime Entry with all calculated fields

Overnight Shift Handling

HRMS behavior (critical to understand):

When a Shift Type has start_time > end_time (e.g. 23:30 → 07:30), HRMS treats it as an overnight shift:

  • The get_shift_timings() function in HRMS detects start_time > end_time and enters the overnight branch
  • A checkin at 23:30 on Jan 15 gets shift_start = Jan 15 23:30 and shift_end = Jan 16 07:30
  • A checkout at 07:30 on Jan 16 gets the same shift_start = Jan 15 23:30 and shift_end = Jan 16 07:30
  • HRMS groups checkins by (employee, shift_start) and creates ONE Attendance record
  • The Attendance date is Jan 15 (the shift_start.date())

Our app handles this by:

  • Using is_overnight_shift flag on shift rules to correctly calculate scheduled hours across midnight
  • The _get_checkin_logs() function searches by shift_start date for fallback matching
  • Duration is always calculated from full datetime timestamps (not time-only), so midnight crossing is automatic

Known HRMS edge case: If last_sync_of_checkin on the Shift Type is set to a value less than the shift duration, overnight OUT checkins may be skipped. Ensure last_sync_of_checkin ≥ shift duration.

Ramadan Mode

When ramadan_mode_enabled = 1 and today falls within [ramadan_start_date, ramadan_end_date]:

  1. Shift rules with applicable_period = "Ramadan" get +100 priority in scoring
  2. Muslim employees match rules with employee_category = "Muslim"
  3. Non-Muslim employees match rules with employee_category = "Non-Muslim"
  4. Rules with employee_category = "All" serve as fallback

Outside the Ramadan date range, only Standard period rules are considered.

Shift Rule Matching (Scoring)

When multiple shift rules exist, the system picks the best match using a weighted score:

Criterion Points Description
Period match +100 Ramadan rule during Ramadan period
Category match +50 Exact religion category match (Muslim/Non-Muslim)
Shift type match +30 Rule's shift_type matches Attendance's shift
Department match +25 Rule's department matches Employee's department
Fallback +10 Rules with employee_category = "All"

The highest-scoring enabled rule wins. Ties are broken by the DB ordering.


Shift Schedule Reference

Standard Period (All Employees)

Shift Check-in Check-out Overnight Scheduled Food Break Grace
Morning 07:30 15:30 No 8h (7.5h net) 30min 15min
Evening 15:30 23:30 No 8h (7.5h net) 30min 15min
Night 23:30 07:30 Yes 8h (7.5h net) 30min 15min

Ramadan Period — Muslim Employees

Shift Check-in Check-out Overnight Scheduled Food Break Grace
Factory Morning 07:00 13:00 No 6h None (fasting) None
Admin Morning 09:00 15:00 No 6h None (fasting) None
Factory Night 00:00 19:30 No 19.5h (18.5h net) 60min Suhoor None

Ramadan Period — Non-Muslim Employees

Shift Check-in Check-out Overnight Scheduled Food Break Grace
Factory Evening 16:00 00:00 Yes 8h (7.5h net) 30min None

DocTypes

Overtime Settings (Single)

Global configuration for overtime processing. One record per site.

Overtime Shift Rule

Defines shift schedules with check-in/out times, breaks, grace periods, and category/period qualifiers. Named as {shift_name}-{employee_category}-{applicable_period}.

Overtime Entry (Submittable)

Individual overtime records linked to Employee + Attendance. Named as OT-{employee}-.####.

Fields: employee, attendance, attendance_date, shift, overtime_hours, rate_multiplier, payable_overtime_hours, status (Draft/Approved/Rejected), and complete shift/checkin details.


Extending / Customization

Adding New Shift Rules

  1. Go to Overtime Shift Rule → New
  2. Fill in shift name, times, period, category
  3. Set overtime_eligible = 1
  4. Save — the rule will be matched automatically by the scoring engine

Custom Rate Logic

Override _get_rate_multiplier() in utils.py if you need per-employee or per-department rates.

Custom Hooks

The app hooks into Attendance.on_submit and Attendance.on_cancel. If you need to add custom logic, extend hooks_handler.py or add your own doc_events in a separate app.

Adding Department-Specific Rules

Set the department field on a shift rule to restrict it. Department match adds +25 to the scoring, giving it priority over generic rules.


Troubleshooting

Problem Solution
No overtime calculated Check Overtime Settingsenabled and auto_create_overtime_entry are checked
Wrong shift rule applied Check scoring: verify applicable_period, employee_category, shift_type, department on rules
Overnight shift gives 0 hours Ensure is_overnight_shift is checked on the rule; verify HRMS Shift Type has start_time > end_time
Checkins not found Ensure Employee Checkins have attendance linked, or shift_start set for fallback search
Ramadan rules not matching Verify ramadan_mode_enabled = 1, dates are set, and today falls within them
Grace period not applying Check allow_late_early_exception is checked and late_early_grace_minutes > 0 on the shift rule
Rate multiplier wrong Check default_overtime_rate_multiplier / holiday_overtime_rate_multiplier in settings
Rounding not working Check overtime_rounding is not "No Rounding" and rounding_interval_minutes > 0

Logs

# Check overtime-specific logs
bench --site your-site.local console
>>> frappe.get_doc("Error Log", {"method": ["like", "%overtime%"]})

# Check scheduler logs
tail -f logs/scheduler.log | grep overtime

Contributing

We welcome contributions! Please see our Contributing Guide for details on how to get started.

Quick Start for Contributors

# Fork and clone your fork
git clone https://github.com/YOUR_USERNAME/overtime.git
cd overtime

# Install pre-commit hooks
pip install pre-commit
pre-commit install

# Create a feature branch
git checkout -b feature/your-feature-name

Tools Used: ruff, eslint, prettier, pyupgrade

Please read our:


License

This project is licensed under the MIT License - see the LICENSE file for details.


Acknowledgments


Support

About

Overtime management in ERPNext v15

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Releases

No releases published

Sponsor this project

Packages

 
 
 

Contributors