From d4ec544b25adb9defb0df6563d9537555795075f Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Fri, 26 Jun 2026 09:38:45 +0530 Subject: [PATCH 1/2] test: add value-level coverage for Budget Variance report Co-Authored-By: Claude Opus 4.8 (1M context) --- .../test_budget_variance_report.py | 82 +++++++++++++++++-- 1 file changed, 77 insertions(+), 5 deletions(-) diff --git a/erpnext/accounts/report/budget_variance_report/test_budget_variance_report.py b/erpnext/accounts/report/budget_variance_report/test_budget_variance_report.py index a3a652cb658..8d404b1c994 100644 --- a/erpnext/accounts/report/budget_variance_report/test_budget_variance_report.py +++ b/erpnext/accounts/report/budget_variance_report/test_budget_variance_report.py @@ -2,26 +2,98 @@ # For license information, please see license.txt import frappe +from frappe.utils import nowdate +from erpnext.accounts.doctype.budget.test_budget import make_budget +from erpnext.accounts.doctype.journal_entry.test_journal_entry import make_journal_entry from erpnext.accounts.report.budget_variance_report.budget_variance_report import execute +from erpnext.accounts.utils import get_fiscal_year from erpnext.tests.utils import ERPNextTestSuite +ACCOUNT = "_Test Account Cost for Goods Sold - _TC" +COST_CENTER = "_Test Cost Center - _TC" +COST_CENTER_2 = "_Test Cost Center 2 - _TC" + class TestBudgetVarianceReport(ERPNextTestSuite): + def setUp(self): + self.fy = get_fiscal_year(nowdate())[0] + + def run_report(self, **extra): + filters = frappe._dict( + { + "company": "_Test Company", + "from_fiscal_year": self.fy, + "to_fiscal_year": self.fy, + "period": "Yearly", + "budget_against": "Cost Center", + **extra, + } + ) + return execute(filters)[1] + + def report_row(self, data, dimension, account=ACCOUNT): + return next( + row for row in data if row["budget_against"] == dimension and row["account"] == account + ) + + def field(self, label): + return frappe.scrub(f"{label} {self.fy}") + def test_report_executes(self): # Smoke-guards the raw-SQL -> query-builder port: the report query must compile and run on # both MariaDB and postgres. - company = frappe.db.get_value("Company", {}, "name") - fy = frappe.db.get_value("Fiscal Year", {}, "name", order_by="year_start_date desc") columns, *_rest = execute( frappe._dict( { - "company": company, - "from_fiscal_year": fy, - "to_fiscal_year": fy, + "company": "_Test Company", + "from_fiscal_year": self.fy, + "to_fiscal_year": self.fy, "period": "Yearly", "budget_against": "Cost Center", } ) ) self.assertTrue(columns) + + def test_budget_amount_shown_with_zero_actual(self): + make_budget(budget_against="Cost Center", cost_center=COST_CENTER, budget_amount=120000, submit_budget=1) + + row = self.report_row(self.run_report(), COST_CENTER) + self.assertEqual(row[self.field("Budget")], 120000) + self.assertEqual(row[self.field("Actual")], 0) + self.assertEqual(row[self.field("Variance")], 120000) + + def test_actual_expense_updates_actual_and_variance(self): + make_budget(budget_against="Cost Center", cost_center=COST_CENTER, budget_amount=120000, submit_budget=1) + # book an actual expense well within the annual budget so the "Stop" action does not block it + make_journal_entry(ACCOUNT, "_Test Bank - _TC", 50000, cost_center=COST_CENTER, submit=True) + + row = self.report_row(self.run_report(), COST_CENTER) + self.assertEqual(row[self.field("Actual")], 50000) + self.assertEqual(row[self.field("Variance")], 70000) # 120000 - 50000 + + def test_budget_against_filter_limits_dimensions(self): + make_budget(budget_against="Cost Center", cost_center=COST_CENTER, budget_amount=120000, submit_budget=1) + make_budget( + budget_against="Cost Center", cost_center=COST_CENTER_2, budget_amount=80000, submit_budget=1 + ) + + data = self.run_report(budget_against_filter=[COST_CENTER]) + dimensions = {row["budget_against"] for row in data} + self.assertEqual(dimensions, {COST_CENTER}) + + def test_monthly_period_totals(self): + make_budget(budget_against="Cost Center", cost_center=COST_CENTER, budget_amount=120000, submit_budget=1) + make_journal_entry(ACCOUNT, "_Test Bank - _TC", 50000, cost_center=COST_CENTER, submit=True) + + row = self.report_row(self.run_report(period="Monthly"), COST_CENTER) + # totals roll up the per-month columns across the year + self.assertEqual(row["total_budget"], 120000) + self.assertEqual(row["total_actual"], 50000) + self.assertEqual(row["total_variance"], 70000) + + def test_no_budget_returns_no_rows(self): + # a dimension without any budget produces no report rows + data = self.run_report(budget_against_filter=["_Test Write Off Cost Center - _TC"]) + self.assertEqual(data, []) From b52a8f5a771ca08ad5cbd201bed46562f78766da Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Wed, 1 Jul 2026 19:34:29 +0530 Subject: [PATCH 2/2] test: apply ruff formatting --- .../test_budget_variance_report.py | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/erpnext/accounts/report/budget_variance_report/test_budget_variance_report.py b/erpnext/accounts/report/budget_variance_report/test_budget_variance_report.py index 8d404b1c994..de1fb541cb6 100644 --- a/erpnext/accounts/report/budget_variance_report/test_budget_variance_report.py +++ b/erpnext/accounts/report/budget_variance_report/test_budget_variance_report.py @@ -33,9 +33,7 @@ class TestBudgetVarianceReport(ERPNextTestSuite): return execute(filters)[1] def report_row(self, data, dimension, account=ACCOUNT): - return next( - row for row in data if row["budget_against"] == dimension and row["account"] == account - ) + return next(row for row in data if row["budget_against"] == dimension and row["account"] == account) def field(self, label): return frappe.scrub(f"{label} {self.fy}") @@ -57,7 +55,9 @@ class TestBudgetVarianceReport(ERPNextTestSuite): self.assertTrue(columns) def test_budget_amount_shown_with_zero_actual(self): - make_budget(budget_against="Cost Center", cost_center=COST_CENTER, budget_amount=120000, submit_budget=1) + make_budget( + budget_against="Cost Center", cost_center=COST_CENTER, budget_amount=120000, submit_budget=1 + ) row = self.report_row(self.run_report(), COST_CENTER) self.assertEqual(row[self.field("Budget")], 120000) @@ -65,7 +65,9 @@ class TestBudgetVarianceReport(ERPNextTestSuite): self.assertEqual(row[self.field("Variance")], 120000) def test_actual_expense_updates_actual_and_variance(self): - make_budget(budget_against="Cost Center", cost_center=COST_CENTER, budget_amount=120000, submit_budget=1) + make_budget( + budget_against="Cost Center", cost_center=COST_CENTER, budget_amount=120000, submit_budget=1 + ) # book an actual expense well within the annual budget so the "Stop" action does not block it make_journal_entry(ACCOUNT, "_Test Bank - _TC", 50000, cost_center=COST_CENTER, submit=True) @@ -74,7 +76,9 @@ class TestBudgetVarianceReport(ERPNextTestSuite): self.assertEqual(row[self.field("Variance")], 70000) # 120000 - 50000 def test_budget_against_filter_limits_dimensions(self): - make_budget(budget_against="Cost Center", cost_center=COST_CENTER, budget_amount=120000, submit_budget=1) + make_budget( + budget_against="Cost Center", cost_center=COST_CENTER, budget_amount=120000, submit_budget=1 + ) make_budget( budget_against="Cost Center", cost_center=COST_CENTER_2, budget_amount=80000, submit_budget=1 ) @@ -84,7 +88,9 @@ class TestBudgetVarianceReport(ERPNextTestSuite): self.assertEqual(dimensions, {COST_CENTER}) def test_monthly_period_totals(self): - make_budget(budget_against="Cost Center", cost_center=COST_CENTER, budget_amount=120000, submit_budget=1) + make_budget( + budget_against="Cost Center", cost_center=COST_CENTER, budget_amount=120000, submit_budget=1 + ) make_journal_entry(ACCOUNT, "_Test Bank - _TC", 50000, cost_center=COST_CENTER, submit=True) row = self.report_row(self.run_report(period="Monthly"), COST_CENTER)