Merge pull request #8587 from prssanna/group-by-dashboard

feat(Dashboards): Add group by dashboard chart type
This commit is contained in:
mergify[bot] 2019-11-04 06:31:53 +00:00 committed by GitHub
commit 0f62dcae04
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 207 additions and 603 deletions

View file

@ -17,7 +17,7 @@
font-weight: bold;
}
.chart-loading-state {
.chart-loading-state, .chart-empty-state {
height: 100%;
margin-top: 160px;
text-align: center;

View file

@ -226,23 +226,26 @@ class DashboardChart {
"Line": "line",
"Bar": "bar",
};
let chart_args = {
title: this.chart_doc.chart_name,
data: this.data,
type: chart_type_map[this.chart_doc.type],
truncateLegends: 1,
colors: [this.chart_doc.color || "light-blue"],
axisOptions: {
xIsSeries: this.chart_doc.timeseries,
shortenYAxisNumbers: 1
}
};
this.chart_container.find('.chart-loading-state').addClass('hide');
if(!this.chart) {
this.chart = new frappe.Chart(this.chart_container.find(".chart-wrapper")[0], chart_args);
this.chart_container.find('.chart-loading-state').addClass('hide');
if (!this.data) {
this.chart_container.find('.chart-empty-state').removeClass('hide');
} else {
this.chart.update(this.data);
let chart_args = {
title: this.chart_doc.chart_name,
data: this.data,
type: chart_type_map[this.chart_doc.type],
colors: [this.chart_doc.color || "light-blue"],
axisOptions: {
xIsSeries: this.chart_doc.timeseries,
shortenYAxisNumbers: 1
}
};
if (!this.chart) {
this.chart = new frappe.Chart(this.chart_container.find(".chart-wrapper")[0], chart_args);
} else {
this.chart.update(this.data);
}
}
}

View file

@ -23,6 +23,8 @@ frappe.ui.form.on('Dashboard Chart', {
// set timeseries based on chart type
if (['Count', 'Average', 'Sum'].includes(frm.doc.chart_type)) {
frm.set_value('timeseries', 1);
} else {
frm.set_value('timeseries', 0);
}
frm.set_value('document_type', '');
},
@ -38,6 +40,7 @@ frappe.ui.form.on('Dashboard Chart', {
timespan: function(frm) {
const time_interval_options = {
"Select Date Range": ["Quarterly", "Monthly", "Weekly", "Daily"],
"Last Year": ["Quarterly", "Monthly", "Weekly", "Daily"],
"Last Quarter": ["Monthly", "Weekly", "Daily"],
"Last Month": ["Weekly", "Daily"],
@ -55,10 +58,14 @@ frappe.ui.form.on('Dashboard Chart', {
{label: __('Last Modified On'), value: 'modified'}
];
let value_fields = [];
let group_by_fields = [];
let aggregate_function_fields = [];
let update_form = function() {
// update select options
frm.set_df_property('based_on', 'options', date_fields);
frm.set_df_property('value_based_on', 'options', value_fields);
frm.set_df_property('group_by_based_on', 'options', group_by_fields);
frm.set_df_property('aggregate_function_based_on', 'options', aggregate_function_fields);
frm.trigger("show_filters");
}
@ -72,6 +79,10 @@ frappe.ui.form.on('Dashboard Chart', {
}
if (['Int', 'Float', 'Currency', 'Percent'].includes(df.fieldtype)) {
value_fields.push({label: df.label, value: df.fieldname});
aggregate_function_fields.push({label: df.label, value: df.fieldname});
}
if (['Link', 'Select'].includes(df.fieldtype)) {
group_by_fields.push({label: df.label, value: df.fieldname});
}
});
update_form();

View file

@ -1,703 +1,212 @@
{
"allow_copy": 0,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 1,
"autoname": "field:chart_name",
"beta": 0,
"creation": "2019-01-10 12:28:06.282875",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"chart_name",
"chart_type",
"source",
"document_type",
"based_on",
"value_based_on",
"group_by_type",
"group_by_based_on",
"aggregate_function_based_on",
"number_of_groups",
"column_break_6",
"timespan",
"from_date",
"to_date",
"time_interval",
"timeseries",
"filters_section",
"filters_json",
"chart_options_section",
"type",
"width",
"column_break_2",
"color",
"section_break_10",
"last_synced_on"
],
"fields": [
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "chart_name",
"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": "Chart Name",
"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,
"fetch_if_empty": 0,
"fieldname": "chart_type",
"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": "Chart Type",
"length": 0,
"no_copy": 0,
"options": "Count\nSum\nAverage\nCustom",
"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": "Count\nSum\nAverage\nCustom\nGroup By"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "eval:doc.chart_type === 'Custom'",
"fetch_if_empty": 0,
"fieldname": "source",
"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": "Chart Source",
"length": 0,
"no_copy": 0,
"options": "Dashboard Chart Source",
"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": "Dashboard Chart Source"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "eval: doc.chart_type !== 'Custom'",
"fetch_if_empty": 0,
"fieldname": "document_type",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Document Type",
"length": 0,
"no_copy": 0,
"options": "DocType",
"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": "DocType"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "eval: doc.chart_type !== 'Custom'",
"fetch_if_empty": 0,
"depends_on": "eval: ['Count', 'Sum', 'Average'].includes(doc.chart_type)",
"fieldname": "based_on",
"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": "Time Series Based On",
"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": "Time Series Based On"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "eval: ['Sum', 'Average'].includes(doc.chart_type)",
"fetch_if_empty": 0,
"depends_on": "eval: ['Sum', 'Average'].includes(doc.chart_type)\n",
"fieldname": "value_based_on",
"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": "Value Based On",
"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": "Value Based On"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "",
"fetch_if_empty": 0,
"fieldname": "column_break_6",
"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": "timeseries",
"fetch_if_empty": 0,
"fieldname": "timespan",
"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": "Timespan",
"length": 0,
"no_copy": 0,
"options": "Last Year\nLast Quarter\nLast Month\nLast Week",
"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": "Last Year\nLast Quarter\nLast Month\nLast Week\nSelect Date Range"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "timeseries",
"fetch_if_empty": 0,
"fieldname": "time_interval",
"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": "Time Interval",
"length": 0,
"no_copy": 0,
"options": "Quarterly\nMonthly\nWeekly\nDaily",
"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": "Quarterly\nMonthly\nWeekly\nDaily"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"default": "0",
"depends_on": "eval:doc.chart_type !== 'Group By'",
"fieldname": "timeseries",
"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": "Time Series",
"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": "Time Series"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "filters_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": "Filters",
"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": "Filters"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "",
"depends_on": "",
"fetch_if_empty": 0,
"fieldname": "filters_json",
"fieldtype": "Code",
"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": "Filters JSON",
"length": 0,
"no_copy": 0,
"options": "JSON",
"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_if_empty": 0,
"fieldname": "chart_options_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": "Chart Options",
"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": "Chart Options"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "type",
"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": "Type",
"length": 0,
"no_copy": 0,
"options": "Line\nBar",
"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_if_empty": 0,
"fieldname": "width",
"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": "Width",
"length": 0,
"no_copy": 0,
"options": "Half\nFull",
"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_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,
"fetch_if_empty": 0,
"fieldname": "color",
"fieldtype": "Color",
"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": "Color",
"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": "Color"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "section_break_10",
"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,
"fetch_if_empty": 0,
"fieldname": "last_synced_on",
"fieldtype": "Datetime",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Last Synced On",
"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
"read_only": 1
},
{
"depends_on": "eval:doc.chart_type === 'Group By'",
"fieldname": "group_by_based_on",
"fieldtype": "Select",
"label": "Group By Based On"
},
{
"default": "Count",
"depends_on": "eval:doc.chart_type === 'Group By'",
"fieldname": "group_by_type",
"fieldtype": "Select",
"label": "Group By Type",
"options": "Count\nSum\nAverage"
},
{
"depends_on": "eval: ['Sum', 'Average'].includes(doc.group_by_type)",
"fieldname": "aggregate_function_based_on",
"fieldtype": "Select",
"label": "Aggregate Function Based On"
},
{
"depends_on": "eval:doc.chart_type === 'Group By'",
"fieldname": "number_of_groups",
"fieldtype": "Int",
"label": "Number of Groups"
},
{
"depends_on": "eval:doc.timespan === 'Choose Time Span'",
"fieldname": "from_date",
"fieldtype": "Date",
"label": "From Date"
},
{
"depends_on": "eval:doc.timespan === 'Choose Time Span'",
"fieldname": "to_date",
"fieldtype": "Date",
"label": "To Date"
}
],
"has_web_view": 0,
"hide_toolbar": 0,
"idx": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2019-04-09 15:04:02.434131",
"modified": "2019-10-29 02:26:14.838057",
"modified_by": "Administrator",
"module": "Desk",
"name": "Dashboard Chart",
"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
}
],
"quick_entry": 0,
"read_only": 0,
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
"title_field": "",
"track_changes": 1,
"track_seen": 0,
"track_views": 0
"track_changes": 1
}

View file

@ -12,19 +12,30 @@ from frappe.model.document import Document
@frappe.whitelist()
@cache_source
def get(chart_name = None, chart = None, no_cache = None, from_date=None, to_date=None, refresh = None):
def get(chart_name = None, chart = None, no_cache = None, from_date = None, to_date = None, refresh = None):
if chart_name:
chart = frappe.get_doc('Dashboard Chart', chart_name)
else:
chart = frappe._dict(frappe.parse_json(chart))
timespan = chart.timespan
from_date = chart.from_date
to_date = chart.to_date
timegrain = chart.time_interval
filters = frappe.parse_json(chart.filters_json)
# don't include cancelled documents
filters['docstatus'] = ('<', 2)
if chart.chart_type == 'Group By':
chart_config = get_group_by_chart_config(chart, filters)
else:
chart_config = get_chart_config(chart, filters, timespan, timegrain, from_date, to_date)
return chart_config
def get_chart_config(chart, filters, timespan, timegrain, from_date, to_date):
if not from_date:
from_date = get_from_date_from_timespan(to_date, timespan)
if not to_date:
@ -32,7 +43,6 @@ def get(chart_name = None, chart = None, no_cache = None, from_date=None, to_dat
# get conditions from filters
conditions, values = frappe.db.build_conditions(filters)
# query will return year, unit and aggregate value
data = frappe.db.sql('''
select
@ -63,7 +73,7 @@ def get(chart_name = None, chart = None, no_cache = None, from_date=None, to_dat
# add missing data points for periods where there was no result
result = add_missing_values(result, timegrain, from_date, to_date)
return {
chart_config = {
"labels": [formatdate(r[0].strftime('%Y-%m-%d')) for r in result],
"datasets": [{
"name": chart.name,
@ -71,11 +81,53 @@ def get(chart_name = None, chart = None, no_cache = None, from_date=None, to_dat
}]
}
return chart_config
def get_group_by_chart_config(chart, filters):
conditions, values = frappe.db.build_conditions(filters)
data = frappe.db.sql('''
select
{aggregate_function}({value_field}) as count,
{group_by_field} as name
from `tab{doctype}`
where {conditions}
group by {group_by_field}
order by count desc
'''.format(
aggregate_function = get_aggregate_function(chart.group_by_type),
value_field = chart.aggregate_function_based_on or '1',
field = chart.aggregate_function_based_on or chart.group_by_based_on,
group_by_field = chart.group_by_based_on,
doctype = chart.document_type,
conditions = conditions,
), values, as_dict = True)
if data:
if chart.number_of_groups and chart.number_of_groups < len(data):
other_count = 0
for i in range(chart.number_of_groups - 1, len(data)):
other_count += data[i]['count']
data = data[0: chart.number_of_groups - 1]
data.append({'name': 'Other', 'count': other_count})
chart_config = {
"labels": [item['name'] if item['name'] else 'Not Specified' for item in data],
"datasets": [{
"name": chart.name,
"values": [item['count'] for item in data]
}]
}
return chart_config
else:
return None
def get_aggregate_function(chart_type):
return {
"Sum": "SUM",
"Count": "COUNT",
"Average": "AVG"
"Average": "AVG",
}[chart_type]
def convert_to_dates(data, timegrain):
@ -210,7 +262,14 @@ class DashboardChart(Document):
self.check_required_field()
def check_required_field(self):
if not self.based_on:
frappe.throw(_("Time series based on is required to create a dashboard chart"))
if not self.document_type:
frappe.throw(_("Document type is required to create a dashboard chart"))
frappe.throw(_("Document type is required to create a dashboard chart"))
if self.chart_type == 'Group By':
if not self.group_by_based_on:
frappe.throw(_("Group By field is required to create a dashboard chart"))
if self.group_by_type in ['Sum', 'Average'] and not self.aggregate_function_based_on:
frappe.throw(_("Aggregate Function field is required to create a dashboard chart"))
else:
if not self.based_on:
frappe.throw(_("Time series based on is required to create a dashboard chart"))

View file

@ -129,3 +129,25 @@ class TestDashboardChart(unittest.TestCase):
self.assertEqual(result.get('datasets')[0].get('values')[2], 0)
frappe.db.rollback()
def test_group_by_chart_type(self):
if frappe.db.exists('Dashboard Chart', 'Test Group By Dashboard Chart'):
frappe.delete_doc('Dashboard Chart', 'Test Group By Dashboard Chart')
frappe.get_doc({"doctype":"ToDo", "description": "test"}).insert()
frappe.get_doc(dict(
doctype = 'Dashboard Chart',
chart_name = 'Test Group By Dashboard Chart',
chart_type = 'Group By',
document_type = 'ToDo',
group_by_based_on = 'status',
filters_json = '{}',
)).insert()
result = get(chart_name ='Test Group By Dashboard Chart', refresh = 1)
todo_status_count = frappe.db.count('ToDo', {'status': result.get('labels')[0]})
self.assertEqual(result.get('datasets')[0].get('values')[0], todo_status_count)
frappe.db.rollback()