"""Unit tests for date_periods, account_hierarchy, totaling services.""" from datetime import date from odoo.tests.common import TransactionCase, tagged from odoo.addons.fusion_accounting_reports.services.date_periods import ( Period, fiscal_year_bounds, month_bounds, quarter_bounds, comparison_period, ) from odoo.addons.fusion_accounting_reports.services.account_hierarchy import ( build_tree, walk, filter_by_account_type, ) from odoo.addons.fusion_accounting_reports.services.totaling import ( aggregate, aggregate_per_account, is_balanced, ) @tagged('post_install', '-at_install') class TestDatePeriods(TransactionCase): def test_fiscal_year_calendar_default(self): period = fiscal_year_bounds(date(2026, 6, 15)) self.assertEqual(period.date_from, date(2026, 1, 1)) self.assertEqual(period.date_to, date(2026, 12, 31)) def test_fiscal_year_april_start(self): period = fiscal_year_bounds(date(2026, 6, 15), fy_start_month=4) self.assertEqual(period.date_from, date(2026, 4, 1)) self.assertEqual(period.date_to, date(2027, 3, 31)) def test_fiscal_year_before_start_returns_prior(self): period = fiscal_year_bounds(date(2026, 2, 15), fy_start_month=4) self.assertEqual(period.date_from, date(2025, 4, 1)) self.assertEqual(period.date_to, date(2026, 3, 31)) def test_month_bounds(self): period = month_bounds(date(2026, 4, 19)) self.assertEqual(period.date_from, date(2026, 4, 1)) self.assertEqual(period.date_to, date(2026, 4, 30)) def test_month_bounds_december(self): period = month_bounds(date(2026, 12, 19)) self.assertEqual(period.date_from, date(2026, 12, 1)) self.assertEqual(period.date_to, date(2026, 12, 31)) def test_quarter_bounds_q2(self): period = quarter_bounds(date(2026, 5, 15)) self.assertEqual(period.date_from, date(2026, 4, 1)) self.assertEqual(period.date_to, date(2026, 6, 30)) def test_comparison_previous_year(self): period = Period(date(2026, 1, 1), date(2026, 12, 31), 'FY 2026') comp = comparison_period(period, 'previous_year') self.assertEqual(comp.date_from, date(2025, 1, 1)) self.assertEqual(comp.date_to, date(2025, 12, 31)) def test_comparison_previous_period_same_length(self): period = Period(date(2026, 4, 1), date(2026, 4, 30), 'Apr 2026') comp = comparison_period(period, 'previous_period') self.assertEqual(comp.date_to, date(2026, 3, 31)) self.assertEqual(comp.days, period.days) def test_period_validates_bounds(self): with self.assertRaises(ValueError): Period(date(2026, 12, 31), date(2026, 1, 1), 'invalid') @tagged('post_install', '-at_install') class TestAccountHierarchy(TransactionCase): def setUp(self): super().setUp() self.flat = [ {'id': 1, 'code': '1', 'name': 'Assets', 'account_type': 'asset_root', 'parent_id': None}, {'id': 2, 'code': '11', 'name': 'Cash', 'account_type': 'asset_cash', 'parent_id': 1}, {'id': 3, 'code': '12', 'name': 'AR', 'account_type': 'asset_receivable', 'parent_id': 1}, {'id': 4, 'code': '2', 'name': 'Liabilities', 'account_type': 'liability_root', 'parent_id': None}, {'id': 5, 'code': '21', 'name': 'AP', 'account_type': 'liability_payable', 'parent_id': 4}, ] def test_build_tree_returns_two_roots(self): roots = build_tree(self.flat) self.assertEqual(len(roots), 2) def test_walk_yields_all_nodes(self): roots = build_tree(self.flat) ids = [n.id for n, _, _ in walk(roots)] self.assertEqual(set(ids), {1, 2, 3, 4, 5}) def test_walk_depth_correct(self): roots = build_tree(self.flat) depths = {n.id: depth for n, depth, _ in walk(roots)} self.assertEqual(depths[1], 0) self.assertEqual(depths[2], 1) self.assertEqual(depths[3], 1) def test_filter_by_type_prefix(self): roots = build_tree(self.flat) assets = filter_by_account_type(roots, 'asset_') self.assertEqual(len(assets), 3) @tagged('post_install', '-at_install') class TestTotaling(TransactionCase): def test_aggregate_empty(self): result = aggregate([]) self.assertEqual(result.debit, 0.0) self.assertEqual(result.line_count, 0) def test_aggregate_simple(self): lines = [ {'debit': 100, 'credit': 0, 'balance': 100, 'account_id': 1}, {'debit': 0, 'credit': 50, 'balance': -50, 'account_id': 1}, ] result = aggregate(lines) self.assertEqual(result.debit, 100) self.assertEqual(result.credit, 50) self.assertEqual(result.balance, 50) def test_aggregate_per_account_groups_correctly(self): lines = [ {'debit': 100, 'credit': 0, 'balance': 100, 'account_id': 1}, {'debit': 50, 'credit': 0, 'balance': 50, 'account_id': 1}, {'debit': 0, 'credit': 25, 'balance': -25, 'account_id': 2}, ] result = aggregate_per_account(lines) self.assertEqual(result[1].debit, 150) self.assertEqual(result[2].credit, 25) def test_is_balanced_true(self): lines = [ {'debit': 100, 'credit': 0, 'balance': 100}, {'debit': 0, 'credit': 100, 'balance': -100}, ] self.assertTrue(is_balanced(lines)) def test_is_balanced_false(self): lines = [ {'debit': 100, 'credit': 0, 'balance': 100}, {'debit': 0, 'credit': 50, 'balance': -50}, ] self.assertFalse(is_balanced(lines))