def get_attendance(self, logs): """Return attendance_status, working_hours, late_entry, early_exit, in_time, out_time for a set of logs belonging to a single shift. Assumptions: 1. These logs belongs to a single shift, single employee and it's not in a holiday date. 2. Logs are in chronological order """ late_entry = early_exit = False total_working_hours, in_time, out_time = calculate_working_hours( logs, self.determine_check_in_and_check_out, self.working_hours_calculation_based_on) if (cint(self.enable_entry_grace_period) and in_time and in_time > logs[0].shift_start + timedelta(minutes=cint(self.late_entry_grace_period))): late_entry = True if (cint(self.enable_exit_grace_period) and out_time and out_time < logs[0].shift_end - timedelta(minutes=cint(self.early_exit_grace_period))): early_exit = True 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 get_attendance(self, logs): """Return attendance_status, working_hours, late_entry, early_exit, in_time, out_time for a set of logs belonging to a single shift. Assumtion: 1. These logs belongs to an single shift, single employee and is not in a holiday date. 2. Logs are in chronological order """ late_entry = early_exit = False total_working_hours, in_time, out_time = calculate_working_hours(logs, self.determine_check_in_and_check_out, self.working_hours_calculation_based_on) if cint(self.enable_entry_grace_period) and in_time and in_time > logs[0].shift_start + timedelta(minutes=cint(self.late_entry_grace_period)): late_entry = True if cint(self.enable_exit_grace_period) and out_time and out_time < logs[0].shift_end - timedelta(minutes=cint(self.early_exit_grace_period)): 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 #customized by TeamPRO #Permission Count and Late Entry Mark import calendar count = 1 frappe.errprint(logs) now_date = (logs[0].time).date() month = calendar.monthrange(now_date.year, now_date.month) start_date = date(now_date.year, now_date.month, 1) end_date = date(now_date.year, now_date.month, month[1]) attendance = frappe.db.sql("""select name,employee,employee_name,shift,late_entry from `tabAttendance` where late_entry = 1 and employee = %s and attendance_date between %s and %s""",(logs[0].employee,start_date,end_date),as_dict = 1) count += len(attendance) if late_entry: if self.allow_permission_count < count: return 'Half Day', 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 get_attendance(self, logs): """Return attendance_status, working_hours for a set of logs belonging to a single shift. Assumtion: 1. These logs belongs to an single shift, single employee and is not in a holiday date. 2. Logs are in chronological order """ total_working_hours = calculate_working_hours(logs, self.determine_check_in_and_check_out, self.working_hours_calculation_based_on) if self.working_hours_threshold_for_absent and total_working_hours < self.working_hours_threshold_for_absent: return 'Absent', total_working_hours 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 return 'Present', total_working_hours
def test_calculate_working_hours(self): check_in_out_type = ['Alternating entries as IN and OUT during the same shift', 'Strictly based on Log Type in Employee Checkin'] working_hours_calc_type = ['First Check-in and Last Check-out', 'Every Valid Check-in and Check-out'] logs_type_1 = [ {'time':now_datetime()-timedelta(minutes=390)}, {'time':now_datetime()-timedelta(minutes=300)}, {'time':now_datetime()-timedelta(minutes=270)}, {'time':now_datetime()-timedelta(minutes=90)}, {'time':now_datetime()-timedelta(minutes=0)} ] logs_type_2 = [ {'time':now_datetime()-timedelta(minutes=390),'log_type':'OUT'}, {'time':now_datetime()-timedelta(minutes=360),'log_type':'IN'}, {'time':now_datetime()-timedelta(minutes=300),'log_type':'OUT'}, {'time':now_datetime()-timedelta(minutes=290),'log_type':'IN'}, {'time':now_datetime()-timedelta(minutes=260),'log_type':'OUT'}, {'time':now_datetime()-timedelta(minutes=240),'log_type':'IN'}, {'time':now_datetime()-timedelta(minutes=150),'log_type':'IN'}, {'time':now_datetime()-timedelta(minutes=60),'log_type':'OUT'} ] logs_type_1 = [frappe._dict(x) for x in logs_type_1] logs_type_2 = [frappe._dict(x) for x in logs_type_2] working_hours = calculate_working_hours(logs_type_1,check_in_out_type[0],working_hours_calc_type[0]) self.assertEqual(working_hours, (6.5, logs_type_1[0].time, logs_type_1[-1].time)) working_hours = calculate_working_hours(logs_type_1,check_in_out_type[0],working_hours_calc_type[1]) self.assertEqual(working_hours, (4.5, logs_type_1[0].time, logs_type_1[-1].time)) working_hours = calculate_working_hours(logs_type_2,check_in_out_type[1],working_hours_calc_type[0]) self.assertEqual(working_hours, (5, logs_type_2[1].time, logs_type_2[-1].time)) working_hours = calculate_working_hours(logs_type_2,check_in_out_type[1],working_hours_calc_type[1]) self.assertEqual(working_hours, (4.5, logs_type_2[1].time, logs_type_2[-1].time))
def test_calculate_working_hours(self): check_in_out_type = [ "Alternating entries as IN and OUT during the same shift", "Strictly based on Log Type in Employee Checkin", ] working_hours_calc_type = [ "First Check-in and Last Check-out", "Every Valid Check-in and Check-out", ] logs_type_1 = [ { "time": now_datetime() - timedelta(minutes=390) }, { "time": now_datetime() - timedelta(minutes=300) }, { "time": now_datetime() - timedelta(minutes=270) }, { "time": now_datetime() - timedelta(minutes=90) }, { "time": now_datetime() - timedelta(minutes=0) }, ] logs_type_2 = [ { "time": now_datetime() - timedelta(minutes=390), "log_type": "OUT" }, { "time": now_datetime() - timedelta(minutes=360), "log_type": "IN" }, { "time": now_datetime() - timedelta(minutes=300), "log_type": "OUT" }, { "time": now_datetime() - timedelta(minutes=290), "log_type": "IN" }, { "time": now_datetime() - timedelta(minutes=260), "log_type": "OUT" }, { "time": now_datetime() - timedelta(minutes=240), "log_type": "IN" }, { "time": now_datetime() - timedelta(minutes=150), "log_type": "IN" }, { "time": now_datetime() - timedelta(minutes=60), "log_type": "OUT" }, ] logs_type_1 = [frappe._dict(x) for x in logs_type_1] logs_type_2 = [frappe._dict(x) for x in logs_type_2] working_hours = calculate_working_hours(logs_type_1, check_in_out_type[0], working_hours_calc_type[0]) self.assertEqual(working_hours, (6.5, logs_type_1[0].time, logs_type_1[-1].time)) working_hours = calculate_working_hours(logs_type_1, check_in_out_type[0], working_hours_calc_type[1]) self.assertEqual(working_hours, (4.5, logs_type_1[0].time, logs_type_1[-1].time)) working_hours = calculate_working_hours(logs_type_2, check_in_out_type[1], working_hours_calc_type[0]) self.assertEqual(working_hours, (5, logs_type_2[1].time, logs_type_2[-1].time)) working_hours = calculate_working_hours(logs_type_2, check_in_out_type[1], working_hours_calc_type[1]) self.assertEqual(working_hours, (4.5, logs_type_2[1].time, logs_type_2[-1].time)) working_hours = calculate_working_hours( [logs_type_2[1], logs_type_2[-1]], check_in_out_type[1], working_hours_calc_type[1]) self.assertEqual(working_hours, (5.0, logs_type_2[1].time, logs_type_2[-1].time))