feat(fusion_accounting_ai): add ReportsAdapter with trial_balance
Made-with: Cursor
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
from .base import DataAdapter, AdapterMode
|
from .base import DataAdapter, AdapterMode
|
||||||
from ._registry import get_adapter, register_adapter
|
from ._registry import get_adapter, register_adapter
|
||||||
|
|
||||||
# Side-effect imports: each adapter module calls register_adapter at module load.
|
from . import bank_rec # noqa: F401
|
||||||
from . import bank_rec # noqa: F401
|
from . import reports # noqa: F401
|
||||||
|
|
||||||
__all__ = ['DataAdapter', 'AdapterMode', 'get_adapter', 'register_adapter']
|
__all__ = ['DataAdapter', 'AdapterMode', 'get_adapter', 'register_adapter']
|
||||||
|
|||||||
56
fusion_accounting_ai/services/data_adapters/reports.py
Normal file
56
fusion_accounting_ai/services/data_adapters/reports.py
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
"""Reports data adapter.
|
||||||
|
|
||||||
|
Routes report-data lookups across:
|
||||||
|
- FUSION: fusion.account.report (added by fusion_accounting_reports, Phase 2)
|
||||||
|
- ENTERPRISE: account.report from account_reports
|
||||||
|
- COMMUNITY: raw aggregations on account.move.line
|
||||||
|
"""
|
||||||
|
|
||||||
|
from .base import DataAdapter
|
||||||
|
from ._registry import register_adapter
|
||||||
|
|
||||||
|
|
||||||
|
class ReportsAdapter(DataAdapter):
|
||||||
|
FUSION_MODEL = 'fusion.account.report'
|
||||||
|
ENTERPRISE_MODULE = 'account_reports'
|
||||||
|
|
||||||
|
def trial_balance(self, date_to=None, company_ids=None):
|
||||||
|
return self._dispatch('trial_balance', date_to=date_to, company_ids=company_ids)
|
||||||
|
|
||||||
|
def trial_balance_via_fusion(self, date_to=None, company_ids=None):
|
||||||
|
# Phase 2 will implement; for now defer to community.
|
||||||
|
return self.trial_balance_via_community(date_to=date_to, company_ids=company_ids)
|
||||||
|
|
||||||
|
def trial_balance_via_enterprise(self, date_to=None, company_ids=None):
|
||||||
|
# Enterprise account_reports has rich filters; for AI-tool consumption,
|
||||||
|
# the community shape suffices and avoids brittle coupling to Odoo's
|
||||||
|
# report-line internals.
|
||||||
|
return self.trial_balance_via_community(date_to=date_to, company_ids=company_ids)
|
||||||
|
|
||||||
|
def trial_balance_via_community(self, date_to=None, company_ids=None):
|
||||||
|
domain = [('parent_state', '=', 'posted')]
|
||||||
|
if date_to:
|
||||||
|
domain.append(('date', '<=', date_to))
|
||||||
|
if company_ids:
|
||||||
|
domain.append(('company_id', 'in', list(company_ids)))
|
||||||
|
|
||||||
|
Line = self.env['account.move.line'].sudo()
|
||||||
|
groups = Line._read_group(
|
||||||
|
domain=domain,
|
||||||
|
groupby=['account_id'],
|
||||||
|
aggregates=['debit:sum', 'credit:sum'],
|
||||||
|
)
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
'account_id': account.id,
|
||||||
|
'account_code': account.code,
|
||||||
|
'account_name': account.name,
|
||||||
|
'debit': debit_sum,
|
||||||
|
'credit': credit_sum,
|
||||||
|
'balance': debit_sum - credit_sum,
|
||||||
|
}
|
||||||
|
for account, debit_sum, credit_sum in groups
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
register_adapter('reports', ReportsAdapter)
|
||||||
@@ -58,3 +58,19 @@ class TestBankRecAdapter(TransactionCase):
|
|||||||
ids = [r['id'] for r in rows]
|
ids = [r['id'] for r in rows]
|
||||||
self.assertIn(self.line.id, ids,
|
self.assertIn(self.line.id, ids,
|
||||||
f"Expected line {self.line.id} in unreconciled list, got: {ids}")
|
f"Expected line {self.line.id} in unreconciled list, got: {ids}")
|
||||||
|
|
||||||
|
|
||||||
|
@tagged('post_install', '-at_install')
|
||||||
|
class TestReportsAdapter(TransactionCase):
|
||||||
|
"""Verify the reports adapter computes a trial-balance-shaped result."""
|
||||||
|
|
||||||
|
def test_trial_balance_returns_rows_in_pure_community(self):
|
||||||
|
adapter = get_adapter(self.env, 'reports')
|
||||||
|
# Compute an empty-filter trial balance for the current company. Should
|
||||||
|
# return a list (possibly empty in a fresh test DB) without errors.
|
||||||
|
result = adapter.trial_balance()
|
||||||
|
self.assertIsInstance(result, list)
|
||||||
|
# Each row should have account_id and balance keys
|
||||||
|
for row in result:
|
||||||
|
self.assertIn('account_id', row)
|
||||||
|
self.assertIn('balance', row)
|
||||||
|
|||||||
Reference in New Issue
Block a user