fix: calculate variance
diff --git a/erpnext/hooks.py b/erpnext/hooks.py
index 5beaea7..f559597 100644
--- a/erpnext/hooks.py
+++ b/erpnext/hooks.py
@@ -242,7 +242,8 @@
"erpnext.erpnext_integrations.doctype.amazon_mws_settings.amazon_mws_settings.schedule_get_order_details",
"erpnext.accounts.doctype.gl_entry.gl_entry.rename_gle_sle_docs",
"erpnext.projects.doctype.project.project.hourly_reminder",
- "erpnext.projects.doctype.project.project.collect_project_status"
+ "erpnext.projects.doctype.project.project.collect_project_status",
+ "erpnext.support.doctype.issue.issue.set_service_level_agreement_variance"
],
"daily": [
"erpnext.stock.reorder_item.reorder_item",
diff --git a/erpnext/support/doctype/issue/issue.js b/erpnext/support/doctype/issue/issue.js
index 1475050..e2e6997 100644
--- a/erpnext/support/doctype/issue/issue.js
+++ b/erpnext/support/doctype/issue/issue.js
@@ -5,7 +5,7 @@
refresh: function (frm) {
- if (frm.doc.status !== "Closed") {
+ if (frm.doc.status !== "Closed" && frm.doc.agreement_fulfilled === "Ongoing") {
if (frm.doc.service_level_agreement) {
set_time_to_resolve_and_response(frm);
}
@@ -25,14 +25,14 @@
if (frm.doc.service_level_agreement) {
frm.dashboard.clear_headline();
- let agreement_status = (frm.doc.agreement_status == "Fulfilled") ?
+ let agreement_fulfilled = (frm.doc.agreement_fulfilled == "Fulfilled") ?
{"indicator": "green", "msg": "Service Level Agreement has been fulfilled"} :
{"indicator": "red", "msg": "Service Level Agreement Failed"};
frm.dashboard.set_headline_alert(
'<div class="row">' +
'<div class="col-xs-12">' +
- '<span class="indicator whitespace-nowrap '+ agreement_status.indicator +'"><span class="hidden-xs">'+ agreement_status.msg +'</span></span> ' +
+ '<span class="indicator whitespace-nowrap '+ agreement_fulfilled.indicator +'"><span class="hidden-xs">'+ agreement_fulfilled.msg +'</span></span> ' +
'</div>' +
'</div>'
);
@@ -112,8 +112,8 @@
function set_time_to_resolve_and_response(frm) {
frm.dashboard.clear_headline();
- var time_to_respond = get_time_left(frm.doc.response_by, frm.doc.agreement_status);
- var time_to_resolve = get_time_left(frm.doc.resolution_by, frm.doc.agreement_status);
+ var time_to_respond = get_time_left(frm.doc.response_by, frm.doc.agreement_fulfilled);
+ var time_to_resolve = get_time_left(frm.doc.resolution_by, frm.doc.agreement_fulfilled);
frm.dashboard.set_headline_alert(
'<div class="row">' +
@@ -127,9 +127,9 @@
);
}
-function get_time_left(timestamp, agreement_status) {
+function get_time_left(timestamp, agreement_fulfilled) {
const diff = moment(timestamp).diff(moment());
const diff_display = diff >= 44500 ? moment.duration(diff).humanize() : moment(0, 'seconds').format('HH:mm');
- let indicator = (diff_display == '00:00' && agreement_status != "Fulfilled") ? "red" : "green";
+ let indicator = (diff_display == '00:00' && agreement_fulfilled != "Fulfilled") ? "red" : "green";
return {"diff_display": diff_display, "indicator": indicator};
}
diff --git a/erpnext/support/doctype/issue/issue.json b/erpnext/support/doctype/issue/issue.json
index 9639702..29cad62 100644
--- a/erpnext/support/doctype/issue/issue.json
+++ b/erpnext/support/doctype/issue/issue.json
@@ -21,9 +21,11 @@
"service_level_section",
"service_level_agreement",
"response_by",
+ "response_by_variance",
"cb",
- "agreement_status",
+ "agreement_fulfilled",
"resolution_by",
+ "resolution_by_variance",
"response",
"mins_to_first_response",
"first_responded_on",
@@ -167,14 +169,6 @@
"read_only": 1
},
{
- "default": "Ongoing",
- "fieldname": "agreement_status",
- "fieldtype": "Select",
- "label": "Agreement Status",
- "options": "Ongoing\nFulfilled\nFailed",
- "read_only": 1
- },
- {
"fieldname": "resolution_by",
"fieldtype": "Datetime",
"label": "Resolution By",
@@ -317,11 +311,33 @@
"fieldname": "via_customer_portal",
"fieldtype": "Check",
"label": "Via Customer Portal"
+ },
+ {
+ "default": "Ongoing",
+ "fieldname": "agreement_fulfilled",
+ "fieldtype": "Select",
+ "label": "Agreement Fulfilled",
+ "options": "Ongoing\nFulfilled\nFailed",
+ "read_only": 1
+ },
+ {
+ "description": "in hours",
+ "fieldname": "response_by_variance",
+ "fieldtype": "Int",
+ "label": "Response By Variance",
+ "read_only": 1
+ },
+ {
+ "description": "in hours",
+ "fieldname": "resolution_by_variance",
+ "fieldtype": "Int",
+ "label": "Resolution By Variance",
+ "read_only": 1
}
],
"icon": "fa fa-ticket",
"idx": 7,
- "modified": "2019-05-03 14:36:19.117560",
+ "modified": "2019-05-10 22:31:09.391044",
"modified_by": "Administrator",
"module": "Support",
"name": "Issue",
diff --git a/erpnext/support/doctype/issue/issue.py b/erpnext/support/doctype/issue/issue.py
index 2b73440..965e53c 100644
--- a/erpnext/support/doctype/issue/issue.py
+++ b/erpnext/support/doctype/issue/issue.py
@@ -68,22 +68,27 @@
status = frappe.db.get_value("Issue", self.name, "status")
if self.status!="Open" and status =="Open" and not self.first_responded_on:
self.first_responded_on = now()
+
if self.status=="Closed" and status !="Closed":
self.resolution_date = now()
- self.update_agreement_status()
+ if not frappe.db.get_value("Issue", self.name, "agreement_fulfilled") == "Ongoing":
+ self.set_service_level_agreement_variance(issue=self.name)
+ self.update_agreement_status()
+
if self.status=="Open" and status !="Open":
# if no date, it should be set as None and not a blank string "", as per mysql strict config
self.resolution_date = None
def update_agreement_status(self):
current_time = frappe.flags.current_time or now_datetime()
- if self.service_level_agreement and self.agreement_status == "Ongoing":
+ if self.service_level_agreement and self.agreement_fulfilled == "Ongoing":
response_time_diff = round(time_diff_in_hours(self.response_by, current_time), 2)
resolution_time_diff = round(time_diff_in_hours(self.resolution_by, current_time), 2)
+
if response_time_diff < 0 or resolution_time_diff < 0:
- self.agreement_status = "Failed"
+ self.agreement_fulfilled = "Failed"
else:
- self.agreement_status = "Fulfilled"
+ self.agreement_fulfilled = "Fulfilled"
def create_communication(self):
communication = frappe.new_doc("Communication")
@@ -151,6 +156,9 @@
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)
+ self.response_by_variance = round(time_diff_in_hours(self.response_by, now_datetime()))
+ self.resolution_by_variance = round(time_diff_in_hours(self.resolution_by, now_datetime()))
+
@frappe.whitelist()
def change_sla_priority(self, priority):
self.set_response_and_resolution_time(priority=priority)
@@ -222,16 +230,32 @@
return current_date_time
def set_service_level_agreement_status():
- issues = frappe.get_list("Issue", filters={"status": "Open", "agreement_status": "Ongoing"})
+ issues = frappe.get_list("Issue", filters={"status": "Open", "agreement_fulfilled": "Ongoing"})
for issue in issues:
doc = frappe.get_doc("Issue", issue.name)
- if doc.service_level_agreement and doc.agreement_status == "Ongoing":
+ if doc.service_level_agreement and doc.agreement_fulfilled == "Ongoing":
response_time_diff = round(time_diff_in_hours(doc.response_by, now_datetime()), 2)
resolution_time_diff = round(time_diff_in_hours(doc.resolution_by, now_datetime()), 2)
if response_time_diff < 0 or resolution_time_diff < 0:
- frappe.db.set_value("Issue", doc.name, "agreement_status", "Failed")
+ frappe.db.set_value("Issue", doc.name, "agreement_fulfilled", "Failed")
else:
- frappe.db.set_value("Issue", doc.name, "agreement_status", "Fulfilled")
+ frappe.db.set_value("Issue", doc.name, "agreement_fulfilled", "Fulfilled")
+
+def set_service_level_agreement_variance(issue=None):
+ filters = {"status": "Open", "agreement_fulfilled": "Ongoing"}
+
+ if issue:
+ filters = {"status": issue}
+
+ issues = frappe.get_list("Issue", filters=filters)
+ for issue in issues:
+ doc = frappe.get_doc("Issue", issue.name)
+ if not doc.first_responded_on and not doc.agreement_fulfilled == "Ongoing":
+ variance = round(time_diff_in_hours(doc.response_by, now_datetime()))
+ frappe.db.set_value("Issue", doc.name, "response_by_variance", variance)
+ if not doc.resolution_dateand and not doc.agreement_fulfilled == "Ongoing":
+ variance = round(time_diff_in_hours(self.resolution_by, now_datetime()))
+ frappe.db.set_value("Issue", doc.name, "resolution_by_variance", variance)
def get_list_context(context=None):
return {