diff --git a/cypress/integration/dashboard_chart.js b/cypress/integration/dashboard_chart.js new file mode 100644 index 0000000000..ae71fcda3a --- /dev/null +++ b/cypress/integration/dashboard_chart.js @@ -0,0 +1,22 @@ +context('Dashboard Chart', () => { + before(() => { + cy.login(); + cy.visit('/app/website'); + }); + + it('Check filter populate for child table doctype', () => { + cy.visit('/app/dashboard-chart/new-dashboard-chart-1'); + cy.get('[data-fieldname="parent_document_type"]').should('have.css', 'display', 'none'); + + cy.get_field('document_type', 'Link'); + cy.fill_field('document_type', 'Workspace Link', 'Link').focus().blur(); + cy.get_field('document_type', 'Link').should('have.value', 'Workspace Link'); + + cy.fill_field('chart_name', 'Test Chart', 'Data'); + + cy.get('[data-fieldname="filters_json"]').click().wait(200); + cy.get('.modal-body .filter-action-buttons .add-filter').click(); + cy.get('.modal-body .fieldname-select-area').click(); + cy.get('.modal-actions .btn-modal-close').click(); + }); +}); \ No newline at end of file diff --git a/frappe/desk/doctype/dashboard_chart/dashboard_chart.js b/frappe/desk/doctype/dashboard_chart/dashboard_chart.js index 635d32d969..e0d2cab8ef 100644 --- a/frappe/desk/doctype/dashboard_chart/dashboard_chart.js +++ b/frappe/desk/doctype/dashboard_chart/dashboard_chart.js @@ -45,6 +45,7 @@ frappe.ui.form.on('Dashboard Chart', { frm.set_df_property("filters_section", "hidden", 1); frm.set_df_property("dynamic_filters_section", "hidden", 1); + frm.trigger('set_parent_document_type'); frm.trigger('set_time_series'); frm.set_query('document_type', function() { return { @@ -110,9 +111,11 @@ frappe.ui.form.on('Dashboard Chart', { frm.set_value('source', ''); frm.set_value('based_on', ''); frm.set_value('value_based_on', ''); + frm.set_value('parent_document_type', ''); frm.set_value('filters_json', '[]'); frm.set_value('dynamic_filters_json', '[]'); frm.trigger('update_options'); + frm.trigger('set_parent_document_type'); }, report_name: function(frm) { @@ -125,7 +128,6 @@ frappe.ui.form.on('Dashboard Chart', { frm.trigger('set_chart_report_filters'); }, - set_chart_report_filters: function(frm) { let report_name = frm.doc.report_name; @@ -148,6 +150,10 @@ frappe.ui.form.on('Dashboard Chart', { } }, + use_report_chart: function(frm) { + !frm.doc.use_report_chart && frm.trigger('set_chart_field_options'); + }, + set_chart_field_options: function(frm) { let filters = frm.doc.filters_json.length > 2 ? JSON.parse(frm.doc.filters_json) : null; if (frm.doc.dynamic_filters_json && frm.doc.dynamic_filters_json.length > 2) { @@ -179,6 +185,9 @@ frappe.ui.form.on('Dashboard Chart', { } else { frappe.msgprint(__('Report has no data, please modify the filters or change the Report Name')); } + } else { + frm.set_value('use_report_chart', 1); + frm.set_df_property('use_report_chart', 'hidden', false); } }); }, @@ -365,6 +374,7 @@ frappe.ui.form.on('Dashboard Chart', { frm.filter_group = new frappe.ui.FilterGroup({ parent: dialog.get_field('filter_area').$wrapper, doctype: frm.doc.document_type, + parent_doctype: frm.doc.parent_document_type, on_change: () => {}, }); @@ -481,6 +491,36 @@ frappe.ui.form.on('Dashboard Chart', { frm.dynamic_filter_table.find('tbody').html(filter_rows); } + }, + + set_parent_document_type: async function(frm) { + let document_type = frm.doc.document_type; + let doc_is_table = document_type && + (await frappe.db.get_value('DocType', document_type, 'istable')).message.istable; + + frm.set_df_property('parent_document_type', 'hidden', !doc_is_table); + + if (document_type && doc_is_table) { + let parent = await frappe.db.get_list('DocField', { + filters: { + 'fieldtype': 'Table', + 'options': document_type + }, + fields: ['parent'] + }); + + parent && frm.set_query('parent_document_type', function() { + return { + filters: { + "name": ['in', parent.map(({ parent }) => parent)] + } + }; + }); + + if (parent.length === 1) { + frm.set_value('parent_document_type', parent[0].parent); + } + } } }); diff --git a/frappe/desk/doctype/dashboard_chart/dashboard_chart.json b/frappe/desk/doctype/dashboard_chart/dashboard_chart.json index d4bba53068..a5d30c10e5 100644 --- a/frappe/desk/doctype/dashboard_chart/dashboard_chart.json +++ b/frappe/desk/doctype/dashboard_chart/dashboard_chart.json @@ -17,6 +17,7 @@ "y_axis", "source", "document_type", + "parent_document_type", "based_on", "value_based_on", "group_by_type", @@ -268,10 +269,18 @@ "fieldname": "use_report_chart", "fieldtype": "Check", "label": "Use Report Chart" + }, + { + "depends_on": "eval: doc.chart_type !== 'Custom' && doc.chart_type !== 'Report'", + "description": "The document type selected is a child table, so the parent document type is required.", + "fieldname": "parent_document_type", + "fieldtype": "Link", + "label": "Parent Document Type", + "options": "DocType" } ], "links": [], - "modified": "2020-07-23 11:10:33.509497", + "modified": "2021-11-09 17:18:11.456145", "modified_by": "Administrator", "module": "Desk", "name": "Dashboard Chart", diff --git a/frappe/desk/doctype/dashboard_chart/dashboard_chart.py b/frappe/desk/doctype/dashboard_chart/dashboard_chart.py index 598b5e0b2b..cb77ef7a1a 100644 --- a/frappe/desk/doctype/dashboard_chart/dashboard_chart.py +++ b/frappe/desk/doctype/dashboard_chart/dashboard_chart.py @@ -333,7 +333,10 @@ class DashboardChart(Document): def check_required_field(self): 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.document_type and frappe.get_meta(self.document_type).istable and not self.parent_document_type: + frappe.throw(_("Parent document type is required to create a dashboard chart")) if self.chart_type == 'Group By': if not self.group_by_based_on: diff --git a/frappe/public/js/frappe/ui/filters/field_select.js b/frappe/public/js/frappe/ui/filters/field_select.js index fdedc1d8aa..0bdb9085f0 100644 --- a/frappe/public/js/frappe/ui/filters/field_select.js +++ b/frappe/public/js/frappe/ui/filters/field_select.js @@ -112,8 +112,11 @@ frappe.ui.FieldSelect = class FieldSelect { // main table var main_table_fields = std_filters.concat(frappe.meta.docfield_list[me.doctype]); $.each(frappe.utils.sort(main_table_fields, "label", "string"), function(i, df) { + let doctype = frappe.get_meta(me.doctype).istable && me.parent_doctype ? + me.parent_doctype : me.doctype; + // show fields where user has read access and if report hide flag is not set - if(frappe.perm.has_perm(me.doctype, df.permlevel, "read")) + if (frappe.perm.has_perm(doctype, df.permlevel, "read")) me.add_field_option(df); }); @@ -129,8 +132,11 @@ frappe.ui.FieldSelect = class FieldSelect { } $.each(frappe.utils.sort(child_table_fields, "label", "string"), function(i, df) { + let doctype = frappe.get_meta(me.doctype).istable && me.parent_doctype ? + me.parent_doctype : me.doctype; + // show fields where user has read access and if report hide flag is not set - if(frappe.perm.has_perm(me.doctype, df.permlevel, "read")) + if (frappe.perm.has_perm(doctype, df.permlevel, "read")) me.add_field_option(df); }); } diff --git a/frappe/public/js/frappe/ui/filters/filter.js b/frappe/public/js/frappe/ui/filters/filter.js index 2151e66236..f5726d3a29 100644 --- a/frappe/public/js/frappe/ui/filters/filter.js +++ b/frappe/public/js/frappe/ui/filters/filter.js @@ -80,6 +80,7 @@ frappe.ui.Filter = class { this.fieldselect = new frappe.ui.FieldSelect({ parent: this.filter_edit_area.find('.fieldname-select-area'), doctype: this.parent_doctype, + parent_doctype: this._parent_doctype, filter_fields: this.filter_fields, input_class: 'input-xs', select: (doctype, fieldname) => { diff --git a/frappe/public/js/frappe/ui/filters/filter_list.js b/frappe/public/js/frappe/ui/filters/filter_list.js index 72312d7f13..18499a3b7e 100644 --- a/frappe/public/js/frappe/ui/filters/filter_list.js +++ b/frappe/public/js/frappe/ui/filters/filter_list.js @@ -201,6 +201,7 @@ frappe.ui.FilterGroup = class { parent: this.wrapper, parent_doctype: this.doctype, doctype: doctype, + _parent_doctype: this.parent_doctype, fieldname: fieldname, condition: condition, value: value, diff --git a/frappe/public/js/frappe/utils/utils.js b/frappe/public/js/frappe/utils/utils.js index 2baff996c6..2dbad5427d 100644 --- a/frappe/public/js/frappe/utils/utils.js +++ b/frappe/public/js/frappe/utils/utils.js @@ -1369,5 +1369,12 @@ Object.assign(frappe.utils, { sleep(time) { return new Promise((resolve) => setTimeout(resolve, time)); + }, + + parse_array(array) { + if (array && array.length !== 0) { + return array; + } + return undefined; } }); diff --git a/frappe/public/js/frappe/views/reports/report_utils.js b/frappe/public/js/frappe/views/reports/report_utils.js index a9a727c4f9..f458a4daf6 100644 --- a/frappe/public/js/frappe/views/reports/report_utils.js +++ b/frappe/public/js/frappe/views/reports/report_utils.js @@ -121,7 +121,7 @@ frappe.report_utils = { ).then(r => { frappe.dom.eval(r.script || ''); return frappe.after_ajax(() => { - return frappe.query_reports[report_name].filters; + return frappe.query_reports[report_name] && frappe.query_reports[report_name].filters; }) }); }, diff --git a/frappe/public/js/frappe/widgets/chart_widget.js b/frappe/public/js/frappe/widgets/chart_widget.js index 47b1f2ff58..ec602b8522 100644 --- a/frappe/public/js/frappe/widgets/chart_widget.js +++ b/frappe/public/js/frappe/widgets/chart_widget.js @@ -455,6 +455,7 @@ export default class ChartWidget extends Widget { create_filter_group_and_add_filters() { this.filter_group = new frappe.ui.FilterGroup({ doctype: this.chart_doc.document_type, + parent_doctype: this.chart_doc.parent_document_type, filter_button: this.filter_button, on_change: () => { this.filters = this.filter_group.get_filters(); @@ -697,11 +698,13 @@ export default class ChartWidget extends Widget { .get_filters_for_chart_type(this.chart_doc).then(filters => { chart_saved_filters = this.update_default_date_filters(filters, chart_saved_filters); this.filters = - user_saved_filters || this.filters || chart_saved_filters; + frappe.utils.parse_array(user_saved_filters) || frappe.utils.parse_array(this.filters) + || frappe.utils.parse_array(chart_saved_filters); }); } else { this.filters = - user_saved_filters || this.filters || chart_saved_filters; + frappe.utils.parse_array(user_saved_filters) || frappe.utils.parse_array(this.filters) + || frappe.utils.parse_array(chart_saved_filters); return Promise.resolve(); } }