diff --git a/frappe/public/js/form_builder/components/Field.vue b/frappe/public/js/form_builder/components/Field.vue index 6dd5e6b5ed..80c8ba5d8d 100644 --- a/frappe/public/js/form_builder/components/Field.vue +++ b/frappe/public/js/form_builder/components/Field.vue @@ -92,11 +92,12 @@ function make_dialog(frm) { filter.pop(); // filter_group component requires options and frm.set_query requires fieldname so storing both - filter[0] = { fieldname, field_option }; + filter[0] = field_option; return filter; }); props.field.df.link_filters = JSON.stringify(filters); + store.form.selected_field = props.field.df; frm.dialog.hide(); }, primary_action_label: __("Apply"), @@ -133,11 +134,6 @@ function make_dialog(frm) { } }); } - - // Setting selected field in store because when we click on the dialog the selected field is set to null - frm.dialog.$wrapper.on("click", () => { - store.form.selected_field = props.field.df; - }); } function make_filter_area(frm, doctype) { @@ -151,10 +147,6 @@ function make_filter_area(frm, doctype) { function add_existing_filter(frm, df) { if (df.link_filters) { let filters = JSON.parse(df.link_filters); - filters.map((filter) => { - // filter_group component requires options and frm.set_query requires fieldname - filter[0] = filter[0].field_option; - }); if (filters) { frm.filter_group.add_filters_to_filter_group(filters); } diff --git a/frappe/public/js/frappe/form/controls/link.js b/frappe/public/js/frappe/form/controls/link.js index 51eb63e88d..7cae8684e8 100644 --- a/frappe/public/js/frappe/form/controls/link.js +++ b/frappe/public/js/frappe/form/controls/link.js @@ -509,6 +509,12 @@ frappe.ui.form.ControlLink = class ControlLink extends frappe.ui.form.ControlDat }); return obj; }; + + // apply link field filters + if (this.df.link_filters && !!this.df.link_filters.length) { + this.apply_link_field_filters(); + } + if (this.get_query || this.df.get_query) { var get_query = this.get_query || this.df.get_query; if ($.isPlainObject(get_query)) { @@ -571,6 +577,38 @@ frappe.ui.form.ControlLink = class ControlLink extends frappe.ui.form.ControlDat $.extend(args.filters, this.df.filters); } } + + apply_link_field_filters() { + let link_filters = JSON.parse(this.df.link_filters); + let filters = this.parse_filters(link_filters); + // take filters from the link field and add to the query + this.get_query = function () { + return { + filters, + }; + }; + } + + parse_filters(link_filters) { + let filters = {}; + link_filters.forEach((filter) => { + let [_, fieldname, operator, value] = filter; + value = String(value).replace(/%/g, ""); + if (value.startsWith("eval:")) { + // get the value to calculate + value = value.split("eval:")[1]; + let context = { + doc: this.doc, + parent: this.doc.parenttype ? this.frm.doc : null, + frappe, + }; + value = frappe.utils.eval(value, context); + } + filters[fieldname] = [operator, value]; + }); + return filters; + } + validate(value) { // validate the value just entered if (this._validated || this.df.options == "[Select]" || this.df.ignore_link_validation) { diff --git a/frappe/public/js/frappe/form/form.js b/frappe/public/js/frappe/form/form.js index 69a7c6e366..b17c84df3d 100644 --- a/frappe/public/js/frappe/form/form.js +++ b/frappe/public/js/frappe/form/form.js @@ -107,7 +107,6 @@ frappe.ui.form.Form = class FrappeForm { // 2 column layout this.setup_std_layout(); - this.setup_filters(); // client script must be called after "setup" - there are no fields_dict attached to the frm otherwise this.script_manager = new frappe.ui.form.ScriptManager({ @@ -273,41 +272,6 @@ frappe.ui.form.Form = class FrappeForm { }); } - setup_filters() { - let fields_with_filters = frappe - .get_meta(this.doctype) - .fields.filter((field) => field.link_filters) - .map((field) => JSON.parse(field.link_filters)); - if (fields_with_filters.length === 0) return; - fields_with_filters = this.parse_filters(fields_with_filters); - for (let link_field in fields_with_filters) { - const filters = fields_with_filters[link_field]; - this.set_query(link_field, () => filters); - } - } - - parse_filters(data) { - const parsed_data = {}; - - for (const d of data) { - for (const condition of d) { - let [doctype, field, operator, value] = condition; - doctype = doctype.fieldname; - if (!parsed_data[doctype]) { - parsed_data[doctype] = { - filters: {}, - }; - } - - if (!parsed_data[doctype].filters[field]) { - parsed_data[doctype].filters[field] = [operator, value]; - } - } - } - - return parsed_data; - } - watch_model_updates() { // watch model updates var me = this;