From 8e413651c2b4cfc9c7754a482f353996393cd507 Mon Sep 17 00:00:00 2001 From: casesolved-co-uk Date: Wed, 24 Mar 2021 02:56:30 +0000 Subject: [PATCH] fix: major refactor to monkey-patch into the QueryReport class --- .../accounts/report/tax_detail/tax_detail.js | 300 +++++++++--------- 1 file changed, 153 insertions(+), 147 deletions(-) diff --git a/erpnext/accounts/report/tax_detail/tax_detail.js b/erpnext/accounts/report/tax_detail/tax_detail.js index 8cdce54852..6049000404 100644 --- a/erpnext/accounts/report/tax_detail/tax_detail.js +++ b/erpnext/accounts/report/tax_detail/tax_detail.js @@ -3,6 +3,8 @@ // Contributed by Case Solved and sponsored by Nulight Studios /* eslint-disable */ +frappe.provide('frappe.query_reports'); + frappe.query_reports["Tax Detail"] = { filters: [ { @@ -50,83 +52,124 @@ frappe.query_reports["Tax Detail"] = { // Remove Add Column and Save from menu report.page.add_inner_button(__("New Report"), () => new_report(), __("Custom Report")); report.page.add_inner_button(__("Load Report"), () => load_report(), __("Custom Report")); - hide_filters(); - }, - after_datatable_render: (datatable) => { - if (frappe.query_report.report_name == 'Tax Detail') { - return; - } - if (this.taxreport) { - this.taxreport.load_report(); - } else { - this.taxreport = new TaxReport(); - } + hide_filters(report); } }; -function hide_filters() { - frappe.query_report.page.page_form[0].querySelectorAll('.form-group.frappe-control').forEach(function setHidden(field) { +function hide_filters(report) { + report.page.page_form[0].querySelectorAll('.form-group.frappe-control').forEach(function setHidden(field) { if (field.dataset.fieldtype == "Read Only") { field.classList.add("hidden"); } }); } -class TaxReport { - // construct after datatable is loaded +erpnext.TaxDetail = class TaxDetail { constructor() { - this.qr = frappe.query_report; - this.page = frappe.query_report.page; - this.create_controls(); + this.patch(); this.load_report(); } - load_report() { - if (this.loaded) { - return; + // Monkey patch the QueryReport class + patch() { + this.qr = frappe.query_report; + this.super = { + refresh_report: this.qr.refresh_report, + show_footer_message: this.qr.show_footer_message } - const report_name = this.qr.report_name; - this.report_name.value = report_name; - frappe.call({ - method: 'erpnext.accounts.report.tax_detail.tax_detail.get_custom_reports', - args: {name: report_name}, - freeze: true - }).then((r) => { - const data = JSON.parse(r.message[report_name]['json']); - this.sections = data.sections || {}; - this.controls['show_detail'].set_input(data.show_detail); - this.set_section(); - }) - this.loaded = 1; + this.qr.refresh_report = () => this.refresh_report(); + this.qr.show_footer_message = () => this.show_footer_message(); + } + show_footer_message() { + // The last thing to run after datatable_render in refresh() + console.log('show_footer_message'); + this.super.show_footer_message.apply(this.qr); + if (this.qr.report_name !== 'Tax Detail') { + this.set_value_options(); + this.show_help(); + if (this.loading) { + this.set_section(''); + } + this.reload_filter(); + } + this.loading = false; + } + refresh_report() { + // Infrequent report build (onload), load filters & data + // super function runs a refresh() serially + // already run within frappe.run_serially + console.log('refresh_report'); + this.loading = true; + this.super.refresh_report.apply(this.qr); + if (this.qr.report_name !== 'Tax Detail') { + frappe.call({ + method: 'erpnext.accounts.report.tax_detail.tax_detail.get_custom_reports', + args: {name: this.qr.report_name} + }).then((r) => { + const data = JSON.parse(r.message[this.qr.report_name]['json']); + this.create_controls(); + this.sections = data.sections || {}; + this.controls['show_detail'].set_input(data.show_detail); + }); + } + } + load_report() { + // One-off report build like titles, menu, etc + // Run when this object is created which happens in qr.load_report + console.log('load_report'); + this.qr.menu_items = this.get_menu_items(); + } + get_menu_items() { + // Replace save button + let new_items = []; + const label = __('Save'); + + for (let item of this.qr.menu_items) { + if (item.label === label) { + new_items.push({ + label: label, + action: this.save_report, + standard: false + }); + } else { + new_items.push(item); + } + } + return new_items; } save_report() { - frappe.call({ - method:'erpnext.accounts.report.tax_detail.tax_detail.save_custom_report', - args: { - reference_report: 'Tax Detail', - report_name: this.qr.report_name, - data: { - columns: this.qr.get_visible_columns(), - sections: this.sections, - show_detail: this.controls['show_detail'].get_input_value() - } - }, - freeze: true - }).then((r) => { - this.reload(); - }); + if (this.qr.report_name !== 'Tax Detail') { + frappe.call({ + method:'erpnext.accounts.report.tax_detail.tax_detail.save_custom_report', + args: { + reference_report: 'Tax Detail', + report_name: this.qr.report_name, + data: { + columns: this.qr.get_visible_columns(), + sections: this.sections, + show_detail: this.controls['show_detail'].get_input_value() + } + }, + freeze: true + }).then((r) => { + this.set_section(''); + }); + } } set_value_options() { - this.fieldname_lookup = {}; - this.label_lookup = {}; - this.qr.columns.forEach((col, index) => { - if (col['fieldtype'] == "Currency") { - this.fieldname_lookup[col['label']] = col['fieldname']; - this.label_lookup[col['fieldname']] = col['label']; - } - }); - const options = Object.keys(this.fieldname_lookup); - this.controls['value_field'].$wrapper.find("select").empty().add_options(options); - this.controls['value_field'].set_input(options[0]); + // May be run with no columns or data + if (this.qr.columns) { + this.fieldname_lookup = {}; + this.label_lookup = {}; + this.qr.columns.forEach((col, index) => { + if (col['fieldtype'] == "Currency") { + this.fieldname_lookup[col['label']] = col['fieldname']; + this.label_lookup[col['fieldname']] = col['label']; + } + }); + const options = Object.keys(this.fieldname_lookup); + this.controls['value_field'].$wrapper.find("select").empty().add_options(options); + this.controls['value_field'].set_input(options[0]); + } } set_value_label_from_filter() { const section_name = this.controls['section_name'].value; @@ -158,46 +201,38 @@ class TaxReport { }); dialog.show(); } - get_filter_controls() { - this.qr.filters.forEach(filter => { - if (filter['fieldname'] == 'mode') { - this.mode = filter; - } - if (filter['fieldname'] == 'report_name') { - this.report_name = filter; - } - }); - } - set_mode(mode) { - this.mode.value = mode; - } - edit_mode() { - return this.mode.value == 'edit'; - } set_section(name) { + // Sets the given section name and then reloads the data if (name && !this.sections[name]) { this.sections[name] = {}; } let options = Object.keys(this.sections); options.unshift(''); this.controls['section_name'].$wrapper.find("select").empty().add_options(options); + const org_mode = this.qr.get_filter_value('mode'); + let refresh = false; if (name) { this.controls['section_name'].set_input(name); + this.qr.set_filter_value('mode', 'edit'); + if (org_mode === 'run') { + refresh = true; + } } else { this.controls['section_name'].set_input(''); + this.qr.set_filter_value('mode', 'run'); + if (org_mode === 'edit') { + refresh = true; + } } - if (this.controls['section_name'].value) { - this.set_mode('edit'); - } else { - this.set_mode('run'); + this.reload_filter(); + if (refresh) { + this.qr.refresh(); } - this.controls['filter_index'].set_input(''); - this.reload(); } reload_filter() { - const section_name = this.controls['section_name'].value; + const section_name = this.controls['section_name'].get_input_value(); if (section_name) { - let fidx = this.controls['filter_index'].value; + let fidx = this.controls['filter_index'].get_input_value(); let section = this.sections[section_name]; let fidxs = Object.keys(section); fidxs.unshift(''); @@ -207,17 +242,16 @@ class TaxReport { this.controls['filter_index'].$wrapper.find("select").empty(); this.controls['filter_index'].set_input(''); } - this.set_filters(); + this.set_table_filters(); } - set_filters() { + set_table_filters() { let filters = {}; - const section_name = this.controls['section_name'].value; - const fidx = this.controls['filter_index'].value; + const section_name = this.controls['section_name'].get_input_value(); + const fidx = this.controls['filter_index'].get_input_value(); if (section_name && fidx) { filters = this.sections[section_name][fidx]['filters']; } this.setAppliedFilters(filters); - this.qr.datatable.columnmanager.applyFilter(filters); this.set_value_label_from_filter(); } setAppliedFilters(filters) { @@ -229,32 +263,20 @@ class TaxReport { input.value = null; } }); - } - reload() { - // Reloads the data. When the datatable is reloaded, load_report() - // will be run by the after_datatable_render event. - // TODO: why does this trigger multiple reloads? - this.qr.refresh(); - this.show_help(); - if (this.edit_mode()) { - this.reload_filter(); - } else { - this.controls['filter_index'].$wrapper.find("select").empty(); - } + this.qr.datatable.columnmanager.applyFilter(filters); } delete(name, type) { if (type === 'section') { delete this.sections[name]; - this.controls['section_name'].$wrapper.find("select").empty().add_options(Object.keys(this.sections)); - this.controls['section_name'].set_input(Object.keys(this.sections)[0] || ''); - this.controls['filter_index'].set_input(''); + const new_section = Object.keys(this.sections)[0] || ''; + this.set_section(new_section); } if (type === 'filter') { - let cur_section = this.controls['section_name'].value; + const cur_section = this.controls['section_name'].get_input_value(); delete this.sections[cur_section][name]; this.controls['filter_index'].set_input(''); + this.reload_filter(); } - this.reload(); } create_controls() { if (this.controls) { @@ -262,7 +284,7 @@ class TaxReport { } let controls = {}; // SELECT in data.js - controls['section_name'] = this.page.add_field({ + controls['section_name'] = this.qr.page.add_field({ label: __('Section'), fieldtype: 'Select', fieldname: 'section_name', @@ -271,7 +293,7 @@ class TaxReport { } }); // BUTTON in button.js - controls['new_section'] = this.page.add_field({ + controls['new_section'] = this.qr.page.add_field({ label: __('New Section'), fieldtype: 'Button', fieldname: 'new_section', @@ -279,33 +301,33 @@ class TaxReport { this.new_section(__('New Section')); } }); - controls['delete_section'] = this.page.add_field({ + controls['delete_section'] = this.qr.page.add_field({ label: __('Delete Section'), fieldtype: 'Button', fieldname: 'delete_section', click: () => { - let cur_section = this.controls['section_name'].value; + let cur_section = this.controls['section_name'].get_input_value(); if (cur_section) { frappe.confirm(__('Are you sure you want to delete section ') + cur_section + '?', () => {this.delete(cur_section, 'section')}); } } }); - controls['filter_index'] = this.page.add_field({ + controls['filter_index'] = this.qr.page.add_field({ label: __('Filter'), fieldtype: 'Select', fieldname: 'filter_index', change: (e) => { this.controls['filter_index'].set_input(this.controls['filter_index'].get_input_value()); - this.set_filters(); + this.set_table_filters(); } }); - controls['add_filter'] = this.page.add_field({ + controls['add_filter'] = this.qr.page.add_field({ label: __('Add Filter'), fieldtype: 'Button', fieldname: 'add_filter', click: () => { - let section_name = this.controls['section_name'].value; + let section_name = this.controls['section_name'].get_input_value(); if (section_name) { let prefix = 'Filter'; let data = { @@ -326,19 +348,19 @@ class TaxReport { } } }); - controls['delete_filter'] = this.page.add_field({ + controls['delete_filter'] = this.qr.page.add_field({ label: __('Delete Filter'), fieldtype: 'Button', fieldname: 'delete_filter', click: () => { - let cur_filter = this.controls['filter_index'].value; + let cur_filter = this.controls['filter_index'].get_input_value(); if (cur_filter) { frappe.confirm(__('Are you sure you want to delete filter ') + cur_filter + '?', () => {this.delete(cur_filter, 'filter')}); } } }); - controls['value_field'] = this.page.add_field({ + controls['value_field'] = this.qr.page.add_field({ label: __('Value Column'), fieldtype: 'Select', fieldname: 'value_field', @@ -346,37 +368,35 @@ class TaxReport { this.controls['value_field'].set_input(this.controls['value_field'].get_input_value()); } }); - controls['save'] = this.page.add_field({ + controls['save'] = this.qr.page.add_field({ label: __('Save & Run'), fieldtype: 'Button', fieldname: 'save', click: () => { - this.controls['section_name'].set_input(''); - this.set_mode('run'); this.save_report(); } }); - controls['show_detail'] = this.page.add_field({ + controls['show_detail'] = this.qr.page.add_field({ label: __('Show Detail'), fieldtype: 'Check', fieldname: 'show_detail', default: 1 }); this.controls = controls; - this.set_value_options(); - this.get_filter_controls(); - this.show_help(); } show_help() { const help = __(`You can add multiple sections to your custom report using the New Section button above. - To specify what data goes in each section, specify column filters below, then save with Add Filter. - Each section can have multiple filters added. - You can specify which Currency column will be summed for each filter in the final report with the Value Column select box. - Once you're done, hit Save & Run.`); - this.qr.show_status(help); + To specify what data goes in each section, specify column filters in the data table, then save with Add Filter. + Each section can have multiple filters added but be careful with the duplicated data rows. + You can specify which Currency column will be summed for each filter in the final report with the Value Column + select box. Once you're done, hit Save & Run.`); + this.qr.$report_footer.append(`
${help}
`); } } +if (!window.taxdetail) { + window.taxdetail = new erpnext.TaxDetail(); +} function get_reports(cb) { frappe.call({ @@ -387,23 +407,9 @@ function get_reports(cb) { }) } -function override_menu() { - //TODO: Replace save button - this.qr.menu_items.forEach((item, idx) => { - if (item['label'] == __('Save')) { - delete this.qr.menu_items[idx]; - } - }) - this.qr.menu_items.push({ - label: __('Save'), - action: this.save_report - }) - this.qr.set_menu_items(); -} - function new_report() { const dialog = new frappe.ui.Dialog({ - title: __("New Report"), + title: __('New Report'), fields: [ { fieldname: 'report_name', @@ -424,7 +430,7 @@ function new_report() { }, freeze: true }).then((r) => { - frappe.set_route("query-report", values.report_name); + frappe.set_route('query-report', values.report_name); }); dialog.hide(); } @@ -435,7 +441,7 @@ function new_report() { function load_report() { get_reports(function load_report_cb(reports) { const dialog = new frappe.ui.Dialog({ - title: __("Load Report"), + title: __('Load Report'), fields: [ { fieldname: 'report_name', @@ -447,7 +453,7 @@ function load_report() { primary_action_label: __('Load'), primary_action: function load_report_pa(values) { dialog.hide(); - frappe.set_route("query-report", values.report_name); + frappe.set_route('query-report', values.report_name); } }); dialog.show();