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

feat: option to enable/disable multiple Shift Assignments for same dates #1100

Merged
15 changes: 14 additions & 1 deletion hrms/hr/doctype/hr_settings/hr_settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
"expense_approver_mandatory_in_expense_claim",
"show_leaves_of_all_department_members_in_calendar",
"auto_leave_encashment",
"shift_settings_section",
"allow_multiple_shift_assignments",
"hiring_settings_section",
"check_vacancies",
"send_interview_reminder",
Expand Down Expand Up @@ -267,13 +269,24 @@
{
"fieldname": "column_break_hyec",
"fieldtype": "Column Break"
},
{
"default": "1",
"fieldname": "allow_multiple_shift_assignments",
"fieldtype": "Check",
"label": "Allow Multiple Shift Assignments for Same Date"
},
{
"fieldname": "shift_settings_section",
"fieldtype": "Section Break",
"label": "Shift Settings"
}
],
"icon": "fa fa-cog",
"idx": 1,
"issingle": 1,
"links": [],
"modified": "2023-11-01 11:06:31.329718",
"modified": "2023-12-07 14:55:37.309553",
"modified_by": "Administrator",
"module": "HR",
"name": "HR Settings",
Expand Down
34 changes: 33 additions & 1 deletion hrms/hr/doctype/shift_assignment/shift_assignment.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from frappe import _
from frappe.model.document import Document
from frappe.query_builder import Criterion
from frappe.utils import add_days, cstr, get_link_to_form, get_time, getdate, now_datetime
from frappe.utils import add_days, cint, cstr, get_link_to_form, get_time, getdate, now_datetime

from hrms.hr.utils import validate_active_employee
from hrms.utils import generate_date_range
Expand All @@ -19,6 +19,10 @@ class OverlappingShiftError(frappe.ValidationError):
pass


class MultipleShiftError(frappe.ValidationError):
pass


class ShiftAssignment(Document):
def validate(self):
validate_active_employee(self.employee)
Expand All @@ -30,11 +34,39 @@ def validate(self):
def validate_overlapping_shifts(self):
overlapping_dates = self.get_overlapping_dates()
if len(overlapping_dates):
self.validate_same_date_multiple_shifts(overlapping_dates)
# if dates are overlapping, check if timings are overlapping, else allow
overlapping_timings = has_overlapping_timings(self.shift_type, overlapping_dates[0].shift_type)
if overlapping_timings:
self.throw_overlap_error(overlapping_dates[0])

def validate_same_date_multiple_shifts(self, overlapping_dates):
if cint(frappe.db.get_single_value("HR Settings", "allow_multiple_shift_assignments")):
if not self.docstatus:
frappe.msgprint(
_(
"Warning: {0} already has an active Shift Assignment {1} for some/all of these dates."
).format(
frappe.bold(self.employee), get_link_to_form("Shift Assignment", overlapping_dates[0].name)
)
)
else:
msg = _("{0} already has an active Shift Assignment {1} for some/all of these dates.").format(
frappe.bold(self.employee),
get_link_to_form("Shift Assignment", overlapping_dates[0].name),
)
msg += "<br><br>"
msg += _("To allow this, enable {0} under {1}.").format(
frappe.bold(_("Allow Multiple Shift Assignments for Same Date")),
get_link_to_form("HR Settings", "HR Settings"),
)

frappe.throw(
title=_("Multiple Shift Assignments"),
msg=msg,
exc=MultipleShiftError,
)

def get_overlapping_dates(self):
if not self.name:
self.name = "New Shift Assignment"
Expand Down
34 changes: 34 additions & 0 deletions hrms/hr/doctype/shift_assignment/test_shift_assignment.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from erpnext.setup.doctype.employee.test_employee import make_employee

from hrms.hr.doctype.shift_assignment.shift_assignment import (
MultipleShiftError,
OverlappingShiftError,
get_actual_start_end_datetime_of_shift,
get_events,
Expand Down Expand Up @@ -66,6 +67,39 @@ def test_overlapping_for_ongoing_shift(self):

self.assertRaises(OverlappingShiftError, shift_assignment.save)

def test_multiple_shift_assignments_for_same_date(self):
setup_shift_type(shift_type="Day Shift")
shift_assignment_1 = frappe.get_doc(
{
"doctype": "Shift Assignment",
"shift_type": "Day Shift",
"company": "_Test Company",
"employee": "_T-Employee-00001",
"start_date": nowdate(),
"end_date": add_days(nowdate(), 30),
"status": "Active",
}
).insert()
shift_assignment_1.submit()

setup_shift_type(shift_type="Night Shift", start_time="19:00:00", end_time="23:00:00")
shift_assignment_2 = frappe.get_doc(
{
"doctype": "Shift Assignment",
"shift_type": "Night Shift",
"company": "_Test Company",
"employee": "_T-Employee-00001",
"start_date": nowdate(),
"end_date": add_days(nowdate(), 30),
"status": "Active",
}
)

frappe.db.set_single_value("HR Settings", "allow_multiple_shift_assignments", 0)
self.assertRaises(MultipleShiftError, shift_assignment_2.save)
frappe.db.set_single_value("HR Settings", "allow_multiple_shift_assignments", 1)
shift_assignment_2.save() # would throw error if multiple shift assignments not allowed

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")
Expand Down
4 changes: 2 additions & 2 deletions hrms/hr/doctype/shift_type/test_shift_type.py
Original file line number Diff line number Diff line change
Expand Up @@ -613,8 +613,8 @@ def setup_shift_type(**args):
{
"doctype": "Shift Type",
"__newname": args.shift_type or "_Test Shift",
"start_time": "08:00:00",
"end_time": "12:00:00",
"start_time": args.start_time or "08:00:00",
"end_time": args.end_time or "12:00:00",
"enable_auto_attendance": 1,
"determine_check_in_and_check_out": "Alternating entries as IN and OUT during the same shift",
"working_hours_calculation_based_on": "First Check-in and Last Check-out",
Expand Down
Loading