Best Python code snippet using hypothesis
test_reconciliation_matching_rules.py
Source:test_reconciliation_matching_rules.py
1# -*- coding: utf-8 -*-2from odoo import fields3from odoo.addons.account.tests.account_test_savepoint import AccountTestInvoicingCommon4from odoo.tests.common import Form5from odoo.tests import tagged6@tagged('post_install', '-at_install')7class TestReconciliationMatchingRules(AccountTestInvoicingCommon):8 @classmethod9 def _create_invoice_line(cls, amount, partner, type):10 ''' Create an invoice on the fly.'''11 invoice_form = Form(cls.env['account.move'].with_context(default_type=type))12 invoice_form.invoice_date = fields.Date.from_string('2019-09-01')13 invoice_form.partner_id = partner14 with invoice_form.invoice_line_ids.new() as invoice_line_form:15 invoice_line_form.name = 'xxxx'16 invoice_line_form.quantity = 117 invoice_line_form.price_unit = amount18 invoice_line_form.tax_ids.clear()19 invoice = invoice_form.save()20 invoice.post()21 lines = invoice.line_ids22 return lines.filtered(lambda l: l.account_id.user_type_id.type in ('receivable', 'payable'))23 def _check_statement_matching(self, rules, expected_values, statements=None):24 if statements is None:25 statements = self.bank_st + self.cash_st26 statement_lines = statements.mapped('line_ids').sorted()27 matching_values = rules._apply_rules(statement_lines)28 for st_line_id, values in matching_values.items():29 values.pop('reconciled_lines', None)30 self.assertDictEqual(values, expected_values[st_line_id])31 @classmethod32 def setUpClass(cls, chart_template_ref=None):33 super().setUpClass(chart_template_ref=chart_template_ref)34 35 cls.account_pay = cls.company_data['default_account_payable']36 cls.account_rcv = cls.company_data['default_account_receivable']37 cls.account_bnk = cls.company_data['default_journal_bank'].default_debit_account_id38 cls.account_cash = cls.company_data['default_journal_cash'].default_debit_account_id39 cls.partner_1 = cls.env['res.partner'].create({'name': 'partner_1'})40 cls.partner_2 = cls.env['res.partner'].create({'name': 'partner_2'})41 # Generate invoice starting at a fixed sequence to avoid matching multiple lines depending the current date.42 cls.company_data['default_journal_sale'].sequence_id._get_current_sequence(sequence_date='2019-01-01').number_next = 543 cls.invoice_line_1 = cls._create_invoice_line(100, cls.partner_1, 'out_invoice')44 cls.invoice_line_2 = cls._create_invoice_line(200, cls.partner_1, 'out_invoice')45 cls.invoice_line_3 = cls._create_invoice_line(300, cls.partner_1, 'in_refund')46 cls.invoice_line_4 = cls._create_invoice_line(1000, cls.partner_2, 'in_invoice')47 cls.rule_0 = cls.env['account.reconcile.model'].search([('company_id', '=', cls.company_data['company'].id), ('rule_type', '=', 'invoice_matching')])48 cls.rule_1 = cls.rule_0.copy()49 cls.rule_1.account_id = cls.company_data['default_account_revenue']50 cls.rule_1.match_partner = True51 cls.rule_1.match_partner_ids |= cls.partner_1 + cls.partner_252 cls.rule_2 = cls.env['account.reconcile.model'].create({53 'name': 'write-off model',54 'rule_type': 'writeoff_suggestion',55 'match_partner': True,56 'match_partner_ids': [],57 'account_id': cls.company_data['default_account_revenue'].id,58 })59 cls.bank_st = cls.env['account.bank.statement'].create({60 'name': 'test bank journal', 'journal_id': cls.company_data['default_journal_bank'].id,61 })62 cls.bank_line_1 = cls.env['account.bank.statement.line'].create({63 'statement_id': cls.bank_st.id,64 'name': 'invoice 2019-0005',65 'partner_id': cls.partner_1.id,66 'amount': 100,67 'sequence': 1,68 })69 cls.bank_line_2 = cls.env['account.bank.statement.line'].create({70 'statement_id': cls.bank_st.id,71 'name': 'xxxxx',72 'partner_id': cls.partner_1.id,73 'amount': 600,74 'sequence': 2,75 })76 cls.cash_st = cls.env['account.bank.statement'].create({77 'name': 'test cash journal', 'journal_id': cls.company_data['default_journal_cash'].id,78 })79 cls.cash_line_1 = cls.env['account.bank.statement.line'].create({80 'statement_id': cls.cash_st.id,81 'name': 'yyyyy',82 'partner_id': cls.partner_2.id,83 'amount': -1000,84 'sequence': 1,85 })86 cls.tax21 = cls.env['account.tax'].create({87 'name': '21%',88 'type_tax_use': 'purchase',89 'amount': 21,90 })91 def test_matching_fields(self):92 ''' Test all fields used to restrict the rules's applicability.'''93 # Check without restriction.94 self._check_statement_matching(self.rule_1, {95 self.bank_line_1.id: {'aml_ids': [self.invoice_line_1.id], 'model': self.rule_1},96 self.bank_line_2.id: {'aml_ids': [97 self.invoice_line_2.id,98 self.invoice_line_3.id,99 self.invoice_line_1.id,100 ], 'model': self.rule_1},101 self.cash_line_1.id: {'aml_ids': [self.invoice_line_4.id], 'model': self.rule_1},102 })103 # Check match_journal_ids.104 self.rule_1.match_journal_ids |= self.cash_st.journal_id105 self._check_statement_matching(self.rule_1, {106 self.bank_line_1.id: {'aml_ids': []},107 self.bank_line_2.id: {'aml_ids': []},108 self.cash_line_1.id: {'aml_ids': [self.invoice_line_4.id], 'model': self.rule_1},109 })110 self.rule_1.match_journal_ids |= self.bank_st.journal_id + self.cash_st.journal_id111 # Check match_nature.112 self.rule_1.match_nature = 'amount_received'113 self._check_statement_matching(self.rule_1, {114 self.bank_line_1.id: {'aml_ids': [self.invoice_line_1.id], 'model': self.rule_1},115 self.bank_line_2.id: {'aml_ids': [116 self.invoice_line_2.id,117 self.invoice_line_3.id,118 self.invoice_line_1.id,119 ], 'model': self.rule_1},120 self.cash_line_1.id: {'aml_ids': []},121 })122 self.rule_1.match_nature = 'amount_paid'123 self._check_statement_matching(self.rule_1, {124 self.bank_line_1.id: {'aml_ids': []},125 self.bank_line_2.id: {'aml_ids': []},126 self.cash_line_1.id: {'aml_ids': [self.invoice_line_4.id], 'model': self.rule_1},127 })128 self.rule_1.match_nature = 'both'129 # Check match_amount.130 self.rule_1.match_amount = 'lower'131 self.rule_1.match_amount_max = 150132 self._check_statement_matching(self.rule_1, {133 self.bank_line_1.id: {'aml_ids': [self.invoice_line_1.id], 'model': self.rule_1},134 self.bank_line_2.id: {'aml_ids': []},135 self.cash_line_1.id: {'aml_ids': []},136 })137 self.rule_1.match_amount = 'greater'138 self.rule_1.match_amount_min = 200139 self._check_statement_matching(self.rule_1, {140 self.bank_line_1.id: {'aml_ids': []},141 self.bank_line_2.id: {'aml_ids': [142 self.invoice_line_1.id,143 self.invoice_line_2.id,144 self.invoice_line_3.id,145 ], 'model': self.rule_1},146 self.cash_line_1.id: {'aml_ids': [self.invoice_line_4.id], 'model': self.rule_1},147 })148 self.rule_1.match_amount = 'between'149 self.rule_1.match_amount_min = 200150 self.rule_1.match_amount_max = 800151 self._check_statement_matching(self.rule_1, {152 self.bank_line_1.id: {'aml_ids': []},153 self.bank_line_2.id: {'aml_ids': [154 self.invoice_line_1.id,155 self.invoice_line_2.id,156 self.invoice_line_3.id,157 ], 'model': self.rule_1},158 self.cash_line_1.id: {'aml_ids': []},159 })160 self.rule_1.match_amount = False161 # Check match_label.162 self.rule_1.match_label = 'contains'163 self.rule_1.match_label_param = 'yyyyy'164 self._check_statement_matching(self.rule_1, {165 self.bank_line_1.id: {'aml_ids': []},166 self.bank_line_2.id: {'aml_ids': []},167 self.cash_line_1.id: {'aml_ids': [self.invoice_line_4.id], 'model': self.rule_1},168 })169 self.rule_1.match_label = 'not_contains'170 self.rule_1.match_label_param = 'xxxxx'171 self._check_statement_matching(self.rule_1, {172 self.bank_line_1.id: {'aml_ids': [self.invoice_line_1.id], 'model': self.rule_1},173 self.bank_line_2.id: {'aml_ids': []},174 self.cash_line_1.id: {'aml_ids': [self.invoice_line_4.id], 'model': self.rule_1},175 })176 self.rule_1.match_label = 'match_regex'177 self.rule_1.match_label_param = 'xxxxx|yyyyy'178 self._check_statement_matching(self.rule_1, {179 self.bank_line_1.id: {'aml_ids': []},180 self.bank_line_2.id: {'aml_ids': [181 self.invoice_line_1.id,182 self.invoice_line_2.id,183 self.invoice_line_3.id,184 ], 'model': self.rule_1},185 self.cash_line_1.id: {'aml_ids': [self.invoice_line_4.id], 'model': self.rule_1},186 })187 self.rule_1.match_label = False188 # Check match_total_amount: line amount >= total residual amount.189 self.rule_1.match_total_amount_param = 90.0190 self.bank_line_1.amount += 5191 self._check_statement_matching(self.rule_1, {192 self.bank_line_1.id: {'aml_ids': [self.invoice_line_1.id], 'model': self.rule_1, 'status': 'write_off'},193 self.bank_line_2.id: {'aml_ids': [194 self.invoice_line_2.id,195 self.invoice_line_3.id,196 self.invoice_line_1.id,197 ], 'model': self.rule_1},198 self.cash_line_1.id: {'aml_ids': [self.invoice_line_4.id], 'model': self.rule_1},199 })200 self.rule_1.match_total_amount_param = 100.0201 self.bank_line_1.amount -= 5202 # Check match_total_amount: line amount <= total residual amount.203 self.rule_1.match_total_amount_param = 90.0204 self.bank_line_1.amount -= 5205 self._check_statement_matching(self.rule_1, {206 self.bank_line_1.id: {'aml_ids': [self.invoice_line_1.id], 'model': self.rule_1, 'status': 'write_off'},207 self.bank_line_2.id: {'aml_ids': [208 self.invoice_line_2.id,209 self.invoice_line_3.id,210 self.invoice_line_1.id,211 ], 'model': self.rule_1},212 self.cash_line_1.id: {'aml_ids': [self.invoice_line_4.id], 'model': self.rule_1},213 })214 self.rule_1.match_total_amount_param = 100.0215 self.bank_line_1.amount += 5216 # Check match_partner_category_ids.217 test_category = self.env.ref('base.res_partner_category_8')218 self.partner_2.category_id = test_category219 self.rule_1.match_partner_category_ids |= test_category220 self._check_statement_matching(self.rule_1, {221 self.bank_line_1.id: {'aml_ids': []},222 self.bank_line_2.id: {'aml_ids': []},223 self.cash_line_1.id: {'aml_ids': [self.invoice_line_4.id], 'model': self.rule_1},224 })225 self.rule_1.match_partner_category_ids = False226 def test_mixin_rules(self):227 ''' Test usage of rules together.'''228 # rule_1 is used before rule_2.229 self.rule_1.sequence = 1230 self.rule_2.sequence = 2231 self._check_statement_matching(self.rule_1 + self.rule_2, {232 self.bank_line_1.id: {'aml_ids': [self.invoice_line_1.id], 'model': self.rule_1},233 self.bank_line_2.id: {'aml_ids': [234 self.invoice_line_2.id,235 self.invoice_line_3.id,236 self.invoice_line_1.id,237 ], 'model': self.rule_1},238 self.cash_line_1.id: {'aml_ids': [self.invoice_line_4.id], 'model': self.rule_1},239 })240 # rule_2 is used before rule_1.241 self.rule_1.sequence = 2242 self.rule_2.sequence = 1243 self._check_statement_matching(self.rule_1 + self.rule_2, {244 self.bank_line_1.id: {'aml_ids': [], 'model': self.rule_2, 'status': 'write_off'},245 self.bank_line_2.id: {'aml_ids': [], 'model': self.rule_2, 'status': 'write_off'},246 self.cash_line_1.id: {'aml_ids': [], 'model': self.rule_2, 'status': 'write_off'},247 })248 # rule_2 is used before rule_1 but only on partner_1.249 self.rule_2.match_partner_ids |= self.partner_1250 self._check_statement_matching(self.rule_1 + self.rule_2, {251 self.bank_line_1.id: {'aml_ids': [], 'model': self.rule_2, 'status': 'write_off'},252 self.bank_line_2.id: {'aml_ids': [], 'model': self.rule_2, 'status': 'write_off'},253 self.cash_line_1.id: {'aml_ids': [self.invoice_line_4.id], 'model': self.rule_1},254 })255 def test_auto_reconcile(self):256 ''' Test auto reconciliation.'''257 self.rule_1.sequence = 2258 self.rule_1.auto_reconcile = True259 self.rule_1.match_total_amount_param = 90260 self.rule_2.sequence = 1261 self.rule_2.match_partner_ids |= self.partner_2262 self.rule_2.auto_reconcile = True263 self.bank_line_1.amount += 5264 self._check_statement_matching(self.rule_1 + self.rule_2, {265 self.bank_line_1.id: {'aml_ids': [self.invoice_line_1.id], 'model': self.rule_1, 'status': 'reconciled'},266 self.bank_line_2.id: {'aml_ids': []},267 self.cash_line_1.id: {'aml_ids': [], 'model': self.rule_2, 'status': 'reconciled'},268 })269 # Check first line has been well reconciled.270 self.assertRecordValues(self.bank_line_1.journal_entry_ids, [271 {'partner_id': self.partner_1.id, 'debit': 0.0, 'credit': 5.0},272 {'partner_id': self.partner_1.id, 'debit': 0.0, 'credit': 100.0},273 {'partner_id': self.partner_1.id, 'debit': 105.0, 'credit': 0.0},274 ])275 # Check second line has been well reconciled.276 self.assertRecordValues(self.cash_line_1.journal_entry_ids, [277 {'partner_id': self.partner_2.id, 'debit': 1000.0, 'credit': 0.0},278 {'partner_id': self.partner_2.id, 'debit': 0.0, 'credit': 1000.0},279 ])280 def test_auto_reconcile_with_tax(self):281 ''' Test auto reconciliation with a tax amount included in the bank statement line'''282 self.rule_1.write({283 'auto_reconcile': True,284 'force_tax_included': True,285 'tax_ids': [(6, 0, self.tax21.ids)],286 'rule_type': 'writeoff_suggestion',287 })288 self.bank_line_2.unlink()289 self.bank_line_1.amount = -121290 self._check_statement_matching(291 self.rule_1,292 {293 self.bank_line_1.id: {'aml_ids': [], 'model': self.rule_1, 'status': 'reconciled'},294 },295 self.bank_st296 )297 # Check first line has been well reconciled.298 self.assertRecordValues(self.bank_line_1.journal_entry_ids, [299 {'partner_id': self.partner_1.id, 'debit': 100.0, 'credit': 0.0, 'tax_ids': [self.tax21.id], 'tax_line_id': False},300 {'partner_id': self.partner_1.id, 'debit': 21.0, 'credit': 0.0, 'tax_ids': [], 'tax_line_id': self.tax21.id},301 {'partner_id': self.partner_1.id, 'debit': 0.0, 'credit': 121.0, 'tax_ids': [], 'tax_line_id': False},302 ])303 def test_reverted_move_matching(self):304 AccountMove = self.env['account.move']305 move = AccountMove.create({306 'name': 'To Revert',307 'journal_id': self.company_data['default_journal_bank'].id,308 })309 partner = self.env['res.partner'].create({'name': 'Eugene'})310 AccountMoveLine = self.env['account.move.line'].with_context(check_move_validity=False)311 AccountMoveLine.create({312 'account_id': self.account_pay.id,313 'move_id': move.id,314 'partner_id': partner.id,315 'name': 'One of these days',316 'debit': 10,317 })318 payment_bnk_line = AccountMoveLine.create({319 'account_id': self.account_bnk.id,320 'move_id': move.id,321 'partner_id': partner.id,322 'name': 'I\'m gonna cut you into little pieces',323 'credit': 10,324 })325 move.post()326 move_reversed = move._reverse_moves()327 self.assertTrue(move_reversed.exists())328 bank_st = self.env['account.bank.statement'].create({329 'name': 'test bank journal', 'journal_id': self.company_data['default_journal_bank'].id,330 })331 bank_line_1 = self.env['account.bank.statement.line'].create({332 'statement_id': bank_st.id,333 'name': '8',334 'partner_id': partner.id,335 'amount': -10,336 'sequence': 1,337 })338 expected_values = {339 bank_line_1.id: {'aml_ids': [payment_bnk_line.id], 'model': self.rule_0}340 }341 self._check_statement_matching(self.rule_0, expected_values, statements=bank_st)342 def test_match_multi_currencies(self):343 ''' Ensure the matching of candidates is made using the right statement line currency.344 In this test, the value of the statement line is 100 USD = 300 GOL = 600 DAR and we want to match two journal345 items of:346 - 100 USD = 200 GOL (= 400 DAR from the statement line point of view)347 - 11 USD = 220 DAR348 Both journal items should be suggested to the user because they represents >95% of the statement line amount (620/600 ~=97)349 (DAR).350 '''351 currency_data_2 = self.setup_multi_currency_data(default_values={352 'name': 'Dark Chocolate Coin',353 'symbol': 'ð«',354 'currency_unit_label': 'Dark Choco',355 'currency_subunit_label': 'Dark Cacao Powder',356 }, rate2016=6.0, rate2017=4.0)357 partner = self.env['res.partner'].create({'name': 'Bernard Perdant'})358 journal = self.env['account.journal'].create({359 'name': 'test_match_multi_currencies',360 'code': 'xxxx',361 'type': 'bank',362 'currency_id': self.currency_data['currency'].id,363 })364 matching_rule = self.env['account.reconcile.model'].create({365 'name': 'test_match_multi_currencies',366 'rule_type': 'invoice_matching',367 'match_partner': True,368 'match_partner_ids': [(6, 0, partner.ids)],369 'match_total_amount': True,370 'match_total_amount_param': 95.0,371 'match_same_currency': False,372 'company_id': self.company_data['company'].id,373 })374 statement = self.env['account.bank.statement'].create({375 'name': 'test_match_multi_currencies',376 'journal_id': journal.id,377 'line_ids': [378 (0, 0, {379 'journal_id': journal.id,380 'date': '2016-01-01',381 'name': 'line',382 'partner_id': partner.id,383 'currency_id': currency_data_2['currency'].id,384 'amount': 300.0, # Rate is 3 GOL = 1 USD in 2016.385 'amount_currency': 600.0, # Rate is 6 DAR = 1 USD in 2016386 }),387 ],388 })389 statement_line = statement.line_ids390 statement.button_open()391 move = self.env['account.move'].create({392 'type': 'entry',393 'date': '2017-01-01',394 'journal_id': self.company_data['default_journal_sale'].id,395 'line_ids': [396 # Rate is 2 GOL = 1 USD in 2017.397 # The statement line will consider this line equivalent to 400 DAR.398 (0, 0, {399 'account_id': self.company_data['default_account_receivable'].id,400 'partner_id': partner.id,401 'currency_id': self.currency_data['currency'].id,402 'debit': 100.0,403 'credit': 0.0,404 'amount_currency': 200.0,405 }),406 # Rate is 20 GOL = 1 USD in 2017.407 (0, 0, {408 'account_id': self.company_data['default_account_receivable'].id,409 'partner_id': partner.id,410 'currency_id': currency_data_2['currency'].id,411 'debit': 11.0,412 'credit': 0.0,413 'amount_currency': 220.0,414 }),415 # Line to balance the journal entry:416 (0, 0, {417 'account_id': self.company_data['default_account_revenue'].id,418 'debit': 0.0,419 'credit': 111.0,420 }),421 ],422 })423 move.post()424 move_line_1 = move.line_ids.filtered(lambda line: line.debit == 100.0)425 move_line_2 = move.line_ids.filtered(lambda line: line.debit == 11.0)426 self.env['account.reconcile.model'].flush()427 self._check_statement_matching(matching_rule, {428 statement_line.id: {'aml_ids': (move_line_1 + move_line_2).ids, 'model': matching_rule}...
Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!