From 83df770d0a9249952334b386e6499dd0a67b5cb6 Mon Sep 17 00:00:00 2001 From: "Guillaume (guva)" Date: Thu, 11 May 2023 14:06:04 +0000 Subject: [PATCH] [FIX] account: move date on reversed exchange move Before this commit, the reversal of a passed exchange move was not created on the correct date: - If sequence is reset by month, the reversal should be created at the end of the month of the exchange move, and if sequence is reset by year, at the end of the year. Steps: - With a foreign currency X activated and two different rates few months in the past. - Create and confirm an invoice with currency X at the date of the first rate. - Register a payment at the date of the second rate (an exchange move is created). - Unreconcile the payment from the invoice. -> A reversal of the exchange move is created, but the date is wrong (set to today's date). opw-2856385 closes odoo/odoo#122981 X-original-commit: 130832942d4bd40e0c11676b030db6fb794bfbdb Signed-off-by: Brice Bartoletti (bib) Signed-off-by: Guillaume Vanleynseele (guva) --- addons/account/tests/common.py | 6 +- .../tests/test_account_move_out_invoice.py | 56 +++++++++++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/addons/account/tests/common.py b/addons/account/tests/common.py index 01bd02083f3..0cd1d40651a 100644 --- a/addons/account/tests/common.py +++ b/addons/account/tests/common.py @@ -382,7 +382,9 @@ class AccountTestInvoicingCommon(TransactionCase): }) @classmethod - def init_invoice(cls, move_type, partner=None, invoice_date=None, post=False, products=None, amounts=None, taxes=None, company=False): + def init_invoice(cls, move_type, partner=None, invoice_date=None, post=False, products=None, amounts=None, taxes=None, company=False, currency=None): + products = [] if products is None else products + amounts = [] if amounts is None else amounts move_form = Form(cls.env['account.move'] \ .with_company(company or cls.env.company) \ .with_context(default_move_type=move_type)) @@ -396,6 +398,8 @@ class AccountTestInvoicingCommon(TransactionCase): if not move_form._get_modifier('date', 'invisible'): move_form.date = move_form.invoice_date move_form.partner_id = partner or cls.partner_a + if currency: + move_form.currency_id = currency for product in (products or []): with move_form.invoice_line_ids.new() as line_form: diff --git a/addons/account/tests/test_account_move_out_invoice.py b/addons/account/tests/test_account_move_out_invoice.py index e350eea5332..bb1a02e39f6 100644 --- a/addons/account/tests/test_account_move_out_invoice.py +++ b/addons/account/tests/test_account_move_out_invoice.py @@ -3377,3 +3377,59 @@ class TestAccountMoveOutInvoiceOnchanges(AccountTestInvoicingCommon): 'credit': 0.0, }, ]) + + @freeze_time('2019-01-01') + def test_date_reversal_exchange_move(self): + """ + Test the date of the reversal of an exchange move created when unreconciling a payment made in the past, when no lock date is set. + It should be the last day of the month of the exchange move date if sequence is incremented by month, + and the last day of the year of the exchange move date if sequence is incremented by year. + """ + for format_incrementor, expected_date in (('month', '2017-01-31'), ('year', '2017-12-31')): + with self.subTest(format_incrementor=format_incrementor, expected_date=expected_date): + invoice = self.init_invoice(move_type='out_invoice', partner=self.partner_a, invoice_date='2016-01-20', post=True, amounts=[750.0], currency=self.currency_data['currency']) + + new_exchange_journal = self.env['account.journal'].create({ + 'name': f'Exchange Journal for {invoice.name}', + 'code': f'EXCH{invoice.sequence_number}', + 'type': 'general', + 'company_id': self.env.company.id, + }) + + # Need a first move in the new journal to initiate the sequence with a right incrementor, depending on the wanted format + self.env['account.move'].create({ + 'journal_id': new_exchange_journal.id, + 'name': 'EXCH/2019/00001' if format_incrementor == 'year' else 'EXCH/2019/01/0001', + 'line_ids': [ + (0, 0, { + 'account_id': self.company_data['default_account_receivable'].id, + 'debit': 125.0, + 'credit': 0.0, + }), + (0, 0, { + 'account_id': self.company_data['default_account_revenue'].id, + 'debit': 0.0, + 'credit': 125.0, + }) + ] + }) + + self.env.company.currency_exchange_journal_id = new_exchange_journal + + self.env['account.payment.register'].with_context(active_model='account.move', active_ids=invoice.ids).create({ + 'payment_date': '2017-01-20', + })._create_payments() + + line_receivable = invoice.line_ids.filtered(lambda l: l.account_id.account_type == 'asset_receivable') + + exchange_move = line_receivable.full_reconcile_id.partial_reconcile_ids.exchange_move_id + + # Date of the exchange move should be the date of the payment + self.assertEqual(exchange_move.date, fields.Date.to_date('2017-01-20')) + + line_receivable.remove_move_reconcile() + + exchange_move_reversal = exchange_move.reversal_move_id + + # Date of the reversal of the exchange move should be the last day of the month/year of the payment depending on the sequence format + self.assertEqual(exchange_move_reversal.date, fields.Date.to_date(expected_date))