Merge pull request #7225 from deepeshgarg007/custom-reports

feat: Allow user to add fields in query reports
This commit is contained in:
Faris Ansari 2019-04-10 16:12:12 +05:30 committed by GitHub
commit 8d7682ecd7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 153 additions and 5 deletions

View file

@ -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",

View file

@ -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 = []

View file

@ -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')}</button>
</div>`);
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() {