feat: Upload Attendance (#20947)

Co-authored-by: Nabin Hait <nabinhait@gmail.com>
diff --git a/erpnext/hr/doctype/upload_attendance/upload_attendance.py b/erpnext/hr/doctype/upload_attendance/upload_attendance.py
index 1707e35..f75bb41 100644
--- a/erpnext/hr/doctype/upload_attendance/upload_attendance.py
+++ b/erpnext/hr/doctype/upload_attendance/upload_attendance.py
@@ -9,6 +9,8 @@
 from frappe import _
 from frappe.utils.csvutils import UnicodeWriter
 from frappe.model.document import Document
+from erpnext.hr.doctype.employee.employee import get_holiday_list_for_employee
+from erpnext.hr.utils import get_holidays_for_employee
 
 class UploadAttendance(Document):
 	pass
@@ -48,6 +50,7 @@
 def get_data(args):
 	dates = get_dates(args)
 	employees = get_active_employees()
+	holidays = get_holidays_for_employees([employee.name for employee in employees], args["from_date"], args["to_date"])
 	existing_attendance_records = get_existing_attendance_records(args)
 	data = []
 	for date in dates:
@@ -63,6 +66,9 @@
 				and getdate(employee.date_of_joining) <= getdate(date) \
 				and getdate(employee.relieving_date) >= getdate(date):
 					existing_attendance = existing_attendance_records[tuple([getdate(date), employee.name])]
+
+			employee_holiday_list = get_holiday_list_for_employee(employee.name)
+
 			row = [
 				existing_attendance and existing_attendance.name or "",
 				employee.name, employee.employee_name, date,
@@ -70,9 +76,22 @@
 				existing_attendance and existing_attendance.leave_type or "", employee.company,
 				existing_attendance and existing_attendance.naming_series or get_naming_series(),
 			]
+			if date in holidays[employee_holiday_list]:
+				row[4] =  "Holiday"
 			data.append(row)
+
 	return data
 
+def get_holidays_for_employees(employees, from_date, to_date):
+	holidays = {}
+	for employee in employees:
+		holiday_list = get_holiday_list_for_employee(employee)
+		holiday = get_holidays_for_employee(employee, getdate(from_date), getdate(to_date))
+		if holiday_list not in holidays:
+			holidays[holiday_list] = holiday
+
+	return holidays
+
 def writedata(w, data):
 	for row in data:
 		w.writerow(row)
@@ -123,6 +142,11 @@
 	frappe.enqueue(import_attendances, rows=rows, now=True if len(rows) < 200 else False)
 
 def import_attendances(rows):
+
+	def remove_holidays(rows):
+		rows = [ row for row in rows if row[4] != "Holiday"]
+		return
+
 	from frappe.modules import scrub
 
 	rows = list(filter(lambda x: x and any(x), rows))
@@ -133,6 +157,8 @@
 	ret = []
 	error = False
 
+	rows = remove_holidays(rows)
+
 	from frappe.utils.csvutils import check_record, import_doc
 
 	for i, row in enumerate(rows):