test: fetching shifts in Employee Checkins

This commit is contained in:
Rucha Mahabal 2022-03-30 23:27:49 +05:30
parent 72501f2161
commit af139193a5

View File

@ -2,10 +2,11 @@
# See license.txt
import unittest
from datetime import timedelta
from datetime import datetime, timedelta
import frappe
from frappe.utils import now_datetime, nowdate
from frappe.tests.utils import FrappeTestCase
from frappe.utils import add_days, get_time, getdate, now_datetime, nowdate
from erpnext.hr.doctype.employee.test_employee import make_employee
from erpnext.hr.doctype.employee_checkin.employee_checkin import (
@ -13,9 +14,15 @@ from erpnext.hr.doctype.employee_checkin.employee_checkin import (
calculate_working_hours,
mark_attendance_and_link_log,
)
from erpnext.hr.doctype.leave_application.test_leave_application import get_first_sunday
class TestEmployeeCheckin(unittest.TestCase):
class TestEmployeeCheckin(FrappeTestCase):
def setUp(self):
frappe.db.delete("Shift Type")
frappe.db.delete("Shift Assignment")
frappe.db.delete("Employee Checkin")
def test_add_log_based_on_employee_field(self):
employee = make_employee("test_add_log_based_on_employee_field@example.com")
employee = frappe.get_doc("Employee", employee)
@ -103,6 +110,144 @@ class TestEmployeeCheckin(unittest.TestCase):
)
self.assertEqual(working_hours, (4.5, logs_type_2[1].time, logs_type_2[-1].time))
def test_fetch_shift(self):
employee = make_employee("test_employee_checkin@example.com", company="_Test Company")
# shift setup for 8-12
shift_type = setup_shift_type()
date = getdate()
make_shift_assignment(shift_type.name, employee, date)
# within shift time
timestamp = datetime.combine(date, get_time("08:45:00"))
log = make_checkin(employee, timestamp)
self.assertEqual(log.shift, shift_type.name)
# "begin checkin before shift time" = 60 mins, so should work for 7:00:00
timestamp = datetime.combine(date, get_time("07:00:00"))
log = make_checkin(employee, timestamp)
self.assertEqual(log.shift, shift_type.name)
# "allow checkout after shift end time" = 60 mins, so should work for 13:00:00
timestamp = datetime.combine(date, get_time("13:00:00"))
log = make_checkin(employee, timestamp)
self.assertEqual(log.shift, shift_type.name)
# should not fetch this shift beyond allowed time
timestamp = datetime.combine(date, get_time("13:01:00"))
log = make_checkin(employee, timestamp)
self.assertIsNone(log.shift)
def test_shift_start_and_end_timings(self):
employee = make_employee("test_employee_checkin@example.com", company="_Test Company")
# shift setup for 8-12
shift_type = setup_shift_type()
date = getdate()
make_shift_assignment(shift_type.name, employee, date)
timestamp = datetime.combine(date, get_time("08:45:00"))
log = make_checkin(employee, timestamp)
self.assertEqual(log.shift, shift_type.name)
self.assertEqual(log.shift_start, datetime.combine(date, get_time("08:00:00")))
self.assertEqual(log.shift_end, datetime.combine(date, get_time("12:00:00")))
self.assertEqual(log.shift_actual_start, datetime.combine(date, get_time("07:00:00")))
self.assertEqual(log.shift_actual_end, datetime.combine(date, get_time("13:00:00")))
def test_fetch_shift_based_on_default_shift(self):
employee = make_employee("test_default_shift@example.com", company="_Test Company")
default_shift = setup_shift_type(
shift_type="Default Shift", start_time="14:00:00", end_time="16:00:00"
)
date = getdate()
frappe.db.set_value("Employee", employee, "default_shift", default_shift.name)
timestamp = datetime.combine(date, get_time("14:45:00"))
log = make_checkin(employee, timestamp)
# should consider default shift
self.assertEqual(log.shift, default_shift.name)
def test_fetch_shift_spanning_over_two_days(self):
employee = make_employee("test_employee_checkin@example.com", company="_Test Company")
shift_type = setup_shift_type(start_time="23:00:00", end_time="01:00:00")
date = getdate()
next_day = add_days(date, 1)
make_shift_assignment(shift_type.name, employee, date)
# log falls in the first day
timestamp = datetime.combine(date, get_time("23:00:00"))
log = make_checkin(employee, timestamp)
self.assertEqual(log.shift, shift_type.name)
self.assertEqual(log.shift_start, datetime.combine(date, get_time("23:00:00")))
self.assertEqual(log.shift_end, datetime.combine(next_day, get_time("01:00:00")))
self.assertEqual(log.shift_actual_start, datetime.combine(date, get_time("22:00:00")))
self.assertEqual(log.shift_actual_end, datetime.combine(next_day, get_time("02:00:00")))
log.delete()
# log falls in the second day
prev_day = add_days(date, -1)
timestamp = datetime.combine(date, get_time("01:30:00"))
log = make_checkin(employee, timestamp)
self.assertEqual(log.shift, shift_type.name)
self.assertEqual(log.shift_start, datetime.combine(prev_day, get_time("23:00:00")))
self.assertEqual(log.shift_end, datetime.combine(date, get_time("01:00:00")))
self.assertEqual(log.shift_actual_start, datetime.combine(prev_day, get_time("22:00:00")))
self.assertEqual(log.shift_actual_end, datetime.combine(date, get_time("02:00:00")))
def test_no_shift_fetched_on_a_holiday(self):
employee = make_employee("test_shift_with_holiday@example.com", company="_Test Company")
setup_shift_type(
shift_type="Test Holiday Shift", holiday_list="Salary Slip Test Holiday List"
)
date = getdate()
first_sunday = get_first_sunday("Salary Slip Test Holiday List", for_date=date)
timestamp = datetime.combine(first_sunday, get_time("08:00:00"))
log = make_checkin(employee, timestamp)
self.assertIsNone(log.shift)
def test_consecutive_shift_assignments_overlapping_within_grace_period(self):
# test adjustment for start and end times if they are overlapping
# within "begin_check_in_before_shift_start_time" and "allow_check_out_after_shift_end_time" periods
employee = make_employee("test_shift_with_holiday@example.com", company="_Test Company")
# 8 - 12
shift1 = setup_shift_type()
# 12:30 - 16:30
shift2 = setup_shift_type(
shift_type="Consecutive Shift", start_time="12:30:00", end_time="16:30:00"
)
# the actual start and end times (with grace) for these shifts are 7 - 13 and 11:30 - 17:30
date = getdate()
make_shift_assignment(shift1.name, employee, date)
make_shift_assignment(shift2.name, employee, date)
# log at 12:30 should set shift2 and actual start as 12 and not 11:30
timestamp = datetime.combine(date, get_time("12:30:00"))
log = make_checkin(employee, timestamp)
self.assertEqual(log.shift, shift2.name)
self.assertEqual(log.shift_start, datetime.combine(date, get_time("12:30:00")))
self.assertEqual(log.shift_actual_start, datetime.combine(date, get_time("12:00:00")))
# log at 12:00 should set shift1 and actual end as 12 and not 1 since the next shift's grace starts
timestamp = datetime.combine(date, get_time("12:00:00"))
log = make_checkin(employee, timestamp)
self.assertEqual(log.shift, shift1.name)
self.assertEqual(log.shift_end, datetime.combine(date, get_time("12:00:00")))
self.assertEqual(log.shift_actual_end, datetime.combine(date, get_time("12:00:00")))
# log at 12:01 should set shift2
timestamp = datetime.combine(date, get_time("12:01:00"))
log = make_checkin(employee, timestamp)
self.assertEqual(log.shift, shift2.name)
def make_n_checkins(employee, n, hours_to_reverse=1):
logs = [make_checkin(employee, now_datetime() - timedelta(hours=hours_to_reverse, minutes=n + 1))]
@ -124,3 +269,45 @@ def make_checkin(employee, time=now_datetime()):
}
).insert()
return log
def setup_shift_type(**args):
args = frappe._dict(args)
shift_type = frappe.new_doc("Shift Type")
shift_type.__newname = args.shift_type or "_Test Shift"
shift_type.start_time = args.start_time or "08:00:00"
shift_type.end_time = args.end_time or "12:00:00"
shift_type.holiday_list = args.holiday_list
shift_type.enable_auto_attendance = 1
shift_type.determine_check_in_and_check_out = (
args.determine_check_in_and_check_out
or "Alternating entries as IN and OUT during the same shift"
)
shift_type.working_hours_calculation_based_on = (
args.working_hours_calculation_based_on or "First Check-in and Last Check-out"
)
shift_type.begin_check_in_before_shift_start_time = (
args.begin_check_in_before_shift_start_time or 60
)
shift_type.allow_check_out_after_shift_end_time = args.allow_check_out_after_shift_end_time or 60
shift_type.save()
return shift_type
def make_shift_assignment(shift_type, employee, start_date, end_date=None):
shift_assignment = frappe.get_doc(
{
"doctype": "Shift Assignment",
"shift_type": shift_type,
"company": "_Test Company",
"employee": employee,
"start_date": start_date,
"end_date": end_date,
}
).insert()
shift_assignment.submit()
return shift_assignment