test(fusion_accounting_reports): P&L integration tests against known fixtures
Made-with: Cursor
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
{
|
||||
'name': 'Fusion Accounting Reports',
|
||||
'version': '19.0.1.0.17',
|
||||
'version': '19.0.1.0.18',
|
||||
'category': 'Accounting/Accounting',
|
||||
'summary': 'AI-augmented financial reports (P&L, balance sheet, trial balance, GL).',
|
||||
'description': """
|
||||
|
||||
@@ -14,3 +14,4 @@ from . import test_reports_controller
|
||||
from . import test_reports_adapter
|
||||
from . import test_fusion_report_tools
|
||||
from . import test_engine_property
|
||||
from . import test_pnl_integration
|
||||
|
||||
107
fusion_accounting_reports/tests/test_pnl_integration.py
Normal file
107
fusion_accounting_reports/tests/test_pnl_integration.py
Normal file
@@ -0,0 +1,107 @@
|
||||
"""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')
|
||||
Reference in New Issue
Block a user