fix: Child table for priority
diff --git a/erpnext/support/doctype/issue/issue.json b/erpnext/support/doctype/issue/issue.json
index 2e23b09..9639702 100644
--- a/erpnext/support/doctype/issue/issue.json
+++ b/erpnext/support/doctype/issue/issue.json
@@ -14,12 +14,12 @@
"raised_by",
"cb00",
"status",
- "service_level_agreement",
"priority",
"issue_type",
"sb_details",
"description",
"service_level_section",
+ "service_level_agreement",
"response_by",
"cb",
"agreement_status",
@@ -115,8 +115,7 @@
"fieldtype": "Select",
"in_standard_filter": 1,
"label": "Priority",
- "options": "Low\nMedium\nHigh",
- "reqd": 1
+ "options": "Low\nMedium\nHigh"
},
{
"fieldname": "issue_type",
@@ -151,7 +150,8 @@
"fieldname": "service_level_agreement",
"fieldtype": "Link",
"label": "Service Level Agreement",
- "options": "Service Level Agreement"
+ "options": "Service Level Agreement",
+ "read_only": 1
},
{
"fieldname": "response_by",
@@ -321,7 +321,7 @@
],
"icon": "fa fa-ticket",
"idx": 7,
- "modified": "2019-05-03 11:11:50.495619",
+ "modified": "2019-05-03 14:36:19.117560",
"modified_by": "Administrator",
"module": "Support",
"name": "Issue",
diff --git a/erpnext/support/doctype/issue/issue.py b/erpnext/support/doctype/issue/issue.py
index d626def..0ff37d7 100644
--- a/erpnext/support/doctype/issue/issue.py
+++ b/erpnext/support/doctype/issue/issue.py
@@ -126,25 +126,29 @@
return replicated_issue.name
def before_insert(self):
- self.set_response_and_resolution_time()
+ self.set_response_and_resolution_time(priority=self.priority)
- def set_response_and_resolution_time(self):
- service_level_agreement = get_active_service_level_agreement_for(self.customer)
+ def set_response_and_resolution_time(self, priority=None):
+ service_level_agreement = get_active_service_level_agreement_for(self.customer, priority)
if service_level_agreement:
self.service_level_agreement = service_level_agreement.name
- self.priority = service_level_agreement.priority
-
- if not self.service_level_agreement: return
+ else:
+ return
service_level = frappe.get_doc("Service Level", service_level_agreement.service_level)
+ priority = service_level.get_service_level_priority(priority)
+ priority.update({
+ "support_and_resolution": service_level.support_and_resolution,
+ "holiday_list": service_level.holiday_list
+ })
if not self.creation:
self.creation = now_datetime()
start_date_time = get_datetime(self.creation)
- self.response_by = get_expected_time_for('response', service_level, start_date_time)
- self.resolution_by = get_expected_time_for('resolution', service_level, start_date_time)
+ self.response_by = get_expected_time_for(parameter='response', service_level=priority, start_date_time=start_date_time)
+ self.resolution_by = get_expected_time_for(parameter='resolution', service_level=priority, start_date_time=start_date_time)
def get_expected_time_for(parameter, service_level, start_date_time):
current_date_time = start_date_time
@@ -154,11 +158,11 @@
# lets assume response time is in days by default
if parameter == 'response':
- allotted_days = service_level.response_time
- time_period = service_level.response_time_period
+ allotted_days = service_level.get("response_time")
+ time_period = service_level.get("response_time_period")
elif parameter == 'resolution':
- allotted_days = service_level.resolution_time
- time_period = service_level.resolution_time_period
+ allotted_days = service_level.get("resolution_time")
+ time_period = service_level.get("resolution_time_period")
else:
frappe.throw(_("{0} parameter is invalid".format(parameter)))
@@ -172,13 +176,13 @@
expected_time_is_set = 1 if allotted_days == 0 and time_period in ['Day', 'Week'] else 0
support_days = {}
- for service in service_level.support_and_resolution:
+ for service in service_level.get("support_and_resolution"):
support_days[service.workday] = frappe._dict({
'start_time': service.start_time,
'end_time': service.end_time,
})
- holidays = get_holidays(service_level.holiday_list)
+ holidays = get_holidays(service_level.get("holiday_list"))
weekdays = get_weekdays()
while not expected_time_is_set:
@@ -248,14 +252,12 @@
for name in names:
set_status(name, status)
-
@frappe.whitelist()
def set_status(name, status):
st = frappe.get_doc("Issue", name)
st.status = status
st.save()
-
def auto_close_tickets():
"""Auto-close replied support tickets after 7 days"""
auto_close_after_days = frappe.db.get_value("Support Settings", "Support Settings", "close_issue_after_days") or 7
@@ -295,6 +297,7 @@
"doctype": "Task"
}
}, target_doc)
+
@frappe.whitelist()
def make_issue_from_communication(communication, ignore_communication_links=False):
""" raise a issue from email """
diff --git a/erpnext/support/doctype/service_level/service_level.json b/erpnext/support/doctype/service_level/service_level.json
index 9dc1a8d..fb4e747 100644
--- a/erpnext/support/doctype/service_level/service_level.json
+++ b/erpnext/support/doctype/service_level/service_level.json
@@ -10,11 +10,7 @@
"column_break_2",
"holiday_list",
"response_and_resoution_time",
- "response_time",
- "resolution_time",
- "column_break_9",
- "response_time_period",
- "resolution_time_period",
+ "priority",
"section_break_01",
"support_and_resolution"
],
@@ -52,36 +48,6 @@
"label": "Response and Resoution Time"
},
{
- "fieldname": "response_time",
- "fieldtype": "Int",
- "label": "Response Time",
- "reqd": 1
- },
- {
- "fieldname": "resolution_time",
- "fieldtype": "Int",
- "label": "Resolution Time",
- "reqd": 1
- },
- {
- "fieldname": "column_break_9",
- "fieldtype": "Column Break"
- },
- {
- "fieldname": "response_time_period",
- "fieldtype": "Select",
- "label": "Response Time Period",
- "options": "Hour\nDay\nWeek",
- "reqd": 1
- },
- {
- "fieldname": "resolution_time_period",
- "fieldtype": "Select",
- "label": "Resolution Time Period",
- "options": "Hour\nDay\nWeek",
- "reqd": 1
- },
- {
"fieldname": "section_break_01",
"fieldtype": "Section Break",
"label": "Support and Resolution"
@@ -92,9 +58,16 @@
"label": "Support and Resolution",
"options": "Service Day",
"reqd": 1
+ },
+ {
+ "fieldname": "priority",
+ "fieldtype": "Table",
+ "label": "Priority",
+ "options": "Service Level Priority",
+ "reqd": 1
}
],
- "modified": "2019-05-03 01:09:43.571945",
+ "modified": "2019-05-04 13:08:33.381734",
"modified_by": "Administrator",
"module": "Support",
"name": "Service Level",
diff --git a/erpnext/support/doctype/service_level/service_level.py b/erpnext/support/doctype/service_level/service_level.py
index 4b41e53..5389afb 100644
--- a/erpnext/support/doctype/service_level/service_level.py
+++ b/erpnext/support/doctype/service_level/service_level.py
@@ -12,35 +12,78 @@
class ServiceLevel(Document):
def validate(self):
+ self.check_priorities()
+ self.check_support_and_resolution()
+
+ def check_priorities(self):
+ priorities = []
+ for priority in self.priority:
+ priorities.append(priority.priority)
+
+ if not (priority.response_time or priority.resolution_time):
+ frappe.throw(_("Set Response Time and Resolution for Priority {0} at index {1}.".format(priority.priority, priority.idx)))
+
+ if priority.response_time_period == "Hour":
+ response = priority.response_time * 0.0416667
+ elif priority.response_time_period == "Day":
+ response = priority.response_time
+ elif priority.response_time_period == "Week":
+ response = priority.response_time * 7
+
+ if priority.resolution_time_period == "Hour":
+ resolution = priority.resolution_time * 0.0416667
+ elif priority.resolution_time_period == "Day":
+ resolution = priority.resolution_time
+ elif priority.resolution_time_period == "Week":
+ resolution = priority.resolution_time * 7
+
+ if response > resolution:
+ frappe.throw(_("Response Time for {0} at index {1} can't be greater than Resolution Time.".format(priority.priority, priority.idx)))
+
+ if not len(set(priorities)) == len(priorities):
+ repeated_priority = get_repeated(priorities)
+ frappe.throw(_("Priority {0} has been repeated twice.".format(repeated_priority)))
+
+ # Check if values for all the priority options is set
+ priority_count = ([field.options for field in frappe.get_meta("Service Level Priority").fields if field.fieldname=='priority'][0]).split("\n")
+ if not len(set(priorities)) == len(priority_count):
+ frappe.throw(_("Set values for all the Priorities."))
+
+ def check_support_and_resolution(self):
week = get_weekdays()
indexes = []
-
- self.check_response_and_resolution_time()
+ support_days = []
for support_and_resolution in self.support_and_resolution:
indexes.append(week.index(support_and_resolution.workday))
+ support_days.append(support_and_resolution.workday)
support_and_resolution.idx = week.index(support_and_resolution.workday) + 1
start_time, end_time = (datetime.strptime(support_and_resolution.start_time, '%H:%M:%S').time(),
datetime.strptime(support_and_resolution.end_time, '%H:%M:%S').time())
if start_time > end_time:
frappe.throw(_("Start Time can't be greater than End Time for {0}.".format(support_and_resolution.workday)))
+
if not len(set(indexes)) == len(indexes):
- frappe.throw(_("Workday has been repeated twice"))
+ repeated_days = get_repeated(support_days)
+ frappe.throw(_("Workday {0} has been repeated twice".format(repeated_days)))
- def check_response_and_resolution_time(self):
- if self.response_time_period == "Hour":
- response = self.response_time * 0.0416667
- elif self.response_time_period == "Day":
- response = self.response_time
- elif self.response_time_period == "Week":
- response = self.response_time * 7
+ def get_service_level_priority(self, priority):
+ priority = frappe.get_doc("Service Level Priority", {"priority": priority, "parent": self.name})
- if self.resolution_time_period == "Hour":
- resolution = self.resolution_time * 0.0416667
- elif self.resolution_time_period == "Day":
- resolution = self.resolution_time
- elif self.resolution_time_period == "Week":
- resolution = self.resolution_time * 7
+ return frappe._dict({
+ "priority": priority.priority,
+ "response_time": priority.response_time,
+ "response_time_period": priority.response_time_period,
+ "resolution_time": priority.resolution_time,
+ "response_time_period": priority.resolution_time_period
+ })
- if response > resolution:
- frappe.throw(_("Response Time can't be greater than Resolution Time"))
\ No newline at end of file
+def get_repeated(values):
+ unique_list = []
+ diff = []
+ for value in values:
+ if value not in unique_list:
+ unique_list.append(value)
+ else:
+ diff.append(value)
+ return " ".join(diff)
diff --git a/erpnext/support/doctype/service_level_agreement/service_level_agreement.js b/erpnext/support/doctype/service_level_agreement/service_level_agreement.js
index 66ec2f3..92d7abd 100644
--- a/erpnext/support/doctype/service_level_agreement/service_level_agreement.js
+++ b/erpnext/support/doctype/service_level_agreement/service_level_agreement.js
@@ -11,7 +11,11 @@
name: frm.doc.service_level
},
callback: function(data){
- for (var i = 0; i < data.message.support_and_resolution.length; i++){
+ console.log(data);
+ for (var i in data.message.priority){
+ frm.add_child("priority", data.message.priority[i]);
+ }
+ for (var i in data.message.support_and_resolution){
frm.add_child("support_and_resolution", data.message.support_and_resolution[i]);
}
frm.refresh();
@@ -19,14 +23,24 @@
});
},
- customer: function(frm) {
+ validate: function(frm) {
frm.doc.service_level_agreement_name = null;
- frm.doc.service_level_agreement_name = frm.doc.priority + ': ' + frm.doc.customer;
+ var sla_name = 'Default Service Level Agreement';
+ if (frm.doc.customer){
+ sla_name = frm.doc.customer;
+ }
+ frm.doc.service_level_agreement_name = sla_name;
},
- default_service_level_agreement: function(frm) {
- frm.doc.service_level_agreement_name = null;
- frm.doc.service_level_agreement_name = frm.doc.priority + ': Default Service Level Agreement';
- },
-
+ priority: function(frm) {
+ if (!frm.doc.__is_local) {
+ frappe.call({
+ "method": "erpnext.support.service_level_agreement.service_level_agreement.get_active_service_level_agreement_for",
+ "args": {
+ "customer": frm.doc.customer,
+ "priority": frm.doc.priority
+ }
+ })
+ }
+ }
});
diff --git a/erpnext/support/doctype/service_level_agreement/service_level_agreement.json b/erpnext/support/doctype/service_level_agreement/service_level_agreement.json
index 67400a1..30a8bfd 100644
--- a/erpnext/support/doctype/service_level_agreement/service_level_agreement.json
+++ b/erpnext/support/doctype/service_level_agreement/service_level_agreement.json
@@ -11,7 +11,6 @@
"holiday_list",
"column_break_2",
"service_level",
- "priority",
"employee_group",
"agreement_details_section",
"start_date",
@@ -19,11 +18,7 @@
"column_break_7",
"end_date",
"response_and_resolution_time_section",
- "response_time",
- "resolution_time",
- "column_break_16",
- "response_time_period",
- "resolution_time_period",
+ "priority",
"support_and_resolution_section_break",
"support_and_resolution"
],
@@ -66,11 +61,9 @@
},
{
"fieldname": "priority",
- "fieldtype": "Select",
+ "fieldtype": "Table",
"label": "Priority",
- "options": "Low\nMedium\nHigh",
- "reqd": 1,
- "set_only_once": 1
+ "options": "Service Level Priority"
},
{
"fetch_from": "service_level.employee_group",
@@ -113,43 +106,12 @@
"label": "End Date"
},
{
+ "collapsible": 1,
"fieldname": "response_and_resolution_time_section",
"fieldtype": "Section Break",
"label": "Response and Resolution Time"
},
{
- "fetch_from": "service_level.response_time",
- "fieldname": "response_time",
- "fieldtype": "Int",
- "label": "Response Time",
- "read_only": 1
- },
- {
- "fetch_from": "service_level.resolution_time",
- "fieldname": "resolution_time",
- "fieldtype": "Int",
- "label": "Resolution Time",
- "read_only": 1
- },
- {
- "fieldname": "column_break_16",
- "fieldtype": "Column Break"
- },
- {
- "fetch_from": "service_level.response_time_period",
- "fieldname": "response_time_period",
- "fieldtype": "Data",
- "label": "Response Time Period",
- "read_only": 1
- },
- {
- "fetch_from": "service_level.resolution_time_period",
- "fieldname": "resolution_time_period",
- "fieldtype": "Data",
- "label": "Resolution Time Period",
- "read_only": 1
- },
- {
"collapsible": 1,
"fieldname": "support_and_resolution_section_break",
"fieldtype": "Section Break",
@@ -170,7 +132,7 @@
"unique": 1
}
],
- "modified": "2019-05-03 01:50:47.135540",
+ "modified": "2019-05-04 13:11:21.373147",
"modified_by": "Administrator",
"module": "Support",
"name": "Service Level Agreement",
diff --git a/erpnext/support/doctype/service_level_agreement/service_level_agreement.py b/erpnext/support/doctype/service_level_agreement/service_level_agreement.py
index a4db835..e879b4a 100644
--- a/erpnext/support/doctype/service_level_agreement/service_level_agreement.py
+++ b/erpnext/support/doctype/service_level_agreement/service_level_agreement.py
@@ -9,21 +9,20 @@
class ServiceLevelAgreement(Document):
- def before_insert(self):
- if self.default_service_level_agreement:
- doc = frappe.get_list("Service Level Agreement", filters=[{"default_service_level_agreement": "1"}])
- if doc:
- frappe.throw(_("A Default Service Level Agreement already exists."))
-
def validate(self):
- if not frm.doc.customer and not frm.doc.default_service_level_agreement:
+ if not (self.customer or self.default_service_level_agreement):
frappe.throw(_("Select a Customer or set as Default Service Level Agreement."))
- if not self.default_service_level_agreement:
+ if self.default_service_level_agreement:
+ if frappe.db.exists("Service Level Agreement", {"default_service_level_agreement": "1"}):
+ frappe.throw(_("A Default Service Level Agreement already exists."))
+ else:
if not (self.start_date and self.end_date):
frappe.throw(_("Enter Start and End Date for the Agreement."))
if self.start_date >= self.end_date:
frappe.throw(_("Start Date of Agreement can't be greater than or equal to End Date."))
+ if self.end_date < frappe.utils.getdate():
+ frappe.throw(_("End Date of Agreement can't be less than today."))
def check_agreement_status():
service_level_agreements = frappe.get_list("Service Level Agreement", filters=[
@@ -37,12 +36,26 @@
service_level_agreement.agreement_status = "Expired"
service_level_agreement.save()
-def get_active_service_level_agreement_for(customer):
- agreement = frappe.get_list("Service Level Agreement",
- filters=[{"agreement_status": "Active"}],
- or_filters=[{'customer': customer},{"default_service_level_agreement": "1"}],
- fields=["name", "service_level", "holiday_list", "priority"],
- order_by='customer DESC',
- limit=1)
+@frappe.whitelist()
+def get_active_service_level_agreement_for(customer, priority):
+
+ agreement = frappe.db.sql("""
+ select `tabService Level Agreement`.name, `tabService Level Agreement`.service_level,
+ `tabService Level Agreement`.holiday_list
+ from `tabService Level Agreement`
+ inner join `tabService Level Priority`
+ on `tabService Level Agreement`.name=`tabService Level Priority`.parent where
+ (
+ `tabService Level Agreement`.customer='{0}' and
+ `tabService Level Agreement`.agreement_status='Active' and
+ `tabService Level Priority`.priority='{1}'
+ ) or
+ (
+ `tabService Level Agreement`.default_service_level_agreement='1'
+ )
+ limit 1
+ """.format(customer, priority), as_dict=True, debug=True)
+
+ print(agreement)
return agreement[0] if agreement else None
\ No newline at end of file
diff --git a/erpnext/support/doctype/service_level_priority/__init__.py b/erpnext/support/doctype/service_level_priority/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/support/doctype/service_level_priority/__init__.py
diff --git a/erpnext/support/doctype/service_level_priority/service_level_priority.json b/erpnext/support/doctype/service_level_priority/service_level_priority.json
new file mode 100644
index 0000000..6693649
--- /dev/null
+++ b/erpnext/support/doctype/service_level_priority/service_level_priority.json
@@ -0,0 +1,74 @@
+{
+ "creation": "2019-05-04 05:54:03.658991",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "priority",
+ "sb_00",
+ "response_time",
+ "response_time_period",
+ "cb_00",
+ "resolution_time",
+ "resolution_time_period"
+ ],
+ "fields": [
+ {
+ "columns": 2,
+ "fieldname": "priority",
+ "fieldtype": "Select",
+ "in_list_view": 1,
+ "label": "Priority",
+ "options": "Low\nMedium\nHigh"
+ },
+ {
+ "fieldname": "sb_00",
+ "fieldtype": "Section Break"
+ },
+ {
+ "columns": 2,
+ "fieldname": "response_time",
+ "fieldtype": "Int",
+ "in_list_view": 1,
+ "label": "Response Time"
+ },
+ {
+ "columns": 2,
+ "fieldname": "resolution_time",
+ "fieldtype": "Int",
+ "in_list_view": 1,
+ "label": "Resolution Time"
+ },
+ {
+ "fieldname": "cb_00",
+ "fieldtype": "Column Break"
+ },
+ {
+ "columns": 2,
+ "fieldname": "response_time_period",
+ "fieldtype": "Select",
+ "in_list_view": 1,
+ "label": "Response Time Period",
+ "options": "Hour\nDay\nWeek"
+ },
+ {
+ "columns": 2,
+ "fieldname": "resolution_time_period",
+ "fieldtype": "Select",
+ "in_list_view": 1,
+ "label": "Resolution Time Period",
+ "options": "Hour\nDay\nWeek"
+ }
+ ],
+ "istable": 1,
+ "modified": "2019-05-04 06:04:32.956731",
+ "modified_by": "Administrator",
+ "module": "Support",
+ "name": "Service Level Priority",
+ "owner": "Administrator",
+ "permissions": [],
+ "quick_entry": 1,
+ "sort_field": "modified",
+ "sort_order": "ASC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/support/doctype/service_level_priority/service_level_priority.py b/erpnext/support/doctype/service_level_priority/service_level_priority.py
new file mode 100644
index 0000000..0c0fe4a
--- /dev/null
+++ b/erpnext/support/doctype/service_level_priority/service_level_priority.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+# import frappe
+from frappe.model.document import Document
+
+class ServiceLevelPriority(Document):
+ pass