from odoo.tests.common import TransactionCase, tagged from odoo.addons.fusion_accounting_bank_rec.services.matching_strategies import ( Candidate, AmountExactStrategy, FIFOStrategy, MultiInvoiceStrategy, MatchResult, ) @tagged('post_install', '-at_install') class TestAmountExactStrategy(TransactionCase): def test_picks_exact_amount(self): candidates = [ Candidate(id=1, amount=99.99, partner_id=42, age_days=10), Candidate(id=2, amount=100.00, partner_id=42, age_days=20), Candidate(id=3, amount=100.50, partner_id=42, age_days=5), ] result = AmountExactStrategy().match(bank_amount=100.00, candidates=candidates) self.assertEqual(result.picked_ids, [2]) self.assertEqual(result.confidence, 1.0) def test_no_match_when_no_exact(self): candidates = [ Candidate(id=1, amount=99.99, partner_id=42, age_days=10), Candidate(id=2, amount=100.50, partner_id=42, age_days=20), ] result = AmountExactStrategy().match(bank_amount=100.00, candidates=candidates) self.assertEqual(result.picked_ids, []) def test_picks_oldest_when_multiple_exact(self): candidates = [ Candidate(id=1, amount=100.00, partner_id=42, age_days=10), Candidate(id=2, amount=100.00, partner_id=42, age_days=30), # oldest Candidate(id=3, amount=100.00, partner_id=42, age_days=20), ] result = AmountExactStrategy().match(bank_amount=100.00, candidates=candidates) self.assertEqual(result.picked_ids, [2]) def test_handles_empty_candidates(self): result = AmountExactStrategy().match(bank_amount=100.00, candidates=[]) self.assertEqual(result.picked_ids, []) @tagged('post_install', '-at_install') class TestFIFOStrategy(TransactionCase): def test_picks_oldest_first(self): candidates = [ Candidate(id=1, amount=50.00, partner_id=42, age_days=10), Candidate(id=2, amount=50.00, partner_id=42, age_days=30), Candidate(id=3, amount=50.00, partner_id=42, age_days=20), ] result = FIFOStrategy().match(bank_amount=100.00, candidates=candidates) self.assertEqual(result.picked_ids, [2, 3]) # oldest two summing to 100 def test_handles_partial_payment(self): candidates = [ Candidate(id=1, amount=200.00, partner_id=42, age_days=30), ] result = FIFOStrategy().match(bank_amount=100.00, candidates=candidates) self.assertEqual(result.picked_ids, [1]) # partial reconcile signaled by residual self.assertEqual(result.residual, -100.00) # over-allocated; engine handles def test_handles_empty_candidates(self): result = FIFOStrategy().match(bank_amount=100.00, candidates=[]) self.assertEqual(result.picked_ids, []) @tagged('post_install', '-at_install') class TestMultiInvoiceStrategy(TransactionCase): def test_finds_smallest_set_summing_to_amount(self): candidates = [ Candidate(id=1, amount=30.00, partner_id=42, age_days=10), Candidate(id=2, amount=40.00, partner_id=42, age_days=15), Candidate(id=3, amount=30.00, partner_id=42, age_days=20), Candidate(id=4, amount=70.00, partner_id=42, age_days=25), ] result = MultiInvoiceStrategy(max_combinations=3).match( bank_amount=100.00, candidates=candidates) # Two-element solutions exist (e.g., {3,4}=100). Strategy should pick a 2-set. self.assertEqual(len(result.picked_ids), 2) # The picked set should sum to 100 picked_amounts = [c.amount for c in candidates if c.id in result.picked_ids] self.assertAlmostEqual(sum(picked_amounts), 100.00, places=2) def test_returns_empty_when_no_combination_sums(self): candidates = [ Candidate(id=1, amount=15.00, partner_id=42, age_days=10), Candidate(id=2, amount=25.00, partner_id=42, age_days=15), ] result = MultiInvoiceStrategy(max_combinations=3).match( bank_amount=100.00, candidates=candidates) self.assertEqual(result.picked_ids, []) def test_respects_max_combinations(self): # Many small invoices — only combinations of ≤3 items considered candidates = [Candidate(id=i, amount=10.00, partner_id=42, age_days=i) for i in range(1, 11)] result = MultiInvoiceStrategy(max_combinations=3).match( bank_amount=100.00, candidates=candidates) # Can't make 100 with ≤3 items of $10 each self.assertEqual(result.picked_ids, []) def test_strategy_name_includes_combination_size(self): candidates = [ Candidate(id=1, amount=50.00, partner_id=42, age_days=10), Candidate(id=2, amount=50.00, partner_id=42, age_days=20), ] result = MultiInvoiceStrategy(max_combinations=3).match( bank_amount=100.00, candidates=candidates) self.assertEqual(set(result.picked_ids), {1, 2}) self.assertIn('multi_invoice', result.strategy_name)