From 3fcd8d84acfa8aac0e4e01b860e153a1c3aa1f29 Mon Sep 17 00:00:00 2001 From: l0gesh29 Date: Fri, 31 Oct 2025 14:00:37 +0530 Subject: [PATCH 1/2] feat: modify accounting dimension as multiselect field --- .../accounts_payable/accounts_payable.js | 15 +++++------- .../accounts_payable_summary.js | 15 +++++------- .../accounts_receivable.js | 15 +++++------- .../accounts_receivable_summary.js | 15 +++++------- .../report/trial_balance/trial_balance.js | 23 ++++++++++--------- 5 files changed, 36 insertions(+), 47 deletions(-) diff --git a/erpnext/accounts/report/accounts_payable/accounts_payable.js b/erpnext/accounts/report/accounts_payable/accounts_payable.js index 1f974a16f95..0562b0da86f 100644 --- a/erpnext/accounts/report/accounts_payable/accounts_payable.js +++ b/erpnext/accounts/report/accounts_payable/accounts_payable.js @@ -26,16 +26,13 @@ frappe.query_reports["Accounts Payable"] = { { fieldname: "cost_center", label: __("Cost Center"), - fieldtype: "Link", - options: "Cost Center", - get_query: () => { - var company = frappe.query_report.get_filter_value("company"); - return { - filters: { - company: company, - }, - }; + fieldtype: "MultiSelectList", + get_data: function (txt) { + return frappe.db.get_link_options("Cost Center", txt, { + company: frappe.query_report.get_filter_value("company"), + }); }, + options: "Cost Center", }, { fieldname: "party_account", diff --git a/erpnext/accounts/report/accounts_payable_summary/accounts_payable_summary.js b/erpnext/accounts/report/accounts_payable_summary/accounts_payable_summary.js index ac9d5bfbd01..18a85af95be 100644 --- a/erpnext/accounts/report/accounts_payable_summary/accounts_payable_summary.js +++ b/erpnext/accounts/report/accounts_payable_summary/accounts_payable_summary.js @@ -45,16 +45,13 @@ frappe.query_reports["Accounts Payable Summary"] = { { fieldname: "cost_center", label: __("Cost Center"), - fieldtype: "Link", - options: "Cost Center", - get_query: () => { - var company = frappe.query_report.get_filter_value("company"); - return { - filters: { - company: company, - }, - }; + fieldtype: "MultiSelectList", + get_data: function (txt) { + return frappe.db.get_link_options("Cost Center", txt, { + company: frappe.query_report.get_filter_value("company"), + }); }, + options: "Cost Center", }, { fieldname: "party_type", diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.js b/erpnext/accounts/report/accounts_receivable/accounts_receivable.js index fa2467b526d..ddee9c6b6b0 100644 --- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.js +++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.js @@ -28,16 +28,13 @@ frappe.query_reports["Accounts Receivable"] = { { fieldname: "cost_center", label: __("Cost Center"), - fieldtype: "Link", - options: "Cost Center", - get_query: () => { - var company = frappe.query_report.get_filter_value("company"); - return { - filters: { - company: company, - }, - }; + fieldtype: "MultiSelectList", + get_data: function (txt) { + return frappe.db.get_link_options("Cost Center", txt, { + company: frappe.query_report.get_filter_value("company"), + }); }, + options: "Cost Center", }, { fieldname: "party_type", diff --git a/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.js b/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.js index ae0bddaa766..1ac2b27ca71 100644 --- a/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.js +++ b/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.js @@ -45,16 +45,13 @@ frappe.query_reports["Accounts Receivable Summary"] = { { fieldname: "cost_center", label: __("Cost Center"), - fieldtype: "Link", - options: "Cost Center", - get_query: () => { - var company = frappe.query_report.get_filter_value("company"); - return { - filters: { - company: company, - }, - }; + fieldtype: "MultiSelectList", + get_data: function (txt) { + return frappe.db.get_link_options("Cost Center", txt, { + company: frappe.query_report.get_filter_value("company"), + }); }, + options: "Cost Center", }, { fieldname: "party_type", diff --git a/erpnext/accounts/report/trial_balance/trial_balance.js b/erpnext/accounts/report/trial_balance/trial_balance.js index e91073a962c..b86f6ab75e0 100644 --- a/erpnext/accounts/report/trial_balance/trial_balance.js +++ b/erpnext/accounts/report/trial_balance/trial_balance.js @@ -47,22 +47,23 @@ frappe.query_reports["Trial Balance"] = { { fieldname: "cost_center", label: __("Cost Center"), - fieldtype: "Link", - options: "Cost Center", - get_query: function () { - var company = frappe.query_report.get_filter_value("company"); - return { - doctype: "Cost Center", - filters: { - company: company, - }, - }; + fieldtype: "MultiSelectList", + get_data: function (txt) { + return frappe.db.get_link_options("Cost Center", txt, { + company: frappe.query_report.get_filter_value("company"), + }); }, + options: "Cost Center", }, { fieldname: "project", label: __("Project"), - fieldtype: "Link", + fieldtype: "MultiSelectList", + get_data: function (txt) { + return frappe.db.get_link_options("Project", txt, { + company: frappe.query_report.get_filter_value("company"), + }); + }, options: "Project", }, { From fcfcaa76c6a2cf190655c226ba773053aa88bb42 Mon Sep 17 00:00:00 2001 From: l0gesh29 Date: Fri, 31 Oct 2025 19:16:35 +0530 Subject: [PATCH 2/2] feat(reports): preserve accounting dimension filters while navigating between reports --- .../accounts_receivable.py | 7 ++----- .../report/trial_balance/trial_balance.py | 15 +++---------- erpnext/public/js/financial_statements.js | 21 +++++++++++++++++-- 3 files changed, 24 insertions(+), 19 deletions(-) diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py index 9e1112ba117..a5b8c2430f8 100644 --- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py +++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py @@ -15,6 +15,7 @@ from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import ( get_accounting_dimensions, get_dimension_with_children, ) +from erpnext.accounts.report.financial_statements import get_cost_centers_with_children from erpnext.accounts.utils import ( build_qb_match_conditions, get_advance_payment_doctypes, @@ -987,11 +988,7 @@ class ReceivablePayableReport: self.add_accounting_dimensions_filters() def get_cost_center_conditions(self): - lft, rgt = frappe.db.get_value("Cost Center", self.filters.cost_center, ["lft", "rgt"]) - cost_center_list = [ - center.name - for center in frappe.get_list("Cost Center", filters={"lft": (">=", lft), "rgt": ("<=", rgt)}) - ] + cost_center_list = get_cost_centers_with_children(self.filters.cost_center) self.qb_selection_filter.append(self.ple.cost_center.isin(cost_center_list)) def add_common_filters(self): diff --git a/erpnext/accounts/report/trial_balance/trial_balance.py b/erpnext/accounts/report/trial_balance/trial_balance.py index e5f8044aee2..933e9cd30d9 100644 --- a/erpnext/accounts/report/trial_balance/trial_balance.py +++ b/erpnext/accounts/report/trial_balance/trial_balance.py @@ -15,6 +15,7 @@ from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import ( from erpnext.accounts.report.financial_statements import ( filter_accounts, filter_out_zero_value_rows, + get_cost_centers_with_children, set_gl_entries_by_account, ) from erpnext.accounts.report.utils import convert_to_presentation_currency, get_currency @@ -101,10 +102,6 @@ def get_data(filters): opening_balances = get_opening_balances(filters, ignore_is_opening) - # add filter inside list so that the query in financial_statements.py doesn't break - if filters.project: - filters.project = [filters.project] - set_gl_entries_by_account( filters.company, filters.from_date, @@ -297,18 +294,12 @@ def get_opening_balance( opening_balance = opening_balance.where(closing_balance.voucher_type != "Period Closing Voucher") if filters.cost_center: - lft, rgt = frappe.db.get_value("Cost Center", filters.cost_center, ["lft", "rgt"]) - cost_center = frappe.qb.DocType("Cost Center") opening_balance = opening_balance.where( - closing_balance.cost_center.isin( - frappe.qb.from_(cost_center) - .select("name") - .where((cost_center.lft >= lft) & (cost_center.rgt <= rgt)) - ) + closing_balance.cost_center.isin(get_cost_centers_with_children(filters.get("cost_center"))) ) if filters.project: - opening_balance = opening_balance.where(closing_balance.project == filters.project) + opening_balance = opening_balance.where(closing_balance.project.isin(filters.project)) if frappe.db.count("Finance Book"): if filters.get("include_default_book_entries"): diff --git a/erpnext/public/js/financial_statements.js b/erpnext/public/js/financial_statements.js index 159daa972d7..2783055613a 100644 --- a/erpnext/public/js/financial_statements.js +++ b/erpnext/public/js/financial_statements.js @@ -75,18 +75,35 @@ erpnext.financial_statements = { }, open_general_ledger: function (data) { if (!data.account && !data.accounts) return; - let project = $.grep(frappe.query_report.filters, function (e) { + let filters = frappe.query_report.filters; + + let project = $.grep(filters, function (e) { return e.df.fieldname == "project"; }); + let cost_center = $.grep(filters, function (e) { + return e.df.fieldname == "cost_center"; + }); + frappe.route_options = { account: data.account || data.accounts, company: frappe.query_report.get_filter_value("company"), from_date: data.from_date || data.year_start_date, to_date: data.to_date || data.year_end_date, - project: project && project.length > 0 ? project[0].$input.val() : "", + project: project && project.length > 0 ? project[0].get_value() : "", + cost_center: cost_center && cost_center.length > 0 ? cost_center[0].get_value() : "", }; + filters.forEach((f) => { + if (f.df.fieldtype == "MultiSelectList") { + if (f.df.fieldname in frappe.route_options) return; + let value = f.get_value(); + if (value && value.length > 0) { + frappe.route_options[f.df.fieldname] = value; + } + } + }); + let report = "General Ledger"; if (["Payable", "Receivable"].includes(data.account_type)) {