From 655c1dd6ab8f4d7227a142b3ad89a8bc4c3df615 Mon Sep 17 00:00:00 2001 From: Rucha Mahabal Date: Sun, 3 Apr 2022 21:47:32 +0530 Subject: [PATCH] fix: attendance fixes - check half day attendance threshold before absent threshold to avoid half day getting marked as absent - round working hours to 2 digits for better accuracy - start and end dates for absent attendance marking --- .../employee_checkin/employee_checkin.py | 2 +- erpnext/hr/doctype/shift_type/shift_type.py | 22 +++++++++++++------ 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/erpnext/hr/doctype/employee_checkin/employee_checkin.py b/erpnext/hr/doctype/employee_checkin/employee_checkin.py index 81c9a460592..662b2362225 100644 --- a/erpnext/hr/doctype/employee_checkin/employee_checkin.py +++ b/erpnext/hr/doctype/employee_checkin/employee_checkin.py @@ -230,7 +230,7 @@ def calculate_working_hours(logs, check_in_out_type, working_hours_calc_type): def time_diff_in_hours(start, end): - return round((end - start).total_seconds() / 3600, 1) + return round(float((end - start).total_seconds()) / 3600, 2) def find_index_in_dict(dict_list, key, value): diff --git a/erpnext/hr/doctype/shift_type/shift_type.py b/erpnext/hr/doctype/shift_type/shift_type.py index f5689d190f2..5e214cf7b7a 100644 --- a/erpnext/hr/doctype/shift_type/shift_type.py +++ b/erpnext/hr/doctype/shift_type/shift_type.py @@ -97,16 +97,16 @@ class ShiftType(Document): ): early_exit = True - if ( - self.working_hours_threshold_for_absent - and total_working_hours < self.working_hours_threshold_for_absent - ): - return "Absent", total_working_hours, late_entry, early_exit, in_time, out_time if ( self.working_hours_threshold_for_half_day and total_working_hours < self.working_hours_threshold_for_half_day ): return "Half Day", total_working_hours, late_entry, early_exit, in_time, out_time + if ( + self.working_hours_threshold_for_absent + and total_working_hours < self.working_hours_threshold_for_absent + ): + return "Absent", total_working_hours, late_entry, early_exit, in_time, out_time return "Present", total_working_hours, late_entry, early_exit, in_time, out_time def mark_absent_for_dates_with_no_attendance(self, employee): @@ -116,7 +116,7 @@ class ShiftType(Document): start_date, end_date = self.get_start_and_end_dates(employee) # no shift assignment found, no need to process absent attendance records - if end_date is None: + if start_date is None: return holiday_list_name = self.holiday_list @@ -137,6 +137,10 @@ class ShiftType(Document): mark_attendance(employee, date, "Absent", self.name) def get_start_and_end_dates(self, employee): + """Returns start and end dates for checking attendance and marking absent + return: start date = max of `process_attendance_after` and DOJ + return: end date = min of shift before `last_sync_of_checkin` and Relieving Date + """ date_of_joining, relieving_date, employee_creation = frappe.db.get_value( "Employee", employee, ["date_of_joining", "relieving_date", "creation"] ) @@ -152,6 +156,8 @@ class ShiftType(Document): shift_details.actual_start if shift_details else get_datetime(self.last_sync_of_checkin) ) + # check if shift is found for 1 day before the last sync of checkin + # absentees are auto-marked 1 day after the shift to wait for any manual attendance records prev_shift = get_employee_shift(employee, last_shift_time - timedelta(days=1), True, "reverse") if prev_shift: end_date = ( @@ -159,7 +165,9 @@ class ShiftType(Document): if relieving_date else prev_shift.start_datetime.date() ) - + else: + # no shift found + return None, None return start_date, end_date def get_assigned_employee(self, from_date=None, consider_default_shift=False):