Merge branch 'develop' into twelve-fixes
This commit is contained in:
		
						commit
						9e07b7d2b8
					
				| @ -49,7 +49,7 @@ The ERPNext code is licensed as GNU General Public License (v3) and the Document | ||||
| ## Contributing | ||||
| 
 | ||||
| 1. [Issue Guidelines](https://github.com/frappe/erpnext/wiki/Issue-Guidelines) | ||||
| 1. [Report Security Vulnerabilities](https://erpnext.com/report) | ||||
| 1. [Report Security Vulnerabilities](https://erpnext.com/security) | ||||
| 1. [Pull Request Requirements](https://github.com/frappe/erpnext/wiki/Contribution-Guidelines) | ||||
| 1. [Translations](https://translate.erpnext.com) | ||||
| 1. [Chart of Accounts](https://charts.erpnext.com) | ||||
|  | ||||
| @ -485,7 +485,7 @@ class SalesInvoice(SellingController): | ||||
| 		"""Set against account for debit to account""" | ||||
| 		against_acc = [] | ||||
| 		for d in self.get('items'): | ||||
| 			if d.income_account not in against_acc: | ||||
| 			if d.income_account and d.income_account not in against_acc: | ||||
| 				against_acc.append(d.income_account) | ||||
| 		self.against_income_account = ','.join(against_acc) | ||||
| 
 | ||||
|  | ||||
| @ -25,7 +25,8 @@ def get_ordered_to_be_billed_data(args): | ||||
| 		from | ||||
| 			`{parent_tab}`, `{child_tab}` | ||||
| 		where | ||||
| 			`{parent_tab}`.name = `{child_tab}`.parent and `{parent_tab}`.docstatus = 1 and `{parent_tab}`.status != 'Closed' | ||||
| 			`{parent_tab}`.name = `{child_tab}`.parent and `{parent_tab}`.docstatus = 1 | ||||
| 			and `{parent_tab}`.status not in ('Closed', 'Completed') | ||||
| 			and `{child_tab}`.amount > 0 and round(`{child_tab}`.billed_amt * | ||||
| 			ifnull(`{parent_tab}`.conversion_rate, 1), {precision}) < `{child_tab}`.base_amount | ||||
| 		order by | ||||
|  | ||||
| @ -107,7 +107,7 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend( | ||||
| 		if(doc.docstatus == 1) { | ||||
| 			if(!in_list(["Closed", "Delivered"], doc.status)) { | ||||
| 				if (this.frm.has_perm("submit")) { | ||||
| 					if(flt(doc.per_billed, 2) < 100 || doc.per_received < 100) { | ||||
| 					if(flt(doc.per_billed, 6) < 100 || flt(doc.per_received, 6) < 100) { | ||||
| 						if (doc.status != "On Hold") { | ||||
| 							this.frm.add_custom_button(__('Hold'), () => this.hold_purchase_order(), __("Status")); | ||||
| 						} else{ | ||||
|  | ||||
| @ -40,17 +40,6 @@ def get_data(): | ||||
| 					"description": _("Tree of financial accounts."), | ||||
| 					"onboard": 1, | ||||
| 				}, | ||||
| 				{ | ||||
| 					"type": "doctype", | ||||
| 					"name": "Journal Entry", | ||||
| 					"description": _("Accounting journal entries."), | ||||
| 					"onboard": 1, | ||||
| 				}, | ||||
| 				{ | ||||
| 					"type": "doctype", | ||||
| 					"name": "Opening Invoice Creation Tool", | ||||
| 					"description": _("Create Opening Sales and Purchase Invoices") | ||||
| 				}, | ||||
| 			] | ||||
| 		}, | ||||
| 		{ | ||||
| @ -73,11 +62,6 @@ def get_data(): | ||||
| 					"name": "Payment Request", | ||||
| 					"description": _("Payment Request"), | ||||
| 				}, | ||||
| 				{ | ||||
| 					"type": "doctype", | ||||
| 					"name": "Payment Entry", | ||||
| 					"description": _("Bank/Cash transactions against party or for internal transfer") | ||||
| 				}, | ||||
| 				{ | ||||
| 					"type": "doctype", | ||||
| 					"name": "Payment Term", | ||||
| @ -179,6 +163,26 @@ def get_data(): | ||||
| 					"name": "Accounting Dimension", | ||||
| 					"description": _("Setup custom dimensions for accounting") | ||||
| 				}, | ||||
| 				{ | ||||
| 					"type": "doctype", | ||||
| 					"name": "Opening Invoice Creation Tool", | ||||
| 					"description": _("Create Opening Sales and Purchase Invoices") | ||||
| 				}, | ||||
| 			] | ||||
| 		}, | ||||
| 		{ | ||||
| 			"label": _("Accounting Entries"), | ||||
| 			"items": [ | ||||
| 				{ | ||||
| 					"type": "doctype", | ||||
| 					"name": "Payment Entry", | ||||
| 					"description": _("Bank/Cash transactions against party or for internal transfer") | ||||
| 				}, | ||||
| 				{ | ||||
| 					"type": "doctype", | ||||
| 					"name": "Journal Entry", | ||||
| 					"description": _("Accounting journal entries.") | ||||
| 				}, | ||||
| 			] | ||||
| 		}, | ||||
| 		{ | ||||
|  | ||||
| @ -18,6 +18,11 @@ def get_data(): | ||||
| 					"onboard": 1, | ||||
| 					"dependencies": ["Employee"] | ||||
| 				}, | ||||
| 				{ | ||||
| 					"type": "doctype", | ||||
| 					"name": "Employee Group", | ||||
| 					"dependencies": ["Employee"] | ||||
| 				}, | ||||
| 				{ | ||||
| 					"type": "doctype", | ||||
| 					"name": "Attendance", | ||||
|  | ||||
| @ -12,6 +12,16 @@ def get_data(): | ||||
| 					"description": _("Support queries from customers."), | ||||
| 					"onboard": 1, | ||||
| 				}, | ||||
| 				{ | ||||
| 					"type": "doctype", | ||||
| 					"name": "Issue Type", | ||||
| 					"description": _("Issue Type."), | ||||
| 				}, | ||||
| 				{ | ||||
| 					"type": "doctype", | ||||
| 					"name": "Issue Priority", | ||||
| 					"description": _("Issue Priority."), | ||||
| 				}, | ||||
| 				{ | ||||
| 					"type": "doctype", | ||||
| 					"name": "Communication", | ||||
| @ -38,11 +48,6 @@ def get_data(): | ||||
| 		{ | ||||
| 			"label": _("Service Level Agreement"), | ||||
| 			"items": [ | ||||
| 				{ | ||||
| 					"type": "doctype", | ||||
| 					"name": "Employee Group", | ||||
| 					"description": _("Support Team."), | ||||
| 				}, | ||||
| 				{ | ||||
| 					"type": "doctype", | ||||
| 					"name": "Service Level", | ||||
|  | ||||
| @ -428,8 +428,9 @@ class BuyingController(StockController): | ||||
| 			elif not flt(d.rejected_qty): | ||||
| 				d.rejected_qty = flt(d.received_qty) -  flt(d.qty) | ||||
| 
 | ||||
| 			val  = flt(d.qty) + flt(d.rejected_qty) | ||||
| 			# Check Received Qty = Accepted Qty + Rejected Qty | ||||
| 			if ((flt(d.qty) + flt(d.rejected_qty)) != flt(d.received_qty)): | ||||
| 			if (flt(val, d.precision("received_qty")) != flt(d.received_qty, d.precision("received_qty"))): | ||||
| 				frappe.throw(_("Accepted + Rejected Qty must be equal to Received quantity for Item {0}").format(d.item_code)) | ||||
| 
 | ||||
| 	def validate_negative_quantity(self, item_row, field_list): | ||||
|  | ||||
| @ -27,7 +27,7 @@ status_map = { | ||||
| 	], | ||||
| 	"Quotation": [ | ||||
| 		["Draft", None], | ||||
| 		["Submitted", "eval:self.docstatus==1"], | ||||
| 		["Open", "eval:self.docstatus==1"], | ||||
| 		["Lost", "eval:self.status=='Lost'"], | ||||
| 		["Ordered", "has_sales_order"], | ||||
| 		["Cancelled", "eval:self.docstatus==2"], | ||||
|  | ||||
| @ -22,7 +22,16 @@ def verify_request(): | ||||
| 	frappe.set_user(woocommerce_settings.creation_user) | ||||
| 
 | ||||
| @frappe.whitelist(allow_guest=True) | ||||
| def order(): | ||||
| def order(*args, **kwargs): | ||||
| 	try: | ||||
| 		_order(*args, **kwargs) | ||||
| 	except Exception: | ||||
| 		error_message = frappe.get_traceback()+"\n\n Request Data: \n"+json.loads(frappe.request.data).__str__() | ||||
| 		frappe.log_error(error_message, "WooCommerce Error") | ||||
| 		raise | ||||
| 
 | ||||
| 
 | ||||
| def _order(*args, **kwargs): | ||||
| 	woocommerce_settings = frappe.get_doc("Woocommerce Settings") | ||||
| 	if frappe.flags.woocomm_test_order_data: | ||||
| 		fd = frappe.flags.woocomm_test_order_data | ||||
|  | ||||
| @ -46,7 +46,7 @@ update_and_get_user_progress = "erpnext.utilities.user_progress_utils.update_def | ||||
| on_session_creation = "erpnext.shopping_cart.utils.set_cart_count" | ||||
| on_logout = "erpnext.shopping_cart.utils.clear_cart_count" | ||||
| 
 | ||||
| treeviews = ['Account', 'Cost Center', 'Warehouse', 'Item Group', 'Customer Group', 'Sales Person', 'Territory', 'Assessment Group'] | ||||
| treeviews = ['Account', 'Cost Center', 'Warehouse', 'Item Group', 'Customer Group', 'Sales Person', 'Territory', 'Assessment Group', 'Department'] | ||||
| 
 | ||||
| # website | ||||
| update_website_context = ["erpnext.shopping_cart.utils.update_website_context", "erpnext.education.doctype.education_settings.education_settings.update_website_context"] | ||||
| @ -242,7 +242,8 @@ scheduler_events = { | ||||
| 		"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.hr.doctype.shift_type.shift_type.process_auto_attendance_for_all_shifts" | ||||
| 		"erpnext.hr.doctype.shift_type.shift_type.process_auto_attendance_for_all_shifts", | ||||
| 		"erpnext.support.doctype.issue.issue.set_service_level_agreement_variance", | ||||
| 	], | ||||
| 	"daily": [ | ||||
| 		"erpnext.stock.reorder_item.reorder_item", | ||||
| @ -264,7 +265,7 @@ scheduler_events = { | ||||
| 		"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" | ||||
|  | ||||
| @ -2,8 +2,8 @@ | ||||
| // For license information, please see license.txt
 | ||||
| frappe.views.calendar["Attendance"] = { | ||||
| 	field_map: { | ||||
| 		"start": "date", | ||||
| 		"end": "date", | ||||
| 		"start": "attendance_date", | ||||
| 		"end": "attendance_date", | ||||
| 		"id": "name", | ||||
| 		"docstatus": 1 | ||||
| 	}, | ||||
|  | ||||
| @ -4,7 +4,7 @@ | ||||
| frappe.ui.form.on('Department', { | ||||
| 	refresh: function(frm) { | ||||
| 		// read-only for root department
 | ||||
| 		if(!frm.doc.parent_department) { | ||||
| 		if(!frm.doc.parent_department && !frm.is_new()) { | ||||
| 			frm.set_read_only(); | ||||
| 			frm.set_intro(__("This is a root department and cannot be edited.")); | ||||
| 		} | ||||
|  | ||||
| @ -1,5 +1,6 @@ | ||||
| { | ||||
|  "allow_copy": 0, | ||||
|  "allow_events_in_timeline": 0, | ||||
|  "allow_guest_to_view": 0, | ||||
|  "allow_import": 1, | ||||
|  "allow_rename": 1, | ||||
| @ -19,6 +20,7 @@ | ||||
|    "bold": 0, | ||||
|    "collapsible": 0, | ||||
|    "columns": 0, | ||||
|    "fetch_if_empty": 0, | ||||
|    "fieldname": "department_name", | ||||
|    "fieldtype": "Data", | ||||
|    "hidden": 0, | ||||
| @ -52,6 +54,7 @@ | ||||
|    "bold": 0, | ||||
|    "collapsible": 0, | ||||
|    "columns": 0, | ||||
|    "fetch_if_empty": 0, | ||||
|    "fieldname": "parent_department", | ||||
|    "fieldtype": "Link", | ||||
|    "hidden": 0, | ||||
| @ -85,6 +88,7 @@ | ||||
|    "bold": 0, | ||||
|    "collapsible": 0, | ||||
|    "columns": 0, | ||||
|    "fetch_if_empty": 0, | ||||
|    "fieldname": "company", | ||||
|    "fieldtype": "Link", | ||||
|    "hidden": 0, | ||||
| @ -118,6 +122,7 @@ | ||||
|    "bold": 1, | ||||
|    "collapsible": 0, | ||||
|    "columns": 0, | ||||
|    "fetch_if_empty": 0, | ||||
|    "fieldname": "is_group", | ||||
|    "fieldtype": "Check", | ||||
|    "hidden": 0, | ||||
| @ -150,6 +155,7 @@ | ||||
|    "bold": 0, | ||||
|    "collapsible": 0, | ||||
|    "columns": 0, | ||||
|    "fetch_if_empty": 0, | ||||
|    "fieldname": "disabled", | ||||
|    "fieldtype": "Check", | ||||
|    "hidden": 0, | ||||
| @ -182,6 +188,7 @@ | ||||
|    "bold": 0, | ||||
|    "collapsible": 0, | ||||
|    "columns": 0, | ||||
|    "fetch_if_empty": 0, | ||||
|    "fieldname": "section_break_4", | ||||
|    "fieldtype": "Section Break", | ||||
|    "hidden": 0, | ||||
| @ -214,6 +221,7 @@ | ||||
|    "collapsible": 0, | ||||
|    "columns": 0, | ||||
|    "description": "Days for which Holidays are blocked for this department.", | ||||
|    "fetch_if_empty": 0, | ||||
|    "fieldname": "leave_block_list", | ||||
|    "fieldtype": "Link", | ||||
|    "hidden": 0, | ||||
| @ -246,6 +254,7 @@ | ||||
|    "bold": 0, | ||||
|    "collapsible": 0, | ||||
|    "columns": 0, | ||||
|    "fetch_if_empty": 0, | ||||
|    "fieldname": "leave_section", | ||||
|    "fieldtype": "Section Break", | ||||
|    "hidden": 0, | ||||
| @ -279,6 +288,7 @@ | ||||
|    "collapsible": 0, | ||||
|    "columns": 0, | ||||
|    "description": "The first Leave Approver in the list will be set as the default Leave Approver.", | ||||
|    "fetch_if_empty": 0, | ||||
|    "fieldname": "leave_approvers", | ||||
|    "fieldtype": "Table", | ||||
|    "hidden": 0, | ||||
| @ -312,6 +322,7 @@ | ||||
|    "bold": 0, | ||||
|    "collapsible": 0, | ||||
|    "columns": 0, | ||||
|    "fetch_if_empty": 0, | ||||
|    "fieldname": "expense_section", | ||||
|    "fieldtype": "Section Break", | ||||
|    "hidden": 0, | ||||
| @ -345,6 +356,7 @@ | ||||
|    "collapsible": 0, | ||||
|    "columns": 0, | ||||
|    "description": "The first Expense Approver in the list will be set as the default Expense Approver.", | ||||
|    "fetch_if_empty": 0, | ||||
|    "fieldname": "expense_approvers", | ||||
|    "fieldtype": "Table", | ||||
|    "hidden": 0, | ||||
| @ -378,6 +390,7 @@ | ||||
|    "bold": 0, | ||||
|    "collapsible": 0, | ||||
|    "columns": 0, | ||||
|    "fetch_if_empty": 0, | ||||
|    "fieldname": "lft", | ||||
|    "fieldtype": "Int", | ||||
|    "hidden": 1, | ||||
| @ -410,6 +423,7 @@ | ||||
|    "bold": 0, | ||||
|    "collapsible": 0, | ||||
|    "columns": 0, | ||||
|    "fetch_if_empty": 0, | ||||
|    "fieldname": "rgt", | ||||
|    "fieldtype": "Int", | ||||
|    "hidden": 1, | ||||
| @ -442,6 +456,7 @@ | ||||
|    "bold": 0, | ||||
|    "collapsible": 0, | ||||
|    "columns": 0, | ||||
|    "fetch_if_empty": 0, | ||||
|    "fieldname": "old_parent", | ||||
|    "fieldtype": "Data", | ||||
|    "hidden": 1, | ||||
| @ -479,7 +494,7 @@ | ||||
|  "issingle": 0, | ||||
|  "istable": 0, | ||||
|  "max_attachments": 0, | ||||
|  "modified": "2018-08-29 06:26:12.995703", | ||||
|  "modified": "2019-06-25 18:43:05.550387", | ||||
|  "modified_by": "Administrator", | ||||
|  "module": "HR", | ||||
|  "name": "Department", | ||||
| @ -543,7 +558,7 @@ | ||||
|    "write": 1 | ||||
|   } | ||||
|  ], | ||||
|  "quick_entry": 1, | ||||
|  "quick_entry": 0, | ||||
|  "read_only": 0, | ||||
|  "read_only_onload": 0, | ||||
|  "show_name_in_global_search": 1, | ||||
|  | ||||
| @ -604,4 +604,6 @@ execute:frappe.delete_doc("Report", "Inactive Items") | ||||
| 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 | ||||
| erpnext.patches.v12_0.make_item_manufacturer | ||||
| erpnext.patches.v12_0.set_quotation_status | ||||
| erpnext.patches.v12_0.set_priority_for_support | ||||
|  | ||||
							
								
								
									
										78
									
								
								erpnext/patches/v12_0/set_priority_for_support.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								erpnext/patches/v12_0/set_priority_for_support.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,78 @@ | ||||
| import frappe | ||||
| 
 | ||||
| def execute(): | ||||
| 	frappe.reload_doc("support", "doctype", "issue_priority") | ||||
| 	frappe.reload_doc("support", "doctype", "service_level_priority") | ||||
| 
 | ||||
| 	set_issue_priority() | ||||
| 	set_priority_for_issue() | ||||
| 	set_priorities_service_level() | ||||
| 	set_priorities_service_level_agreement() | ||||
| 
 | ||||
| def set_issue_priority(): | ||||
| 	# Adds priority from issue to Issue Priority DocType as Priority is a new DocType. | ||||
| 	for priority in frappe.get_meta("Issue").get_field("priority").options.split("\n"): | ||||
| 		if priority and not frappe.db.exists("Issue Priority", priority): | ||||
| 			frappe.get_doc({ | ||||
| 				"doctype": "Issue Priority", | ||||
| 				"name": priority | ||||
| 			}).insert(ignore_permissions=True) | ||||
| 
 | ||||
| def set_priority_for_issue(): | ||||
| 	# Sets priority for Issues as Select field is changed to Link field. | ||||
| 	issue_priority = frappe.get_list("Issue", fields=["name", "priority"]) | ||||
| 	frappe.reload_doc("support", "doctype", "issue") | ||||
| 
 | ||||
| 	for issue in issue_priority: | ||||
| 		frappe.db.set_value("Issue", issue.name, "priority", issue.priority) | ||||
| 
 | ||||
| def set_priorities_service_level(): | ||||
| 	# Migrates "priority", "response_time", "response_time_period", "resolution_time", "resolution_time_period" to Child Table | ||||
| 	# as a Service Level can have multiple priorities | ||||
| 	try: | ||||
| 		service_level_priorities = frappe.get_list("Service Level", fields=["name", "priority", "response_time", "response_time_period", "resolution_time", "resolution_time_period"]) | ||||
| 
 | ||||
| 		frappe.reload_doc("support", "doctype", "service_level") | ||||
| 
 | ||||
| 		for service_level in service_level_priorities: | ||||
| 			if service_level: | ||||
| 				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) | ||||
| 	except frappe.db.TableMissingError: | ||||
| 		frappe.reload_doc("support", "doctype", "service_level") | ||||
| 
 | ||||
| def set_priorities_service_level_agreement(): | ||||
| 	# Migrates "priority", "response_time", "response_time_period", "resolution_time", "resolution_time_period" to Child Table | ||||
| 	# as a Service Level Agreement can have multiple priorities | ||||
| 	try: | ||||
| 		service_level_agreement_priorities = frappe.get_list("Service Level Agreement", fields=["name", "priority", "response_time", "response_time_period", "resolution_time", "resolution_time_period"]) | ||||
| 
 | ||||
| 		frappe.reload_doc("support", "doctype", "service_level_agreement") | ||||
| 
 | ||||
| 		for service_level_agreement in service_level_agreement_priorities: | ||||
| 			if service_level_agreement: | ||||
| 				doc = frappe.get_doc("Service Level Agreement", service_level_agreement.name) | ||||
| 
 | ||||
| 				if doc.customer: | ||||
| 					doc.entity_type = "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) | ||||
| 	except frappe.db.TableMissingError: | ||||
| 		frappe.reload_doc("support", "doctype", "service_level_agreement") | ||||
							
								
								
									
										7
									
								
								erpnext/patches/v12_0/set_quotation_status.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								erpnext/patches/v12_0/set_quotation_status.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,7 @@ | ||||
| from __future__ import unicode_literals | ||||
| import frappe | ||||
| 
 | ||||
| def execute(): | ||||
| 
 | ||||
| 	frappe.db.sql(""" UPDATE `tabQuotation` set status = 'Open' | ||||
| 		where docstatus = 1 and status = 'Submitted' """) | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -2,11 +2,11 @@ frappe.listview_settings['Quotation'] = { | ||||
| 	add_fields: ["customer_name", "base_grand_total", "status", | ||||
| 		"company", "currency", 'valid_till'], | ||||
| 	get_indicator: function(doc) { | ||||
| 		if(doc.status==="Submitted") { | ||||
| 		if(doc.status==="Open") { | ||||
| 			if (doc.valid_till && doc.valid_till < frappe.datetime.nowdate()) { | ||||
| 				return [__("Expired"), "darkgrey", "valid_till,<," + frappe.datetime.nowdate()]; | ||||
| 			} else { | ||||
| 				return [__("Submitted"), "blue", "status,=,Submitted"]; | ||||
| 				return [__("Open"), "orange", "status,=,Open"]; | ||||
| 			} | ||||
| 		} else if(doc.status==="Ordered") { | ||||
| 			return [__("Ordered"), "green", "status,=,Ordered"]; | ||||
|  | ||||
| @ -34,7 +34,7 @@ frappe.ui.form.on("Sales Order", { | ||||
| 	}, | ||||
| 	refresh: function(frm) { | ||||
| 		if(frm.doc.docstatus === 1 && frm.doc.status !== 'Closed' | ||||
| 			&& flt(frm.doc.per_delivered) < 100 && flt(frm.doc.per_billed) < 100) { | ||||
| 			&& flt(frm.doc.per_delivered, 6) < 100 && flt(frm.doc.per_billed, 6) < 100) { | ||||
| 			frm.add_custom_button(__('Update Items'), () => { | ||||
| 				erpnext.utils.update_child_items({ | ||||
| 					frm: frm, | ||||
|  | ||||
| @ -8,7 +8,7 @@ from frappe import _ | ||||
| 
 | ||||
| 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() | ||||
|  | ||||
| @ -173,6 +173,11 @@ def install(country=None): | ||||
| 			{"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')}, | ||||
|  | ||||
| @ -419,6 +419,8 @@ def get_returned_qty_map(delivery_note): | ||||
| @frappe.whitelist() | ||||
| def make_sales_invoice(source_name, target_doc=None): | ||||
| 	doc = frappe.get_doc('Delivery Note', source_name) | ||||
| 
 | ||||
| 	to_make_invoice_qty_map = {} | ||||
| 	returned_qty_map = get_returned_qty_map(source_name) | ||||
| 	invoiced_qty_map = get_invoiced_qty_map(source_name) | ||||
| 
 | ||||
| @ -439,8 +441,7 @@ def make_sales_invoice(source_name, target_doc=None): | ||||
| 			target.update(get_fetch_values("Sales Invoice", 'company_address', target.company_address)) | ||||
| 
 | ||||
| 	def update_item(source_doc, target_doc, source_parent): | ||||
| 		target_doc.qty, returned_qty = get_pending_qty(source_doc) | ||||
| 		returned_qty_map[source_doc.item_code] = returned_qty | ||||
| 		target_doc.qty = to_make_invoice_qty_map[source_doc.name] | ||||
| 
 | ||||
| 		if source_doc.serial_no and source_parent.per_billed > 0: | ||||
| 			target_doc.serial_no = get_delivery_note_serial_no(source_doc.item_code, | ||||
| @ -448,7 +449,12 @@ def make_sales_invoice(source_name, target_doc=None): | ||||
| 
 | ||||
| 	def get_pending_qty(item_row): | ||||
| 		pending_qty = item_row.qty - invoiced_qty_map.get(item_row.name, 0) | ||||
| 		returned_qty = flt(returned_qty_map.get(item_row.item_code, 0)) | ||||
| 
 | ||||
| 		returned_qty = 0 | ||||
| 		if returned_qty_map.get(item_row.item_code, 0) > 0: | ||||
| 			returned_qty = flt(returned_qty_map.get(item_row.item_code, 0)) | ||||
| 			returned_qty_map[item_row.item_code] -= pending_qty | ||||
| 
 | ||||
| 		if returned_qty: | ||||
| 			if returned_qty >= pending_qty: | ||||
| 				pending_qty = 0 | ||||
| @ -456,7 +462,10 @@ def make_sales_invoice(source_name, target_doc=None): | ||||
| 			else: | ||||
| 				pending_qty -= returned_qty | ||||
| 				returned_qty = 0 | ||||
| 		return pending_qty, returned_qty | ||||
| 
 | ||||
| 		to_make_invoice_qty_map[item_row.name] = pending_qty | ||||
| 
 | ||||
| 		return pending_qty | ||||
| 
 | ||||
| 	doc = get_mapped_doc("Delivery Note", source_name, { | ||||
| 		"Delivery Note": { | ||||
| @ -476,7 +485,7 @@ def make_sales_invoice(source_name, target_doc=None): | ||||
| 				"cost_center": "cost_center" | ||||
| 			}, | ||||
| 			"postprocess": update_item, | ||||
| 			"filter": lambda d: get_pending_qty(d)[0] <= 0 if not doc.get("is_return") else get_pending_qty(d)[0] > 0 | ||||
| 			"filter": lambda d: get_pending_qty(d) <= 0 if not doc.get("is_return") else get_pending_qty(d) > 0 | ||||
| 		}, | ||||
| 		"Sales Taxes and Charges": { | ||||
| 			"doctype": "Sales Taxes and Charges", | ||||
|  | ||||
| @ -1,13 +1,43 @@ | ||||
| frappe.ui.form.on("Issue", { | ||||
| 	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_filters", | ||||
| 				args: { | ||||
| 					name: frm.doc.service_level_agreement, | ||||
| 					customer: frm.doc.customer | ||||
| 				}, | ||||
| 				callback: function (r) { | ||||
| 					if (r && r.message) { | ||||
| 						frm.set_query('priority', function() { | ||||
| 							return { | ||||
| 								filters: { | ||||
| 									"name": ["in", r.message.priority], | ||||
| 								} | ||||
| 							}; | ||||
| 						}); | ||||
| 						frm.set_query('service_level_agreement', function() { | ||||
| 							return { | ||||
| 								filters: { | ||||
| 									"name": ["in", r.message.service_level_agreements], | ||||
| 								} | ||||
| 							}; | ||||
| 						}); | ||||
| 					} | ||||
| 				} | ||||
| 			}); | ||||
| 		} | ||||
| 	}, | ||||
| 
 | ||||
| 	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 +50,22 @@ frappe.ui.form.on("Issue", { | ||||
| 				}); | ||||
| 			}, __("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 +73,27 @@ frappe.ui.form.on("Issue", { | ||||
| 		} | ||||
| 	}, | ||||
| 
 | ||||
| 	priority: function(frm) { | ||||
| 		if (frm.doc.service_level_agreement) { | ||||
| 			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) { | ||||
| 		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 +148,26 @@ frappe.ui.form.on("Issue", { | ||||
| }); | ||||
| 
 | ||||
| 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}; | ||||
| } | ||||
|  | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -11,7 +11,7 @@ from frappe.utils import now, time_diff_in_hours, now_datetime, getdate, get_wee | ||||
| 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,39 @@ class Issue(Document): | ||||
| 	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 update_agreement_fulfilled_on_custom_status(self): | ||||
| 		""" | ||||
| 			Update Agreement Fulfilled status using Custom Scripts for Custom Issue Status | ||||
| 		""" | ||||
| 		if not self.first_responded_on: # first_responded_on set when first reply is sent to customer | ||||
| 			self.response_by_variance = round(time_diff_in_hours(self.response_by, now_datetime()), 2) | ||||
| 
 | ||||
| 		if not self.resolution_date: # resolution_date set when issue has been closed | ||||
| 			self.resolution_by_variance = round(time_diff_in_hours(self.resolution_by, now_datetime()), 2) | ||||
| 
 | ||||
| 		self.agreement_fulfilled = "Fulfilled" if self.response_by_variance > 0 and self.resolution_by_variance > 0 else "Failed" | ||||
| 		self.save(ignore_permissions=True) | ||||
| 
 | ||||
| 	def create_communication(self): | ||||
| 		communication = frappe.new_doc("Communication") | ||||
| @ -124,23 +141,42 @@ class Issue(Document): | ||||
| 	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 +186,11 @@ def get_expected_time_for(parameter, service_level, start_date_time): | ||||
| 
 | ||||
| 	# 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,20 +204,22 @@ def get_expected_time_for(parameter, service_level, start_date_time): | ||||
| 	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: | ||||
| 		current_weekday = weekdays[current_date_time.weekday()] | ||||
| 
 | ||||
| 		if not is_holiday(current_date_time, holidays) and current_weekday in support_days: | ||||
| 			start_time = current_date_time - datetime(current_date_time.year, current_date_time.month, current_date_time.day) if getdate(current_date_time) == getdate(start_date_time) else support_days[current_weekday].start_time | ||||
| 			start_time = current_date_time - datetime(current_date_time.year, current_date_time.month, current_date_time.day) \ | ||||
| 				if getdate(current_date_time) == getdate(start_date_time) and get_time_in_timedelta(current_date_time.time()) > support_days[current_weekday].start_time \ | ||||
| 				else support_days[current_weekday].start_time | ||||
| 			end_time = support_days[current_weekday].end_time | ||||
| 			time_left_today = time_diff_in_hours(end_time, start_time) | ||||
| 
 | ||||
| @ -207,6 +245,28 @@ def get_expected_time_for(parameter, service_level, start_date_time): | ||||
| 
 | ||||
| 	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 +304,12 @@ def set_multiple_status(names, status): | ||||
| 	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 +349,7 @@ def make_task(source_name, target_doc=None): | ||||
| 			"doctype": "Task" | ||||
| 		} | ||||
| 	}, target_doc) | ||||
| 
 | ||||
| @frappe.whitelist() | ||||
| def make_issue_from_communication(communication, ignore_communication_links=False): | ||||
| 	""" raise a issue from email """ | ||||
| @ -307,3 +366,10 @@ def make_issue_from_communication(communication, ignore_communication_links=Fals | ||||
| 	link_communication_to_document(doc, "Issue", issue.name, ignore_communication_links) | ||||
| 
 | ||||
| 	return issue.name | ||||
| 
 | ||||
| def get_time_in_timedelta(time): | ||||
| 	""" | ||||
| 		Converts datetime.time(10, 36, 55, 961454) to datetime.timedelta(seconds=38215) | ||||
| 	""" | ||||
| 	import datetime | ||||
| 	return datetime.timedelta(hours=time.hour, minutes=time.minute, seconds=time.second) | ||||
| @ -4,8 +4,8 @@ from __future__ import unicode_literals | ||||
| 
 | ||||
| import frappe | ||||
| import unittest | ||||
| from erpnext.support.doctype.service_level_agreement.test_service_level_agreement import make_service_level_agreement | ||||
| from frappe.utils import now_datetime | ||||
| from erpnext.support.doctype.service_level_agreement.test_service_level_agreement import create_service_level_agreements_for_issues | ||||
| from frappe.utils import now_datetime, get_datetime | ||||
| import datetime | ||||
| from datetime import timedelta | ||||
| from frappe.desk.form import assign_to | ||||
| @ -18,56 +18,104 @@ class TestIssue(unittest.TestCase): | ||||
| 
 | ||||
| 
 | ||||
| 	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" | ||||
| 		creation = datetime.datetime(2019, 3, 4, 12, 0) | ||||
| 
 | ||||
| 		# 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", 1) | ||||
| 
 | ||||
| 		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", 2) | ||||
| 
 | ||||
| 		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", 3) | ||||
| 
 | ||||
| 		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) | ||||
| 		issue = make_issue(creation=creation, index=4) | ||||
| 
 | ||||
| 		self.assertEquals(issue.response_by, datetime.datetime(2019, 3, 4, 16, 0)) | ||||
| 		self.assertEquals(issue.resolution_by, datetime.datetime(2019, 3, 4, 18, 0)) | ||||
| 
 | ||||
| 		creation = "2019-03-04 14:00:00" | ||||
| 		# make issue with default SLA before working hours | ||||
| 		creation = datetime.datetime(2019, 3, 4, 7, 0) | ||||
| 		issue = make_issue(creation=creation, index=5) | ||||
| 
 | ||||
| 		self.assertEquals(issue.response_by, datetime.datetime(2019, 3, 4, 14, 0)) | ||||
| 		self.assertEquals(issue.resolution_by, datetime.datetime(2019, 3, 4, 16, 0)) | ||||
| 
 | ||||
| 		# make issue with default SLA after working hours | ||||
| 		creation = datetime.datetime(2019, 3, 4, 20, 0) | ||||
| 		issue = make_issue(creation, index=6) | ||||
| 
 | ||||
| 		self.assertEquals(issue.response_by, datetime.datetime(2019, 3, 6, 14, 0)) | ||||
| 		self.assertEquals(issue.resolution_by, datetime.datetime(2019, 3, 6, 16, 0)) | ||||
| 
 | ||||
| 		# make issue with default SLA next day | ||||
| 		issue = make_issue(creation) | ||||
| 		creation = datetime.datetime(2019, 3, 4, 14, 0) | ||||
| 		issue = make_issue(creation=creation, index=7) | ||||
| 
 | ||||
| 		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') | ||||
| 		self.assertEqual(issue.agreement_fulfilled, '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') | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| def make_issue(creation=None, customer=None): | ||||
| def make_issue(creation=None, customer=None, index=0): | ||||
| 
 | ||||
| 	issue = frappe.get_doc({ | ||||
| 		"doctype": "Issue", | ||||
| 		"subject": "Issue 1", | ||||
| 		"subject": "Service Level Agreement Issue {0}".format(index), | ||||
| 		"customer": customer, | ||||
| 		"raised_by": "test@example.com", | ||||
| 		"description": "Service Level Agreement Issue", | ||||
| 		"creation": creation | ||||
| 	}).insert() | ||||
| 	}).insert(ignore_permissions=True) | ||||
| 
 | ||||
| 	return issue | ||||
| 	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) | ||||
|  | ||||
							
								
								
									
										0
									
								
								erpnext/support/doctype/issue_priority/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								erpnext/support/doctype/issue_priority/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										8
									
								
								erpnext/support/doctype/issue_priority/issue_priority.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								erpnext/support/doctype/issue_priority/issue_priority.js
									
									
									
									
									
										Normal file
									
								
							| @ -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) {
 | ||||
| 
 | ||||
| 	// }
 | ||||
| }); | ||||
							
								
								
									
										39
									
								
								erpnext/support/doctype/issue_priority/issue_priority.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								erpnext/support/doctype/issue_priority/issue_priority.json
									
									
									
									
									
										Normal file
									
								
							| @ -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 | ||||
| } | ||||
							
								
								
									
										14
									
								
								erpnext/support/doctype/issue_priority/issue_priority.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								erpnext/support/doctype/issue_priority/issue_priority.py
									
									
									
									
									
										Normal file
									
								
							| @ -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")) | ||||
| @ -0,0 +1,28 @@ | ||||
| # -*- 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): | ||||
| 
 | ||||
| 	def test_priorities(self): | ||||
| 		make_priorities() | ||||
| 		priorities = frappe.get_list("Issue Priority") | ||||
| 
 | ||||
| 		for priority in priorities: | ||||
| 			self.assertIn(priority.name, ["Low", "Medium", "High"]) | ||||
| 
 | ||||
| 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) | ||||
| @ -1,115 +1,56 @@ | ||||
| { | ||||
|  "allow_copy": 0,  | ||||
|  "allow_guest_to_view": 0,  | ||||
|  "allow_import": 1,  | ||||
|  "allow_rename": 0,  | ||||
|  "autoname": "Prompt",  | ||||
|  "beta": 0,  | ||||
|  "creation": "2017-10-06 12:53:34.714153",  | ||||
|  "custom": 0,  | ||||
|  "docstatus": 0,  | ||||
|  "doctype": "DocType",  | ||||
|  "document_type": "Setup",  | ||||
|  "editable_grid": 1,  | ||||
|  "engine": "InnoDB",  | ||||
|  "allow_import": 1, | ||||
|  "allow_rename": 1, | ||||
|  "autoname": "Prompt", | ||||
|  "creation": "2017-10-06 12:53:34.714153", | ||||
|  "doctype": "DocType", | ||||
|  "document_type": "Setup", | ||||
|  "editable_grid": 1, | ||||
|  "engine": "InnoDB", | ||||
|  "field_order": [ | ||||
|   "description" | ||||
|  ], | ||||
|  "fields": [ | ||||
|   { | ||||
|    "allow_bulk_edit": 0,  | ||||
|    "allow_on_submit": 0,  | ||||
|    "bold": 0,  | ||||
|    "collapsible": 0,  | ||||
|    "columns": 0,  | ||||
|    "fieldname": "description",  | ||||
|    "fieldtype": "Small Text",  | ||||
|    "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": "Description",  | ||||
|    "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,  | ||||
|    "unique": 0 | ||||
|    "fieldname": "description", | ||||
|    "fieldtype": "Small Text", | ||||
|    "label": "Description" | ||||
|   } | ||||
|  ],  | ||||
|  "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": "2017-11-15 17:27:19.796807",  | ||||
|  "modified_by": "Administrator",  | ||||
|  "module": "Support",  | ||||
|  "name": "Issue Type",  | ||||
|  "name_case": "Title Case",  | ||||
|  "owner": "Administrator",  | ||||
|  ], | ||||
|  "modified": "2019-06-26 16:56:39.863392", | ||||
|  "modified_by": "Administrator", | ||||
|  "module": "Support", | ||||
|  "name": "Issue Type", | ||||
|  "name_case": "Title Case", | ||||
|  "owner": "Administrator", | ||||
|  "permissions": [ | ||||
|   { | ||||
|    "amend": 0,  | ||||
|    "apply_user_permissions": 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,  | ||||
|    "create": 1, | ||||
|    "delete": 1, | ||||
|    "email": 1, | ||||
|    "export": 1, | ||||
|    "print": 1, | ||||
|    "read": 1, | ||||
|    "report": 1, | ||||
|    "role": "System Manager", | ||||
|    "share": 1, | ||||
|    "write": 1 | ||||
|   },  | ||||
|   }, | ||||
|   { | ||||
|    "amend": 0,  | ||||
|    "apply_user_permissions": 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": "Support Team",  | ||||
|    "set_user_permissions": 0,  | ||||
|    "share": 1,  | ||||
|    "submit": 0,  | ||||
|    "create": 1, | ||||
|    "delete": 1, | ||||
|    "email": 1, | ||||
|    "export": 1, | ||||
|    "print": 1, | ||||
|    "read": 1, | ||||
|    "report": 1, | ||||
|    "role": "Support Team", | ||||
|    "share": 1, | ||||
|    "write": 1 | ||||
|   } | ||||
|  ],  | ||||
|  "quick_entry": 1,  | ||||
|  "read_only": 0,  | ||||
|  "read_only_onload": 0,  | ||||
|  "search_fields": "",  | ||||
|  "show_name_in_global_search": 0,  | ||||
|  "sort_field": "modified",  | ||||
|  "sort_order": "DESC",  | ||||
|  "title_field": "",  | ||||
|  "track_changes": 1,  | ||||
|  "track_seen": 0 | ||||
|  ], | ||||
|  "quick_entry": 1, | ||||
|  "sort_field": "modified", | ||||
|  "sort_order": "DESC", | ||||
|  "track_changes": 1 | ||||
| } | ||||
| @ -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 | ||||
| } | ||||
| @ -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" | ||||
| } | ||||
| @ -12,35 +12,84 @@ from frappe.utils import get_weekdays | ||||
| 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")) | ||||
| 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) | ||||
|  | ||||
| @ -0,0 +1,12 @@ | ||||
| from frappe import _ | ||||
| 
 | ||||
| def get_data(): | ||||
| 	return { | ||||
| 		'fieldname': 'service_level', | ||||
| 		'transactions': [ | ||||
| 			{ | ||||
| 				'label': _('Service Level Agreement'), | ||||
| 				'items': ['Service Level Agreement'] | ||||
| 			} | ||||
| 		] | ||||
| 	} | ||||
| @ -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 @@ def make_service_level(): | ||||
| 		] | ||||
| 	}) | ||||
| 
 | ||||
| 	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 @@ def make_holiday_list(): | ||||
| 					"holiday_date": "2019-02-11" | ||||
| 				}, | ||||
| 			] | ||||
| 		}).insert() | ||||
| 		}).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) | ||||
|  | ||||
| @ -11,11 +11,19 @@ frappe.ui.form.on('Service Level Agreement', { | ||||
| 				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(); | ||||
| 			} | ||||
| 		}); | ||||
| 	} | ||||
| 	}, | ||||
| }); | ||||
|  | ||||
| @ -1,764 +1,188 @@ | ||||
| { | ||||
|  "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", | ||||
|   "entity_section", | ||||
|   "entity_type", | ||||
|   "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 | ||||
|    "label": "Default 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": "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 | ||||
|    "reqd": 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 | ||||
|   }, | ||||
|   { | ||||
|    "fieldname": "column_break_10", | ||||
|    "fieldtype": "Column Break" | ||||
|   }, | ||||
|   { | ||||
|    "fieldname": "entity", | ||||
|    "fieldtype": "Dynamic Link", | ||||
|    "in_list_view": 1, | ||||
|    "in_standard_filter": 1, | ||||
|    "label": "Entity", | ||||
|    "options": "entity_type" | ||||
|   }, | ||||
|   { | ||||
|    "depends_on": "eval: !doc.default_service_level_agreement", | ||||
|    "fieldname": "entity_section", | ||||
|    "fieldtype": "Section Break", | ||||
|    "label": "Entity" | ||||
|   }, | ||||
|   { | ||||
|    "fieldname": "entity_type", | ||||
|    "fieldtype": "Select", | ||||
|    "in_standard_filter": 1, | ||||
|    "label": "Entity Type", | ||||
|    "options": "\nCustomer\nCustomer Group\nTerritory" | ||||
|   } | ||||
|  ], | ||||
|  "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-20 18:04:14.293378", | ||||
|  "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 | ||||
| } | ||||
| @ -9,37 +9,88 @@ from frappe import _ | ||||
| 
 | ||||
| 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.")) | ||||
| 
 | ||||
| 		if self.entity_type and self.entity: | ||||
| 			if frappe.db.exists("Service Level Agreement", {"entity_type": self.entity_type, "entity": self.entity, "name": ["!=", self.name]}): | ||||
| 				frappe.throw(_("Service Level Agreement with Entity Type {0} and Entity {1} already exists.").format(self.entity_type, self.entity)) | ||||
| 
 | ||||
| 	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 | ||||
| 	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 | ||||
| 
 | ||||
| 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") | ||||
| 
 | ||||
| @frappe.whitelist() | ||||
| def get_service_level_agreement_filters(name, customer=None): | ||||
| 	if not customer: | ||||
| 		or_filters = [ | ||||
| 			["Service Level Agreement", "default_service_level_agreement", "=", 1] | ||||
| 		] | ||||
| 	else: | ||||
| 		or_filters = [ | ||||
| 			["Service Level Agreement", "entity", "in", [customer, get_customer_group(customer), get_customer_territory(customer), "IS NULL"]], | ||||
| 			["Service Level Agreement", "default_service_level_agreement", "=", 1] | ||||
| 		] | ||||
| 
 | ||||
| 	return { | ||||
| 		"priority": [priority.priority for priority in frappe.get_list("Service Level Priority", filters={"parent": name}, fields=["priority"])], | ||||
| 		"service_level_agreements": [d.name for d in frappe.get_list("Service Level Agreement", or_filters=or_filters)] | ||||
| 	} | ||||
| @ -0,0 +1,12 @@ | ||||
| from frappe import _ | ||||
| 
 | ||||
| def get_data(): | ||||
| 	return { | ||||
| 		'fieldname': 'service_level_agreement', | ||||
| 		'transactions': [ | ||||
| 			{ | ||||
| 				'label': _('Issue'), | ||||
| 				'items': ['Issue'] | ||||
| 			} | ||||
| 		] | ||||
| 	} | ||||
| @ -5,29 +5,107 @@ from __future__ import unicode_literals | ||||
| 
 | ||||
| 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", | ||||
| 			entity_type=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.entity_type, get_default_service_level_agreement.entity_type) | ||||
| 		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", | ||||
| 			entity_type="Customer", entity=customer, response_time=2, resolution_time=3) | ||||
| 		get_customer_service_level_agreement = get_service_level_agreement(entity_type="Customer", entity=customer) | ||||
| 
 | ||||
| 		self.assertEqual(create_customer_service_level_agreement.name, get_customer_service_level_agreement.name) | ||||
| 		self.assertEqual(create_customer_service_level_agreement.entity_type, get_customer_service_level_agreement.entity_type) | ||||
| 		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", | ||||
| 			entity_type="Customer Group", entity=customer_group, response_time=2, resolution_time=3) | ||||
| 		get_customer_group_service_level_agreement = get_service_level_agreement(entity_type="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.entity_type, get_customer_group_service_level_agreement.entity_type) | ||||
| 		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", | ||||
| 			entity_type="Territory", entity=territory, response_time=2, resolution_time=3) | ||||
| 		get_territory_service_level_agreement = get_service_level_agreement(entity_type="Territory", entity=territory) | ||||
| 
 | ||||
| 		self.assertEqual(create_territory_service_level_agreement.name, get_territory_service_level_agreement.name) | ||||
| 		self.assertEqual(create_territory_service_level_agreement.entity_type, get_territory_service_level_agreement.entity_type) | ||||
| 		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, entity_type=None, entity=None): | ||||
| 	if default_service_level_agreement: | ||||
| 		filters = {"default_service_level_agreement": default_service_level_agreement} | ||||
| 	else: | ||||
| 		filters = {"entity_type": entity_type, "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, entity_type, 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, | ||||
| 		"entity_type": entity_type, | ||||
| 		"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 @@ def make_service_level_agreement(): | ||||
| 		] | ||||
| 	}) | ||||
| 
 | ||||
| 	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({ | ||||
| 			"entity_type": entity_type, | ||||
| 			"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 @@ def make_service_level_agreement(): | ||||
| 		"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 | ||||
| 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", | ||||
| 		entity_type=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", | ||||
| 		entity_type="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", | ||||
| 		entity_type="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", | ||||
| 		entity_type="Territory", entity="_Test SLA Territory", response_time=2, resolution_time=3) | ||||
|  | ||||
| @ -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 | ||||
| } | ||||
| @ -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 | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user