From 2c9f7cf371ac0ee8d6751a87b6f44bd33edb17f7 Mon Sep 17 00:00:00 2001 From: Rucha Mahabal Date: Fri, 5 Jun 2020 16:35:57 +0530 Subject: [PATCH] feat: pause SLA on statuses configuration --- erpnext/support/doctype/issue/issue.json | 3 +- erpnext/support/doctype/issue/issue.py | 64 ++++++++++--------- .../doctype/pause_sla_on_status/__init__.py | 0 .../pause_sla_on_status.json | 33 ++++++++++ .../pause_sla_on_status.py | 10 +++ .../support_settings/support_settings.js | 10 ++- .../support_settings/support_settings.json | 13 +++- 7 files changed, 100 insertions(+), 33 deletions(-) create mode 100644 erpnext/support/doctype/pause_sla_on_status/__init__.py create mode 100644 erpnext/support/doctype/pause_sla_on_status/pause_sla_on_status.json create mode 100644 erpnext/support/doctype/pause_sla_on_status/pause_sla_on_status.py diff --git a/erpnext/support/doctype/issue/issue.json b/erpnext/support/doctype/issue/issue.json index 70595e483a..712b70c2dd 100644 --- a/erpnext/support/doctype/issue/issue.json +++ b/erpnext/support/doctype/issue/issue.json @@ -403,6 +403,7 @@ { "fieldname": "on_hold_since", "fieldtype": "Datetime", + "hidden": 1, "label": "On Hold Since", "read_only": 1, "show_days": 1, @@ -420,7 +421,7 @@ "icon": "fa fa-ticket", "idx": 7, "links": [], - "modified": "2020-06-04 15:53:38.322514", + "modified": "2020-06-05 15:45:24.474425", "modified_by": "Administrator", "module": "Support", "name": "Issue", diff --git a/erpnext/support/doctype/issue/issue.py b/erpnext/support/doctype/issue/issue.py index ac700c91e7..146eb5a249 100644 --- a/erpnext/support/doctype/issue/issue.py +++ b/erpnext/support/doctype/issue/issue.py @@ -78,40 +78,44 @@ class Issue(Document): self.handle_hold_time(status) def handle_hold_time(self, status): - # set response and resolution variance as None as the issue is on Hold for status as Replied - if self.status == "Replied" and status != "Replied": - self.on_hold_since = frappe.flags.current_time or now_datetime() - if not self.first_responded_on: - self.response_by = None - self.response_by_variance = None - self.resolution_by = None - self.resolution_by_variance = None + if frappe.db.get_single_value("Support Settings", "track_service_level_agreement"): + # set response and resolution variance as None as the issue is on Hold for status as Replied + pause_sla_on = frappe.db.get_all("Pause SLA On Status", fields=["status"]) + hold_statuses = [entry.status for entry in pause_sla_on] - # calculate hold time when status is changed from Replied to any other status - if self.status != "Replied" and status == "Replied": - hold_time = self.total_hold_time if self.total_hold_time else 0 - now_time = frappe.flags.current_time or now_datetime() - self.total_hold_time = hold_time + time_diff_in_seconds(now_time, self.on_hold_since) + if self.status in hold_statuses and status not in hold_statuses: + self.on_hold_since = frappe.flags.current_time or now_datetime() + if not self.first_responded_on: + self.response_by = None + self.response_by_variance = None + self.resolution_by = None + self.resolution_by_variance = None - # re-calculate SLA variables after issue changes from Replied to Open - # add hold time to SLA variables - if self.status == "Open" and status == "Replied": - start_date_time = get_datetime(self.service_level_agreement_creation) - priority = get_priority(self) - now_time = frappe.flags.current_time or now_datetime() - hold_time = time_diff_in_seconds(now_time, self.on_hold_since) + # calculate hold time when status is changed from Replied to any other status + if self.status not in hold_statuses and status in hold_statuses: + hold_time = self.total_hold_time if self.total_hold_time else 0 + now_time = frappe.flags.current_time or now_datetime() + self.total_hold_time = hold_time + time_diff_in_seconds(now_time, self.on_hold_since) - if not self.first_responded_on: - response_by = get_expected_time_for(parameter="response", service_level=priority, start_date_time=start_date_time) - self.response_by = add_to_date(response_by, seconds=round(hold_time)) - response_by_variance = round(time_diff_in_hours(self.response_by, now_time)) - self.response_by_variance = response_by_variance + (hold_time // 3600) + # re-calculate SLA variables after issue changes from Replied to Open + # add hold time to SLA variables + if self.status == "Open" and status in hold_statuses: + start_date_time = get_datetime(self.service_level_agreement_creation) + priority = get_priority(self) + now_time = frappe.flags.current_time or now_datetime() + hold_time = time_diff_in_seconds(now_time, self.on_hold_since) - resolution_by = get_expected_time_for(parameter="resolution", service_level=priority, start_date_time=start_date_time) - self.resolution_by = add_to_date(resolution_by, seconds=round(hold_time)) - resolution_by_variance = round(time_diff_in_hours(self.resolution_by, now_time)) - self.resolution_by_variance = resolution_by_variance + (hold_time // 3600) - self.on_hold_since = None + if not self.first_responded_on: + response_by = get_expected_time_for(parameter="response", service_level=priority, start_date_time=start_date_time) + self.response_by = add_to_date(response_by, seconds=round(hold_time)) + response_by_variance = round(time_diff_in_hours(self.response_by, now_time)) + self.response_by_variance = response_by_variance + (hold_time // 3600) + + resolution_by = get_expected_time_for(parameter="resolution", service_level=priority, start_date_time=start_date_time) + self.resolution_by = add_to_date(resolution_by, seconds=round(hold_time)) + resolution_by_variance = round(time_diff_in_hours(self.resolution_by, now_time)) + self.resolution_by_variance = resolution_by_variance + (hold_time // 3600) + self.on_hold_since = None def update_agreement_status(self): if self.service_level_agreement and self.agreement_fulfilled == "Ongoing": diff --git a/erpnext/support/doctype/pause_sla_on_status/__init__.py b/erpnext/support/doctype/pause_sla_on_status/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/erpnext/support/doctype/pause_sla_on_status/pause_sla_on_status.json b/erpnext/support/doctype/pause_sla_on_status/pause_sla_on_status.json new file mode 100644 index 0000000000..5b03f25f48 --- /dev/null +++ b/erpnext/support/doctype/pause_sla_on_status/pause_sla_on_status.json @@ -0,0 +1,33 @@ +{ + "actions": [], + "creation": "2020-06-05 13:59:43.265588", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "status" + ], + "fields": [ + { + "fieldname": "status", + "fieldtype": "Select", + "in_list_view": 1, + "label": "Status", + "reqd": 1, + "show_days": 1, + "show_seconds": 1 + } + ], + "istable": 1, + "links": [], + "modified": "2020-06-05 15:15:29.986608", + "modified_by": "Administrator", + "module": "Support", + "name": "Pause SLA On Status", + "owner": "Administrator", + "permissions": [], + "quick_entry": 1, + "sort_field": "modified", + "sort_order": "DESC", + "track_changes": 1 +} \ No newline at end of file diff --git a/erpnext/support/doctype/pause_sla_on_status/pause_sla_on_status.py b/erpnext/support/doctype/pause_sla_on_status/pause_sla_on_status.py new file mode 100644 index 0000000000..a3b547e480 --- /dev/null +++ b/erpnext/support/doctype/pause_sla_on_status/pause_sla_on_status.py @@ -0,0 +1,10 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2020, 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 PauseSLAOnStatus(Document): + pass diff --git a/erpnext/support/doctype/support_settings/support_settings.js b/erpnext/support/doctype/support_settings/support_settings.js index 1d1069d58b..33ddf0b079 100644 --- a/erpnext/support/doctype/support_settings/support_settings.js +++ b/erpnext/support/doctype/support_settings/support_settings.js @@ -2,7 +2,15 @@ // For license information, please see license.txt frappe.ui.form.on('Support Settings', { - refresh: function(frm) { + setup: function(frm) { + let allow_statuses = []; + const exclude_statuses = ['Open', 'Closed', 'Resolved']; + frappe.model.with_doctype('Issue', () => { + let statuses = frappe.meta.get_docfield('Issue', 'status', frm.doc.name).options; + statuses = statuses.split('\n'); + allow_statuses = statuses.filter((status) => !exclude_statuses.includes(status)); + frappe.meta.get_docfield('Pause SLA On Status', 'status', frm.doc.name).options = [''].concat(allow_statuses); + }); } }); diff --git a/erpnext/support/doctype/support_settings/support_settings.json b/erpnext/support/doctype/support_settings/support_settings.json index 3f52181a46..da4b607e2c 100644 --- a/erpnext/support/doctype/support_settings/support_settings.json +++ b/erpnext/support/doctype/support_settings/support_settings.json @@ -10,6 +10,7 @@ "allow_resetting_service_level_agreement", "issues_sb", "close_issue_after_days", + "pause_sla_on_status", "portal_sb", "get_started_sections", "show_latest_forum_posts", @@ -123,14 +124,24 @@ }, { "default": "0", + "depends_on": "eval:doc.track_service_level_agreement;", "fieldname": "allow_resetting_service_level_agreement", "fieldtype": "Check", "label": "Allow Resetting Service Level Agreement" + }, + { + "depends_on": "eval:doc.track_service_level_agreement;", + "fieldname": "pause_sla_on_status", + "fieldtype": "Table", + "label": "Pause SLA On", + "options": "Pause SLA On Status", + "show_days": 1, + "show_seconds": 1 } ], "issingle": 1, "links": [], - "modified": "2020-04-28 14:11:15.117019", + "modified": "2020-06-05 16:35:13.905096", "modified_by": "Administrator", "module": "Support", "name": "Support Settings",