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
diff --git a/erpnext/hr/doctype/employee_checkin/employee_checkin.py b/erpnext/hr/doctype/employee_checkin/employee_checkin.py
index 81c9a46..662b236 100644
--- a/erpnext/hr/doctype/employee_checkin/employee_checkin.py
+++ b/erpnext/hr/doctype/employee_checkin/employee_checkin.py
@@ -230,7 +230,7 @@
 
 
 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 f5689d1..5e214cf 100644
--- a/erpnext/hr/doctype/shift_type/shift_type.py
+++ b/erpnext/hr/doctype/shift_type/shift_type.py
@@ -98,15 +98,15 @@
 			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 @@
 		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 @@
 				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 @@
 			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 @@
 				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):