|
| 1 | +# Copyright (c) 2026, Frappe Technologies Pvt. Ltd. and Contributors |
| 2 | +# See license.txt |
| 3 | + |
| 4 | +import frappe |
| 5 | +from frappe.utils import today |
| 6 | + |
| 7 | +from erpnext.accounts.doctype.journal_entry.test_journal_entry import make_journal_entry |
| 8 | +from erpnext.accounts.report.dimension_wise_accounts_balance_report.dimension_wise_accounts_balance_report import ( |
| 9 | + execute, |
| 10 | +) |
| 11 | +from erpnext.accounts.utils import get_fiscal_year |
| 12 | +from erpnext.tests.utils import ERPNextTestSuite |
| 13 | + |
| 14 | + |
| 15 | +class TestDimensionWiseAccountsBalance(ERPNextTestSuite): |
| 16 | + """Balances accounts one column per value of an accounting dimension (here |
| 17 | + Cost Center). Locks the two behaviours that matter: an entry lands in its |
| 18 | + own dimension column as debit - credit, and children roll up into parents.""" |
| 19 | + |
| 20 | + def setUp(self): |
| 21 | + frappe.set_user("Administrator") |
| 22 | + self.company = "_Test Company" |
| 23 | + self.expense_account = "_Test Account Cost for Goods Sold - _TC" |
| 24 | + self.cash_account = "Cash - _TC" |
| 25 | + |
| 26 | + def _make_cost_center(self, name): |
| 27 | + full_name = f"{name} - _TC" |
| 28 | + if not frappe.db.exists("Cost Center", full_name): |
| 29 | + frappe.get_doc( |
| 30 | + { |
| 31 | + "doctype": "Cost Center", |
| 32 | + "cost_center_name": name, |
| 33 | + "parent_cost_center": "_Test Company - _TC", |
| 34 | + "company": self.company, |
| 35 | + "is_group": 0, |
| 36 | + } |
| 37 | + ).insert() |
| 38 | + return full_name |
| 39 | + |
| 40 | + def _filters(self, **overrides): |
| 41 | + filters = frappe._dict( |
| 42 | + { |
| 43 | + "company": self.company, |
| 44 | + "dimension": "Cost Center", |
| 45 | + "fiscal_year": get_fiscal_year(today(), company=self.company)[0], |
| 46 | + } |
| 47 | + ) |
| 48 | + filters.update(overrides) |
| 49 | + return filters |
| 50 | + |
| 51 | + def test_dimension_column_and_rollup(self): |
| 52 | + # a dedicated cost center isolates our column from any other posted data |
| 53 | + cost_center = self._make_cost_center("Test Dimension CC") |
| 54 | + make_journal_entry( |
| 55 | + self.expense_account, |
| 56 | + self.cash_account, |
| 57 | + 300, |
| 58 | + cost_center=cost_center, |
| 59 | + posting_date=today(), |
| 60 | + submit=True, |
| 61 | + ) |
| 62 | + |
| 63 | + columns, data = execute(self._filters()) |
| 64 | + column = frappe.scrub(cost_center) |
| 65 | + self.assertIn(column, [c["fieldname"] for c in columns]) |
| 66 | + |
| 67 | + rows = {row["account"]: row for row in data} |
| 68 | + |
| 69 | + # the entry shows as debit - credit under its own dimension column |
| 70 | + self.assertEqual(rows[self.expense_account][column], 300.0) |
| 71 | + self.assertEqual(rows[self.cash_account][column], -300.0) |
| 72 | + |
| 73 | + # and rolls up into each account's parent (isolated to our cost center) |
| 74 | + expense_parent = frappe.db.get_value("Account", self.expense_account, "parent_account") |
| 75 | + cash_parent = frappe.db.get_value("Account", self.cash_account, "parent_account") |
| 76 | + self.assertEqual(rows[expense_parent][column], 300.0) |
| 77 | + self.assertEqual(rows[cash_parent][column], -300.0) |
| 78 | + |
| 79 | + def test_requires_fiscal_year(self): |
| 80 | + filters = self._filters() |
| 81 | + filters.pop("fiscal_year") |
| 82 | + self.assertRaises(frappe.ValidationError, execute, filters) |
0 commit comments