feat: Assign shift for period or create ongoing assignment

This commit is contained in:
Anurag Mishra 2020-06-18 17:41:53 +05:30
parent e447c79f9d
commit afa98bb39b
2 changed files with 100 additions and 42 deletions

View File

@ -10,9 +10,11 @@
"employee",
"employee_name",
"shift_type",
"status",
"column_break_3",
"company",
"date",
"start_date",
"end_date",
"shift_request",
"department",
"amended_from"
@ -59,12 +61,6 @@
"options": "Company",
"reqd": 1
},
{
"fieldname": "date",
"fieldtype": "Date",
"in_list_view": 1,
"label": "Date"
},
{
"fieldname": "shift_request",
"fieldtype": "Link",
@ -80,11 +76,36 @@
"options": "Shift Assignment",
"print_hide": 1,
"read_only": 1
},
{
"fieldname": "start_date",
"fieldtype": "Date",
"in_list_view": 1,
"label": "Start Date",
"reqd": 1
},
{
"allow_on_submit": 1,
"fieldname": "end_date",
"fieldtype": "Date",
"label": "End Date",
"show_days": 1,
"show_seconds": 1
},
{
"allow_on_submit": 1,
"default": "Active",
"fieldname": "status",
"fieldtype": "Select",
"label": "Status",
"options": "Active\nInactive",
"show_days": 1,
"show_seconds": 1
}
],
"is_submittable": 1,
"links": [],
"modified": "2019-12-12 15:49:06.956901",
"modified": "2020-06-15 14:27:54.310773",
"modified_by": "Administrator",
"module": "HR",
"name": "Shift Assignment",

View File

@ -11,38 +11,64 @@ from erpnext.hr.doctype.employee.employee import get_holiday_list_for_employee
from erpnext.hr.doctype.holiday_list.holiday_list import is_holiday
from datetime import timedelta, datetime
class OverlapError(frappe.ValidationError): pass
class ShiftAssignment(Document):
def validate(self):
self.validate_overlapping_dates()
if self.end_date and self.end_date <= self.start_date:
frappe.throw(_("End Date should not be less than Start Date"))
def validate_overlapping_dates(self):
if not self.name:
self.name = "New Shift Assignment"
d = frappe.db.sql("""
select
name, shift_type, date
condition = """and (
end_date is null
or
%(start_date)s between start_date and end_date
"""
if self.end_date:
condition += """ or
%(end_date)s between start_date and end_date
or
start_date between %(start_date)s and %(end_date)s
) """
else:
condition += """ ) """
assigned_shifts = frappe.db.sql("""
select name, shift_type, start_date ,end_date, docstatus, status
from `tabShift Assignment`
where employee = %(employee)s and docstatus < 2
and date = %(date)s
and name != %(name)s""", {
where
employee=%(employee)s and docstatus < 2
and name != %(name)s
and status = "Active"
{0}
""".format(condition), {
"employee": self.employee,
"shift_type": self.shift_type,
"date": self.date,
"start_date": self.start_date,
"end_date": self.end_date,
"name": self.name
}, as_dict = 1)
for date_overlap in d:
if date_overlap['name']:
self.throw_overlap_error(date_overlap)
for shift in assigned_shifts:
if shift.name:
self.throw_overlap_error(shift)
def throw_overlap_error(self, d):
msg = _("Employee {0} has already applied for {1} on {2} : ").format(self.employee,
d['shift_type'], formatdate(d['date'])) \
+ """ <b><a href="#Form/Shift Assignment/{0}">{0}</a></b>""".format(d["name"])
frappe.throw(msg, OverlapError)
def throw_overlap_error(self, shift_details):
shift_details = frappe._dict(shift_details)
if shift_details.docstatus == 0:
msg = _("Employee {0} has already applied for {1}: {2}").format(self.employee, self.shift_type, shift_details.name)
if shift_details.docstatus == 1 and shift_details.status == "Active":
msg = _("Employee {0} already have Active Shift {1}: {2}").format(self.employee, self.shift_type, shift_details.name)
if shift_details.start_date:
msg += _(" from {0}").format(getdate(self.start_date).strftime("%d-%m-%Y"))
if shift_details.end_date:
msg += _(" to {0}").format(getdate(self.end_date).strftime("%d-%m-%Y"))
if msg:
frappe.throw(msg)
@frappe.whitelist()
def get_events(start, end, filters=None):
@ -62,19 +88,22 @@ def get_events(start, end, filters=None):
return events
def add_assignments(events, start, end, conditions=None):
query = """select name, date, employee_name,
query = """select name, start_date, end_date, employee_name,
employee, docstatus
from `tabShift Assignment` where
date <= %(date)s
and docstatus < 2"""
start_date >= %(start_date)s
and docstatus < 2""".format()
if conditions:
query += conditions
for d in frappe.db.sql(query, {"date":start, "date":end}, as_dict=True):
for d in frappe.db.sql(query, {"start_date":start}, as_dict=True):
from pprint import pprint
pprint(d)
e = {
"name": d.name,
"doctype": "Shift Assignment",
"date": d.date,
"start_date": d.start_date,
"end_date": d.end_date if d.end_date else nowdate(),
"title": cstr(d.employee_name) + \
cstr(d.shift_type),
"docstatus": d.docstatus
@ -92,7 +121,14 @@ def get_employee_shift(employee, for_date=nowdate(), consider_default_shift=Fals
:param next_shift_direction: One of: None, 'forward', 'reverse'. Direction to look for next shift if shift not found on given date.
"""
default_shift = frappe.db.get_value('Employee', employee, 'default_shift')
shift_type_name = frappe.db.get_value('Shift Assignment', {'employee':employee, 'date': for_date, 'docstatus': '1'}, 'shift_type')
shift_assignment_details = frappe.db.get_value('Shift Assignment', {'employee':employee, 'start_date':('<=', for_date), 'docstatus': '1', 'status': "Active"}, ['shift_type', 'end_date'])
shift_type_name = shift_assignment_details[0]
# if end_date present means that shift is over after end_date else it is a ongoing shift.
if shift_assignment_details[1] and for_date >= shift_assignment_details[1] :
shift_type_name = None
if not shift_type_name and consider_default_shift:
shift_type_name = default_shift
if shift_type_name:
@ -117,12 +153,13 @@ def get_employee_shift(employee, for_date=nowdate(), consider_default_shift=Fals
direction = '<' if next_shift_direction == 'reverse' else '>'
sort_order = 'desc' if next_shift_direction == 'reverse' else 'asc'
dates = frappe.db.get_all('Shift Assignment',
'date',
{'employee':employee, 'date':(direction, for_date), 'docstatus': '1'},
'start_date',
{'employee':employee, 'start_date':(direction, for_date), 'docstatus': '1', "status": "Active"},
as_list=True,
limit=MAX_DAYS, order_by="date "+sort_order)
for date in dates:
shift_details = get_employee_shift(employee, date[0], consider_default_shift, None)
shift_details = get_employee_shift(employee, date.start_date, consider_default_shift, None)
if shift_details:
shift_type_name = shift_details.shift_type.name
for_date = date[0]