diff --git a/frappe/core/doctype/report/report.json b/frappe/core/doctype/report/report.json index 4c8b77de5f..a26bc3164f 100644 --- a/frappe/core/doctype/report/report.json +++ b/frappe/core/doctype/report/report.json @@ -21,6 +21,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "report_name", "fieldtype": "Data", "hidden": 0, @@ -52,6 +53,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "ref_doctype", "fieldtype": "Link", "hidden": 0, @@ -84,6 +86,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "is_standard", "fieldtype": "Select", "hidden": 0, @@ -116,6 +119,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "module", "fieldtype": "Link", "hidden": 0, @@ -148,6 +152,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "add_total_row", "fieldtype": "Check", "hidden": 0, @@ -179,6 +184,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "column_break_4", "fieldtype": "Column Break", "hidden": 0, @@ -209,6 +215,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "report_type", "fieldtype": "Select", "hidden": 0, @@ -241,6 +248,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "disabled", "fieldtype": "Check", "hidden": 0, @@ -272,6 +280,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "icon", "fieldtype": "Data", "hidden": 0, @@ -304,6 +313,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "color", "fieldtype": "Data", "hidden": 0, @@ -337,6 +347,7 @@ "collapsible": 0, "columns": 0, "depends_on": "eval: doc.is_standard == \"No\"", + "fetch_if_empty": 0, "fieldname": "letter_head", "fieldtype": "Link", "hidden": 0, @@ -370,6 +381,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "section_break_6", "fieldtype": "Section Break", "hidden": 0, @@ -401,6 +413,7 @@ "collapsible": 0, "columns": 0, "depends_on": "eval:doc.report_type==\"Query Report\"", + "fetch_if_empty": 0, "fieldname": "query", "fieldtype": "Code", "hidden": 0, @@ -434,6 +447,7 @@ "columns": 0, "depends_on": "", "description": "JavaScript Format: frappe.query_reports['REPORTNAME'] = {}", + "fetch_if_empty": 0, "fieldname": "javascript", "fieldtype": "Code", "hidden": 1, @@ -466,6 +480,7 @@ "collapsible": 0, "columns": 0, "depends_on": "eval:doc.report_type==\"Report Builder\"", + "fetch_if_empty": 0, "fieldname": "json", "fieldtype": "Code", "hidden": 0, @@ -497,6 +512,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "permission_rules", "fieldtype": "Section Break", "hidden": 0, @@ -530,6 +546,7 @@ "collapsible": 0, "columns": 0, "depends_on": "eval:doc.is_standard == 'Yes'", + "fetch_if_empty": 0, "fieldname": "roles", "fieldtype": "Table", "hidden": 0, @@ -563,6 +580,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "disable_prepared_report", "fieldtype": "Check", "hidden": 0, @@ -595,6 +613,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "prepared_report", "fieldtype": "Check", "hidden": 1, @@ -633,7 +652,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2019-01-25 12:04:50.833264", + "modified": "2019-04-07 20:32:30.943582", "modified_by": "Administrator", "module": "Core", "name": "Report", diff --git a/frappe/desk/query_report.py b/frappe/desk/query_report.py index 7ec767c227..5790c42878 100644 --- a/frappe/desk/query_report.py +++ b/frappe/desk/query_report.py @@ -353,6 +353,14 @@ def add_total_row(result, columns, meta = None): result.append(total_row) return result +@frappe.whitelist() +def get_data_for_custom_field(doctype, field): + + value_map = frappe._dict(frappe.get_all(doctype, + fields=["name", field], + as_list=1)) + + return value_map def get_filtered_data(ref_doctype, columns, data, user): result = [] diff --git a/frappe/public/js/frappe/views/reports/query_report.js b/frappe/public/js/frappe/views/reports/query_report.js index 596a6501ad..de4bd03e75 100644 --- a/frappe/public/js/frappe/views/reports/query_report.js +++ b/frappe/public/js/frappe/views/reports/query_report.js @@ -321,7 +321,6 @@ frappe.views.QueryReport = class QueryReport extends frappe.views.BaseList { this.add_prepared_report_buttons(data.doc); } this.toggle_message(false); - if (data.result && data.result.length) { this.prepare_report_data(data); @@ -418,12 +417,13 @@ frappe.views.QueryReport = class QueryReport extends frappe.views.BaseList { this.raw_data = data; this.columns = this.prepare_columns(data.columns); this.data = this.prepare_data(data.result); - + this.linked_doctypes = this.get_linked_doctypes(); this.tree_report = this.data.some(d => 'indent' in d); } render_datatable() { let data = this.data; + if (this.raw_data.add_total_row) { data = data.slice(); data.splice(-1, 1); @@ -962,6 +962,69 @@ frappe.views.QueryReport = class QueryReport extends frappe.views.BaseList { action: () => frappe.set_route('List', 'Auto Email Report', {'report' : this.report_name}), standard: true }, + { + label: __('Add Column'), + action: () => { + let d = new frappe.ui.Dialog({ + title: __('Add Column'), + fields: [ + { + fieldtype: 'Select', + fieldname: 'doctype', + label: __('From Document Type'), + options: this.linked_doctypes.map(df => ({ label: df.doctype, value: df.doctype })), + change: () => { + let doctype = d.get_value('doctype'); + frappe.model.with_doctype(doctype, () => { + let fields = frappe.meta.get_docfields(doctype) + .map(df => ({ label: df.label, value: df.fieldname })); + d.set_df_property('field', 'options', fields); + + }); + } + }, + { + fieldtype: 'Select', + label: __('Field'), + fieldname: 'field', + options: [] + }, + { + fieldtype: 'Select', + label: __('Insert After'), + fieldname: 'insert_after', + options: this.columns.map(df => df.label) + } + ], + primary_action: (values) => { + const custom_columns = []; + let df = frappe.meta.get_docfield(values.doctype, values.field); + custom_columns.push({ + fieldname: df.fieldname, + fieldtype: df.fieldtype, + label: df.label, + width: 100 + }); + frappe.call({ + method: 'frappe.desk.query_report.get_data_for_custom_field', + args: { + field: values.field, + doctype: values.doctype + }, + callback: (r) => { + const custom_data = r.message; + const link_field = this.doctype_field_map[values.doctype]; + this.add_custom_column(custom_columns, custom_data, link_field, values.field, values.insert_after); + d.hide(); + } + }); + } + }) + + d.show(); + }, + standard: true + }, { label: __('User Permissions'), action: () => frappe.set_route('List', 'User Permission', { @@ -979,6 +1042,64 @@ frappe.views.QueryReport = class QueryReport extends frappe.views.BaseList { ]; } + add_custom_column(custom_column, custom_data, link_field, column_field, insert_after) { + const column = this.prepare_columns(custom_column); + + const insert_after_index = this.columns + .findIndex(column => column.label === insert_after); + this.columns.splice(insert_after_index + 1, 0, column[0]); + + this.data.forEach(row => { + row[column_field] = custom_data[row[link_field]]; + }); + + this.render_datatable(); + } + + get_linked_doctypes() { + let doctypes = []; + let dynamic_links = []; + let dynamic_doctypes = new Set(); + this.doctype_field_map = {}; + + this.columns.forEach(df => { + if (df.fieldtype == "Link" && df.options && df.options != "Currency") { + doctypes.push({ + doctype: df.options, + fieldname: df.fieldname + }); + } + else if (df.fieldtype == "Dynamic Link" && df.options) { + dynamic_links.push({ + link_name: df.options, + fieldname: df.fieldname + }); + } + }); + + this.data.forEach(row => { + dynamic_links.forEach(field => { + if (row[field.link_name]){ + dynamic_doctypes.add(row[field.link_name] + ":" + field.fieldname); + } + }); + }); + + doctypes = doctypes.concat(Array.from(dynamic_doctypes).map(d => { + const doc_field_pair = d.split(":"); + return { + doctype: doc_field_pair[0], + fieldname: doc_field_pair[1] + }; + })); + + doctypes.forEach(doc => { + this.doctype_field_map[doc.doctype] = doc.fieldname; + }); + + return doctypes; + } + setup_report_wrapper() { if (this.$report) return; @@ -1017,9 +1138,9 @@ frappe.views.QueryReport = class QueryReport extends frappe.views.BaseList { ${__('Collapse All')} `); this.page.footer.before(this.$tree_footer); + this.$tree_footer.find('[data-action=collapse_all_rows]').show(); + this.$tree_footer.find('[data-action=expand_all_rows]').hide(); } - this.$tree_footer.find('[data-action=collapse_all_rows]').show(); - this.$tree_footer.find('[data-action=expand_all_rows]').hide(); } expand_all_rows() {