refactor(fusion_accounting_ai): route legacy reconcile tools through engine
Some checks failed
fusion_accounting CI / test (fusion_accounting_ai) (push) Has been cancelled
fusion_accounting CI / test (fusion_accounting_core) (push) Has been cancelled
fusion_accounting CI / test (fusion_accounting_migration) (push) Has been cancelled

When fusion_accounting_bank_rec is installed, match_bank_line_to_payments
and auto_reconcile_bank_lines now use fusion.reconcile.engine via the
BankRecAdapter, gaining precedent recording, AI suggestion superseding,
and shared validation. Legacy paths preserved for Enterprise/Community-
only installs (engine model absent -> fall back to set_line_bank_statement_line
and _try_auto_reconcile_statement_lines).

Also wraps engine.reconcile_batch's per-line loop in a savepoint so a
single bad line's DB error (e.g. check-constraint violation) no longer
poisons the whole batch transaction; the existing per-line try/except
now isolates failures as originally intended.

Made-with: Cursor
This commit is contained in:
gsinghpal
2026-04-19 11:37:34 -04:00
parent 3993f58910
commit 5020129c45
4 changed files with 88 additions and 9 deletions

View File

@@ -12,3 +12,4 @@ from . import test_reconcile_engine_integration
from . import test_bank_rec_prompt
from . import test_bank_rec_adapter
from . import test_bank_rec_tools
from . import test_legacy_tools_refactor

View File

@@ -0,0 +1,59 @@
"""Tests verifying legacy tools route through fusion.reconcile.engine when present.
These tests run in the fusion_accounting_bank_rec context where the engine IS
available, so they assert the engine path is taken and produces correct
results. The fallback path is exercised by the existing fusion_accounting_ai
tests when fusion_accounting_bank_rec is not installed."""
from unittest.mock import patch
from odoo.tests.common import TransactionCase, tagged
from odoo.addons.fusion_accounting_ai.services.tools import bank_reconciliation as tools
from . import _factories as f
@tagged('post_install', '-at_install')
class TestLegacyToolsRefactor(TransactionCase):
def setUp(self):
super().setUp()
self.partner = self.env['res.partner'].create({'name': 'Refactor Test Partner'})
def test_match_bank_line_to_payments_uses_engine(self):
"""When engine is present, match_bank_line_to_payments must produce
a partial reconcile via the engine, not via set_line_bank_statement_line."""
bank_line, recv_lines = f.make_reconcileable_pair(
self.env, amount=180.00, partner=self.partner)
result = tools.match_bank_line_to_payments(self.env, {
'statement_line_id': bank_line.id,
'move_line_ids': recv_lines.ids,
})
self.assertEqual(result.get('status'), 'matched')
bank_line.invalidate_recordset(['is_reconciled'])
self.assertTrue(bank_line.is_reconciled)
# Verify a precedent was recorded - engine-only behaviour
Precedent = self.env['fusion.reconcile.precedent']
precedents = Precedent.search([('partner_id', '=', self.partner.id)])
self.assertGreater(len(precedents), 0,
"Engine path should record a precedent; legacy path would not")
def test_auto_reconcile_bank_lines_uses_engine(self):
"""When engine is present, auto_reconcile_bank_lines must call
fusion.reconcile.engine.reconcile_batch (not the Enterprise-only
_try_auto_reconcile_statement_lines fallback). We patch
reconcile_batch to verify routing without running the real engine
across every legacy unreconciled line in the test DB."""
Engine = type(self.env['fusion.reconcile.engine'])
with patch.object(
Engine, 'reconcile_batch', autospec=True,
return_value={'reconciled_count': 2, 'skipped': 0, 'errors': []},
) as engine_call:
result = tools.auto_reconcile_bank_lines(self.env, {
'company_id': self.env.company.id,
})
self.assertEqual(result['status'], 'completed')
self.assertTrue(engine_call.called,
"Engine path must invoke fusion.reconcile.engine.reconcile_batch")
# Verify the engine was passed the strategy='auto' kwarg per spec
_self, _lines = engine_call.call_args.args[0], engine_call.call_args.args[1]
self.assertEqual(engine_call.call_args.kwargs.get('strategy'), 'auto')