Merge branch 'develop' of https://github.com/frappe/erpnext into sla_fix
diff --git a/erpnext/config/hr.py b/erpnext/config/hr.py
index 0f009b8..342cc6e 100644
--- a/erpnext/config/hr.py
+++ b/erpnext/config/hr.py
@@ -20,6 +20,11 @@
},
{
"type": "doctype",
+ "name": "Employee Group",
+ "dependencies": ["Employee"]
+ },
+ {
+ "type": "doctype",
"name": "Attendance",
"onboard": 1,
"dependencies": ["Employee"]
diff --git a/erpnext/config/support.py b/erpnext/config/support.py
index 47dc53e..0301bb3 100644
--- a/erpnext/config/support.py
+++ b/erpnext/config/support.py
@@ -14,6 +14,16 @@
},
{
"type": "doctype",
+ "name": "Issue Type",
+ "description": _("Issue Type."),
+ },
+ {
+ "type": "doctype",
+ "name": "Issue Priority",
+ "description": _("Issue Priority."),
+ },
+ {
+ "type": "doctype",
"name": "Communication",
"description": _("Communication log."),
"onboard": 1,
@@ -40,11 +50,6 @@
"items": [
{
"type": "doctype",
- "name": "Employee Group",
- "description": _("Support Team."),
- },
- {
- "type": "doctype",
"name": "Service Level",
"description": _("Service Level."),
},
diff --git a/erpnext/hooks.py b/erpnext/hooks.py
index da0972b..b272f60 100644
--- a/erpnext/hooks.py
+++ b/erpnext/hooks.py
@@ -240,7 +240,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",
@@ -262,7 +263,7 @@
"erpnext.projects.doctype.project.project.update_project_sales_billing",
"erpnext.projects.doctype.project.project.send_project_status_email_to_users",
"erpnext.quality_management.doctype.quality_review.quality_review.review",
- "erpnext.support.doctype.service_level_agreement.service_level_agreement.check_agreement_status"
+ "erpnext.support.doctype.service_level_agreement.service_level_agreement.check_agreement_status",
],
"daily_long": [
"erpnext.manufacturing.doctype.bom_update_tool.bom_update_tool.update_latest_price_in_all_boms"
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 747177a..63d4cfc 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -604,4 +604,5 @@
erpnext.patches.v11_1.delete_scheduling_tool
erpnext.patches.v12_0.make_custom_fields_for_bank_remittance #14-06-2019
execute:frappe.delete_doc_if_exists("Page", "support-analytics")
-erpnext.patches.v12_0.make_item_manufacturer
\ No newline at end of file
+erpnext.patches.v12_0.make_item_manufacturer
+erpnext.patches.v12_0.set_priority_for_support
diff --git a/erpnext/patches/v12_0/move_parameters_to_priority.py b/erpnext/patches/v12_0/move_parameters_to_priority.py
new file mode 100644
index 0000000..310bfe2
--- /dev/null
+++ b/erpnext/patches/v12_0/move_parameters_to_priority.py
@@ -0,0 +1,38 @@
+# Copyright (c) 2017, Frappe and Contributors
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+import frappe
+
+def execute():
+ priority = ["Low", "Medium", "High"]
+
+ service_levels = frappe.get_list("Service Level")
+ for service_level in service_levels:
+ doc = frappe.get_doc("Service Level", service_level)
+ for value in priority:
+ doc.append("priorities",
+ {
+ "priority": "{0}".format(value),
+ "response_time": doc.response_time,
+ "response_time_period": doc.response_time_period,
+ "resolution_time": doc.resolution_time,
+ "resolution_time_period": doc.resolution_time_period,
+ }
+ )
+ doc.save(ignore_permissions=True)
+
+ service_level_agreements = frappe.get_list("Service Level Agreement")
+ for service_level_agreement in service_level_agreements:
+ doc = frappe.get_doc("Service Level Agreement", service_level_agreement)
+ for value in priority:
+ doc.append("priorities",
+ {
+ "priority": "{0}".format(value),
+ "response_time": doc.response_time,
+ "response_time_period": doc.response_time_period,
+ "resolution_time": doc.resolution_time,
+ "resolution_time_period": doc.resolution_time_period,
+ }
+ )
+ doc.save(ignore_permissions=True)
\ No newline at end of file
diff --git a/erpnext/patches/v12_0/set_priority_for_support.py b/erpnext/patches/v12_0/set_priority_for_support.py
new file mode 100644
index 0000000..966978a
--- /dev/null
+++ b/erpnext/patches/v12_0/set_priority_for_support.py
@@ -0,0 +1,59 @@
+import frappe
+
+def execute():
+ frappe.reload_doc("support", "doctype", "issue_priority")
+
+ priorities = frappe.get_meta("Issue").get_field("priority").options.split("\n")
+
+ for priority in priorities:
+ if not frappe.db.exists("Issue Priority", priority):
+ frappe.get_doc({
+ "doctype": "Issue Priority",
+ "name": priority
+ }).insert(ignore_permissions=True)
+
+ issue_priority = frappe.get_list("Issue", fields=["name", "priority"])
+
+ service_level_priority = frappe.get_list("Service Level", fields=["name", "priority", "response_time", "response_time_period", \
+ "resolution_time", "resolution_time_period"])
+
+ service_level_agreement_priority = frappe.get_list("Service Level Agreement", fields=["name", "priority", "response_time", \
+ "response_time_period", "resolution_time", "resolution_time_period"])
+
+ frappe.reload_doc("support", "doctype", "issue")
+ frappe.reload_doc("support", "doctype", "service_level_priority")
+ frappe.reload_doc("support", "doctype", "service_level")
+ frappe.reload_doc("support", "doctype", "service_level_agreement")
+
+ for issue in issue_priority:
+ frappe.db.set_value("Issue", issue.name, "priority", issue.priority)
+
+ for service_level in service_level_priority:
+ doc = frappe.get_doc("Service Level", service_level.name)
+ doc.append("priorities", {
+ "priority": service_level.priority,
+ "default_priority": 1,
+ "response_time": service_level.response_time,
+ "response_time_period": service_level.response_time_period,
+ "resolution_time": service_level.resolution_time,
+ "resolution_time_period": service_level.resolution_time_period
+ })
+ doc.save(ignore_permissions=True)
+
+ for service_level_agreement in service_level_agreement_priority:
+
+ doc = frappe.get_doc("Service Level Agreement", service_level_agreement.name)
+
+ if doc.customer:
+ doc.apply_to = "Customer"
+ doc.entity = doc.customer
+
+ doc.append("priorities", {
+ "priority": service_level_agreement.priority,
+ "default_priority": 1,
+ "response_time": service_level_agreement.response_time,
+ "response_time_period": service_level_agreement.response_time_period,
+ "resolution_time": service_level_agreement.resolution_time,
+ "resolution_time_period": service_level_agreement.resolution_time_period
+ })
+ doc.save(ignore_permissions=True)
\ No newline at end of file
diff --git a/erpnext/setup/doctype/customer_group/customer_group.py b/erpnext/setup/doctype/customer_group/customer_group.py
index 388ddca..f62613e 100644
--- a/erpnext/setup/doctype/customer_group/customer_group.py
+++ b/erpnext/setup/doctype/customer_group/customer_group.py
@@ -8,7 +8,7 @@
from frappe.utils.nestedset import NestedSet
class CustomerGroup(NestedSet):
- nsm_parent_field = 'parent_customer_group';
+ nsm_parent_field = 'parent_customer_group'
def on_update(self):
self.validate_name_with_customer()
diff --git a/erpnext/setup/setup_wizard/operations/install_fixtures.py b/erpnext/setup/setup_wizard/operations/install_fixtures.py
index 89f4e30..4b734df 100644
--- a/erpnext/setup/setup_wizard/operations/install_fixtures.py
+++ b/erpnext/setup/setup_wizard/operations/install_fixtures.py
@@ -173,6 +173,11 @@
{"attribute_value": _("White"), "abbr": "WHI"}
]},
+ # Issue Priority
+ {'doctype': 'Issue Priority', 'name': _('Low')},
+ {'doctype': 'Issue Priority', 'name': _('Medium')},
+ {'doctype': 'Issue Priority', 'name': _('High')},
+
#Job Applicant Source
{'doctype': 'Job Applicant Source', 'source_name': _('Website Listing')},
{'doctype': 'Job Applicant Source', 'source_name': _('Walk In')},
diff --git a/erpnext/support/doctype/issue/issue.js b/erpnext/support/doctype/issue/issue.js
index 97b34e9..7c93973 100644
--- a/erpnext/support/doctype/issue/issue.js
+++ b/erpnext/support/doctype/issue/issue.js
@@ -2,12 +2,33 @@
onload: function(frm) {
frm.email_field = "raised_by";
if (frm.doc.service_level_agreement) {
- set_time_to_resolve_and_response(frm);
+ frappe.call({
+ method: "erpnext.support.doctype.service_level_agreement.service_level_agreement.get_service_level_agreement_priorities",
+ args: {
+ name: frm.doc.service_level_agreement,
+ },
+ callback: function (r) {
+ if (r && r.message) {
+ frm.set_query('priority', function() {
+ return {
+ filters: {
+ "name": ["in", r.message],
+ }
+ };
+ });
+ }
+ }
+ });
}
},
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);
+ }
+
frm.add_custom_button(__("Close"), function () {
frm.set_value("status", "Closed");
frm.save();
@@ -20,6 +41,22 @@
});
}, __("Make"));
} else {
+ if (frm.doc.service_level_agreement) {
+ frm.dashboard.clear_headline();
+
+ 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_fulfilled.indicator +'"><span class="hidden-xs">'+ agreement_fulfilled.msg +'</span></span> ' +
+ '</div>' +
+ '</div>'
+ );
+ }
+
frm.add_custom_button(__("Reopen"), function () {
frm.set_value("status", "Open");
frm.save();
@@ -27,6 +64,35 @@
}
},
+ priority: function(frm) {
+ if (frm.doc.service_level_agreement) {
+ frappe.show_alert({
+ indicator: 'green',
+ message: __('Changing Priority.')
+ });
+ frm.call('change_service_level_agreement_and_priority', {
+ "priority": frm.doc.priority,
+ "service_level_agreement": frm.doc.service_level_agreement
+ }).then(() => {
+ frappe.msgprint(__("Issue Priority changed to {0}.", [frm.doc.priority]));
+ frm.refresh();
+ });
+ }
+ },
+
+ service_level_agreement: function(frm) {
+ frappe.show_alert({
+ indicator: 'green',
+ message: __('Changing Service Level Agreement.')
+ });
+ frm.call('change_service_level_agreement_and_priority', {
+ "service_level_agreement": frm.doc.service_level_agreement
+ }).then(() => {
+ frappe.msgprint(__("Service Level Agreement changed to {0}.", [frm.doc.service_level_agreement]));
+ frm.refresh();
+ });
+ },
+
timeline_refresh: function(frm) {
// create button for "Help Article"
if(frappe.model.can_create('Help Article')) {
@@ -81,36 +147,26 @@
});
function set_time_to_resolve_and_response(frm) {
+ frm.dashboard.clear_headline();
- const customer = frm.fields_dict['customer'].$wrapper;
- const email_account = frm.fields_dict['email_account'].$wrapper;
+ 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);
- const time_to_respond = $(get_time_left_element(__('Time To Respond'), frm.doc.response_by));
- const time_to_resolve = $(get_time_left_element(__('Time To Resolve'), frm.doc.resolution_by));
-
- time_to_respond.insertAfter(customer);
- time_to_resolve.insertAfter(email_account);
+ frm.dashboard.set_headline_alert(
+ '<div class="row">' +
+ '<div class="col-xs-6">' +
+ '<span class="indicator whitespace-nowrap '+ time_to_respond.indicator +'"><span class="hidden-xs">Time to Respond: '+ time_to_respond.diff_display +'</span></span> ' +
+ '</div>' +
+ '<div class="col-xs-6">' +
+ '<span class="indicator whitespace-nowrap '+ time_to_resolve.indicator +'"><span class="hidden-xs">Time to Resolve: '+ time_to_resolve.diff_display +'</span></span> ' +
+ '</div>' +
+ '</div>'
+ );
}
-function get_time_left_element(label, timestamp) {
- $('.'+ frappe.scrub(label) +'').remove();
- return `
- <div class="frappe-control input-max-width `+ frappe.scrub(label) +`" data-field_name="`+ frappe.scrub(label) +`">
- <div class="form-group">
- <div class="clearfix">
- <label class="control-label" style="padding-right: 0px;">
- ${label}
- </label>
- </div>
- <div class="control-input-wrapper">
- <div class="control-value like-disabled-input">${get_time_left(timestamp)}</div>
- </div>
- </div>
- </div>
- `;
-}
-
-function get_time_left(timestamp) {
+function get_time_left(timestamp, agreement_fulfilled) {
const diff = moment(timestamp).diff(moment());
- return diff >= 44500 ? moment.duration(diff).humanize() : 0;
+ const diff_display = diff >= 44500 ? moment.duration(diff).humanize() : moment(0, 'seconds').format('HH:mm');
+ 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 91b718e..3ad5153 100644
--- a/erpnext/support/doctype/issue/issue.json
+++ b/erpnext/support/doctype/issue/issue.json
@@ -1,1309 +1,364 @@
{
- "allow_copy": 0,
- "allow_events_in_timeline": 0,
- "allow_guest_to_view": 0,
- "allow_import": 1,
- "allow_rename": 1,
- "autoname": "naming_series:",
- "beta": 0,
- "creation": "2013-02-01 10:36:25",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "Setup",
- "editable_grid": 0,
- "engine": "InnoDB",
+ "allow_import": 1,
+ "allow_rename": 1,
+ "autoname": "naming_series:",
+ "creation": "2013-02-01 10:36:25",
+ "doctype": "DocType",
+ "document_type": "Setup",
+ "engine": "InnoDB",
+ "field_order": [
+ "subject_section",
+ "naming_series",
+ "subject",
+ "customer",
+ "raised_by",
+ "cb00",
+ "status",
+ "priority",
+ "issue_type",
+ "sb_details",
+ "description",
+ "service_level_section",
+ "service_level_agreement",
+ "response_by",
+ "response_by_variance",
+ "cb",
+ "agreement_fulfilled",
+ "resolution_by",
+ "resolution_by_variance",
+ "response",
+ "mins_to_first_response",
+ "first_responded_on",
+ "additional_info",
+ "lead",
+ "contact",
+ "email_account",
+ "column_break_16",
+ "customer_name",
+ "project",
+ "company",
+ "section_break_19",
+ "resolution_details",
+ "column_break1",
+ "opening_date",
+ "opening_time",
+ "resolution_date",
+ "content_type",
+ "attachment",
+ "via_customer_portal"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "subject_section",
- "fieldtype": "Section 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,
- "label": "Subject",
- "length": 0,
- "no_copy": 0,
- "options": "fa fa-flag",
- "permlevel": 0,
- "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
- },
+ "fieldname": "subject_section",
+ "fieldtype": "Section Break",
+ "label": "Subject",
+ "options": "fa fa-flag"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "",
- "fetch_if_empty": 0,
- "fieldname": "naming_series",
- "fieldtype": "Select",
- "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": "Series",
- "length": 0,
- "no_copy": 1,
- "options": "ISS-.YYYY.-",
- "permlevel": 0,
- "print_hide": 1,
- "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": 1,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "naming_series",
+ "fieldtype": "Select",
+ "label": "Series",
+ "no_copy": 1,
+ "options": "ISS-.YYYY.-",
+ "print_hide": 1,
+ "set_only_once": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 1,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "subject",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 1,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Subject",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "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
- },
+ "bold": 1,
+ "fieldname": "subject",
+ "fieldtype": "Data",
+ "in_global_search": 1,
+ "label": "Subject",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "customer",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 1,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Customer",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "customer",
- "oldfieldtype": "Link",
- "options": "Customer",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 1,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "customer",
+ "fieldtype": "Link",
+ "in_global_search": 1,
+ "label": "Customer",
+ "oldfieldname": "customer",
+ "oldfieldtype": "Link",
+ "options": "Customer",
+ "print_hide": 1,
+ "search_index": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 1,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:doc.__islocal",
- "fetch_if_empty": 0,
- "fieldname": "raised_by",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 1,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Raised By (Email)",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "raised_by",
- "oldfieldtype": "Data",
- "options": "Email",
- "permlevel": 0,
- "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
- },
+ "bold": 1,
+ "depends_on": "eval:doc.__islocal",
+ "fieldname": "raised_by",
+ "fieldtype": "Data",
+ "in_global_search": 1,
+ "in_list_view": 1,
+ "label": "Raised By (Email)",
+ "oldfieldname": "raised_by",
+ "oldfieldtype": "Data",
+ "options": "Email"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "cb00",
- "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,
- "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
- },
+ "fieldname": "cb00",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "Open",
- "fetch_if_empty": 0,
- "fieldname": "status",
- "fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 1,
- "label": "Status",
- "length": 0,
- "no_copy": 1,
- "oldfieldname": "status",
- "oldfieldtype": "Select",
- "options": "Open\nReplied\nHold\nClosed",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 1,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "default": "Open",
+ "fieldname": "status",
+ "fieldtype": "Select",
+ "in_list_view": 1,
+ "in_standard_filter": 1,
+ "label": "Status",
+ "no_copy": 1,
+ "oldfieldname": "status",
+ "oldfieldtype": "Select",
+ "options": "Open\nReplied\nHold\nClosed",
+ "search_index": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "Medium",
- "depends_on": "",
- "fetch_if_empty": 0,
- "fieldname": "priority",
- "fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 1,
- "label": "Priority",
- "length": 0,
- "no_copy": 0,
- "options": "Low\nMedium\nHigh",
- "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
- },
+ "fieldname": "priority",
+ "fieldtype": "Link",
+ "in_standard_filter": 1,
+ "label": "Priority",
+ "options": "Issue Priority"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "issue_type",
- "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": "Issue Type",
- "length": 0,
- "no_copy": 0,
- "options": "Issue 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": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "issue_type",
+ "fieldtype": "Link",
+ "label": "Issue Type",
+ "options": "Issue Type"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 1,
- "collapsible_depends_on": "eval:doc.status!=\"Closed\"",
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "sb_details",
- "fieldtype": "Section 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,
- "label": "Details",
- "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
- },
+ "collapsible": 1,
+ "collapsible_depends_on": "eval:doc.status!=\"Closed\"",
+ "fieldname": "sb_details",
+ "fieldtype": "Section Break",
+ "label": "Details"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 1,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
- "fetch_if_empty": 0,
- "fieldname": "description",
- "fieldtype": "Text Editor",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 1,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Description",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "problem_description",
- "oldfieldtype": "Text",
- "permlevel": 0,
- "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
- },
+ "bold": 1,
+ "fieldname": "description",
+ "fieldtype": "Text Editor",
+ "in_global_search": 1,
+ "label": "Description",
+ "oldfieldname": "problem_description",
+ "oldfieldtype": "Text"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 1,
- "columns": 0,
- "depends_on": "eval: doc.service_level_agreement",
- "fetch_if_empty": 0,
- "fieldname": "service_level_section",
- "fieldtype": "Section 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,
- "label": "Service Level",
- "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
- },
+ "collapsible": 1,
+ "depends_on": "eval: doc.service_level_agreement",
+ "fieldname": "service_level_section",
+ "fieldtype": "Section Break",
+ "label": "Service Level"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "service_level_agreement",
- "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": "Service Level Agreement",
- "length": 0,
- "no_copy": 0,
- "options": "Service Level Agreement",
- "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
- },
+ "fieldname": "service_level_agreement",
+ "fieldtype": "Link",
+ "label": "Service Level Agreement",
+ "options": "Service Level Agreement"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "response_by",
- "fieldtype": "Datetime",
- "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": "Response By",
- "length": 0,
- "no_copy": 0,
- "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
- },
+ "fieldname": "response_by",
+ "fieldtype": "Datetime",
+ "label": "Response By",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 1,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "cb",
- "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,
- "label": "",
- "length": 0,
- "no_copy": 0,
- "options": "fa fa-pushpin",
- "permlevel": 0,
- "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
- },
+ "collapsible": 1,
+ "fieldname": "cb",
+ "fieldtype": "Column Break",
+ "options": "fa fa-pushpin",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "Ongoing",
- "fetch_if_empty": 0,
- "fieldname": "agreement_status",
- "fieldtype": "Select",
- "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": "Agreement Status",
- "length": 0,
- "no_copy": 0,
- "options": "Ongoing\nFulfilled\nFailed",
- "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
- },
+ "fieldname": "resolution_by",
+ "fieldtype": "Datetime",
+ "label": "Resolution By",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "resolution_by",
- "fieldtype": "Datetime",
- "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": "Resolution By",
- "length": 0,
- "no_copy": 0,
- "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
- },
+ "collapsible": 1,
+ "fieldname": "response",
+ "fieldtype": "Section Break",
+ "label": "Response"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 1,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "response",
- "fieldtype": "Section 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,
- "label": "Response",
- "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
- },
+ "bold": 1,
+ "fieldname": "mins_to_first_response",
+ "fieldtype": "Float",
+ "label": "Mins to First Response",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 1,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "mins_to_first_response",
- "fieldtype": "Float",
- "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": "Mins to First Response",
- "length": 0,
- "no_copy": 0,
- "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
- },
+ "fieldname": "first_responded_on",
+ "fieldtype": "Datetime",
+ "label": "First Responded On"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "first_responded_on",
- "fieldtype": "Datetime",
- "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": "First Responded On",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "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
- },
+ "collapsible": 1,
+ "fieldname": "additional_info",
+ "fieldtype": "Section Break",
+ "label": "Reference",
+ "options": "fa fa-pushpin",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 1,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "additional_info",
- "fieldtype": "Section 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,
- "label": "Reference",
- "length": 0,
- "no_copy": 0,
- "options": "fa fa-pushpin",
- "permlevel": 0,
- "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
- },
+ "fieldname": "lead",
+ "fieldtype": "Link",
+ "label": "Lead",
+ "options": "Lead"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "lead",
- "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": "Lead",
- "length": 0,
- "no_copy": 0,
- "options": "Lead",
- "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
- },
+ "fieldname": "contact",
+ "fieldtype": "Link",
+ "label": "Contact",
+ "options": "Contact"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "contact",
- "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": "Contact",
- "length": 0,
- "no_copy": 0,
- "options": "Contact",
- "permlevel": 0,
- "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
- },
+ "fieldname": "email_account",
+ "fieldtype": "Link",
+ "label": "Email Account",
+ "options": "Email Account"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "email_account",
- "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": "Email Account",
- "length": 0,
- "no_copy": 0,
- "options": "Email Account",
- "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
- },
+ "fieldname": "column_break_16",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "column_break_16",
- "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
- },
+ "bold": 1,
+ "fieldname": "customer_name",
+ "fieldtype": "Data",
+ "label": "Customer Name",
+ "oldfieldname": "customer_name",
+ "oldfieldtype": "Data",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 1,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "customer_name",
- "fieldtype": "Data",
- "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": "Customer Name",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "customer_name",
- "oldfieldtype": "Data",
- "permlevel": 0,
- "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
- },
+ "fieldname": "project",
+ "fieldtype": "Link",
+ "label": "Project",
+ "options": "Project"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "project",
- "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": "Project",
- "length": 0,
- "no_copy": 0,
- "options": "Project",
- "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
- },
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "label": "Company",
+ "options": "Company",
+ "print_hide": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "company",
- "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": "Company",
- "length": 0,
- "no_copy": 0,
- "options": "Company",
- "permlevel": 0,
- "print_hide": 1,
- "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
- },
+ "collapsible": 1,
+ "fieldname": "section_break_19",
+ "fieldtype": "Section Break",
+ "label": "Resolution"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 1,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "section_break_19",
- "fieldtype": "Section 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,
- "label": "Resolution",
- "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
- },
+ "depends_on": "eval:!doc.__islocal",
+ "fieldname": "resolution_details",
+ "fieldtype": "Text Editor",
+ "label": "Resolution Details",
+ "no_copy": 1,
+ "oldfieldname": "resolution_details",
+ "oldfieldtype": "Text"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:!doc.__islocal",
- "fetch_if_empty": 0,
- "fieldname": "resolution_details",
- "fieldtype": "Text Editor",
- "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": "Resolution Details",
- "length": 0,
- "no_copy": 1,
- "oldfieldname": "resolution_details",
- "oldfieldtype": "Text",
- "permlevel": 0,
- "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
- },
+ "depends_on": "eval:!doc.__islocal",
+ "fieldname": "column_break1",
+ "fieldtype": "Column Break",
+ "oldfieldtype": "Column Break",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:!doc.__islocal",
- "fetch_if_empty": 0,
- "fieldname": "column_break1",
- "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,
- "oldfieldtype": "Column Break",
- "permlevel": 0,
- "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
- },
+ "default": "Today",
+ "fieldname": "opening_date",
+ "fieldtype": "Date",
+ "label": "Opening Date",
+ "no_copy": 1,
+ "oldfieldname": "opening_date",
+ "oldfieldtype": "Date",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "Today",
- "fetch_if_empty": 0,
- "fieldname": "opening_date",
- "fieldtype": "Date",
- "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": "Opening Date",
- "length": 0,
- "no_copy": 1,
- "oldfieldname": "opening_date",
- "oldfieldtype": "Date",
- "permlevel": 0,
- "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
- },
+ "fieldname": "opening_time",
+ "fieldtype": "Time",
+ "label": "Opening Time",
+ "no_copy": 1,
+ "oldfieldname": "opening_time",
+ "oldfieldtype": "Time",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "opening_time",
- "fieldtype": "Time",
- "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": "Opening Time",
- "length": 0,
- "no_copy": 1,
- "oldfieldname": "opening_time",
- "oldfieldtype": "Time",
- "permlevel": 0,
- "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
- },
+ "depends_on": "eval:!doc.__islocal",
+ "fieldname": "resolution_date",
+ "fieldtype": "Datetime",
+ "label": "Resolution Date",
+ "no_copy": 1,
+ "oldfieldname": "resolution_date",
+ "oldfieldtype": "Date",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:!doc.__islocal",
- "fetch_if_empty": 0,
- "fieldname": "resolution_date",
- "fieldtype": "Datetime",
- "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": "Resolution Date",
- "length": 0,
- "no_copy": 1,
- "oldfieldname": "resolution_date",
- "oldfieldtype": "Date",
- "permlevel": 0,
- "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
- },
+ "fieldname": "content_type",
+ "fieldtype": "Data",
+ "hidden": 1,
+ "label": "Content Type"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "content_type",
- "fieldtype": "Data",
- "hidden": 1,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Content Type",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "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
- },
+ "fieldname": "attachment",
+ "fieldtype": "Attach",
+ "hidden": 1,
+ "label": "Attachment"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "attachment",
- "fieldtype": "Attach",
- "hidden": 1,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Attachment",
- "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
- },
+ "default": "0",
+ "fieldname": "via_customer_portal",
+ "fieldtype": "Check",
+ "label": "Via Customer Portal"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "via_customer_portal",
- "fieldtype": "Check",
- "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": "Via Customer Portal",
- "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
+ "default": "Ongoing",
+ "fieldname": "agreement_fulfilled",
+ "fieldtype": "Select",
+ "label": "Service Level Agreement Fulfilled",
+ "options": "Ongoing\nFulfilled\nFailed",
+ "read_only": 1
+ },
+ {
+ "description": "in hours",
+ "fieldname": "response_by_variance",
+ "fieldtype": "Float",
+ "label": "Response By Variance",
+ "read_only": 1
+ },
+ {
+ "description": "in hours",
+ "fieldname": "resolution_by_variance",
+ "fieldtype": "Float",
+ "label": "Resolution By Variance",
+ "read_only": 1
}
- ],
- "has_web_view": 0,
- "hide_toolbar": 0,
- "icon": "fa fa-ticket",
- "idx": 7,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2019-04-23 18:04:42.039620",
+ ],
+ "icon": "fa fa-ticket",
+ "idx": 7,
+ "modified": "2019-05-20 15:19:00.771333",
"modified_by": "Administrator",
- "module": "Support",
- "name": "Issue",
- "owner": "Administrator",
+ "module": "Support",
+ "name": "Issue",
+ "owner": "Administrator",
"permissions": [
{
- "amend": 0,
- "cancel": 0,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Support Team",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Support Team",
+ "share": 1,
"write": 1
}
- ],
- "quick_entry": 1,
- "read_only": 0,
- "search_fields": "status,customer,subject,raised_by",
- "show_name_in_global_search": 0,
- "sort_order": "ASC",
- "timeline_field": "customer",
- "title_field": "subject",
- "track_changes": 0,
- "track_seen": 1,
- "track_views": 0
+ ],
+ "quick_entry": 1,
+ "search_fields": "status,customer,subject,raised_by",
+ "sort_field": "modified",
+ "sort_order": "ASC",
+ "timeline_field": "customer",
+ "title_field": "subject",
+ "track_seen": 1
}
\ No newline at end of file
diff --git a/erpnext/support/doctype/issue/issue.py b/erpnext/support/doctype/issue/issue.py
index dca06d4..773e61a 100644
--- a/erpnext/support/doctype/issue/issue.py
+++ b/erpnext/support/doctype/issue/issue.py
@@ -11,7 +11,7 @@
from datetime import datetime, timedelta
from frappe.model.mapper import get_mapped_doc
from frappe.utils.user import is_website_user
-from ..service_level_agreement.service_level_agreement import get_active_service_level_agreement_for
+from erpnext.support.doctype.service_level_agreement.service_level_agreement import get_active_service_level_agreement_for
from erpnext.crm.doctype.opportunity.opportunity import assign_to_user
from frappe.email.inbox import link_communication_to_document
@@ -63,22 +63,28 @@
def update_status(self):
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()
+ self.first_responded_on = frappe.flags.current_time or now_datetime()
+
if self.status=="Closed" and status !="Closed":
- self.resolution_date = now()
- self.update_agreement_status()
+ self.resolution_date = frappe.flags.current_time or now_datetime()
+ if frappe.db.get_value("Issue", self.name, "agreement_fulfilled") == "Ongoing":
+ 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:
- if (round(time_diff_in_hours(self.response_by, current_time), 2) < 0
- or round(time_diff_in_hours(self.resolution_by, current_time), 2) < 0):
- self.agreement_status = "Failed"
+
+ if self.service_level_agreement and self.agreement_fulfilled == "Ongoing":
+ if frappe.db.get_value("Issue", self.name, "response_by_variance") < 0 or \
+ frappe.db.get_value("Issue", self.name, "resolution_by_variance") < 0:
+
+ self.agreement_fulfilled = "Failed"
else:
- self.agreement_status = "Fulfilled"
+ self.agreement_fulfilled = "Fulfilled"
def create_communication(self):
communication = frappe.new_doc("Communication")
@@ -124,23 +130,42 @@
def before_insert(self):
self.set_response_and_resolution_time()
- def set_response_and_resolution_time(self):
- service_level_agreement = get_active_service_level_agreement_for(self.customer)
- if service_level_agreement:
- self.service_level_agreement = service_level_agreement.name
- self.priority = service_level_agreement.priority
+ def set_response_and_resolution_time(self, priority=None, service_level_agreement=None):
+ service_level_agreement = get_active_service_level_agreement_for(priority=priority,
+ customer=self.customer, service_level_agreement=service_level_agreement)
- if not self.service_level_agreement: return
+ if not service_level_agreement:
+ if frappe.db.get_value("Issue", self.name, "service_level_agreement"):
+ frappe.throw(_("Couldn't Set Service Level Agreement {0}.".format(self.service_level_agreement)))
+ return
- service_level = frappe.get_doc("Service Level", service_level_agreement.service_level)
+ if (service_level_agreement.customer and self.customer) and not (service_level_agreement.customer == self.customer):
+ frappe.throw(_("This Service Level Agreement is specific to Customer {0}".format(service_level_agreement.customer)))
+
+ self.service_level_agreement = service_level_agreement.name
+ self.priority = service_level_agreement.default_priority if not priority else priority
+
+ service_level_agreement = frappe.get_doc("Service Level Agreement", service_level_agreement.name)
+ priority = service_level_agreement.get_service_level_agreement_priority(self.priority)
+ priority.update({
+ "support_and_resolution": service_level_agreement.support_and_resolution,
+ "holiday_list": service_level_agreement.holiday_list
+ })
if not self.creation:
self.creation = now_datetime()
start_date_time = get_datetime(self.creation)
+ 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 = 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_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_service_level_agreement_and_priority(self, priority=None, service_level_agreement=None):
+ self.set_response_and_resolution_time(priority=priority, service_level_agreement=service_level_agreement)
+ self.save(ignore_permissions=True)
def get_expected_time_for(parameter, service_level, start_date_time):
current_date_time = start_date_time
@@ -150,11 +175,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)))
@@ -168,13 +193,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:
@@ -207,6 +232,28 @@
return current_date_time
+def set_service_level_agreement_variance(issue=None):
+ current_time = frappe.flags.current_time or now_datetime()
+
+ filters = {"status": "Open", "agreement_fulfilled": "Ongoing"}
+ if issue:
+ filters = {"name": issue}
+
+ for issue in frappe.get_list("Issue", filters=filters):
+ doc = frappe.get_doc("Issue", issue.name)
+
+ if not doc.first_responded_on: # first_responded_on set when first reply is sent to customer
+ variance = round(time_diff_in_hours(doc.response_by, current_time), 2)
+ frappe.db.set_value("Issue", doc.name, "response_by_variance", variance)
+ if variance < 0:
+ frappe.db.set_value("Issue", doc.name, "agreement_fulfilled", "Failed")
+
+ if not doc.resolution_date: # resolution_date set when issue has been closed
+ variance = round(time_diff_in_hours(doc.resolution_by, current_time), 2)
+ frappe.db.set_value("Issue", doc.name, "resolution_by_variance", variance)
+ if variance < 0:
+ frappe.db.set_value("Issue", doc.name, "agreement_fulfilled", "Failed")
+
def get_list_context(context=None):
return {
"title": _("Issues"),
@@ -244,14 +291,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
@@ -291,6 +336,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/issue/test_issue.py b/erpnext/support/doctype/issue/test_issue.py
index 48ba1f6..1a793a6 100644
--- a/erpnext/support/doctype/issue/test_issue.py
+++ b/erpnext/support/doctype/issue/test_issue.py
@@ -4,7 +4,7 @@
import frappe
import unittest
-from erpnext.support.doctype.service_level_agreement.test_service_level_agreement import make_service_level_agreement
+from erpnext.support.doctype.service_level_agreement.test_service_level_agreement import create_service_level_agreements_for_issues
from frappe.utils import now_datetime
import datetime
from datetime import timedelta
@@ -18,15 +18,30 @@
def test_response_time_and_resolution_time_based_on_different_sla(self):
- make_service_level_agreement()
+ create_service_level_agreements_for_issues()
creation = "2019-03-04 12:00:00"
# make issue with customer specific SLA
- issue = make_issue(creation, '_Test Customer')
+ customer = create_customer("_Test Customer", "__Test SLA Customer Group", "__Test SLA Territory")
+ issue = make_issue(creation, "_Test Customer")
- self.assertEquals(issue.response_by, datetime.datetime(2019, 3, 7, 18, 0))
- self.assertEquals(issue.resolution_by, datetime.datetime(2019, 3, 9, 18, 0))
+ self.assertEquals(issue.response_by, datetime.datetime(2019, 3, 4, 14, 0))
+ self.assertEquals(issue.resolution_by, datetime.datetime(2019, 3, 4, 15, 0))
+
+ # make issue with customer_group specific SLA
+ customer = create_customer("__Test Customer", "_Test SLA Customer Group", "__Test SLA Territory")
+ issue = make_issue(creation, "__Test Customer")
+
+ self.assertEquals(issue.response_by, datetime.datetime(2019, 3, 4, 14, 0))
+ self.assertEquals(issue.resolution_by, datetime.datetime(2019, 3, 4, 15, 0))
+
+ # make issue with territory specific SLA
+ customer = create_customer("___Test Customer", "__Test SLA Customer Group", "_Test SLA Territory")
+ issue = make_issue(creation, "___Test Customer")
+
+ self.assertEquals(issue.response_by, datetime.datetime(2019, 3, 4, 14, 0))
+ self.assertEquals(issue.resolution_by, datetime.datetime(2019, 3, 4, 15, 0))
# make issue with default SLA
issue = make_issue(creation)
@@ -41,33 +56,51 @@
self.assertEquals(issue.response_by, datetime.datetime(2019, 3, 4, 18, 0))
self.assertEquals(issue.resolution_by, datetime.datetime(2019, 3, 6, 12, 0))
- frappe.flags.current_time = datetime.datetime(2019, 3, 3, 12, 0)
+ frappe.flags.current_time = datetime.datetime(2019, 3, 4, 15, 0)
issue.status = 'Closed'
issue.save()
- self.assertEqual(issue.agreement_status, 'Fulfilled')
-
- issue.status = 'Open'
- issue.save()
-
- frappe.flags.current_time = datetime.datetime(2019, 3, 5, 12, 0)
-
- issue.status = 'Closed'
- issue.save()
-
- self.assertEqual(issue.agreement_status, 'Failed')
-
-
+ self.assertEqual(issue.agreement_fulfilled, 'Fulfilled')
def make_issue(creation=None, customer=None):
issue = frappe.get_doc({
"doctype": "Issue",
- "subject": "Issue 1",
+ "subject": "Service Level Agreement Issue",
"customer": customer,
"raised_by": "test@example.com",
+ "description": "Service Level Agreement Issue",
"creation": creation
- }).insert()
+ }).insert(ignore_permissions=True)
- return issue
\ No newline at end of file
+ return issue
+
+def create_customer(name, customer_group, territory):
+
+ create_customer_group(customer_group)
+ create_territory(territory)
+
+ if not frappe.db.exists("Customer", {"customer_name": name}):
+ frappe.get_doc({
+ "doctype": "Customer",
+ "customer_name": name,
+ "customer_group": customer_group,
+ "territory": territory
+ }).insert(ignore_permissions=True)
+
+def create_customer_group(customer_group):
+
+ if not frappe.db.exists("Customer Group", {"customer_group_name": customer_group}):
+ frappe.get_doc({
+ "doctype": "Customer Group",
+ "customer_group_name": customer_group
+ }).insert(ignore_permissions=True)
+
+def create_territory(territory):
+
+ if not frappe.db.exists("Territory", {"territory_name": territory}):
+ frappe.get_doc({
+ "doctype": "Territory",
+ "territory_name": territory,
+ }).insert(ignore_permissions=True)
diff --git a/erpnext/support/doctype/issue_priority/__init__.py b/erpnext/support/doctype/issue_priority/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/support/doctype/issue_priority/__init__.py
diff --git a/erpnext/support/doctype/issue_priority/issue_priority.js b/erpnext/support/doctype/issue_priority/issue_priority.js
new file mode 100644
index 0000000..37ce6a5
--- /dev/null
+++ b/erpnext/support/doctype/issue_priority/issue_priority.js
@@ -0,0 +1,8 @@
+// Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Issue Priority', {
+ // refresh: function(frm) {
+
+ // }
+});
diff --git a/erpnext/support/doctype/issue_priority/issue_priority.json b/erpnext/support/doctype/issue_priority/issue_priority.json
new file mode 100644
index 0000000..38a187b
--- /dev/null
+++ b/erpnext/support/doctype/issue_priority/issue_priority.json
@@ -0,0 +1,39 @@
+{
+ "autoname": "Prompt",
+ "creation": "2019-05-20 15:14:21.604447",
+ "doctype": "DocType",
+ "engine": "InnoDB",
+ "field_order": [
+ "description"
+ ],
+ "fields": [
+ {
+ "fieldname": "description",
+ "fieldtype": "Small Text",
+ "label": "Description"
+ }
+ ],
+ "modified": "2019-05-20 17:06:38.095647",
+ "modified_by": "Administrator",
+ "module": "Support",
+ "name": "Issue Priority",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "System Manager",
+ "share": 1,
+ "write": 1
+ }
+ ],
+ "quick_entry": 1,
+ "sort_field": "modified",
+ "sort_order": "ASC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/support/doctype/issue_priority/issue_priority.py b/erpnext/support/doctype/issue_priority/issue_priority.py
new file mode 100644
index 0000000..cecaaaa
--- /dev/null
+++ b/erpnext/support/doctype/issue_priority/issue_priority.py
@@ -0,0 +1,14 @@
+# -*- 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 import _
+from frappe.model.document import Document
+
+class IssuePriority(Document):
+
+ def validate(self):
+ if frappe.db.exists("Issue Priority", {"name": self.name}):
+ frappe.throw(_("Issue Priority Already Exists"))
diff --git a/erpnext/support/doctype/issue_priority/test_issue_priority.py b/erpnext/support/doctype/issue_priority/test_issue_priority.py
new file mode 100644
index 0000000..0d65122
--- /dev/null
+++ b/erpnext/support/doctype/issue_priority/test_issue_priority.py
@@ -0,0 +1,22 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+import frappe
+import unittest
+
+class TestIssuePriority(unittest.TestCase):
+ pass
+
+def make_priorities():
+ insert_priority("Low")
+ insert_priority("Medium")
+ insert_priority("High")
+
+def insert_priority(name):
+ if not frappe.db.exists("Issue Priority", name):
+ frappe.get_doc({
+ "doctype": "Issue Priority",
+ "name": name
+ }).insert(ignore_permissions=True)
\ No newline at end of file
diff --git a/erpnext/support/doctype/service_day/service_day.json b/erpnext/support/doctype/service_day/service_day.json
index 8ed006d..68614b1 100644
--- a/erpnext/support/doctype/service_day/service_day.json
+++ b/erpnext/support/doctype/service_day/service_day.json
@@ -1,203 +1,53 @@
{
- "allow_copy": 0,
- "allow_events_in_timeline": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "beta": 0,
"creation": "2019-03-04 12:55:36.403035",
- "custom": 0,
- "docstatus": 0,
"doctype": "DocType",
- "document_type": "",
"editable_grid": 1,
"engine": "InnoDB",
+ "field_order": [
+ "workday",
+ "section_break_2",
+ "start_time",
+ "column_break_3",
+ "end_time"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
"fieldname": "workday",
"fieldtype": "Select",
- "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": "Workday",
- "length": 0,
- "no_copy": 0,
- "options": "Monday\nTuesday\nWednesday\nThursday\nFriday\nSaturday\nSunday",
- "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
+ "options": "Monday\nTuesday\nWednesday\nThursday\nFriday\nSaturday\nSunday"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "section_break_2",
- "fieldtype": "Section 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
+ "fieldtype": "Section Break"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "start_time",
"fieldtype": "Time",
- "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": "Start Time",
- "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
+ "label": "Start Time"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "column_break_3",
- "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
+ "fieldtype": "Column Break"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "end_time",
"fieldtype": "Time",
- "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": "End Time",
- "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
+ "label": "End Time"
}
],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 0,
"istable": 1,
- "max_attachments": 0,
- "modified": "2019-03-04 12:55:36.403035",
+ "modified": "2019-05-05 19:15:08.999579",
"modified_by": "Administrator",
"module": "Support",
"name": "Service Day",
- "name_case": "",
"owner": "Administrator",
"permissions": [],
"quick_entry": 1,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
- "track_changes": 1,
- "track_seen": 0,
- "track_views": 0
+ "track_changes": 1
}
\ No newline at end of file
diff --git a/erpnext/support/doctype/service_level/service_level.json b/erpnext/support/doctype/service_level/service_level.json
index 2dd335e..dced3aa 100644
--- a/erpnext/support/doctype/service_level/service_level.json
+++ b/erpnext/support/doctype/service_level/service_level.json
@@ -1,488 +1,111 @@
{
- "allow_copy": 0,
- "allow_events_in_timeline": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
"autoname": "field:service_level",
- "beta": 0,
"creation": "2018-11-19 12:44:30.407502",
- "custom": 0,
- "docstatus": 0,
"doctype": "DocType",
- "document_type": "",
"editable_grid": 1,
"engine": "InnoDB",
+ "field_order": [
+ "service_level",
+ "employee_group",
+ "column_break_2",
+ "holiday_list",
+ "default_priority",
+ "response_and_resoution_time",
+ "priorities",
+ "section_break_01",
+ "support_and_resolution"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "service_level",
"fieldtype": "Data",
- "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": "Level",
- "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": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
"unique": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "priority",
- "fieldtype": "Select",
- "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": "Priority",
- "length": 0,
- "no_copy": 0,
- "options": "Low\nMedium\nHigh",
- "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_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "column_break_2",
- "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
+ "fieldtype": "Column Break"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "holiday_list",
"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": "Holiday List (ignored during SLA calculation)",
- "length": 0,
- "no_copy": 0,
"options": "Holiday List",
- "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
+ "reqd": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "employee_group",
"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": "Employee Group",
- "length": 0,
- "no_copy": 0,
- "options": "Employee Group",
- "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
+ "options": "Employee Group"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "response_and_resoution_time",
"fieldtype": "Section 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,
- "label": "Response and Resoution Time",
- "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
+ "label": "Response and Resoution Time"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "response_time",
- "fieldtype": "Int",
- "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": "Response Time",
- "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": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
- "fieldname": "resolution_time",
- "fieldtype": "Int",
- "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": "Resolution Time",
- "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": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
- "fieldname": "column_break_9",
- "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_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
- "fieldname": "response_time_period",
- "fieldtype": "Select",
- "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": "Response Time Period",
- "length": 0,
- "no_copy": 0,
- "options": "Hour\nDay\nWeek",
- "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_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "resolution_time_period",
- "fieldtype": "Select",
- "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": "Resolution Time Period",
- "length": 0,
- "no_copy": 0,
- "options": "Hour\nDay\nWeek",
- "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_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
"fieldname": "section_break_01",
"fieldtype": "Section 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,
- "label": "Support and Resolution",
- "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
+ "label": "Support Hours"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "support_and_resolution",
"fieldtype": "Table",
- "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": "Support and Resolution",
- "length": 0,
- "no_copy": 0,
"options": "Service Day",
- "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
+ "reqd": 1
+ },
+ {
+ "fieldname": "priorities",
+ "fieldtype": "Table",
+ "label": "Priorities",
+ "options": "Service Level Priority",
+ "reqd": 1
+ },
+ {
+ "fieldname": "default_priority",
+ "fieldtype": "Link",
+ "label": "Default Priority",
+ "options": "Issue Priority",
+ "read_only": 1
}
],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2019-03-04 12:55:53.215841",
+ "modified": "2019-06-06 12:58:03.464056",
"modified_by": "Administrator",
"module": "Support",
"name": "Service Level",
- "name_case": "",
"owner": "Administrator",
"permissions": [
{
- "amend": 0,
- "cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
- "set_user_permissions": 0,
"share": 1,
- "submit": 0,
+ "write": 1
+ },
+ {
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "All",
+ "share": 1,
"write": 1
}
],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 0,
"sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 0,
- "track_seen": 0,
- "track_views": 0
+ "sort_order": "DESC"
}
\ No newline at end of file
diff --git a/erpnext/support/doctype/service_level/service_level.py b/erpnext/support/doctype/service_level/service_level.py
index 4b41e53..4e70a01 100644
--- a/erpnext/support/doctype/service_level/service_level.py
+++ b/erpnext/support/doctype/service_level/service_level.py
@@ -12,35 +12,84 @@
class ServiceLevel(Document):
def validate(self):
- week = get_weekdays()
- indexes = []
+ self.check_priorities()
+ self.check_support_and_resolution()
- self.check_response_and_resolution_time()
+ def check_priorities(self):
+ default_priority = []
+ priorities = []
+
+ for priority in self.priorities:
+ # Check if response and resolution time is set for every 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)))
+
+ priorities.append(priority.priority)
+
+ if priority.default_priority:
+ default_priority.append(priority.default_priority)
+
+ 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)))
+
+ # Check if repeated priority
+ if not len(set(priorities)) == len(priorities):
+ repeated_priority = get_repeated(priorities)
+ frappe.throw(_("Priority {0} has been repeated.".format(repeated_priority)))
+
+ # Check if repeated default priority
+ if not len(set(default_priority)) == len(default_priority):
+ frappe.throw(_("Select only one Priority as Default."))
+
+ # set default priority from priorities
+ try:
+ self.default_priority = next(d.priority for d in self.priorities if d.default_priority)
+ except Exception:
+ frappe.throw(_("Select a Default Priority."))
+
+ def check_support_and_resolution(self):
+ week = get_weekdays()
+ support_days = []
for support_and_resolution in self.support_and_resolution:
- indexes.append(week.index(support_and_resolution.workday))
+ # Check if start and end time is set for every support day
+ if not (support_and_resolution.start_time or support_and_resolution.end_time):
+ frappe.throw(_("Set Start Time and End Time for \
+ Support Day {0} at index {1}.".format(support_and_resolution.workday, support_and_resolution.idx)))
+
+ 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"))
- 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
+ if support_and_resolution.start_time >= support_and_resolution.end_time:
+ frappe.throw(_("Start Time can't be greater than or equal to End Time \
+ for {0}.".format(support_and_resolution.workday)))
- 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
+ # Check for repeated workday
+ if not len(set(support_days)) == len(support_days):
+ repeated_days = get_repeated(support_days)
+ frappe.throw(_("Workday {0} has been repeated.".format(repeated_days)))
- 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(str(value))
+ else:
+ if value not in diff:
+ diff.append(str(value))
+ return " ".join(diff)
diff --git a/erpnext/support/doctype/service_level/service_level_dashboard.py b/erpnext/support/doctype/service_level/service_level_dashboard.py
new file mode 100644
index 0000000..393095e
--- /dev/null
+++ b/erpnext/support/doctype/service_level/service_level_dashboard.py
@@ -0,0 +1,12 @@
+from frappe import _
+
+def get_data():
+ return {
+ 'fieldname': 'service_level',
+ 'transactions': [
+ {
+ 'label': _('Service Level Agreement'),
+ 'items': ['Service Level Agreement']
+ }
+ ]
+ }
\ No newline at end of file
diff --git a/erpnext/support/doctype/service_level/test_service_level.py b/erpnext/support/doctype/service_level/test_service_level.py
index 3843e31..09577df 100644
--- a/erpnext/support/doctype/service_level/test_service_level.py
+++ b/erpnext/support/doctype/service_level/test_service_level.py
@@ -3,31 +3,65 @@
# See license.txt
from __future__ import unicode_literals
from erpnext.hr.doctype.employee_group.test_employee_group import make_employee_group
-from frappe.utils import now_datetime
-import datetime
-from datetime import timedelta
+from erpnext.support.doctype.issue_priority.test_issue_priority import make_priorities
import frappe
import unittest
class TestServiceLevel(unittest.TestCase):
- pass
-def make_service_level():
- employee_group = make_employee_group()
- make_holiday_list()
+ def test_service_level(self):
+ employee_group = make_employee_group()
+ make_holiday_list()
+ make_priorities()
- # Default Service Level Agreement
- default_service_level = frappe.get_doc({
+ # Default Service Level
+ test_make_service_level = create_service_level("__Test Service Level", "__Test Holiday List", employee_group, 4, 6)
+ get_make_service_level = get_service_level("__Test Service Level")
+
+ self.assertEqual(test_make_service_level.name, get_make_service_level.name)
+ self.assertEqual(test_make_service_level.holiday_list, get_make_service_level.holiday_list)
+ self.assertEqual(test_make_service_level.employee_group, get_make_service_level.employee_group)
+
+ # Service Level
+ test_make_service_level = create_service_level("_Test Service Level", "__Test Holiday List", employee_group, 2, 3)
+ get_make_service_level = get_service_level("_Test Service Level")
+
+ self.assertEqual(test_make_service_level.name, get_make_service_level.name)
+ self.assertEqual(test_make_service_level.holiday_list, get_make_service_level.holiday_list)
+ self.assertEqual(test_make_service_level.employee_group, get_make_service_level.employee_group)
+
+
+def create_service_level(service_level, holiday_list, employee_group, response_time, resolution_time):
+ sl = frappe.get_doc({
"doctype": "Service Level",
- "service_level": "__Test Service Level",
- "holiday_list": "__Test Holiday List",
- "priority": "Medium",
+ "service_level": service_level,
+ "holiday_list": holiday_list,
"employee_group": employee_group,
- "response_time": 4,
- "response_time_period": "Hour",
- "resolution_time": 6,
- "resolution_time_period": "Hour",
+ "priorities": [
+ {
+ "priority": "Low",
+ "response_time": response_time,
+ "response_time_period": "Hour",
+ "resolution_time": resolution_time,
+ "resolution_time_period": "Hour",
+ },
+ {
+ "priority": "Medium",
+ "response_time": response_time,
+ "default_priority": 1,
+ "response_time_period": "Hour",
+ "resolution_time": resolution_time,
+ "resolution_time_period": "Hour",
+ },
+ {
+ "priority": "High",
+ "response_time": response_time,
+ "response_time_period": "Hour",
+ "resolution_time": resolution_time,
+ "resolution_time_period": "Hour",
+ }
+ ],
"support_and_resolution": [
{
"workday": "Monday",
@@ -67,73 +101,21 @@
]
})
- default_service_level_exists = frappe.db.exists("Service Level", "__Test Service Level")
- if not default_service_level_exists:
- default_service_level.insert()
+ sl_exists = frappe.db.exists("Service Level", {"service_level": service_level})
- service_level = frappe.get_doc({
- "doctype": "Service Level",
- "service_level": "_Test Service Level",
- "holiday_list": "__Test Holiday List",
- "priority": "Medium",
- "employee_group": employee_group,
- "response_time": 2,
- "response_time_period": "Day",
- "resolution_time": 3,
- "resolution_time_period": "Day",
- "support_and_resolution": [
- {
- "workday": "Monday",
- "start_time": "10:00:00",
- "end_time": "18:00:00",
- },
- {
- "workday": "Tuesday",
- "start_time": "10:00:00",
- "end_time": "18:00:00",
- },
- {
- "workday": "Wednesday",
- "start_time": "10:00:00",
- "end_time": "18:00:00",
- },
- {
- "workday": "Thursday",
- "start_time": "10:00:00",
- "end_time": "18:00:00",
- },
- {
- "workday": "Friday",
- "start_time": "10:00:00",
- "end_time": "18:00:00",
- },
- {
- "workday": "Saturday",
- "start_time": "10:00:00",
- "end_time": "18:00:00",
- },
- {
- "workday": "Sunday",
- "start_time": "10:00:00",
- "end_time": "18:00:00",
- }
- ]
- })
- service_level_exist = frappe.db.exists("Service Level", "_Test Service Level")
- if not service_level_exist:
- service_level.insert()
- return service_level.service_level
+ if not sl_exists:
+ sl.insert()
+ return sl
else:
- return service_level_exist
+ return frappe.get_doc("Service Level", {"service_level": service_level})
-def get_service_level():
- service_level = frappe.db.exists("Service Level", "_Test Service Level")
- return service_level
+def get_service_level(service_level):
+ return frappe.get_doc("Service Level", service_level)
def make_holiday_list():
holiday_list = frappe.db.exists("Holiday List", "__Test Holiday List")
if not holiday_list:
- now = datetime.datetime.now()
+ now = frappe.utils.now_datetime()
holiday_list = frappe.get_doc({
"doctype": "Holiday List",
"holiday_list_name": "__Test Holiday List",
@@ -153,4 +135,15 @@
"holiday_date": "2019-02-11"
},
]
- }).insert()
\ No newline at end of file
+ }).insert()
+
+def create_service_level_for_sla():
+ employee_group = make_employee_group()
+ make_holiday_list()
+ make_priorities()
+
+ # Default Service Level
+ create_service_level("__Test Service Level", "__Test Holiday List", employee_group, 4, 6)
+
+ # Service Level
+ create_service_level("_Test Service Level", "__Test Holiday List", employee_group, 2, 3)
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 884e3eb..1d486f4 100644
--- a/erpnext/support/doctype/service_level_agreement/service_level_agreement.js
+++ b/erpnext/support/doctype/service_level_agreement/service_level_agreement.js
@@ -11,11 +11,19 @@
name: frm.doc.service_level
},
callback: function(data){
- for (var i = 0; i < data.message.support_and_resolution.length; i++){
- frm.add_child("support_and_resolution", data.message.support_and_resolution[i]);
+ let count = Math.max(data.message.priorities.length, data.message.support_and_resolution.length);
+ let i = 0;
+ while (i < count){
+ if (data.message.priorities[i]) {
+ frm.add_child("priorities", data.message.priorities[i]);
+ }
+ if (data.message.support_and_resolution[i]) {
+ frm.add_child("support_and_resolution", data.message.support_and_resolution[i]);
+ }
+ i++;
}
frm.refresh();
}
});
- }
+ },
});
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 27d7ad5..f7505d6 100644
--- a/erpnext/support/doctype/service_level_agreement/service_level_agreement.json
+++ b/erpnext/support/doctype/service_level_agreement/service_level_agreement.json
@@ -1,764 +1,190 @@
{
- "allow_copy": 0,
- "allow_events_in_timeline": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "autoname": "Prompt",
- "beta": 0,
+ "autoname": "format:SLA-{service_level}-{####}",
"creation": "2018-12-26 21:08:15.448812",
- "custom": 0,
- "docstatus": 0,
"doctype": "DocType",
- "document_type": "",
"editable_grid": 1,
"engine": "InnoDB",
+ "field_order": [
+ "service_level",
+ "default_service_level_agreement",
+ "holiday_list",
+ "column_break_2",
+ "employee_group",
+ "default_priority",
+ "apply_to_section",
+ "apply_to",
+ "column_break_10",
+ "entity",
+ "agreement_details_section",
+ "start_date",
+ "active",
+ "column_break_7",
+ "end_date",
+ "response_and_resolution_time_section",
+ "priorities",
+ "support_and_resolution_section_break",
+ "support_and_resolution"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "",
- "depends_on": "eval: !doc.default_service_level_agreement",
- "fetch_if_empty": 0,
- "fieldname": "customer",
- "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": "Customer",
- "length": 0,
- "no_copy": 0,
- "options": "Customer",
- "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_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval: !doc.customer",
- "fetch_if_empty": 0,
+ "default": "0",
+ "depends_on": "eval: !doc.customer;",
"fieldname": "default_service_level_agreement",
"fieldtype": "Check",
- "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": "Default Service Level Agreement",
- "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
+ "set_only_once": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "service_level",
"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,
+ "in_standard_filter": 1,
"label": "Service Level",
- "length": 0,
- "no_copy": 0,
"options": "Service Level",
- "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
+ "set_only_once": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fetch_from": "service_level.holiday_list",
- "fetch_if_empty": 0,
"fieldname": "holiday_list",
"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": "Holiday List",
- "length": 0,
- "no_copy": 0,
"options": "Holiday List",
- "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
+ "read_only": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "column_break_2",
- "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
+ "fieldtype": "Column Break"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
- "fetch_from": "service_level.priority",
- "fetch_if_empty": 0,
- "fieldname": "priority",
- "fieldtype": "Data",
- "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": "Priority",
- "length": 0,
- "no_copy": 0,
- "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_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fetch_from": "service_level.employee_group",
- "fetch_if_empty": 0,
"fieldname": "employee_group",
"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,
+ "in_list_view": 1,
+ "in_standard_filter": 1,
"label": "Employee Group",
- "length": 0,
- "no_copy": 0,
"options": "Employee Group",
- "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
+ "read_only": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "collapsible_depends_on": "",
- "columns": 0,
- "depends_on": "eval: !doc.default_service_level_agreement",
- "fetch_if_empty": 0,
"fieldname": "agreement_details_section",
"fieldtype": "Section 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,
- "label": "Agreement Details",
- "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
+ "label": "Agreement Details"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"depends_on": "eval: !doc.default_service_level_agreement",
- "fetch_if_empty": 0,
"fieldname": "start_date",
"fieldtype": "Date",
- "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": "Start Date",
- "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
+ "label": "Start Date"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "Active",
- "depends_on": "eval: !doc.default_service_level_agreement",
- "fetch_if_empty": 0,
- "fieldname": "agreement_status",
- "fieldtype": "Select",
- "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": "Agreement Status",
- "length": 0,
- "no_copy": 0,
- "options": "Active\nExpired",
- "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_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"depends_on": "eval: !doc.default_contract",
- "fetch_if_empty": 0,
"fieldname": "column_break_7",
- "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
+ "fieldtype": "Column Break"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"depends_on": "eval: !doc.default_service_level_agreement",
- "fetch_if_empty": 0,
"fieldname": "end_date",
"fieldtype": "Date",
- "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": "End Date",
- "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
+ "label": "End Date"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
+ "collapsible": 1,
"fieldname": "response_and_resolution_time_section",
"fieldtype": "Section 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,
- "label": "Response and Resolution Time",
- "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
+ "label": "Response and Resolution Time"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_from": "service_level.response_time",
- "fetch_if_empty": 0,
- "fieldname": "response_time",
- "fieldtype": "Int",
- "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": "Response Time",
- "length": 0,
- "no_copy": 0,
- "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_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_from": "service_level.resolution_time",
- "fetch_if_empty": 0,
- "fieldname": "resolution_time",
- "fieldtype": "Int",
- "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": "Resolution Time",
- "length": 0,
- "no_copy": 0,
- "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_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "column_break_16",
- "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_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_from": "service_level.response_time_period",
- "fetch_if_empty": 0,
- "fieldname": "response_time_period",
- "fieldtype": "Data",
- "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": "Response Time Period",
- "length": 0,
- "no_copy": 0,
- "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_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_from": "service_level.resolution_time_period",
- "fetch_if_empty": 0,
- "fieldname": "resolution_time_period",
- "fieldtype": "Data",
- "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": "Resolution Time Period",
- "length": 0,
- "no_copy": 0,
- "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_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
"collapsible": 1,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "support_and_resolution_section_break",
"fieldtype": "Section 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,
- "label": "Support and Resolution",
- "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
+ "label": "Support Hours"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "support_and_resolution",
"fieldtype": "Table",
- "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": "Support and Resolution",
- "length": 0,
- "no_copy": 0,
- "options": "Service Day",
- "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
+ "options": "Service Day"
+ },
+ {
+ "fieldname": "priorities",
+ "fieldtype": "Table",
+ "label": "Priorities",
+ "options": "Service Level Priority"
+ },
+ {
+ "fetch_from": "service_level.default_priority",
+ "fieldname": "default_priority",
+ "fieldtype": "Link",
+ "label": "Default Priority",
+ "options": "Issue Priority",
+ "read_only": 1
+ },
+ {
+ "default": "1",
+ "fieldname": "active",
+ "fieldtype": "Check",
+ "label": "Active",
+ "read_only": 1
+ },
+ {
+ "depends_on": "eval: !doc.default_service_level_agreement",
+ "fieldname": "apply_to_section",
+ "fieldtype": "Section Break",
+ "label": "Apply To"
+ },
+ {
+ "fieldname": "apply_to",
+ "fieldtype": "Select",
+ "in_standard_filter": 1,
+ "label": "Apply To",
+ "options": "\nCustomer\nCustomer Group\nTerritory"
+ },
+ {
+ "fieldname": "column_break_10",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "entity",
+ "fieldtype": "Dynamic Link",
+ "in_list_view": 1,
+ "in_standard_filter": 1,
+ "label": "Entity",
+ "options": "apply_to"
}
],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2019-03-17 22:36:53.576464",
+ "modified": "2019-06-10 11:32:47.778830",
"modified_by": "Administrator",
"module": "Support",
"name": "Service Level Agreement",
- "name_case": "",
"owner": "Administrator",
"permissions": [
{
- "amend": 0,
- "cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
- "set_user_permissions": 0,
"share": 1,
- "submit": 0,
"write": 1
},
{
- "amend": 0,
- "cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "All",
- "set_user_permissions": 0,
"share": 1,
- "submit": 0,
"write": 1
}
],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
- "track_changes": 1,
- "track_seen": 0,
- "track_views": 0
+ "track_changes": 1
}
\ No newline at end of file
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 911d069..aeeb86d 100644
--- a/erpnext/support/doctype/service_level_agreement/service_level_agreement.py
+++ b/erpnext/support/doctype/service_level_agreement/service_level_agreement.py
@@ -9,37 +9,71 @@
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 self.default_service_level_agreement:
- 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.default_service_level_agreement:
+ if frappe.db.exists("Service Level Agreement", {"default_service_level_agreement": "1", "name": ["!=", self.name]}):
+ frappe.throw(_("A Default Service Level Agreement already exists."))
+ else:
+ if self.start_date and self.end_date:
+ 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 get_service_level_agreement_priority(self, priority):
+ priority = frappe.get_doc("Service Level Priority", {"priority": priority, "parent": self.name})
+
+ return frappe._dict({
+ "priority": priority.priority,
+ "response_time": priority.response_time,
+ "response_time_period": priority.response_time_period,
+ "resolution_time": priority.resolution_time,
+ "resolution_time_period": priority.resolution_time_period
+ })
def check_agreement_status():
service_level_agreements = frappe.get_list("Service Level Agreement", filters=[
- {"agreement_status": "Active"},
+ {"active": 1},
{"default_service_level_agreement": 0}
- ])
- service_level_agreements.reverse()
+ ], fields=["name"])
+
for service_level_agreement in service_level_agreements:
- service_level_agreement = frappe.get_doc("Service Level Agreement", service_level_agreement)
- if service_level_agreement.end_date < frappe.utils.getdate():
- service_level_agreement.agreement_status = "Expired"
- service_level_agreement.save()
+ doc = frappe.get_doc("Service Level Agreement", service_level_agreement.name)
+ if doc.end_date and doc.end_date < frappe.utils.getdate():
+ frappe.db.set_value("Service Level Agreement", service_level_agreement.name, "active", 0)
-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)
+def get_active_service_level_agreement_for(priority, customer=None, service_level_agreement=None):
+ filters = [
+ ["Service Level Agreement", "active", "=", 1],
+ ]
- return agreement[0] if agreement else None
\ No newline at end of file
+ if priority:
+ filters.append(["Service Level Priority", "priority", "=", priority])
+
+ or_filters = [
+ ["Service Level Agreement", "entity", "in", [customer, get_customer_group(customer), get_customer_territory(customer)]]
+ ]
+ if service_level_agreement:
+ or_filters = [
+ ["Service Level Agreement", "name", "=", service_level_agreement],
+ ]
+
+ or_filters.append(["Service Level Agreement", "default_service_level_agreement", "=", 1])
+
+ agreement = frappe.get_list("Service Level Agreement", filters=filters, or_filters=or_filters,
+ fields=["name", "default_priority"])
+
+ return agreement[0] if agreement else None
+
+@frappe.whitelist()
+def get_service_level_agreement_priorities(name):
+ return [priority.priority for priority in frappe.get_list("Service Level Priority", filters={"parent": name}, fields=["priority"])]
+
+def get_customer_group(customer):
+ if customer:
+ return frappe.db.get_value("Customer", customer, "customer_group")
+
+def get_customer_territory(customer):
+ if customer:
+ return frappe.db.get_value("Customer", customer, "territory")
\ No newline at end of file
diff --git a/erpnext/support/doctype/service_level_agreement/service_level_agreement_dashboard.py b/erpnext/support/doctype/service_level_agreement/service_level_agreement_dashboard.py
new file mode 100644
index 0000000..f2bd681
--- /dev/null
+++ b/erpnext/support/doctype/service_level_agreement/service_level_agreement_dashboard.py
@@ -0,0 +1,12 @@
+from frappe import _
+
+def get_data():
+ return {
+ 'fieldname': 'service_level_agreement',
+ 'transactions': [
+ {
+ 'label': _('Issue'),
+ 'items': ['Issue']
+ }
+ ]
+ }
\ No newline at end of file
diff --git a/erpnext/support/doctype/service_level_agreement/test_service_level_agreement.py b/erpnext/support/doctype/service_level_agreement/test_service_level_agreement.py
index e5737e0..e04265f 100644
--- a/erpnext/support/doctype/service_level_agreement/test_service_level_agreement.py
+++ b/erpnext/support/doctype/service_level_agreement/test_service_level_agreement.py
@@ -5,29 +5,107 @@
import frappe
import unittest
-from erpnext.support.doctype.service_level.test_service_level import make_service_level
+from erpnext.support.doctype.service_level.test_service_level import create_service_level_for_sla
class TestServiceLevelAgreement(unittest.TestCase):
- pass
-def make_service_level_agreement():
- make_service_level()
+ def test_service_level_agreement(self):
+ create_service_level_for_sla()
- # Default Service Level Agreement
- default_service_level_agreement = frappe.get_doc({
+ # Default Service Level Agreement
+ create_default_service_level_agreement = create_service_level_agreement(default_service_level_agreement=1,
+ service_level="__Test Service Level", holiday_list="__Test Holiday List", employee_group="_Test Employee Group",
+ apply_to=None, entity=None, response_time=4, resolution_time=6)
+ get_default_service_level_agreement = get_service_level_agreement(default_service_level_agreement=1)
+
+ self.assertEqual(create_default_service_level_agreement.name, get_default_service_level_agreement.name)
+ self.assertEqual(create_default_service_level_agreement.apply_to, get_default_service_level_agreement.apply_to)
+ self.assertEqual(create_default_service_level_agreement.entity, get_default_service_level_agreement.entity)
+ self.assertEqual(create_default_service_level_agreement.default_service_level_agreement, get_default_service_level_agreement.default_service_level_agreement)
+
+ # Service Level Agreement for Customer
+ customer = create_customer()
+ create_customer_service_level_agreement = create_service_level_agreement(default_service_level_agreement=0,
+ service_level="_Test Service Level", holiday_list="__Test Holiday List", employee_group="_Test Employee Group",
+ apply_to="Customer", entity=customer, response_time=2, resolution_time=3)
+ get_customer_service_level_agreement = get_service_level_agreement(apply_to="Customer", entity=customer)
+
+ self.assertEqual(create_customer_service_level_agreement.name, get_customer_service_level_agreement.name)
+ self.assertEqual(create_customer_service_level_agreement.apply_to, get_customer_service_level_agreement.apply_to)
+ self.assertEqual(create_customer_service_level_agreement.entity, get_customer_service_level_agreement.entity)
+ self.assertEqual(create_customer_service_level_agreement.default_service_level_agreement, get_customer_service_level_agreement.default_service_level_agreement)
+
+ # Service Level Agreement for Customer Group
+ customer_group = create_customer_group()
+ create_customer_group_service_level_agreement = create_service_level_agreement(default_service_level_agreement=0,
+ service_level="_Test Service Level", holiday_list="__Test Holiday List", employee_group="_Test Employee Group",
+ apply_to="Customer Group", entity=customer_group, response_time=2, resolution_time=3)
+ get_customer_group_service_level_agreement = get_service_level_agreement(apply_to="Customer Group", entity=customer_group)
+
+ self.assertEqual(create_customer_group_service_level_agreement.name, get_customer_group_service_level_agreement.name)
+ self.assertEqual(create_customer_group_service_level_agreement.apply_to, get_customer_group_service_level_agreement.apply_to)
+ self.assertEqual(create_customer_group_service_level_agreement.entity, get_customer_group_service_level_agreement.entity)
+ self.assertEqual(create_customer_group_service_level_agreement.default_service_level_agreement, get_customer_group_service_level_agreement.default_service_level_agreement)
+
+ # Service Level Agreement for Territory
+ territory = create_territory()
+ create_territory_service_level_agreement = create_service_level_agreement(default_service_level_agreement=0,
+ service_level="_Test Service Level", holiday_list="__Test Holiday List", employee_group="_Test Employee Group",
+ apply_to="Territory", entity=territory, response_time=2, resolution_time=3)
+ get_territory_service_level_agreement = get_service_level_agreement(apply_to="Territory", entity=territory)
+
+ self.assertEqual(create_territory_service_level_agreement.name, get_territory_service_level_agreement.name)
+ self.assertEqual(create_territory_service_level_agreement.apply_to, get_territory_service_level_agreement.apply_to)
+ self.assertEqual(create_territory_service_level_agreement.entity, get_territory_service_level_agreement.entity)
+ self.assertEqual(create_territory_service_level_agreement.default_service_level_agreement, get_territory_service_level_agreement.default_service_level_agreement)
+
+
+def get_service_level_agreement(default_service_level_agreement=None, apply_to=None, entity=None):
+ if default_service_level_agreement:
+ filters = {"default_service_level_agreement": default_service_level_agreement}
+ else:
+ filters = {"apply_to": apply_to, "entity": entity}
+
+ service_level_agreement = frappe.get_doc("Service Level Agreement", filters)
+ return service_level_agreement
+
+def create_service_level_agreement(default_service_level_agreement, service_level, holiday_list, employee_group,
+ response_time, apply_to, entity, resolution_time):
+
+ service_level_agreement = frappe.get_doc({
"doctype": "Service Level Agreement",
- "name": "__Test Service Level Agreement",
- "default_service_level_agreement": 1,
- "service_level": "__Test Service Level",
- "holiday_list": "__Test Holiday List",
- "priority": "Medium",
- "employee_group": "_Test Employee Group",
+ "default_service_level_agreement": default_service_level_agreement,
+ "service_level": service_level,
+ "holiday_list": holiday_list,
+ "employee_group": employee_group,
+ "apply_to": apply_to,
+ "entity": entity,
"start_date": frappe.utils.getdate(),
"end_date": frappe.utils.add_to_date(frappe.utils.getdate(), days=100),
- "response_time": 4,
- "response_time_period": "Hour",
- "resolution_time": 6,
- "resolution_time_period": "Hour",
+ "priorities": [
+ {
+ "priority": "Low",
+ "response_time": response_time,
+ "response_time_period": "Hour",
+ "resolution_time": resolution_time,
+ "resolution_time_period": "Hour",
+ },
+ {
+ "priority": "Medium",
+ "response_time": response_time,
+ "default_priority": 1,
+ "response_time_period": "Hour",
+ "resolution_time": resolution_time,
+ "resolution_time_period": "Hour",
+ },
+ {
+ "priority": "High",
+ "response_time": response_time,
+ "response_time_period": "Hour",
+ "resolution_time": resolution_time,
+ "resolution_time_period": "Hour",
+ }
+ ],
"support_and_resolution": [
{
"workday": "Monday",
@@ -67,11 +145,26 @@
]
})
- default_service_level_agreement_exists = frappe.db.exists("Service Level Agreement", "__Test Service Level Agreement")
- if not default_service_level_agreement_exists:
- default_service_level_agreement.insert()
+ filters = {
+ "default_service_level_agreement": service_level_agreement.default_service_level_agreement,
+ "service_level": service_level_agreement.service_level
+ }
+ if not default_service_level_agreement:
+ filters.update({
+ "apply_to": apply_to,
+ "entity": entity
+ })
+ service_level_agreement_exists = frappe.db.exists("Service Level Agreement", filters)
+
+ if not service_level_agreement_exists:
+ service_level_agreement.insert(ignore_permissions=True)
+ return service_level_agreement
+ else:
+ return frappe.get_doc("Service Level Agreement", service_level_agreement_exists)
+
+def create_customer():
customer = frappe.get_doc({
"doctype": "Customer",
"customer_name": "_Test Customer",
@@ -80,70 +173,53 @@
"territory": "Rest Of The World"
})
if not frappe.db.exists("Customer", "_Test Customer"):
- customer.insert()
+ customer.insert(ignore_permissions=True)
+ return customer.name
else:
- customer = frappe.get_doc("Customer", "_Test Customer")
+ return frappe.db.exists("Customer", "_Test Customer")
- service_level_agreement = frappe.get_doc({
- "doctype": "Service Level Agreement",
- "name": "_Test Service Level Agreement",
- "customer": customer.customer_name,
- "service_level": "_Test Service Level",
- "holiday_list": "__Test Holiday List",
- "priority": "Medium",
- "employee_group": "_Test Employee Group",
- "start_date": frappe.utils.getdate(),
- "end_date": frappe.utils.add_to_date(frappe.utils.getdate(), days=100),
- "response_time": 2,
- "response_time_period": "Day",
- "resolution_time": 3,
- "resolution_time_period": "Day",
- "support_and_resolution": [
- {
- "workday": "Monday",
- "start_time": "10:00:00",
- "end_time": "18:00:00",
- },
- {
- "workday": "Tuesday",
- "start_time": "10:00:00",
- "end_time": "18:00:00",
- },
- {
- "workday": "Wednesday",
- "start_time": "10:00:00",
- "end_time": "18:00:00",
- },
- {
- "workday": "Thursday",
- "start_time": "10:00:00",
- "end_time": "18:00:00",
- },
- {
- "workday": "Friday",
- "start_time": "10:00:00",
- "end_time": "18:00:00",
- },
- {
- "workday": "Saturday",
- "start_time": "10:00:00",
- "end_time": "18:00:00",
- },
- {
- "workday": "Sunday",
- "start_time": "10:00:00",
- "end_time": "18:00:00",
- }
- ]
+def create_customer_group():
+ customer_group = frappe.get_doc({
+ "doctype": "Customer Group",
+ "customer_group_name": "_Test SLA Customer Group"
})
- service_level_agreement_exists = frappe.db.exists("Service Level Agreement", "_Test Service Level Agreement")
- if not service_level_agreement_exists:
- service_level_agreement.insert()
- return service_level_agreement.name
+ if not frappe.db.exists("Customer Group", {"customer_group_name": "_Test SLA Customer Group"}):
+ customer_group.insert()
+ return customer_group.name
else:
- return service_level_agreement_exists
+ return frappe.db.exists("Customer Group", {"customer_group_name": "_Test SLA Customer Group"})
-def get_service_level_agreement():
- service_level_agreement = frappe.db.exists("Service Level Agreement", "_Test Service Level Agreement")
- return service_level_agreement
\ No newline at end of file
+def create_territory():
+ territory = frappe.get_doc({
+ "doctype": "Territory",
+ "territory_name": "_Test SLA Territory",
+ })
+
+ if not frappe.db.exists("Territory", {"territory_name": "_Test SLA Territory"}):
+ territory.insert()
+ return territory.name
+ else:
+ return frappe.db.exists("Territory", {"territory_name": "_Test SLA Territory"})
+
+def create_service_level_agreements_for_issues():
+ create_service_level_for_sla()
+
+ create_service_level_agreement(default_service_level_agreement=1,
+ service_level="__Test Service Level", holiday_list="__Test Holiday List", employee_group="_Test Employee Group",
+ apply_to=None, entity=None, response_time=4, resolution_time=6)
+
+ create_customer()
+ create_service_level_agreement(default_service_level_agreement=0,
+ service_level="_Test Service Level", holiday_list="__Test Holiday List", employee_group="_Test Employee Group",
+ apply_to="Customer", entity="_Test Customer", response_time=2, resolution_time=3)
+
+ create_customer_group()
+ create_service_level_agreement(default_service_level_agreement=0,
+ service_level="_Test Service Level", holiday_list="__Test Holiday List", employee_group="_Test Employee Group",
+ apply_to="Customer Group", entity="_Test SLA Customer Group", response_time=2, resolution_time=3)
+
+ create_territory()
+ create_service_level_agreement(default_service_level_agreement=0,
+ service_level="_Test Service Level", holiday_list="__Test Holiday List", employee_group="_Test Employee Group",
+ apply_to="Territory", entity="_Test SLA Territory", response_time=2, resolution_time=3)
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..cd87a1c
--- /dev/null
+++ b/erpnext/support/doctype/service_level_priority/service_level_priority.json
@@ -0,0 +1,87 @@
+{
+ "creation": "2019-05-04 05:54:03.658991",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "priority",
+ "cb_01",
+ "default_priority",
+ "sb_00",
+ "response_time",
+ "response_time_period",
+ "cb_00",
+ "resolution_time",
+ "resolution_time_period"
+ ],
+ "fields": [
+ {
+ "columns": 2,
+ "fieldname": "priority",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Priority",
+ "options": "Issue Priority"
+ },
+ {
+ "fieldname": "sb_00",
+ "fieldtype": "Section Break"
+ },
+ {
+ "columns": 1,
+ "fieldname": "response_time",
+ "fieldtype": "Int",
+ "in_list_view": 1,
+ "label": "Response Time"
+ },
+ {
+ "columns": 1,
+ "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"
+ },
+ {
+ "fieldname": "cb_01",
+ "fieldtype": "Column Break"
+ },
+ {
+ "default": "0",
+ "fieldname": "default_priority",
+ "fieldtype": "Check",
+ "in_list_view": 1,
+ "label": "Default Priority"
+ }
+ ],
+ "istable": 1,
+ "modified": "2019-05-21 06:54:42.674377",
+ "modified_by": "Administrator",
+ "module": "Support",
+ "name": "Service Level Priority",
+ "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/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