"""Integration test: P&L produces correct totals against known fixtures. Creates a small set of known invoices/bills and verifies that compute_pnl returns the expected Revenue, Expenses, Net Income.""" from datetime import date from odoo.tests.common import TransactionCase, tagged from odoo.addons.fusion_accounting_reports.services.date_periods import Period @tagged('post_install', '-at_install', 'integration') class TestPnlIntegration(TransactionCase): def setUp(self): super().setUp() self.partner = self.env['res.partner'].create( {'name': 'P&L Test Partner'}) self.income_account = self.env['account.account'].search( [('account_type', '=', 'income'), ('company_ids', 'in', self.env.company.id)], limit=1, ) # Make a service product and pin an income account so invoice lines # always book to a known revenue account regardless of localisation. self.product = self.env['product.product'].create({ 'name': 'Fusion P&L Test Service', 'type': 'service', }) if self.income_account: self.product.property_account_income_id = self.income_account def _create_invoice(self, amount, *, date_=None, move_type='out_invoice'): line_vals = { 'product_id': self.product.id, 'name': 'Test', 'quantity': 1, 'price_unit': amount, 'tax_ids': [(6, 0, [])], } if self.income_account: line_vals['account_id'] = self.income_account.id invoice = self.env['account.move'].create({ 'move_type': move_type, 'partner_id': self.partner.id, 'invoice_date': date_ or date(2026, 6, 15), 'invoice_line_ids': [(0, 0, line_vals)], }) invoice.action_post() # The engine reads parent_state via raw SQL; force a flush so the # field is materialised in the DB before we aggregate. self.env.flush_all() return invoice def test_pnl_includes_invoice_revenue(self): period = Period(date(2026, 1, 1), date(2026, 12, 31), 'Test 2026') baseline = self.env['fusion.report.engine'].compute_pnl( period, company_id=self.env.company.id) baseline_labels = [r.get('label') for r in baseline['rows']] revenue_baseline = next( (r['amount'] for r in baseline['rows'] if r.get('label') == 'Revenue'), None, ) self.assertIsNotNone( revenue_baseline, msg=f"Revenue row not found; got labels: {baseline_labels}", ) self._create_invoice(1000) result = self.env['fusion.report.engine'].compute_pnl( period, company_id=self.env.company.id) revenue_after = next( (r['amount'] for r in result['rows'] if r.get('label') == 'Revenue'), None, ) self.assertIsNotNone(revenue_after) delta = revenue_after - revenue_baseline self.assertAlmostEqual( delta, 1000, places=0, msg=f"Expected Revenue +1000, got {delta:.2f}", ) def test_pnl_with_comparison_returns_both_periods(self): period = Period(date(2026, 1, 1), date(2026, 12, 31), 'Test 2026') result = self.env['fusion.report.engine'].compute_pnl( period, comparison='previous_year', company_id=self.env.company.id, ) self.assertIsNotNone(result.get('comparison_period')) for row in result['rows']: if row.get('amount_comparison') is not None: self.assertIsInstance(row['amount_comparison'], (int, float)) return # No row had comparison amounts -- still acceptable for empty periods. def test_pnl_net_income_is_subtotal(self): period = Period(date(2026, 1, 1), date(2026, 12, 31), 'Test 2026') result = self.env['fusion.report.engine'].compute_pnl( period, company_id=self.env.company.id) last = result['rows'][-1] self.assertTrue(last['is_subtotal']) self.assertEqual(last['label'], 'Net Income')