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 ._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']
|
||||
|
||||
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]
|
||||
self.assertIn(self.line.id, 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