Sep 16 - Optimize code, part 2
This commit is contained in:
@@ -85,6 +85,20 @@ def _overnight_aware_sort_key(record):
|
||||
seconds_total += 24 * 3600
|
||||
return seconds_total
|
||||
|
||||
def _pair_is_regular(check_in_record, check_out_record) -> bool:
|
||||
"""
|
||||
True when a completed pair counts toward the 40-hour overtime rule.
|
||||
|
||||
SP / PW / PT / C hours are paid but never build toward overtime (§13). The
|
||||
OUT record's work type wins, mirroring effective_work_type elsewhere, so a
|
||||
Regular IN paired with an SP OUT counts as SP.
|
||||
"""
|
||||
in_work_type = getattr(check_in_record, 'work_type', None)
|
||||
out_work_type = getattr(check_out_record, 'work_type', None)
|
||||
effective = out_work_type or in_work_type
|
||||
return effective not in ('SP', 'PW', 'PT', 'C')
|
||||
|
||||
|
||||
def _qtr(decimal_hours: float) -> float:
|
||||
"""
|
||||
Round a decimal-hours value to the nearest quarter hour (.00/.25/.50/.75).
|
||||
@@ -596,6 +610,10 @@ def export_time_attendance_excel(records, project_name_for_filename, date_range_
|
||||
current_week_start = None
|
||||
grand_regular_hours = 0
|
||||
grand_ot_hours = 0
|
||||
# Regular-only hours feeding the 40-hour overtime rule. SP/PW/PT/C hours
|
||||
# are worked and paid, but they do NOT build toward overtime (§13), so
|
||||
# they are excluded here while column H still shows every hour worked.
|
||||
weekly_regular_hours = 0
|
||||
# Accumulate SP/PW/PT/C hours from cross-type pairs (where the calculator
|
||||
# could not detect them because it processes each work-type stream independently).
|
||||
cross_type_sp_hours = 0.0
|
||||
@@ -624,20 +642,22 @@ def export_time_attendance_excel(records, project_name_for_filename, date_range_
|
||||
_report_start = start_date
|
||||
week_start = (_report_start + timedelta(days=((date_obj.date() - _report_start).days // 7) * 7))
|
||||
if current_week_start is not None and week_start != current_week_start:
|
||||
# Write weekly total row
|
||||
week_regular = min(weekly_total_hours, 40.0)
|
||||
week_overtime = max(0, weekly_total_hours - 40.0)
|
||||
|
||||
# Write weekly total row. Column H = every hour worked; Regular
|
||||
# and OT are computed from regular hours only (SP/PW/PT/C excluded).
|
||||
week_regular = min(weekly_regular_hours, 40.0)
|
||||
week_overtime = max(0, weekly_regular_hours - 40.0)
|
||||
|
||||
ws.cell(row=current_row, column=7, value='Weekly Total: ').font = bold_font
|
||||
ws.cell(row=current_row, column=8, value=_qtr(weekly_total_hours)).font = bold_font
|
||||
ws.cell(row=current_row, column=9, value=_qtr(week_regular)).font = bold_font
|
||||
ws.cell(row=current_row, column=10, value=_qtr(week_overtime)).font = bold_font
|
||||
|
||||
|
||||
grand_regular_hours += week_regular
|
||||
grand_ot_hours += week_overtime
|
||||
current_row += 1
|
||||
|
||||
|
||||
weekly_total_hours = 0
|
||||
weekly_regular_hours = 0
|
||||
|
||||
current_week_start = week_start
|
||||
|
||||
@@ -666,6 +686,8 @@ def export_time_attendance_excel(records, project_name_for_filename, date_range_
|
||||
# group, and sum only complete pairs. This ensures the daily total in
|
||||
# column H matches exactly the pairs rendered in the export rows.
|
||||
_day_total_hours = 0.0
|
||||
# Same pairs, minus SP/PW/PT/C: the overtime base (§13)
|
||||
_day_regular_hours = 0.0
|
||||
# Track which records are consumed by same-building pairing so the
|
||||
# cross-building pass only considers true orphans.
|
||||
_same_building_used_ids = set()
|
||||
@@ -704,6 +726,8 @@ def export_time_attendance_excel(records, project_name_for_filename, date_range_
|
||||
if _duration > 24:
|
||||
continue
|
||||
_day_total_hours += _duration
|
||||
if _pair_is_regular(_in_r, _out_r):
|
||||
_day_regular_hours += _duration
|
||||
_out_used[_oi2] = True
|
||||
_same_building_used_ids.add(id(_in_r))
|
||||
_same_building_used_ids.add(id(_out_r))
|
||||
@@ -768,6 +792,8 @@ def export_time_attendance_excel(records, project_name_for_filename, date_range_
|
||||
'hours': _cb_dur,
|
||||
})
|
||||
_day_total_hours += _cb_dur
|
||||
if _pair_is_regular(_cb_in, _cb_out):
|
||||
_day_regular_hours += _cb_dur
|
||||
logger_handler.logger.info(
|
||||
f"[TA Export] Cross-building pair for employee {employee_id} on {date_str}: "
|
||||
f"IN {_cb_in.location_name} @ {_cb_in.check_in_time} → "
|
||||
@@ -788,6 +814,7 @@ def export_time_attendance_excel(records, project_name_for_filename, date_range_
|
||||
|
||||
total_hours = _qtr(_day_total_hours)
|
||||
weekly_total_hours += total_hours
|
||||
weekly_regular_hours += _qtr(_day_regular_hours)
|
||||
|
||||
# Daily total display (only shown on last location's last row)
|
||||
daily_total_display = _qtr(total_hours) if total_hours > 0 else ''
|
||||
@@ -1282,10 +1309,10 @@ def export_time_attendance_excel(records, project_name_for_filename, date_range_
|
||||
# END CROSS-BUILDING PAIR ROW WRITING
|
||||
# -------------------------------------------------------------------
|
||||
|
||||
# Write final weekly total for this employee
|
||||
# Write final weekly total for this employee (Regular/OT from regular hours only)
|
||||
if weekly_total_hours > 0:
|
||||
week_regular = min(weekly_total_hours, 40.0)
|
||||
week_overtime = max(0, weekly_total_hours - 40.0)
|
||||
week_regular = min(weekly_regular_hours, 40.0)
|
||||
week_overtime = max(0, weekly_regular_hours - 40.0)
|
||||
|
||||
ws.cell(row=current_row, column=7, value='Weekly Total: ').font = bold_font
|
||||
ws.cell(row=current_row, column=8, value=_qtr(weekly_total_hours)).font = bold_font
|
||||
@@ -1757,7 +1784,21 @@ def export_time_attendance_by_building_excel(records, project_name_for_filename,
|
||||
date_cell.font = Font(name='Aptos Narrow', size=11)
|
||||
date_cell.alignment = Alignment(horizontal='left')
|
||||
current_row += 1
|
||||
|
||||
|
||||
# Row 5: how the totals in this sheet are calculated. Overtime here is per
|
||||
# BUILDING (each block counts only that building's hours), so an employee
|
||||
# split across two buildings shows no overtime even past 40 hours — the main
|
||||
# Time Attendance export totals the week across all buildings.
|
||||
ws.merge_cells(f'A{current_row}:N{current_row}')
|
||||
ot_note_cell = ws.cell(
|
||||
row=current_row, column=1,
|
||||
value=('Note: Weekly Total / Regular / OT below are per building, and overtime excludes '
|
||||
'SP / PW / PT / C hours. Use the main Time Attendance export for payroll totals.')
|
||||
)
|
||||
ot_note_cell.font = Font(name='Aptos Narrow', size=10, italic=True)
|
||||
ot_note_cell.alignment = Alignment(horizontal='left')
|
||||
current_row += 1
|
||||
|
||||
# Empty rows before first building
|
||||
current_row += 2
|
||||
|
||||
@@ -1967,6 +2008,9 @@ def export_time_attendance_by_building_excel(records, project_name_for_filename,
|
||||
current_week_start = None
|
||||
grand_regular_hours = 0
|
||||
grand_ot_hours = 0
|
||||
# Regular-only hours for the 40-hour rule (SP/PW/PT/C excluded, §13).
|
||||
# Note: per BUILDING in this sheet — see the note under the date range.
|
||||
weekly_regular_hours = 0
|
||||
# Accumulate raw regular-only (non-SP/PW/PT) pair hours.
|
||||
# Used for the "Regular" summary row when the employee also has
|
||||
# special work-type hours.
|
||||
@@ -1993,9 +2037,10 @@ def export_time_attendance_by_building_excel(records, project_name_for_filename,
|
||||
_report_start = start_date
|
||||
week_start = (_report_start + timedelta(days=((date_obj.date() - _report_start).days // 7) * 7))
|
||||
if current_week_start is not None and week_start != current_week_start:
|
||||
# Write weekly total row
|
||||
week_regular = min(weekly_total_hours, 40.0)
|
||||
week_overtime = max(0, weekly_total_hours - 40.0)
|
||||
# Write weekly total row. Column H = every hour worked at this
|
||||
# building; Regular and OT come from regular hours only.
|
||||
week_regular = min(weekly_regular_hours, 40.0)
|
||||
week_overtime = max(0, weekly_regular_hours - 40.0)
|
||||
|
||||
ws.cell(row=current_row, column=7, value='Weekly Total: ').font = bold_font
|
||||
ws.cell(row=current_row, column=8, value=_qtr(weekly_total_hours)).font = bold_font
|
||||
@@ -2005,8 +2050,9 @@ def export_time_attendance_by_building_excel(records, project_name_for_filename,
|
||||
grand_regular_hours += week_regular
|
||||
grand_ot_hours += week_overtime
|
||||
current_row += 1
|
||||
|
||||
|
||||
weekly_total_hours = 0
|
||||
weekly_regular_hours = 0
|
||||
|
||||
current_week_start = week_start
|
||||
|
||||
@@ -2145,6 +2191,7 @@ def export_time_attendance_by_building_excel(records, project_name_for_filename,
|
||||
# Calculate daily hours
|
||||
daily_hours = 0
|
||||
_bb_day_non_sp_hours = 0.0 # weekly summary sheet excludes SP time
|
||||
_bb_day_regular_hours = 0.0 # overtime base: excludes SP/PW/PT/C
|
||||
for pair in pairs:
|
||||
if pair['check_in'] and pair['check_out'] and not pair['is_miss_punch']:
|
||||
pair_in = datetime.combine(date_obj, pair['check_in'].check_in_time)
|
||||
@@ -2165,11 +2212,13 @@ def export_time_attendance_by_building_excel(records, project_name_for_filename,
|
||||
_bb_eff_wt = _bb_out_wt or _bb_in_wt # prefer OUT's type (mirrors main export)
|
||||
if _bb_eff_wt not in ('SP', 'PW', 'PT', 'C'):
|
||||
regular_only_hours += _bb_dur
|
||||
_bb_day_regular_hours += _bb_dur
|
||||
if _bb_eff_wt != 'SP':
|
||||
_bb_day_non_sp_hours += _bb_dur
|
||||
|
||||
daily_hours = _qtr(daily_hours)
|
||||
weekly_total_hours += daily_hours
|
||||
weekly_regular_hours += _qtr(_bb_day_regular_hours)
|
||||
|
||||
# Same week anchoring as the Weekly Total rows (report start date)
|
||||
_bb_week_idx = (date_obj.date() - start_date).days // 7
|
||||
@@ -2250,10 +2299,10 @@ def export_time_attendance_by_building_excel(records, project_name_for_filename,
|
||||
|
||||
current_row += 1
|
||||
|
||||
# Write final weekly total
|
||||
# Write final weekly total (Regular/OT from regular hours only)
|
||||
if weekly_total_hours > 0:
|
||||
week_regular = min(weekly_total_hours, 40.0)
|
||||
week_overtime = max(0, weekly_total_hours - 40.0)
|
||||
week_regular = min(weekly_regular_hours, 40.0)
|
||||
week_overtime = max(0, weekly_regular_hours - 40.0)
|
||||
|
||||
ws.cell(row=current_row, column=7, value='Weekly Total: ').font = bold_font
|
||||
ws.cell(row=current_row, column=8, value=_qtr(weekly_total_hours)).font = bold_font
|
||||
|
||||
Reference in New Issue
Block a user