March 11 2026: changed overnight shift calculation
This commit is contained in:
@@ -9673,9 +9673,15 @@ def export_time_attendance_excel(records, project_name_for_filename, date_range_
|
|||||||
_nxt_ins = [r for r in _next_recs if not _is_out(r)]
|
_nxt_ins = [r for r in _next_recs if not _is_out(r)]
|
||||||
_nxt_outs = [r for r in _next_recs if _is_out(r)]
|
_nxt_outs = [r for r in _next_recs if _is_out(r)]
|
||||||
|
|
||||||
# Day N must have an unmatched late check-in (more INs than OUTs,
|
# Early-morning OUTs on Day N (hour <= 3) are overnight orphans from
|
||||||
|
# Day N-1. Counting them as regular Day N outs inflates the out-count
|
||||||
|
# and makes the day appear balanced, which suppresses detection of an
|
||||||
|
# unmatched late IN that needs a next-day OUT. Exclude them.
|
||||||
|
_day_outs_non_early = [r for r in _day_outs if r.check_in_time.hour > 3]
|
||||||
|
|
||||||
|
# Day N must have an unmatched late check-in (more INs than non-early OUTs,
|
||||||
# with at least one IN at or after 20:00)
|
# with at least one IN at or after 20:00)
|
||||||
if len(_day_ins) <= len(_day_outs):
|
if len(_day_ins) <= len(_day_outs_non_early):
|
||||||
continue
|
continue
|
||||||
_late_ins = [r for r in _day_ins if r.check_in_time.hour >= 20]
|
_late_ins = [r for r in _day_ins if r.check_in_time.hour >= 20]
|
||||||
if not _late_ins:
|
if not _late_ins:
|
||||||
|
|||||||
@@ -504,13 +504,25 @@ class WorkingHoursCalculator:
|
|||||||
check_ins = [r for r in day_records if r.record_type == 'check_in']
|
check_ins = [r for r in day_records if r.record_type == 'check_in']
|
||||||
check_outs = [r for r in day_records if r.record_type == 'check_out']
|
check_outs = [r for r in day_records if r.record_type == 'check_out']
|
||||||
|
|
||||||
|
# Early-morning OUTs on Day N (hour <= OVERNIGHT_CHECKOUT_HOUR) are
|
||||||
|
# themselves overnight orphans from Day N-1. Counting them as regular
|
||||||
|
# Day N outs inflates the out-count and makes the day appear balanced,
|
||||||
|
# suppressing overnight detection for the late IN that actually needs
|
||||||
|
# a next-day OUT. Exclude them from the balance comparison.
|
||||||
|
check_outs_non_early = [
|
||||||
|
r for r in check_outs
|
||||||
|
if (r.check_in_time.hour if isinstance(r.check_in_time, time) else r.timestamp.hour)
|
||||||
|
> OVERNIGHT_CHECKOUT_HOUR
|
||||||
|
]
|
||||||
|
|
||||||
# Any unmatched check-ins that started late in the evening?
|
# Any unmatched check-ins that started late in the evening?
|
||||||
unmatched_late_ins = []
|
unmatched_late_ins = []
|
||||||
for ci in check_ins:
|
for ci in check_ins:
|
||||||
ci_hour = ci.check_in_time.hour if isinstance(ci.check_in_time, time) else ci.timestamp.hour
|
ci_hour = ci.check_in_time.hour if isinstance(ci.check_in_time, time) else ci.timestamp.hour
|
||||||
if ci_hour >= OVERNIGHT_CHECKIN_HOUR:
|
if ci_hour >= OVERNIGHT_CHECKIN_HOUR:
|
||||||
# Check that there is no check-out already on the same day for this in
|
# Use non-early outs so orphaned early-morning OUTs from
|
||||||
if len(check_outs) < len(check_ins):
|
# the prior night do not mask an unmatched late IN.
|
||||||
|
if len(check_outs_non_early) < len(check_ins):
|
||||||
unmatched_late_ins.append(ci)
|
unmatched_late_ins.append(ci)
|
||||||
|
|
||||||
if not unmatched_late_ins:
|
if not unmatched_late_ins:
|
||||||
|
|||||||
Reference in New Issue
Block a user