feat: Issue Analytics Script Report (#23604)
* feat: Issue Analytics Report * feat: add more filters, code clean-up * fix: add report link to desk page * test: Issue Analytics Report * fix: sider issues * fix: test * debug: travis * debug: travis * fix: travis * fix: travis Co-authored-by: Marica <maricadsouza221197@gmail.com> Co-authored-by: Nabin Hait <nabinhait@gmail.com>
This commit is contained in:
parent
c3d82a889a
commit
ea19434af4
@ -28,7 +28,7 @@
|
||||
{
|
||||
"hidden": 0,
|
||||
"label": "Reports",
|
||||
"links": "[\n {\n \"dependencies\": [\n \"Issue\"\n ],\n \"doctype\": \"Issue\",\n \"is_query_report\": true,\n \"label\": \"First Response Time for Issues\",\n \"name\": \"First Response Time for Issues\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Issue\"\n ],\n \"doctype\": \"Issue\",\n \"is_query_report\": true,\n \"label\": \"Issue Summary\",\n \"name\": \"Issue Summary\",\n \"type\": \"report\"\n }\n]"
|
||||
"links": "[\n {\n \"dependencies\": [\n \"Issue\"\n ],\n \"doctype\": \"Issue\",\n \"is_query_report\": true,\n \"label\": \"First Response Time for Issues\",\n \"name\": \"First Response Time for Issues\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Issue\"\n ],\n \"doctype\": \"Issue\",\n \"is_query_report\": true,\n \"label\": \"Issue Analytics\",\n \"name\": \"Issue Analytics\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Issue\"\n ],\n \"doctype\": \"Issue\",\n \"is_query_report\": true,\n \"label\": \"Issue Summary\",\n \"name\": \"Issue Summary\",\n \"type\": \"report\"\n }\n]"
|
||||
}
|
||||
],
|
||||
"category": "Modules",
|
||||
@ -43,7 +43,7 @@
|
||||
"idx": 0,
|
||||
"is_standard": 1,
|
||||
"label": "Support",
|
||||
"modified": "2020-10-12 18:40:22.252915",
|
||||
"modified": "2021-01-13 20:15:03.064256",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Support",
|
||||
"name": "Support",
|
||||
|
@ -214,7 +214,7 @@ class Issue(Document):
|
||||
|
||||
def before_insert(self):
|
||||
if frappe.db.get_single_value("Support Settings", "track_service_level_agreement"):
|
||||
self.set_response_and_resolution_time()
|
||||
self.set_response_and_resolution_time(priority=self.priority, service_level_agreement=self.service_level_agreement)
|
||||
|
||||
def set_response_and_resolution_time(self, priority=None, service_level_agreement=None):
|
||||
service_level_agreement = get_active_service_level_agreement_for(priority=priority,
|
||||
|
@ -135,15 +135,19 @@ class TestIssue(unittest.TestCase):
|
||||
self.assertEqual(flt(issue.total_hold_time, 2), 2700)
|
||||
|
||||
|
||||
def make_issue(creation=None, customer=None, index=0):
|
||||
def make_issue(creation=None, customer=None, index=0, priority=None, issue_type=None):
|
||||
issue = frappe.get_doc({
|
||||
"doctype": "Issue",
|
||||
"subject": "Service Level Agreement Issue {0}".format(index),
|
||||
"customer": customer,
|
||||
"raised_by": "test@example.com",
|
||||
"description": "Service Level Agreement Issue",
|
||||
"issue_type": issue_type,
|
||||
"priority": priority,
|
||||
"creation": creation,
|
||||
"service_level_agreement_creation": creation
|
||||
"opening_date": creation,
|
||||
"service_level_agreement_creation": creation,
|
||||
"company": "_Test Company"
|
||||
}).insert(ignore_permissions=True)
|
||||
|
||||
return issue
|
||||
|
0
erpnext/support/report/issue_analytics/__init__.py
Normal file
0
erpnext/support/report/issue_analytics/__init__.py
Normal file
141
erpnext/support/report/issue_analytics/issue_analytics.js
Normal file
141
erpnext/support/report/issue_analytics/issue_analytics.js
Normal file
@ -0,0 +1,141 @@
|
||||
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
/* eslint-disable */
|
||||
|
||||
frappe.query_reports["Issue Analytics"] = {
|
||||
"filters": [
|
||||
{
|
||||
fieldname: "company",
|
||||
label: __("Company"),
|
||||
fieldtype: "Link",
|
||||
options: "Company",
|
||||
default: frappe.defaults.get_user_default("Company"),
|
||||
reqd: 1
|
||||
},
|
||||
{
|
||||
fieldname: "based_on",
|
||||
label: __("Based On"),
|
||||
fieldtype: "Select",
|
||||
options: ["Customer", "Issue Type", "Issue Priority", "Assigned To"],
|
||||
default: "Customer",
|
||||
reqd: 1
|
||||
},
|
||||
{
|
||||
fieldname: "from_date",
|
||||
label: __("From Date"),
|
||||
fieldtype: "Date",
|
||||
default: frappe.defaults.get_global_default("year_start_date"),
|
||||
reqd: 1
|
||||
},
|
||||
{
|
||||
fieldname:"to_date",
|
||||
label: __("To Date"),
|
||||
fieldtype: "Date",
|
||||
default: frappe.defaults.get_global_default("year_end_date"),
|
||||
reqd: 1
|
||||
},
|
||||
{
|
||||
fieldname: "range",
|
||||
label: __("Range"),
|
||||
fieldtype: "Select",
|
||||
options: [
|
||||
{ "value": "Weekly", "label": __("Weekly") },
|
||||
{ "value": "Monthly", "label": __("Monthly") },
|
||||
{ "value": "Quarterly", "label": __("Quarterly") },
|
||||
{ "value": "Yearly", "label": __("Yearly") }
|
||||
],
|
||||
default: "Monthly",
|
||||
reqd: 1
|
||||
},
|
||||
{
|
||||
fieldname: "status",
|
||||
label: __("Status"),
|
||||
fieldtype: "Select",
|
||||
options:[
|
||||
{label: __('Open'), value: 'Open'},
|
||||
{label: __('Replied'), value: 'Replied'},
|
||||
{label: __('Resolved'), value: 'Resolved'},
|
||||
{label: __('Closed'), value: 'Closed'}
|
||||
]
|
||||
},
|
||||
{
|
||||
fieldname: "priority",
|
||||
label: __("Issue Priority"),
|
||||
fieldtype: "Link",
|
||||
options: "Issue Priority"
|
||||
},
|
||||
{
|
||||
fieldname: "customer",
|
||||
label: __("Customer"),
|
||||
fieldtype: "Link",
|
||||
options: "Customer"
|
||||
},
|
||||
{
|
||||
fieldname: "project",
|
||||
label: __("Project"),
|
||||
fieldtype: "Link",
|
||||
options: "Project"
|
||||
},
|
||||
{
|
||||
fieldname: "assigned_to",
|
||||
label: __("Assigned To"),
|
||||
fieldtype: "Link",
|
||||
options: "User"
|
||||
}
|
||||
],
|
||||
after_datatable_render: function(datatable_obj) {
|
||||
$(datatable_obj.wrapper).find(".dt-row-0").find('input[type=checkbox]').click();
|
||||
},
|
||||
get_datatable_options(options) {
|
||||
return Object.assign(options, {
|
||||
checkboxColumn: true,
|
||||
events: {
|
||||
onCheckRow: function(data) {
|
||||
if (data && data.length) {
|
||||
row_name = data[2].content;
|
||||
row_values = data.slice(3).map(function(column) {
|
||||
return column.content;
|
||||
})
|
||||
entry = {
|
||||
'name': row_name,
|
||||
'values': row_values
|
||||
}
|
||||
|
||||
let raw_data = frappe.query_report.chart.data;
|
||||
let new_datasets = raw_data.datasets;
|
||||
|
||||
var found = false;
|
||||
|
||||
for(var i=0; i < new_datasets.length; i++){
|
||||
if (new_datasets[i].name == row_name){
|
||||
found = true;
|
||||
new_datasets.splice(i,1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found){
|
||||
new_datasets.push(entry);
|
||||
}
|
||||
|
||||
let new_data = {
|
||||
labels: raw_data.labels,
|
||||
datasets: new_datasets
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
frappe.query_report.chart.update(new_data)
|
||||
},500)
|
||||
|
||||
|
||||
setTimeout(() => {
|
||||
frappe.query_report.chart.draw(true);
|
||||
}, 1000)
|
||||
|
||||
frappe.query_report.raw_chart_data = new_data;
|
||||
}
|
||||
},
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
26
erpnext/support/report/issue_analytics/issue_analytics.json
Normal file
26
erpnext/support/report/issue_analytics/issue_analytics.json
Normal file
@ -0,0 +1,26 @@
|
||||
{
|
||||
"add_total_row": 1,
|
||||
"columns": [],
|
||||
"creation": "2020-10-09 19:52:10.227317",
|
||||
"disable_prepared_report": 0,
|
||||
"disabled": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "Report",
|
||||
"filters": [],
|
||||
"idx": 0,
|
||||
"is_standard": "Yes",
|
||||
"modified": "2020-10-11 19:43:19.358625",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Support",
|
||||
"name": "Issue Analytics",
|
||||
"owner": "Administrator",
|
||||
"prepared_report": 0,
|
||||
"ref_doctype": "Issue",
|
||||
"report_name": "Issue Analytics",
|
||||
"report_type": "Script Report",
|
||||
"roles": [
|
||||
{
|
||||
"role": "Support Team"
|
||||
}
|
||||
]
|
||||
}
|
222
erpnext/support/report/issue_analytics/issue_analytics.py
Normal file
222
erpnext/support/report/issue_analytics/issue_analytics.py
Normal file
@ -0,0 +1,222 @@
|
||||
# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
import json
|
||||
from six import iteritems
|
||||
from frappe import _, scrub
|
||||
from frappe.utils import getdate, flt, add_to_date, add_days
|
||||
from erpnext.accounts.utils import get_fiscal_year
|
||||
|
||||
def execute(filters=None):
|
||||
return IssueAnalytics(filters).run()
|
||||
|
||||
class IssueAnalytics(object):
|
||||
def __init__(self, filters=None):
|
||||
"""Issue Analytics Report"""
|
||||
self.filters = frappe._dict(filters or {})
|
||||
self.get_period_date_ranges()
|
||||
|
||||
def run(self):
|
||||
self.get_columns()
|
||||
self.get_data()
|
||||
self.get_chart_data()
|
||||
|
||||
return self.columns, self.data, None, self.chart
|
||||
|
||||
def get_columns(self):
|
||||
self.columns = []
|
||||
|
||||
if self.filters.based_on == 'Customer':
|
||||
self.columns.append({
|
||||
'label': _('Customer'),
|
||||
'options': 'Customer',
|
||||
'fieldname': 'customer',
|
||||
'fieldtype': 'Link',
|
||||
'width': 200
|
||||
})
|
||||
|
||||
elif self.filters.based_on == 'Assigned To':
|
||||
self.columns.append({
|
||||
'label': _('User'),
|
||||
'fieldname': 'user',
|
||||
'fieldtype': 'Link',
|
||||
'options': 'User',
|
||||
'width': 200
|
||||
})
|
||||
|
||||
elif self.filters.based_on == 'Issue Type':
|
||||
self.columns.append({
|
||||
'label': _('Issue Type'),
|
||||
'fieldname': 'issue_type',
|
||||
'fieldtype': 'Link',
|
||||
'options': 'Issue Type',
|
||||
'width': 200
|
||||
})
|
||||
|
||||
elif self.filters.based_on == 'Issue Priority':
|
||||
self.columns.append({
|
||||
'label': _('Issue Priority'),
|
||||
'fieldname': 'priority',
|
||||
'fieldtype': 'Link',
|
||||
'options': 'Issue Priority',
|
||||
'width': 200
|
||||
})
|
||||
|
||||
for end_date in self.periodic_daterange:
|
||||
period = self.get_period(end_date)
|
||||
self.columns.append({
|
||||
'label': _(period),
|
||||
'fieldname': scrub(period),
|
||||
'fieldtype': 'Int',
|
||||
'width': 120
|
||||
})
|
||||
|
||||
self.columns.append({
|
||||
'label': _('Total'),
|
||||
'fieldname': 'total',
|
||||
'fieldtype': 'Int',
|
||||
'width': 120
|
||||
})
|
||||
|
||||
def get_data(self):
|
||||
self.get_issues()
|
||||
self.get_rows()
|
||||
|
||||
def get_period(self, date):
|
||||
months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
|
||||
|
||||
if self.filters.range == 'Weekly':
|
||||
period = 'Week ' + str(date.isocalendar()[1])
|
||||
elif self.filters.range == 'Monthly':
|
||||
period = str(months[date.month - 1])
|
||||
elif self.filters.range == 'Quarterly':
|
||||
period = 'Quarter ' + str(((date.month - 1) // 3) + 1)
|
||||
else:
|
||||
year = get_fiscal_year(date, self.filters.company)
|
||||
period = str(year[0])
|
||||
|
||||
if getdate(self.filters.from_date).year != getdate(self.filters.to_date).year and self.filters.range != 'Yearly':
|
||||
period += ' ' + str(date.year)
|
||||
|
||||
return period
|
||||
|
||||
def get_period_date_ranges(self):
|
||||
from dateutil.relativedelta import relativedelta, MO
|
||||
from_date, to_date = getdate(self.filters.from_date), getdate(self.filters.to_date)
|
||||
|
||||
increment = {
|
||||
'Monthly': 1,
|
||||
'Quarterly': 3,
|
||||
'Half-Yearly': 6,
|
||||
'Yearly': 12
|
||||
}.get(self.filters.range, 1)
|
||||
|
||||
if self.filters.range in ['Monthly', 'Quarterly']:
|
||||
from_date = from_date.replace(day=1)
|
||||
elif self.filters.range == 'Yearly':
|
||||
from_date = get_fiscal_year(from_date)[1]
|
||||
else:
|
||||
from_date = from_date + relativedelta(from_date, weekday=MO(-1))
|
||||
|
||||
self.periodic_daterange = []
|
||||
for dummy in range(1, 53):
|
||||
if self.filters.range == 'Weekly':
|
||||
period_end_date = add_days(from_date, 6)
|
||||
else:
|
||||
period_end_date = add_to_date(from_date, months=increment, days=-1)
|
||||
|
||||
if period_end_date > to_date:
|
||||
period_end_date = to_date
|
||||
|
||||
self.periodic_daterange.append(period_end_date)
|
||||
|
||||
from_date = add_days(period_end_date, 1)
|
||||
if period_end_date == to_date:
|
||||
break
|
||||
|
||||
def get_issues(self):
|
||||
filters = self.get_common_filters()
|
||||
self.field_map = {
|
||||
'Customer': 'customer',
|
||||
'Issue Type': 'issue_type',
|
||||
'Issue Priority': 'priority',
|
||||
'Assigned To': '_assign'
|
||||
}
|
||||
|
||||
self.entries = frappe.db.get_all('Issue',
|
||||
fields=[self.field_map.get(self.filters.based_on), 'name', 'opening_date'],
|
||||
filters=filters,
|
||||
debug=1
|
||||
)
|
||||
|
||||
def get_common_filters(self):
|
||||
filters = {}
|
||||
filters['opening_date'] = ('between', [self.filters.from_date, self.filters.to_date])
|
||||
|
||||
if self.filters.get('assigned_to'):
|
||||
filters['_assign'] = ('like', '%' + self.filters.get('assigned_to') + '%')
|
||||
|
||||
for entry in ['company', 'status', 'priority', 'customer', 'project']:
|
||||
if self.filters.get(entry):
|
||||
filters[entry] = self.filters.get(entry)
|
||||
|
||||
return filters
|
||||
|
||||
def get_rows(self):
|
||||
self.data = []
|
||||
self.get_periodic_data()
|
||||
|
||||
for entity, period_data in iteritems(self.issue_periodic_data):
|
||||
if self.filters.based_on == 'Customer':
|
||||
row = {'customer': entity}
|
||||
elif self.filters.based_on == 'Assigned To':
|
||||
row = {'user': entity}
|
||||
elif self.filters.based_on == 'Issue Type':
|
||||
row = {'issue_type': entity}
|
||||
elif self.filters.based_on == 'Issue Priority':
|
||||
row = {'priority': entity}
|
||||
|
||||
total = 0
|
||||
for end_date in self.periodic_daterange:
|
||||
period = self.get_period(end_date)
|
||||
amount = flt(period_data.get(period, 0.0))
|
||||
row[scrub(period)] = amount
|
||||
total += amount
|
||||
|
||||
row['total'] = total
|
||||
|
||||
self.data.append(row)
|
||||
|
||||
def get_periodic_data(self):
|
||||
self.issue_periodic_data = frappe._dict()
|
||||
|
||||
for d in self.entries:
|
||||
period = self.get_period(d.get('opening_date'))
|
||||
|
||||
if self.filters.based_on == 'Assigned To':
|
||||
if d._assign:
|
||||
for entry in json.loads(d._assign):
|
||||
self.issue_periodic_data.setdefault(entry, frappe._dict()).setdefault(period, 0.0)
|
||||
self.issue_periodic_data[entry][period] += 1
|
||||
|
||||
else:
|
||||
field = self.field_map.get(self.filters.based_on)
|
||||
value = d.get(field)
|
||||
if not value:
|
||||
value = _('Not Specified')
|
||||
|
||||
self.issue_periodic_data.setdefault(value, frappe._dict()).setdefault(period, 0.0)
|
||||
self.issue_periodic_data[value][period] += 1
|
||||
|
||||
def get_chart_data(self):
|
||||
length = len(self.columns)
|
||||
labels = [d.get('label') for d in self.columns[1:length-1]]
|
||||
self.chart = {
|
||||
'data': {
|
||||
'labels': labels,
|
||||
'datasets': []
|
||||
},
|
||||
'type': 'line'
|
||||
}
|
211
erpnext/support/report/issue_analytics/test_issue_analytics.py
Normal file
211
erpnext/support/report/issue_analytics/test_issue_analytics.py
Normal file
@ -0,0 +1,211 @@
|
||||
from __future__ import unicode_literals
|
||||
import unittest
|
||||
import frappe
|
||||
from frappe.utils import getdate, add_months
|
||||
from erpnext.support.report.issue_analytics.issue_analytics import execute
|
||||
from erpnext.support.doctype.issue.test_issue import make_issue, create_customer
|
||||
from erpnext.support.doctype.service_level_agreement.test_service_level_agreement import create_service_level_agreements_for_issues
|
||||
from frappe.desk.form.assign_to import add as add_assignment
|
||||
|
||||
months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
|
||||
|
||||
class TestIssueAnalytics(unittest.TestCase):
|
||||
@classmethod
|
||||
def setUpClass(self):
|
||||
frappe.db.sql("delete from `tabIssue` where company='_Test Company'")
|
||||
frappe.db.set_value("Support Settings", None, "track_service_level_agreement", 1)
|
||||
|
||||
current_month_date = getdate()
|
||||
last_month_date = add_months(current_month_date, -1)
|
||||
self.current_month = str(months[current_month_date.month - 1]).lower() + '_' + str(current_month_date.year)
|
||||
self.last_month = str(months[last_month_date.month - 1]).lower() + '_' + str(last_month_date.year)
|
||||
|
||||
def test_issue_analytics(self):
|
||||
create_service_level_agreements_for_issues()
|
||||
create_issue_types()
|
||||
create_records()
|
||||
|
||||
self.compare_result_for_customer()
|
||||
self.compare_result_for_issue_type()
|
||||
self.compare_result_for_issue_priority()
|
||||
self.compare_result_for_assignment()
|
||||
|
||||
def compare_result_for_customer(self):
|
||||
filters = {
|
||||
'company': '_Test Company',
|
||||
'based_on': 'Customer',
|
||||
'from_date': add_months(getdate(), -1),
|
||||
'to_date': getdate(),
|
||||
'range': 'Monthly'
|
||||
}
|
||||
|
||||
report = execute(filters)
|
||||
|
||||
expected_data = [
|
||||
{
|
||||
'customer': '__Test Customer 2',
|
||||
self.last_month: 1.0,
|
||||
self.current_month: 0.0,
|
||||
'total': 1.0
|
||||
},
|
||||
{
|
||||
'customer': '__Test Customer 1',
|
||||
self.last_month: 0.0,
|
||||
self.current_month: 1.0,
|
||||
'total': 1.0
|
||||
},
|
||||
{
|
||||
'customer': '__Test Customer',
|
||||
self.last_month: 1.0,
|
||||
self.current_month: 1.0,
|
||||
'total': 2.0
|
||||
}
|
||||
]
|
||||
|
||||
self.assertEqual(expected_data, report[1]) # rows
|
||||
self.assertEqual(len(report[0]), 4) # cols
|
||||
|
||||
def compare_result_for_issue_type(self):
|
||||
filters = {
|
||||
'company': '_Test Company',
|
||||
'based_on': 'Issue Type',
|
||||
'from_date': add_months(getdate(), -1),
|
||||
'to_date': getdate(),
|
||||
'range': 'Monthly'
|
||||
}
|
||||
|
||||
report = execute(filters)
|
||||
|
||||
expected_data = [
|
||||
{
|
||||
'issue_type': 'Discomfort',
|
||||
self.last_month: 1.0,
|
||||
self.current_month: 0.0,
|
||||
'total': 1.0
|
||||
},
|
||||
{
|
||||
'issue_type': 'Service Request',
|
||||
self.last_month: 0.0,
|
||||
self.current_month: 1.0,
|
||||
'total': 1.0
|
||||
},
|
||||
{
|
||||
'issue_type': 'Bug',
|
||||
self.last_month: 1.0,
|
||||
self.current_month: 1.0,
|
||||
'total': 2.0
|
||||
}
|
||||
]
|
||||
|
||||
self.assertEqual(expected_data, report[1]) # rows
|
||||
self.assertEqual(len(report[0]), 4) # cols
|
||||
|
||||
def compare_result_for_issue_priority(self):
|
||||
filters = {
|
||||
'company': '_Test Company',
|
||||
'based_on': 'Issue Priority',
|
||||
'from_date': add_months(getdate(), -1),
|
||||
'to_date': getdate(),
|
||||
'range': 'Monthly'
|
||||
}
|
||||
|
||||
report = execute(filters)
|
||||
|
||||
expected_data = [
|
||||
{
|
||||
'priority': 'Medium',
|
||||
self.last_month: 1.0,
|
||||
self.current_month: 1.0,
|
||||
'total': 2.0
|
||||
},
|
||||
{
|
||||
'priority': 'Low',
|
||||
self.last_month: 1.0,
|
||||
self.current_month: 0.0,
|
||||
'total': 1.0
|
||||
},
|
||||
{
|
||||
'priority': 'High',
|
||||
self.last_month: 0.0,
|
||||
self.current_month: 1.0,
|
||||
'total': 1.0
|
||||
}
|
||||
]
|
||||
|
||||
self.assertEqual(expected_data, report[1]) # rows
|
||||
self.assertEqual(len(report[0]), 4) # cols
|
||||
|
||||
def compare_result_for_assignment(self):
|
||||
filters = {
|
||||
'company': '_Test Company',
|
||||
'based_on': 'Assigned To',
|
||||
'from_date': add_months(getdate(), -1),
|
||||
'to_date': getdate(),
|
||||
'range': 'Monthly'
|
||||
}
|
||||
|
||||
report = execute(filters)
|
||||
|
||||
expected_data = [
|
||||
{
|
||||
'user': 'test@example.com',
|
||||
self.last_month: 1.0,
|
||||
self.current_month: 1.0,
|
||||
'total': 2.0
|
||||
},
|
||||
{
|
||||
'user': 'test1@example.com',
|
||||
self.last_month: 2.0,
|
||||
self.current_month: 1.0,
|
||||
'total': 3.0
|
||||
}
|
||||
]
|
||||
|
||||
self.assertEqual(expected_data, report[1]) # rows
|
||||
self.assertEqual(len(report[0]), 4) # cols
|
||||
|
||||
|
||||
def create_issue_types():
|
||||
for entry in ['Bug', 'Service Request', 'Discomfort']:
|
||||
if not frappe.db.exists('Issue Type', entry):
|
||||
frappe.get_doc({
|
||||
'doctype': 'Issue Type',
|
||||
'__newname': entry
|
||||
}).insert()
|
||||
|
||||
|
||||
def create_records():
|
||||
create_customer("__Test Customer", "_Test SLA Customer Group", "__Test SLA Territory")
|
||||
create_customer("__Test Customer 1", "_Test SLA Customer Group", "__Test SLA Territory")
|
||||
create_customer("__Test Customer 2", "_Test SLA Customer Group", "__Test SLA Territory")
|
||||
|
||||
current_month_date = getdate()
|
||||
last_month_date = add_months(current_month_date, -1)
|
||||
|
||||
issue = make_issue(current_month_date, "__Test Customer", 2, "High", "Bug")
|
||||
add_assignment({
|
||||
"assign_to": ["test@example.com"],
|
||||
"doctype": "Issue",
|
||||
"name": issue.name
|
||||
})
|
||||
|
||||
issue = make_issue(last_month_date, "__Test Customer", 2, "Low", "Bug")
|
||||
add_assignment({
|
||||
"assign_to": ["test1@example.com"],
|
||||
"doctype": "Issue",
|
||||
"name": issue.name
|
||||
})
|
||||
|
||||
issue = make_issue(current_month_date, "__Test Customer 1", 2, "Medium", "Service Request")
|
||||
add_assignment({
|
||||
"assign_to": ["test1@example.com"],
|
||||
"doctype": "Issue",
|
||||
"name": issue.name
|
||||
})
|
||||
|
||||
issue = make_issue(last_month_date, "__Test Customer 2", 2, "Medium", "Discomfort")
|
||||
add_assignment({
|
||||
"assign_to": ["test@example.com", "test1@example.com"],
|
||||
"doctype": "Issue",
|
||||
"name": issue.name
|
||||
})
|
Loading…
Reference in New Issue
Block a user