Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(Auto Attendance): incorrect previous shift computation for a timestamp leading to incorrect absent marking (backport #1703) #1755

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading