mirror of
https://github.com/frappe/erpnext.git
synced 2026-06-08 15:42:52 +00:00
Shift Management (#13667)
* [fix] #13634 * review_changes * rename function * rename function
This commit is contained in:
@@ -263,10 +263,6 @@ def get_data():
|
|||||||
{
|
{
|
||||||
"type": "doctype",
|
"type": "doctype",
|
||||||
"name": "Shift Assignment",
|
"name": "Shift Assignment",
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "doctype",
|
|
||||||
"name": "Shift Assignment Tool",
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"allow_copy": 0,
|
"allow_copy": 0,
|
||||||
"allow_guest_to_view": 0,
|
"allow_guest_to_view": 0,
|
||||||
"allow_import": 0,
|
"allow_import": 1,
|
||||||
"allow_rename": 0,
|
"allow_rename": 0,
|
||||||
"autoname": "SH.#####",
|
"autoname": "SH.#####",
|
||||||
"beta": 0,
|
"beta": 0,
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
"ignore_xss_filter": 0,
|
"ignore_xss_filter": 0,
|
||||||
"in_filter": 0,
|
"in_filter": 0,
|
||||||
"in_global_search": 0,
|
"in_global_search": 0,
|
||||||
"in_list_view": 1,
|
"in_list_view": 0,
|
||||||
"in_standard_filter": 0,
|
"in_standard_filter": 0,
|
||||||
"label": "Employee",
|
"label": "Employee",
|
||||||
"length": 0,
|
"length": 0,
|
||||||
@@ -183,7 +183,7 @@
|
|||||||
"ignore_xss_filter": 0,
|
"ignore_xss_filter": 0,
|
||||||
"in_filter": 0,
|
"in_filter": 0,
|
||||||
"in_global_search": 0,
|
"in_global_search": 0,
|
||||||
"in_list_view": 1,
|
"in_list_view": 0,
|
||||||
"in_standard_filter": 0,
|
"in_standard_filter": 0,
|
||||||
"label": "Company",
|
"label": "Company",
|
||||||
"length": 0,
|
"length": 0,
|
||||||
@@ -215,7 +215,7 @@
|
|||||||
"ignore_xss_filter": 0,
|
"ignore_xss_filter": 0,
|
||||||
"in_filter": 0,
|
"in_filter": 0,
|
||||||
"in_global_search": 0,
|
"in_global_search": 0,
|
||||||
"in_list_view": 0,
|
"in_list_view": 1,
|
||||||
"in_standard_filter": 0,
|
"in_standard_filter": 0,
|
||||||
"label": "Date",
|
"label": "Date",
|
||||||
"length": 0,
|
"length": 0,
|
||||||
@@ -233,6 +233,38 @@
|
|||||||
"translatable": 0,
|
"translatable": 0,
|
||||||
"unique": 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_bulk_edit": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
@@ -275,7 +307,7 @@
|
|||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"max_attachments": 0,
|
"max_attachments": 0,
|
||||||
"modified": "2018-04-14 15:42:12.617715",
|
"modified": "2018-04-17 14:50:09.125737",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "HR",
|
"module": "HR",
|
||||||
"name": "Shift Assignment",
|
"name": "Shift Assignment",
|
||||||
|
|||||||
@@ -4,7 +4,77 @@
|
|||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import frappe
|
import frappe
|
||||||
|
from frappe import _
|
||||||
from frappe.model.document import Document
|
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):
|
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'])) \
|
||||||
|
+ """ <b><a href="#Form/Shift Request/{0}">{0}</a></b>""".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)
|
||||||
@@ -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"
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"allow_copy": 0,
|
"allow_copy": 0,
|
||||||
"allow_guest_to_view": 0,
|
"allow_guest_to_view": 0,
|
||||||
"allow_import": 0,
|
"allow_import": 1,
|
||||||
"allow_rename": 0,
|
"allow_rename": 0,
|
||||||
"autoname": "SREQ.#####",
|
"autoname": "SREQ.#####",
|
||||||
"beta": 0,
|
"beta": 0,
|
||||||
@@ -13,6 +13,38 @@
|
|||||||
"editable_grid": 1,
|
"editable_grid": 1,
|
||||||
"engine": "InnoDB",
|
"engine": "InnoDB",
|
||||||
"fields": [
|
"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_bulk_edit": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
@@ -77,6 +109,36 @@
|
|||||||
"translatable": 0,
|
"translatable": 0,
|
||||||
"unique": 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_bulk_edit": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
@@ -109,38 +171,6 @@
|
|||||||
"translatable": 0,
|
"translatable": 0,
|
||||||
"unique": 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_bulk_edit": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
@@ -245,7 +275,7 @@
|
|||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"max_attachments": 0,
|
"max_attachments": 0,
|
||||||
"modified": "2018-04-14 15:40:39.590051",
|
"modified": "2018-04-16 11:01:25.902995",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "HR",
|
"module": "HR",
|
||||||
"name": "Shift Request",
|
"name": "Shift Request",
|
||||||
|
|||||||
@@ -4,7 +4,84 @@
|
|||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import frappe
|
import frappe
|
||||||
|
from frappe import _
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
|
from frappe.utils import formatdate, getdate
|
||||||
|
|
||||||
|
class OverlapError(frappe.ValidationError): pass
|
||||||
|
|
||||||
class ShiftRequest(Document):
|
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'])) \
|
||||||
|
+ """ <b><a href="#Form/Shift Request/{0}">{0}</a></b>""".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
|
||||||
Reference in New Issue
Block a user