Attendance Engine Rules
Windows
For shift with start, end, is_overnight:
earliest_in = start - early_in_min
latest_in = start + grace_in_min
earliest_out = end - early_out_min
latest_out = end + grace_out_min
Punch direction in / auto is valid in [earliest_in, latest_in].
Punch direction out / auto is valid in [earliest_out, latest_out].
Direction = auto
Clients that can't determine direction (e.g. Telegram) send direction = auto. The server:
- If there is no
first_in_atyet → treats asin. - Else → treats as
out.
Overnight Shifts
For is_overnight = true:
startandendare on different calendar days.assigned_foris the start date.last_out_atcan fall onassigned_for + 1.
Status Derivation
Given the computed worked_minutes:
| Rule | Output |
|---|---|
first_in_at IS NULL AND no leave/holiday | absent |
leave row active for the date | leave |
holiday row for the unit | holiday |
| weekoff pattern matches | weekoff |
worked_minutes ≥ full_day_threshold | present |
half_day_threshold ≤ worked_minutes < full_day_threshold | half_day |
worked_minutes < half_day_threshold | absent |
Thresholds are configurable per unit with sensible defaults (full: 8h, half: 4h).
Multiple Punches
All punches land in punch_logs. The processor never rejects punches. But it adds MULTIPLE_PUNCHES flag when more than one in or one out is recorded in the same shift window.
Recalculation Triggers
- Regularization approved.
- Shift changed.
- Locum assigned or revoked.
- Attendance manually edited.
- Leave approved.
- Policy change on the unit (geo-enable, device-binding toggle).
Recalculation is a queued job that replays the raw punches through the current rules.