diff --git a/frappe/desk/reportview.py b/frappe/desk/reportview.py index 8bad1a2612..ae58f3baea 100644 --- a/frappe/desk/reportview.py +++ b/frappe/desk/reportview.py @@ -27,6 +27,13 @@ def get_list(): # uncompressed (refactored from frappe.model.db_query.get_list) return execute(**get_form_params()) +@frappe.whitelist() +@frappe.read_only() +def get_count(): + args = get_form_params() + args.fields = ['{distinct}count(name) as total_count'.format(distinct = 'distinct ' if args.distinct=='true' else '')] + return execute(**args)[0].get('total_count') + def execute(doctype, *args, **kwargs): return DatabaseQuery(doctype).execute(*args, **kwargs) @@ -35,6 +42,7 @@ def get_form_params(): data = frappe._dict(frappe.local.form_dict) clean_params(data) parse_json(data) + setup_group_by(data) validate_fields(data) if data.filters: @@ -99,6 +107,22 @@ def validate_filters(data, filters): if not df: raise_invalid_field(fieldname) +def setup_group_by(data): + ''' + Add columns for aggregated values e.g. count(name) + ''' + if data.group_by: + if data.aggregate_function.lower() not in ('count', 'sum', 'avg'): + frappe.throw('Invalid aggregate function') + if '`' in data.aggregate_on: + raise_invalid_field(data.aggregate_on) + data.fields.append('{aggregate_function}(`tab{doctype}`.`{aggregate_on}`) AS _aggregate_column'.format(**data)) + if data.aggregate_on: + data.fields.append(data.aggregate_on) + + data.pop('aggregate_on') + data.pop('aggregate_function') + def raise_invalid_field(fieldname): frappe.throw(_('Field not permitted in query') + ': {0}'.format(fieldname), frappe.DataError) diff --git a/frappe/public/js/frappe/db.js b/frappe/public/js/frappe/db.js index 1cfc6f3696..6073c7d3f0 100644 --- a/frappe/public/js/frappe/db.js +++ b/frappe/public/js/frappe/db.js @@ -92,25 +92,25 @@ frappe.db = { }, count: function(doctype, args={}) { let filters = args.filters || {}; - const with_child_table_filter = Array.isArray(filters) && filters.some(filter => { + + // has a filter with childtable? + const distinct = Array.isArray(filters) && filters.some(filter => { return filter[0] !== doctype; }); - const fields = [ - // cannot break this line as it adds extra \n's and \t's which breaks the query - `count(${with_child_table_filter ? 'distinct': ''} ${frappe.model.get_full_column_name('name', doctype)}) AS total_count` - ]; + const fields = []; return frappe.call({ type: 'GET', - method: 'frappe.desk.reportview.get', + method: 'frappe.desk.reportview.get_count', args: { doctype, filters, fields, + distinct, } }).then(r => { - return r.message.values[0][0]; + return r.message.values; }); }, get_link_options(doctype, txt = '', filters={}) { diff --git a/frappe/public/js/frappe/ui/group_by/group_by.js b/frappe/public/js/frappe/ui/group_by/group_by.js index fa699b1a91..53e4914f0d 100644 --- a/frappe/public/js/frappe/ui/group_by/group_by.js +++ b/frappe/public/js/frappe/ui/group_by/group_by.js @@ -286,15 +286,6 @@ frappe.ui.GroupBy = class { set_args(args) { if (this.aggregate_function && this.group_by) { - let aggregate_column, aggregate_on_field; - - if (this.aggregate_function === 'count') { - aggregate_column = 'count(`tab' + this.doctype + '`.`name`)'; - } else { - aggregate_column = `${this.aggregate_function}(${this.aggregate_on})`; - aggregate_on_field = this.aggregate_on; - } - this.report_view.group_by = this.group_by; this.report_view.sort_by = '_aggregate_column'; this.report_view.sort_order = 'desc'; @@ -316,17 +307,14 @@ frappe.ui.GroupBy = class { '_aggregate_column', this.aggregate_on_doctype || this.doctype, ]); - args.fields.push(aggregate_column + ' as _aggregate_column'); - - if (aggregate_on_field) { - args.fields.push(aggregate_on_field); - } // setup columns in datatable this.report_view.setup_columns(); Object.assign(args, { with_comment_count: false, + aggregate_on: this.aggregate_on || 'name', + aggregate_function: this.aggregate_function || 'count', group_by: this.report_view.group_by || null, order_by: '_aggregate_column desc', });