diff --git a/erpnext/hr/doctype/employee_checkin/employee_checkin.py b/erpnext/hr/doctype/employee_checkin/employee_checkin.py index 87f48b7e2578..f3cd864c908b 100644 --- a/erpnext/hr/doctype/employee_checkin/employee_checkin.py +++ b/erpnext/hr/doctype/employee_checkin/employee_checkin.py @@ -5,7 +5,7 @@ import frappe from frappe import _ from frappe.model.document import Document -from frappe.utils import cint, get_datetime +from frappe.utils import cint, get_datetime, get_link_to_form from erpnext.hr.doctype.shift_assignment.shift_assignment import ( get_actual_start_end_datetime_of_shift, @@ -127,19 +127,17 @@ def mark_attendance_and_link_log( log_names = [x.name for x in logs] employee = logs[0].employee if attendance_status == "Skip": - frappe.db.sql( - """update `tabEmployee Checkin` - set skip_auto_attendance = %s - where name in %s""", - ("1", log_names), - ) + skip_attendance_in_checkins(log_names) return None + elif attendance_status in ("Present", "Absent", "Half Day"): employee_doc = frappe.get_doc("Employee", employee) - if not frappe.db.exists( + duplicate = frappe.db.exists( "Attendance", {"employee": employee, "attendance_date": attendance_date, "docstatus": ("!=", "2")}, - ): + ) + + if not duplicate: doc_dict = { "doctype": "Attendance", "employee": employee, @@ -155,6 +153,12 @@ def mark_attendance_and_link_log( } attendance = frappe.get_doc(doc_dict).insert() attendance.submit() + + if attendance_status == "Absent": + attendance.add_comment( + text=_("Employee was marked Absent for not meeting the working hours threshold.") + ) + frappe.db.sql( """update `tabEmployee Checkin` set attendance = %s @@ -163,12 +167,10 @@ def mark_attendance_and_link_log( ) return attendance else: - frappe.db.sql( - """update `tabEmployee Checkin` - set skip_auto_attendance = %s - where name in %s""", - ("1", log_names), - ) + skip_attendance_in_checkins(log_names) + if duplicate: + add_comment_in_checkins(log_names, duplicate) + return None else: frappe.throw(_("{} is an invalid Attendance Status.").format(attendance_status)) @@ -237,3 +239,29 @@ def time_diff_in_hours(start, end): def find_index_in_dict(dict_list, key, value): return next((index for (index, d) in enumerate(dict_list) if d[key] == value), None) + + +def add_comment_in_checkins(log_names, duplicate): + text = _("Auto Attendance skipped due to duplicate attendance record: {}").format( + get_link_to_form("Attendance", duplicate) + ) + + for name in log_names: + frappe.get_doc( + { + "doctype": "Comment", + "comment_type": "Comment", + "reference_doctype": "Employee Checkin", + "reference_name": name, + "content": text, + } + ).insert(ignore_permissions=True) + + +def skip_attendance_in_checkins(log_names): + EmployeeCheckin = frappe.qb.DocType("Employee Checkin") + ( + frappe.qb.update(EmployeeCheckin) + .set("skip_auto_attendance", 1) + .where(EmployeeCheckin.name.isin(log_names)) + ).run() diff --git a/erpnext/hr/doctype/shift_type/shift_type.py b/erpnext/hr/doctype/shift_type/shift_type.py index 3f5cb222bfaf..2000eeb54439 100644 --- a/erpnext/hr/doctype/shift_type/shift_type.py +++ b/erpnext/hr/doctype/shift_type/shift_type.py @@ -139,7 +139,17 @@ def mark_absent_for_dates_with_no_attendance(self, employee): for date in dates: shift_details = get_employee_shift(employee, date, True) if shift_details and shift_details.shift_type.name == self.name: - mark_attendance(employee, date, "Absent", self.name) + attendance = mark_attendance(employee, date, "Absent", self.name) + if attendance: + frappe.get_doc( + { + "doctype": "Comment", + "comment_type": "Comment", + "reference_doctype": "Attendance", + "reference_name": attendance, + "content": frappe._("Employee was marked Absent due to missing Employee Checkins."), + } + ).insert(ignore_permissions=True) def get_assigned_employee(self, from_date=None, consider_default_shift=False): filters = {"start_date": (">", from_date), "shift_type": self.name, "docstatus": "1"}