test: add value-level coverage for Budget Variance report

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Nabin Hait
2026-06-26 09:38:45 +05:30
parent 6d035274d7
commit d4ec544b25

View File

@@ -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, [])