Skip to content

Commit

Permalink
Merge pull request #1703 from ruchamahabal/fix-absent-marking-logic
Browse files Browse the repository at this point in the history
fix(Auto Attendance): incorrect previous shift computation for a timestamp leading to incorrect absent marking
  • Loading branch information
ruchamahabal authored May 7, 2024
2 parents c4d7be1 + ab2f109 commit b075940
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 1 deletion.
6 changes: 5 additions & 1 deletion hrms/hr/doctype/shift_assignment/shift_assignment.py
Original file line number Diff line number Diff line change
Expand Up @@ -459,7 +459,11 @@ def get_prev_or_next_shift(
for date_range in shift_dates:
# midnight shifts will span more than a day
start_date, end_date = date_range[0], add_days(date_range[1], 1)
reverse = next_shift_direction == "reverse"

if reverse := (next_shift_direction == "reverse"):
end_date = min(end_date, for_timestamp.date())
elif next_shift_direction == "forward":
start_date = max(start_date, for_timestamp.date())

for dt in generate_date_range(start_date, end_date, reverse=reverse):
shift_details = get_employee_shift(
Expand Down
33 changes: 33 additions & 0 deletions hrms/hr/doctype/shift_assignment/test_shift_assignment.py
Original file line number Diff line number Diff line change
Expand Up @@ -295,3 +295,36 @@ def test_consecutive_day_and_night_shifts(self):
self.assertEqual(checkin.shift_type, checkout.shift_type)
self.assertEqual(checkin.actual_start.date(), today)
self.assertEqual(checkout.actual_end.date(), today)

def test_shift_details_on_consecutive_days_with_overlapping_timings(self):
# defaults
employee = make_employee("[email protected]", company="_Test Company")
today = getdate()
yesterday = add_days(today, -1)

# shift 1
shift_type = setup_shift_type(shift_type="Morning", start_time="07:00:00", end_time="12:00:00")
make_shift_assignment(shift_type.name, employee, add_days(yesterday, -1), yesterday)

# shift 2
shift_type = setup_shift_type(shift_type="Afternoon", start_time="09:30:00", end_time="14:00:00")
make_shift_assignment(shift_type.name, employee, today, add_days(today, 1))

# current_shift shift log - checkin in the grace period of current shift, non-overlapping with prev shift
current_shift = get_actual_start_end_datetime_of_shift(
employee, get_datetime(f"{today} 14:01:00"), True
)
self.assertEqual(current_shift.shift_type.name, "Afternoon")
self.assertEqual(current_shift.actual_start, get_datetime(f"{today} 08:30:00"))
self.assertEqual(current_shift.actual_end, get_datetime(f"{today} 15:00:00"))

# previous shift
checkin = get_actual_start_end_datetime_of_shift(
employee, get_datetime(f"{yesterday} 07:01:00"), True
)
checkout = get_actual_start_end_datetime_of_shift(
employee, get_datetime(f"{yesterday} 13:00:00"), True
)
self.assertTrue(checkin.shift_type.name == checkout.shift_type.name == "Morning")
self.assertEqual(checkin.actual_start, get_datetime(f"{yesterday} 06:00:00"))
self.assertEqual(checkout.actual_end, get_datetime(f"{yesterday} 13:00:00"))
23 changes: 23 additions & 0 deletions hrms/hr/doctype/shift_type/test_shift_type.py
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,29 @@ def test_mark_absent_for_dates_with_no_attendance_for_midnight_shift(self):
self.assertEqual(len(absent_records), 2)

def test_do_not_mark_absent_before_shift_actual_end_time(self):
from hrms.hr.doctype.employee_checkin.test_employee_checkin import make_checkin

employee = make_employee("[email protected]", company="_Test Company")
today = getdate()
yesterday = add_days(today, -1)

# shift 1
shift_1 = setup_shift_type(shift_type="Morning", start_time="07:00:00", end_time="12:30:00")
make_shift_assignment(shift_1.name, employee, add_days(yesterday, -1), yesterday)

# shift 2
shift_2 = setup_shift_type(shift_type="Afternoon", start_time="09:30:00", end_time="18:00:00")
make_shift_assignment(shift_2.name, employee, today, add_days(today, 1))

# update last sync of checkin for shift 2
shift_2.process_attendance_after = add_days(today, -2)
shift_2.last_sync_of_checkin = datetime.combine(today, get_time("09:01:00"))
shift_2.save()
shift_2.process_auto_attendance()

self.assertIsNone(frappe.db.get_value("Attendance", {"attendance_date": today, "employee": employee}))

def test_do_not_mark_absent_before_shift_actual_end_time_for_midnight_shift(self):
"""
Tests employee is not marked absent for a shift spanning 2 days
before its actual end time
Expand Down

0 comments on commit b075940

Please sign in to comment.