Updated overtime calculations (GOOD STATE)

This commit is contained in:
Nguyen Ngo
2025-09-11 10:51:49 -04:00
parent 089497ef8f
commit 81da08ad58
2 changed files with 43 additions and 31 deletions
+1 -1
View File
@@ -5516,7 +5516,7 @@ def get_miss_punch_details(employee_id):
converted_records.append(converted_record) converted_records.append(converted_record)
# Calculate working hours using the same calculator as the dashboard # Calculate working hours using the same calculator as the dashboard
from single_checkin_calculator import SingleCheckInCalculator # from single_checkin_calculator import SingleCheckInCalculator
calculator = SingleCheckInCalculator() calculator = SingleCheckInCalculator()
# Calculate hours for this employee # Calculate hours for this employee
+39 -27
View File
@@ -702,7 +702,7 @@ class PayrollExcelExporter:
def _write_employee_section(self, worksheet, employee_id: str, employee_name: str, def _write_employee_section(self, worksheet, employee_id: str, employee_name: str,
emp_data: Dict, start_date: datetime, end_date: datetime, emp_data: Dict, start_date: datetime, end_date: datetime,
attendance_records: List[Dict], start_row: int) -> int: attendance_records: List[Dict], start_row: int) -> int:
"""Write individual employee section with multiple pairs per day, daily totals, weekly totals, and grand total""" """Write individual employee section with FIXED WEEKLY OVERTIME CALCULATION"""
current_row = start_row current_row = start_row
# Employee info header (merged across columns A-O) # Employee info header (merged across columns A-O)
@@ -746,9 +746,7 @@ class PayrollExcelExporter:
day_info['location'] = sorted_records[0].qr_code.location or '' day_info['location'] = sorted_records[0].qr_code.location or ''
day_info['building_address'] = sorted_records[0].qr_code.location_address or '' day_info['building_address'] = sorted_records[0].qr_code.location_address or ''
# Initialize weekly totals tracking # FIXED: Initialize ALL weekly totals tracking variables
weekly_regular_hours = 0
weekly_ot_hours = 0
weekly_total_hours = 0 weekly_total_hours = 0
# Track overall totals for grand total # Track overall totals for grand total
@@ -760,6 +758,9 @@ class PayrollExcelExporter:
# Track week boundaries (assuming payroll period starts on Monday) # Track week boundaries (assuming payroll period starts on Monday)
current_week_start = None current_week_start = None
# Log the overtime calculation change
print(f"🔧 FIXED: Using weekly overtime calculation (40 hrs/week) for employee {employee_id}")
# Write data rows using the calculated daily hours from emp_data # Write data rows using the calculated daily hours from emp_data
for date_str in sorted(emp_data['daily_hours'].keys()): for date_str in sorted(emp_data['daily_hours'].keys()):
date_obj = datetime.strptime(date_str, '%Y-%m-%d') date_obj = datetime.strptime(date_str, '%Y-%m-%d')
@@ -780,30 +781,33 @@ class PayrollExcelExporter:
# Calculate week boundaries # Calculate week boundaries
week_start = date_obj - timedelta(days=date_obj.weekday()) # Monday of the week week_start = date_obj - timedelta(days=date_obj.weekday()) # Monday of the week
# Check if we've moved to a new week and need to write weekly total # FIXED: Check if we've moved to a new week and need to write weekly total
if current_week_start is not None and week_start != current_week_start: if current_week_start is not None and week_start != current_week_start:
# Calculate weekly overtime using 40-hour threshold
week_regular = min(weekly_total_hours, 40.0)
week_overtime = max(0, weekly_total_hours - 40.0)
# Write weekly total row for previous week # Write weekly total row for previous week
current_row = self._write_weekly_total_row(worksheet, current_row, current_row = self._write_weekly_total_row(worksheet, current_row,
weekly_regular_hours, weekly_ot_hours, weekly_total_hours) week_regular, week_overtime, weekly_total_hours)
# Add to grand totals
grand_regular_hours += week_regular
grand_ot_hours += week_overtime
# Reset weekly counters # Reset weekly counters
weekly_regular_hours = 0
weekly_ot_hours = 0
weekly_total_hours = 0 weekly_total_hours = 0
current_week_start = week_start current_week_start = week_start
total_hours = day_hours_data.get('total_hours', 0) total_hours = day_hours_data.get('total_hours', 0)
regular_hours = min(total_hours, 8.0) # Max 8 regular hours per day
ot_hours = max(0, total_hours - 8.0)
# Add to weekly and grand totals # FIXED: Remove daily overtime calculation - now calculated weekly only
weekly_regular_hours += regular_hours # OLD CODE: regular_hours = min(total_hours, 8.0) # Max 8 regular hours per day
weekly_ot_hours += ot_hours # OLD CODE: ot_hours = max(0, total_hours - 8.0)
# Add to weekly totals (no daily overtime calculation)
weekly_total_hours += total_hours weekly_total_hours += total_hours
grand_regular_hours += regular_hours
grand_ot_hours += ot_hours
grand_total_hours += total_hours grand_total_hours += total_hours
# Get location info for this date # Get location info for this date
@@ -829,10 +833,11 @@ class PayrollExcelExporter:
start_record = day_records[i] start_record = day_records[i]
end_record = day_records[i + 1] end_record = day_records[i + 1]
# FIXED: Pass total_hours without daily overtime split
current_row = self._write_record_pair_row( current_row = self._write_record_pair_row(
worksheet, current_row, date_obj, start_record, end_record, worksheet, current_row, date_obj, start_record, end_record,
location, building_address, total_hours, regular_hours, ot_hours, location, building_address, total_hours, 0, 0, # No daily regular/ot split
pairs_written, total_hours, total_pairs_for_day # Add total_pairs parameter pairs_written, total_hours, total_pairs_for_day
) )
pairs_written += 1 pairs_written += 1
total_pairs_written += 1 # Track total pairs total_pairs_written += 1 # Track total pairs
@@ -841,13 +846,19 @@ class PayrollExcelExporter:
start_record = day_records[0] if day_records else None start_record = day_records[0] if day_records else None
current_row = self._write_single_record_row( current_row = self._write_single_record_row(
worksheet, current_row, date_obj, start_record, worksheet, current_row, date_obj, start_record,
location, building_address, total_hours, regular_hours, ot_hours location, building_address, total_hours, 0, 0 # No daily regular/ot split
) )
# Write final weekly total if we have data # FIXED: Write final weekly total with proper weekly overtime calculation
if weekly_total_hours > 0: if weekly_total_hours > 0:
week_regular = min(weekly_total_hours, 40.0)
week_overtime = max(0, weekly_total_hours - 40.0)
current_row = self._write_weekly_total_row(worksheet, current_row, current_row = self._write_weekly_total_row(worksheet, current_row,
weekly_regular_hours, weekly_ot_hours, weekly_total_hours) week_regular, week_overtime, weekly_total_hours)
# Add final week to grand totals
grand_regular_hours += week_regular
grand_ot_hours += week_overtime
# Write grand total row # Write grand total row
current_row = self._write_grand_total_row(worksheet, current_row, current_row = self._write_grand_total_row(worksheet, current_row,
@@ -856,8 +867,9 @@ class PayrollExcelExporter:
# Add space between employees # Add space between employees
current_row += 2 current_row += 2
# Log the export action (use print for now since logger_handler import is complex) # Log the export action with fixed overtime calculation
print(f"✅ Template format export: Employee {employee_id} ({employee_name}) data written with {total_pairs_written} record pairs, weekly totals, and grand total") print(f" FIXED Template format export: Employee {employee_id} ({employee_name}) data written with weekly overtime calculation (40 hrs/week)")
print(f"📊 Total: {grand_total_hours:.2f} hrs, Regular: {grand_regular_hours:.2f} hrs, Overtime: {grand_ot_hours:.2f} hrs")
return current_row return current_row
@@ -936,8 +948,8 @@ class PayrollExcelExporter:
"", # F - Zone (empty) "", # F - Zone (empty)
pair_hours, # G - Hours/Building pair_hours, # G - Hours/Building
daily_total_display, # H - Daily Total (only on last pair) daily_total_display, # H - Daily Total (only on last pair)
regular_hours if is_last_pair else "", # I - Regular Hours (only on last pair) "", # I - Regular Hours (only on last pair)
ot_hours if is_last_pair else "", # J - OT Hours (only on last pair) "", # J - OT Hours (only on last pair)
building_address_display, # K - Building Address building_address_display, # K - Building Address
recorded_location_display, # L - Recorded Location recorded_location_display, # L - Recorded Location
distance_value, # M - Distance distance_value, # M - Distance
@@ -1002,8 +1014,8 @@ class PayrollExcelExporter:
"", # F - Zone "", # F - Zone
total_hours, # G - Hours/Building total_hours, # G - Hours/Building
total_hours, # H - Daily Total total_hours, # H - Daily Total
regular_hours, # I - Regular Hours "", # I - Regular Hours
ot_hours, # J - OT Hours "", # J - OT Hours
building_address, # K - Building Address building_address, # K - Building Address
recorded_location, # L - Recorded Location recorded_location, # L - Recorded Location
distance_value, # M - Distance distance_value, # M - Distance