[FIX] account: Fix statement line rounding issue multi-currency

When reconciling a statement line with multiple lines in a multi-currency environment, it could lead to a rounding issue due to the currency rates. It could lead to an auto-generated open-balance of 0.01 amount to auto-balance the journal entry but the result is wrong since the partner has an open amount left on the receivable/payable account.

closes odoo/odoo#64636

X-original-commit: 4d4e6e588d14742f153a1c6b67d510e0c21e5d64
Signed-off-by: oco-odoo <oco-odoo@users.noreply.github.com>
Signed-off-by: Laurent Smet <smetl@users.noreply.github.com>
This commit is contained in:
Laurent Smet
2021-01-15 17:21:20 +00:00
parent 568fe91341
commit 5af64d1758
2 changed files with 72 additions and 2 deletions
@@ -1028,6 +1028,9 @@ class AccountBankStatementLine(models.Model):
'''
self.ensure_one()
journal = self.journal_id
company_currency = journal.company_id.currency_id
foreign_currency = self.foreign_currency_id or journal.currency_id or company_currency
liquidity_lines, suspense_lines, other_lines = self._seek_for_lines()
@@ -1044,6 +1047,7 @@ class AccountBankStatementLine(models.Model):
reconciliation_overview = []
total_balance = liquidity_lines.balance
total_amount_currency = liquidity_lines.amount_currency
# Step 1: Split 'lines_vals_list' into two batches:
# - The existing account.move.lines that need to be reconciled with the statement line.
@@ -1065,6 +1069,7 @@ class AccountBankStatementLine(models.Model):
# Newly created account.move.line from scratch.
line_vals = self._prepare_counterpart_move_line_vals(vals)
total_balance += line_vals['debit'] - line_vals['credit']
total_amount_currency += line_vals['amount_currency']
reconciliation_overview.append({
'line_vals': line_vals,
@@ -1076,6 +1081,7 @@ class AccountBankStatementLine(models.Model):
for line, counterpart_vals in zip(existing_lines, to_process_vals):
line_vals = self._prepare_counterpart_move_line_vals(counterpart_vals, move_line=line)
balance = line_vals['debit'] - line_vals['credit']
amount_currency = line_vals['amount_currency']
reconciliation_vals = {
'line_vals': line_vals,
@@ -1088,7 +1094,7 @@ class AccountBankStatementLine(models.Model):
payment_vals = self.env['account.payment.register']\
.with_context(active_model='account.move.line', active_ids=line.ids)\
.create({
'amount': abs(line_vals['amount_currency']) if line_vals['currency_id'] else abs(balance),
'amount': abs(amount_currency) if line_vals['currency_id'] else abs(balance),
'payment_date': self.date,
'payment_type': 'inbound' if balance < 0.0 else 'outbound',
'journal_id': self.journal_id.id,
@@ -1131,8 +1137,21 @@ class AccountBankStatementLine(models.Model):
reconciliation_overview.append(reconciliation_vals)
total_balance += balance
total_amount_currency += amount_currency
# Step 3: If the journal entry is not yet balanced, create an open balance.
# Step 3: Fix rounding issue due to currency conversions.
# Add the remaining balance on the first encountered line starting with the custom ones.
if foreign_currency.is_zero(total_amount_currency) and not company_currency.is_zero(total_balance):
vals = reconciliation_overview[0]['line_vals']
new_balance = vals['debit'] - vals['credit'] - total_balance
vals.update({
'debit': new_balance if new_balance > 0.0 else 0.0,
'credit': -new_balance if new_balance < 0.0 else 0.0,
})
total_balance = 0.0
# Step 4: If the journal entry is not yet balanced, create an open balance.
if self.company_currency_id.round(total_balance):
counterpart_vals = {
@@ -1498,3 +1498,54 @@ class TestAccountBankStatementLine(TestAccountBankStatementCommon):
'amount_residual_currency': 0.0,
},
])
def test_conversion_rate_rounding_issue(self):
''' Ensure the reconciliation is well handling the rounding issue due to multiple currency conversion rates.
In this test, the resulting journal entry after reconciliation is:
{'amount_currency': 7541.66, 'debit': 6446.97, 'credit': 0.0}
{'amount_currency': 226.04, 'debit': 193.22, 'credit': 0.0}
{'amount_currency': -7767.70, 'debit': 0.0, 'credit': 6640.19}
... but 226.04 / 1.1698 = 193.23. In this situation, 0.01 has been removed from this write-off line in order to
avoid an unecessary open-balance line being an exchange difference issue.
'''
self.bank_journal_2.currency_id = self.currency_2
self.currency_data['rates'][-1].rate = 1.1698
statement = self.env['account.bank.statement'].create({
'name': 'test_statement',
'date': '2017-01-01',
'journal_id': self.bank_journal_2.id,
'line_ids': [
(0, 0, {
'date': '2019-01-01',
'payment_ref': 'line_1',
'partner_id': self.partner_a.id,
'amount': 7541.66,
}),
],
})
statement.button_post()
statement_line = statement.line_ids
payment = self.env['account.payment'].create({
'amount': 7767.70,
'date': '2019-01-01',
'currency_id': self.currency_2.id,
'payment_type': 'inbound',
'partner_type': 'customer',
})
payment.action_post()
liquidity_lines, counterpart_lines, writeoff_lines = payment._seek_for_lines()
self.assertRecordValues(liquidity_lines, [{'amount_currency': 7767.70}])
statement_line.reconcile([
{'id': liquidity_lines.id},
{'balance': 226.04, 'account_id': self.company_data['default_account_revenue'].id, 'name': "write-off"},
])
self.assertRecordValues(statement_line.line_ids, [
{'amount_currency': 7541.66, 'debit': 6446.97, 'credit': 0.0},
{'amount_currency': 226.04, 'debit': 193.22, 'credit': 0.0},
{'amount_currency': -7767.70, 'debit': 0.0, 'credit': 6640.19},
])