Merge pull request #19973 from deepeshgarg007/budget_variance_dimension
feat: Dynamic filters for dimensions in budget variance report
diff --git a/erpnext/accounts/report/budget_variance_report/budget_variance_report.js b/erpnext/accounts/report/budget_variance_report/budget_variance_report.js
index 2451187..3ec4d30 100644
--- a/erpnext/accounts/report/budget_variance_report/budget_variance_report.js
+++ b/erpnext/accounts/report/budget_variance_report/budget_variance_report.js
@@ -46,13 +46,24 @@
fieldtype: "Select",
options: ["Cost Center", "Project"],
default: "Cost Center",
- reqd: 1
+ reqd: 1,
+ on_change: function() {
+ frappe.query_report.set_filter_value("budget_against_filter", []);
+ frappe.query_report.refresh();
+ }
},
{
- fieldname: "cost_center",
- label: __("Cost Center"),
- fieldtype: "Link",
- options: "Cost Center"
+ fieldname:"budget_against_filter",
+ label: __('Dimension Filter'),
+ fieldtype: "MultiSelectList",
+ get_data: function(txt) {
+ if (!frappe.query_report.filters) return;
+
+ let budget_against = frappe.query_report.get_filter_value('budget_against');
+ if (!budget_against) return;
+
+ return frappe.db.get_link_options(budget_against, txt);
+ }
},
{
fieldname:"show_cumulative",
diff --git a/erpnext/accounts/report/budget_variance_report/budget_variance_report.py b/erpnext/accounts/report/budget_variance_report/budget_variance_report.py
index 8d65ac8..39e218b 100644
--- a/erpnext/accounts/report/budget_variance_report/budget_variance_report.py
+++ b/erpnext/accounts/report/budget_variance_report/budget_variance_report.py
@@ -12,22 +12,22 @@
from pprint import pprint
def execute(filters=None):
if not filters: filters = {}
- validate_filters(filters)
+
columns = get_columns(filters)
- if filters.get("cost_center"):
- cost_centers = [filters.get("cost_center")]
+ if filters.get("budget_against_filter"):
+ dimensions = filters.get("budget_against_filter")
else:
- cost_centers = get_cost_centers(filters)
+ dimensions = get_cost_centers(filters)
period_month_ranges = get_period_month_ranges(filters["period"], filters["from_fiscal_year"])
- cam_map = get_cost_center_account_month_map(filters)
+ cam_map = get_dimension_account_month_map(filters)
data = []
- for cost_center in cost_centers:
- cost_center_items = cam_map.get(cost_center)
- if cost_center_items:
- for account, monthwise_data in iteritems(cost_center_items):
- row = [cost_center, account]
+ for dimension in dimensions:
+ dimension_items = cam_map.get(dimension)
+ if dimension_items:
+ for account, monthwise_data in iteritems(dimension_items):
+ row = [dimension, account]
totals = [0, 0, 0]
for year in get_fiscal_years(filters):
last_total = 0
@@ -55,10 +55,6 @@
return columns, data
-def validate_filters(filters):
- if filters.get("budget_against") != "Cost Center" and filters.get("cost_center"):
- frappe.throw(_("Filter based on Cost Center is only applicable if Budget Against is selected as Cost Center"))
-
def get_columns(filters):
columns = [_(filters.get("budget_against")) + ":Link/%s:150"%(filters.get("budget_against")), _("Account") + ":Link/Account:150"]
@@ -98,11 +94,12 @@
else:
return frappe.db.sql_list("""select name from `tab{tab}`""".format(tab=filters.get("budget_against"))) #nosec
-#Get cost center & target details
-def get_cost_center_target_details(filters):
+#Get dimension & target details
+def get_dimension_target_details(filters):
cond = ""
- if filters.get("cost_center"):
- cond += " and b.cost_center=%s" % frappe.db.escape(filters.get("cost_center"))
+ if filters.get("budget_against_filter"):
+ cond += " and b.{budget_against} in (%s)".format(budget_against = \
+ frappe.scrub(filters.get('budget_against'))) % ', '.join(['%s']* len(filters.get('budget_against_filter')))
return frappe.db.sql("""
select b.{budget_against} as budget_against, b.monthly_distribution, ba.account, ba.budget_amount,b.fiscal_year
@@ -110,8 +107,8 @@
where b.name=ba.parent and b.docstatus = 1 and b.fiscal_year between %s and %s
and b.budget_against = %s and b.company=%s {cond} order by b.fiscal_year
""".format(budget_against=filters.get("budget_against").replace(" ", "_").lower(), cond=cond),
- (filters.from_fiscal_year,filters.to_fiscal_year,filters.budget_against, filters.company), as_dict=True)
-
+ tuple([filters.from_fiscal_year,filters.to_fiscal_year,filters.budget_against, filters.company] + filters.get('budget_against_filter')),
+ as_dict=True)
#Get target distribution details of accounts of cost center
@@ -153,14 +150,14 @@
return cc_actual_details
-def get_cost_center_account_month_map(filters):
+def get_dimension_account_month_map(filters):
import datetime
- cost_center_target_details = get_cost_center_target_details(filters)
+ dimension_target_details = get_dimension_target_details(filters)
tdd = get_target_distribution_details(filters)
cam_map = {}
- for ccd in cost_center_target_details:
+ for ccd in dimension_target_details:
actual_details = get_actual_details(ccd.budget_against, filters)
for month_id in range(1, 13):