diff --git a/app.py b/app.py index a9fe568..6bbd5f7 100644 --- a/app.py +++ b/app.py @@ -9613,7 +9613,16 @@ def export_time_attendance_excel(records, project_name_for_filename, date_range_ if _di + 1 >= len(sorted_dk): continue + # Guard: _dk or _ndk may have been deleted by a prior iteration + # when all its records were moved to the previous day's bucket. + # Without this check, iterating the stale sorted_dk snapshot raises KeyError. + if _dk not in daily_location_data: + continue + _ndk = sorted_dk[_di + 1] + if _ndk not in daily_location_data: + continue + # Must be consecutive calendar days _dn = datetime.strptime(_dk, '%Y-%m-%d').date() _dn1 = datetime.strptime(_ndk, '%Y-%m-%d').date() diff --git a/working_hours_calculator.py b/working_hours_calculator.py index b9b13a1..bf15372 100644 --- a/working_hours_calculator.py +++ b/working_hours_calculator.py @@ -490,6 +490,14 @@ class WorkingHoursCalculator: for work_type in ['regular', 'SP', 'PW', 'PT']: all_dates = sorted(daily_records_by_type[work_type].keys()) for i, date_key in enumerate(all_dates): + # Guard: date_key may have been deleted by a prior iteration when all + # its records were moved to the previous day's bucket. + # Without this check, iterating the stale all_dates snapshot raises KeyError, + # which is silently caught by the outer try/except and returns an empty + # daily_hours dict — causing the employee to show zero rows in the export. + if date_key not in daily_records_by_type[work_type]: + continue + day_records = daily_records_by_type[work_type][date_key] # Count unpaired check-ins (late evening) @@ -513,6 +521,10 @@ class WorkingHoursCalculator: continue next_date_key = all_dates[i + 1] + # Guard: next_date_key may also have been deleted by a prior iteration + if next_date_key not in daily_records_by_type[work_type]: + continue + # Verify it is truly the next day from datetime import date as date_type day_n = datetime.strptime(date_key, '%Y-%m-%d').date()