diff --git a/erpnext/hr/doctype/employee_checkin/test_employee_checkin.py b/erpnext/hr/doctype/employee_checkin/test_employee_checkin.py index ed7877f928c..b0716be1b7c 100644 --- a/erpnext/hr/doctype/employee_checkin/test_employee_checkin.py +++ b/erpnext/hr/doctype/employee_checkin/test_employee_checkin.py @@ -23,6 +23,8 @@ from erpnext.hr.doctype.employee_checkin.employee_checkin import ( mark_attendance_and_link_log, ) from erpnext.hr.doctype.leave_application.test_leave_application import get_first_sunday +from erpnext.hr.doctype.shift_assignment.test_shift_assignment import make_shift_assignment +from erpnext.hr.doctype.shift_type.test_shift_type import setup_shift_type from erpnext.payroll.doctype.salary_slip.test_salary_slip import make_holiday_list @@ -280,45 +282,3 @@ 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 diff --git a/erpnext/hr/doctype/shift_assignment/test_shift_assignment.py b/erpnext/hr/doctype/shift_assignment/test_shift_assignment.py index 4a1ec293bde..8759870a206 100644 --- a/erpnext/hr/doctype/shift_assignment/test_shift_assignment.py +++ b/erpnext/hr/doctype/shift_assignment/test_shift_assignment.py @@ -4,16 +4,23 @@ import unittest import frappe -from frappe.utils import add_days, nowdate +from frappe.tests.utils import FrappeTestCase +from frappe.utils import add_days, getdate, nowdate + +from erpnext.hr.doctype.employee.test_employee import make_employee +from erpnext.hr.doctype.shift_assignment.shift_assignment import OverlappingShiftError +from erpnext.hr.doctype.shift_type.test_shift_type import setup_shift_type test_dependencies = ["Shift Type"] -class TestShiftAssignment(unittest.TestCase): +class TestShiftAssignment(FrappeTestCase): def setUp(self): - frappe.db.sql("delete from `tabShift Assignment`") + frappe.db.delete("Shift Assignment") + frappe.db.delete("Shift Type") def test_make_shift_assignment(self): + setup_shift_type(shift_type="Day Shift") shift_assignment = frappe.get_doc( { "doctype": "Shift Assignment", @@ -29,7 +36,7 @@ class TestShiftAssignment(unittest.TestCase): def test_overlapping_for_ongoing_shift(self): # shift should be Ongoing if Only start_date is present and status = Active - + setup_shift_type(shift_type="Day Shift") shift_assignment_1 = frappe.get_doc( { "doctype": "Shift Assignment", @@ -54,11 +61,11 @@ class TestShiftAssignment(unittest.TestCase): } ) - self.assertRaises(frappe.ValidationError, shift_assignment.save) + self.assertRaises(OverlappingShiftError, shift_assignment.save) def test_overlapping_for_fixed_period_shift(self): # shift should is for Fixed period if Only start_date and end_date both are present and status = Active - + setup_shift_type(shift_type="Day Shift") shift_assignment_1 = frappe.get_doc( { "doctype": "Shift Assignment", @@ -85,4 +92,81 @@ class TestShiftAssignment(unittest.TestCase): } ) - self.assertRaises(frappe.ValidationError, shift_assignment_3.save) + self.assertRaises(OverlappingShiftError, shift_assignment_3.save) + + def test_overlapping_for_a_fixed_period_shift_and_ongoing_shift(self): + employee = make_employee("test_shift_assignment@example.com", company="_Test Company") + + # shift setup for 8-12 + shift_type = setup_shift_type(shift_type="Shift 1", start_time="08:00:00", end_time="12:00:00") + date = getdate() + # shift with end date + make_shift_assignment(shift_type.name, employee, date, add_days(date, 30)) + + # shift setup for 13-15 + shift_type = setup_shift_type(shift_type="Shift 2", start_time="11:00:00", end_time="15:00:00") + date = getdate() + + # shift assignment without end date + shift2 = frappe.get_doc( + { + "doctype": "Shift Assignment", + "shift_type": shift_type.name, + "company": "_Test Company", + "employee": employee, + "start_date": date, + } + ) + self.assertRaises(OverlappingShiftError, shift2.insert) + + def test_overlap_validation_for_shifts_on_same_day_with_overlapping_timeslots(self): + employee = make_employee("test_shift_assignment@example.com", company="_Test Company") + + # shift setup for 8-12 + shift_type = setup_shift_type(shift_type="Shift 1", start_time="08:00:00", end_time="12:00:00") + date = getdate() + make_shift_assignment(shift_type.name, employee, date) + + # shift setup for 13-15 + shift_type = setup_shift_type(shift_type="Shift 2", start_time="11:00:00", end_time="15:00:00") + date = getdate() + + shift2 = frappe.get_doc( + { + "doctype": "Shift Assignment", + "shift_type": shift_type.name, + "company": "_Test Company", + "employee": employee, + "start_date": date, + } + ) + self.assertRaises(OverlappingShiftError, shift2.insert) + + def test_multiple_shift_assignments_for_same_day(self): + employee = make_employee("test_shift_assignment@example.com", company="_Test Company") + + # shift setup for 8-12 + shift_type = setup_shift_type(shift_type="Shift 1", start_time="08:00:00", end_time="12:00:00") + date = getdate() + make_shift_assignment(shift_type.name, employee, date) + + # shift setup for 13-15 + shift_type = setup_shift_type(shift_type="Shift 2", start_time="13:00:00", end_time="15:00:00") + date = getdate() + make_shift_assignment(shift_type.name, employee, date) + + +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 diff --git a/erpnext/hr/doctype/shift_type/test_shift_type.py b/erpnext/hr/doctype/shift_type/test_shift_type.py index 7d2f29cd6cc..b91a7c3d7ff 100644 --- a/erpnext/hr/doctype/shift_type/test_shift_type.py +++ b/erpnext/hr/doctype/shift_type/test_shift_type.py @@ -3,6 +3,34 @@ import unittest +import frappe + class TestShiftType(unittest.TestCase): pass + + +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