From 2215d4c593983b3ed4a52af66fb3b6d9ca561cd8 Mon Sep 17 00:00:00 2001 From: Pawan Mehta Date: Wed, 18 Apr 2018 10:59:59 +0530 Subject: [PATCH] Shift Management (#13667) * [fix] #13634 * review_changes * rename function * rename function --- erpnext/config/hr.py | 4 - .../shift_assignment/shift_assignment.json | 42 +++++++- .../shift_assignment/shift_assignment.py | 72 +++++++++++++- .../shift_assignment_calendar.js | 19 ++++ .../doctype/shift_request/shift_request.json | 98 ++++++++++++------- .../hr/doctype/shift_request/shift_request.py | 79 ++++++++++++++- erpnext/hr/doctype/shift_type/shift_type.py | 2 +- 7 files changed, 270 insertions(+), 46 deletions(-) create mode 100644 erpnext/hr/doctype/shift_assignment/shift_assignment_calendar.js diff --git a/erpnext/config/hr.py b/erpnext/config/hr.py index 9a8298120aa..fb00529c165 100644 --- a/erpnext/config/hr.py +++ b/erpnext/config/hr.py @@ -263,10 +263,6 @@ def get_data(): { "type": "doctype", "name": "Shift Assignment", - }, - { - "type": "doctype", - "name": "Shift Assignment Tool", } ] }, diff --git a/erpnext/hr/doctype/shift_assignment/shift_assignment.json b/erpnext/hr/doctype/shift_assignment/shift_assignment.json index 87d69e4816a..897cfed68af 100644 --- a/erpnext/hr/doctype/shift_assignment/shift_assignment.json +++ b/erpnext/hr/doctype/shift_assignment/shift_assignment.json @@ -1,7 +1,7 @@ { "allow_copy": 0, "allow_guest_to_view": 0, - "allow_import": 0, + "allow_import": 1, "allow_rename": 0, "autoname": "SH.#####", "beta": 0, @@ -26,7 +26,7 @@ "ignore_xss_filter": 0, "in_filter": 0, "in_global_search": 0, - "in_list_view": 1, + "in_list_view": 0, "in_standard_filter": 0, "label": "Employee", "length": 0, @@ -183,7 +183,7 @@ "ignore_xss_filter": 0, "in_filter": 0, "in_global_search": 0, - "in_list_view": 1, + "in_list_view": 0, "in_standard_filter": 0, "label": "Company", "length": 0, @@ -215,7 +215,7 @@ "ignore_xss_filter": 0, "in_filter": 0, "in_global_search": 0, - "in_list_view": 0, + "in_list_view": 1, "in_standard_filter": 0, "label": "Date", "length": 0, @@ -233,6 +233,38 @@ "translatable": 0, "unique": 0 }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "shift_request", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Shift Request", + "length": 0, + "no_copy": 0, + "options": "Shift Request", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, { "allow_bulk_edit": 0, "allow_on_submit": 0, @@ -275,7 +307,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2018-04-14 15:42:12.617715", + "modified": "2018-04-17 14:50:09.125737", "modified_by": "Administrator", "module": "HR", "name": "Shift Assignment", diff --git a/erpnext/hr/doctype/shift_assignment/shift_assignment.py b/erpnext/hr/doctype/shift_assignment/shift_assignment.py index 272dd2b32d4..fbbfe3102ab 100644 --- a/erpnext/hr/doctype/shift_assignment/shift_assignment.py +++ b/erpnext/hr/doctype/shift_assignment/shift_assignment.py @@ -4,7 +4,77 @@ from __future__ import unicode_literals import frappe +from frappe import _ from frappe.model.document import Document +from frappe.utils import cint, cstr, date_diff, flt, formatdate, getdate + +class OverlapError(frappe.ValidationError): pass class ShiftAssignment(Document): - pass + def validate(self): + self.validate_overlapping_dates(); + + def validate_overlapping_dates(self): + if not self.name: + self.name = "New Shift Assignment" + + d = frappe.db.sql(""" + select + name, shift_type, date + from `tabShift Assignment` + where employee = %(employee)s and docstatus < 2 + and date = %(date)s + and name != %(name)s""", { + "employee": self.employee, + "shift_type": self.shift_type, + "date": self.date, + "name": self.name + }, as_dict = 1) + + for date_overlap in d: + if date_overlap['name']: + self.throw_overlap_error(date_overlap) + + 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'])) \ + + """ {0}""".format(d["name"]) + frappe.throw(msg, OverlapError) + +@frappe.whitelist() +def get_events(start, end, filters=None): + events = [] + + employee = frappe.db.get_value("Employee", {"user_id": frappe.session.user}, ["name", "company"], + as_dict=True) + if employee: + employee, company = employee.name, employee.company + else: + employee='' + company=frappe.db.get_value("Global Defaults", None, "default_company") + + from frappe.desk.reportview import get_filters_cond + conditions = get_filters_cond("Shift Assignment", filters, []) + add_assignments(events, start, end, conditions=conditions) + return events + +def add_assignments(events, start, end, conditions=None): + query = """select name, date, employee_name, + employee, docstatus + from `tabShift Assignment` where + date <= %(date)s + and docstatus < 2""" + if conditions: + query += conditions + + for d in frappe.db.sql(query, {"date":start, "date":end}, as_dict=True): + e = { + "name": d.name, + "doctype": "Shift Assignment", + "date": d.date, + "title": cstr(d.employee_name) + \ + cstr(d.shift_type), + "docstatus": d.docstatus + } + if e not in events: + events.append(e) \ No newline at end of file diff --git a/erpnext/hr/doctype/shift_assignment/shift_assignment_calendar.js b/erpnext/hr/doctype/shift_assignment/shift_assignment_calendar.js new file mode 100644 index 00000000000..c2c9bc073ad --- /dev/null +++ b/erpnext/hr/doctype/shift_assignment/shift_assignment_calendar.js @@ -0,0 +1,19 @@ +// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors +// For license information, please see license.txt + +frappe.views.calendar["Shift Assignment"] = { + field_map: { + "start": "date", + "end": "date", + "id": "name", + "docstatus": 1 + }, + options: { + header: { + left: 'prev,next today', + center: 'title', + right: 'month' + } + }, + get_events_method: "erpnext.hr.doctype.shift_assignment.shift_assignment.get_events" +} \ No newline at end of file diff --git a/erpnext/hr/doctype/shift_request/shift_request.json b/erpnext/hr/doctype/shift_request/shift_request.json index 1210d157dc6..04a3edf7064 100644 --- a/erpnext/hr/doctype/shift_request/shift_request.json +++ b/erpnext/hr/doctype/shift_request/shift_request.json @@ -1,7 +1,7 @@ { "allow_copy": 0, "allow_guest_to_view": 0, - "allow_import": 0, + "allow_import": 1, "allow_rename": 0, "autoname": "SREQ.#####", "beta": 0, @@ -13,6 +13,38 @@ "editable_grid": 1, "engine": "InnoDB", "fields": [ + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "shift_type", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Shift Type", + "length": 0, + "no_copy": 0, + "options": "Shift Type", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, { "allow_bulk_edit": 0, "allow_on_submit": 0, @@ -77,6 +109,36 @@ "translatable": 0, "unique": 0 }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "column_break_4", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, { "allow_bulk_edit": 0, "allow_on_submit": 0, @@ -109,38 +171,6 @@ "translatable": 0, "unique": 0 }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "shift_type", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Shift Type", - "length": 0, - "no_copy": 0, - "options": "Shift Type", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, { "allow_bulk_edit": 0, "allow_on_submit": 0, @@ -245,7 +275,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2018-04-14 15:40:39.590051", + "modified": "2018-04-16 11:01:25.902995", "modified_by": "Administrator", "module": "HR", "name": "Shift Request", diff --git a/erpnext/hr/doctype/shift_request/shift_request.py b/erpnext/hr/doctype/shift_request/shift_request.py index e6755ae44e5..7057d20d73e 100644 --- a/erpnext/hr/doctype/shift_request/shift_request.py +++ b/erpnext/hr/doctype/shift_request/shift_request.py @@ -4,7 +4,84 @@ from __future__ import unicode_literals import frappe +from frappe import _ from frappe.model.document import Document +from frappe.utils import formatdate, getdate + +class OverlapError(frappe.ValidationError): pass class ShiftRequest(Document): - pass + def validate(self): + self.validate_dates(); + self.validate_shift_request_overlap_dates(); + + def on_submit(self): + date_list = self.get_working_days(self.from_date, self.to_date) + for date in date_list: + assignment_doc = frappe.new_doc("Shift Assignment") + assignment_doc.company = self.company + assignment_doc.shift_type = self.shift_type + assignment_doc.employee = self.employee + assignment_doc.date = date + assignment_doc.shift_request = self.name + assignment_doc.insert() + assignment_doc.submit() + + def validate_dates(self): + if self.from_date and self.to_date and (getdate(self.to_date) < getdate(self.from_date)): + frappe.throw(_("To date cannot be before from date")) + + def validate_shift_request_overlap_dates(self): + if not self.name: + self.name = "New Shift Request" + + d = frappe.db.sql(""" + select + name, shift_type, from_date, to_date + from `tabShift Request` + where employee = %(employee)s and docstatus < 2 + and ((%(from_date)s >= from_date + and %(from_date)s <= to_date) or + ( %(to_date)s >= from_date + and %(to_date)s <= to_date )) + and name != %(name)s""", { + "employee": self.employee, + "shift_type": self.shift_type, + "from_date": self.from_date, + "to_date": self.to_date, + "name": self.name + }, as_dict=1) + + for date_overlap in d: + if date_overlap ['name']: + self.throw_overlap_error(date_overlap) + + def throw_overlap_error(self, d): + msg = _("Employee {0} has already applied for {1} between {2} and {3} : ").format(self.employee, + d['shift_type'], formatdate(d['from_date']), formatdate(d['to_date'])) \ + + """ {0}""".format(d["name"]) + frappe.throw(msg, OverlapError) + + def get_working_days(self, start_date, end_date): + start_date, end_date = getdate(start_date), getdate(end_date) + + from datetime import timedelta + + date_list = [] + employee_holiday_list = [] + + employee_holidays = frappe.db.sql("""select holiday_date from `tabHoliday` + where parent in (select holiday_list from `tabEmployee` + where name = %s)""",self.employee,as_dict=1) + + for d in employee_holidays: + employee_holiday_list.append(d.holiday_date) + + reference_date = start_date + + while reference_date <= end_date: + if reference_date not in employee_holiday_list: + date_list.append(reference_date) + reference_date += timedelta(days=1) + + return date_list \ No newline at end of file diff --git a/erpnext/hr/doctype/shift_type/shift_type.py b/erpnext/hr/doctype/shift_type/shift_type.py index 6721439ce61..88ae243dda1 100644 --- a/erpnext/hr/doctype/shift_type/shift_type.py +++ b/erpnext/hr/doctype/shift_type/shift_type.py @@ -7,4 +7,4 @@ import frappe from frappe.model.document import Document class ShiftType(Document): - pass + pass \ No newline at end of file