[FIX] account: Fix creation of statement with zero amount/amount_currency

During the migration, it could happen some statement lines are created with a zero amount in company currency or foreign currency.
It this specific case, we can't retrieve the correct amounts by multiplying the statement line conversion rate because X * 0 is always zero.
This commit ensures the amounts are well preserved in such case.

X-original-commit: a75bc7fdf014daf965cad72917ac475cbf83f6ac
This commit is contained in:
Laurent Smet
2020-07-30 08:48:37 +00:00
parent 17a8a6d933
commit 6c9b5d6f6f
2 changed files with 207 additions and 25 deletions
+63 -25
View File
@@ -657,8 +657,10 @@ class AccountBankStatementLine(models.Model):
# use the foreign currency set on the statement line.
amount_currency = amount_residual_currency
balance_journal_currency = (amount_currency / statement_line_rate) if statement_line_rate else 0.0
balance = journal_currency._convert(balance_journal_currency, company_currency, journal.company_id, self.date)
if statement_line_rate:
balance = journal_currency._convert(amount_currency / statement_line_rate, company_currency, journal.company_id, self.date)
else:
balance = amount_residual
elif currency_id == journal_currency.id and self.foreign_currency_id == company_currency:
@@ -666,10 +668,15 @@ class AccountBankStatementLine(models.Model):
# There is also a foreign currency set on the statement line that is the same as the company one.
# Then, the journal item to create will use the company's currency.
amount_currency = amount_residual_currency
balance = amount_currency * statement_line_rate
currency_id = False
amount_currency = 0.0
if statement_line_rate:
amount_currency = amount_residual_currency
balance = amount_currency * statement_line_rate
currency_id = False
amount_currency = 0.0
else:
balance = amount_residual
currency_id = False
amount_currency = 0.0
elif currency_id == journal_currency.id and self.foreign_currency_id != company_currency:
@@ -677,20 +684,30 @@ class AccountBankStatementLine(models.Model):
# There is also a foreign currency set on the statement line.
# The residual amount will be convert to the foreign currency set on the statement line.
amount_currency = amount_residual_currency
balance = journal_currency._convert(amount_currency, company_currency, journal.company_id, self.date)
amount_currency *= statement_line_rate
currency_id = self.foreign_currency_id.id
if statement_line_rate:
journal_amount_currency = amount_residual_currency
balance = journal_currency._convert(journal_amount_currency, company_currency, journal.company_id, self.date)
amount_currency = journal_amount_currency * statement_line_rate
currency_id = self.foreign_currency_id.id
else:
amount_currency = amount_residual_currency
balance = amount_residual
currency_id = self.foreign_currency_id.id
else:
# Whatever the currency set on the journal item passed as parameter, the counterpart line
# will be expressed in the foreign currency set on the statement line.
balance = amount_residual
amount_currency = company_currency._convert(balance, journal_currency, journal.company_id, self.date)
amount_currency *= statement_line_rate
currency_id = self.foreign_currency_id.id
if statement_line_rate:
balance = amount_residual
journal_amount_currency = company_currency._convert(balance, journal_currency, journal.company_id, self.date)
amount_currency = journal_amount_currency * statement_line_rate
currency_id = self.foreign_currency_id.id
else:
amount_currency = amount_residual_currency
balance = amount_residual
currency_id = self.foreign_currency_id.id
elif self.foreign_currency_id and not journal_currency:
@@ -698,12 +715,17 @@ class AccountBankStatementLine(models.Model):
# In that case, the 'amount' set on the statement line is expressed in the company's currency
# and is used as conversion rate between the company's currency and the foreign currency.
if currency_id == self.foreign_currency_id.id:
amount_currency = amount_residual_currency
balance = amount_currency / statement_line_rate if statement_line_rate else 0.0
if statement_line_rate:
if currency_id == self.foreign_currency_id.id:
amount_currency = amount_residual_currency
balance = amount_currency / statement_line_rate
else:
balance = amount_residual
amount_currency = balance * statement_line_rate
currency_id = self.foreign_currency_id.id
else:
balance = amount_residual
amount_currency = balance * statement_line_rate
amount_currency = amount_residual_currency
currency_id = self.foreign_currency_id.id
elif not self.foreign_currency_id and journal_currency:
@@ -740,9 +762,12 @@ class AccountBankStatementLine(models.Model):
if self.foreign_currency_id == company_currency:
amount_currency = 0.0
elif statement_line_rate:
journal_amount_currency = company_currency._convert(balance, journal_currency, journal.company_id, self.date)
amount_currency = journal_amount_currency * statement_line_rate
currency_id = self.foreign_currency_id.id
else:
amount_currency = company_currency._convert(balance, journal_currency, journal.company_id, self.date)
amount_currency *= statement_line_rate
amount_currency = amount_residual_currency
currency_id = self.foreign_currency_id.id
elif self.foreign_currency_id and not journal_currency:
@@ -750,8 +775,11 @@ class AccountBankStatementLine(models.Model):
# Different currencies set on the company and the statement line.
# Record the counterpart line using the foreign currency.
amount_currency = balance * statement_line_rate
currency_id = self.foreign_currency_id.id
if statement_line_rate:
amount_currency = balance * statement_line_rate
else:
amount_currency = amount_residual_currency
elif not self.foreign_currency_id and journal_currency:
@@ -800,9 +828,18 @@ class AccountBankStatementLine(models.Model):
counterpart_vals = {
'name': self.payment_ref,
'account_id': counterpart_account_id,
'amount_residual': liquidity_line_vals['debit'] - liquidity_line_vals['credit'],
}
if liquidity_line_vals['currency_id']:
if self.foreign_currency_id and self.foreign_currency_id != self.company_currency_id:
# Ensure the counterpart will have exactly the same amount in foreign currency as the amount set in the
# statement line to avoid some rounding issues when making a currency conversion.
counterpart_vals.update({
'currency_id': self.foreign_currency_id.id,
'amount_residual_currency': self.amount_currency,
})
elif liquidity_line_vals['currency_id']:
# Ensure the counterpart will have a balance exactly equals to the amount in journal currency.
# This avoid some rounding issues when the currency rate between two currencies is not symmetrical.
# E.g:
@@ -811,10 +848,8 @@ class AccountBankStatementLine(models.Model):
counterpart_vals.update({
'currency_id': liquidity_line_vals['currency_id'],
'balance': -liquidity_line_vals['amount_currency'],
'amount_residual_currency': liquidity_line_vals['amount_currency'],
})
else:
counterpart_vals['balance'] = liquidity_line_vals['credit'] - liquidity_line_vals['debit']
counterpart_line_vals = self._prepare_counterpart_move_line_vals(counterpart_vals)
return [liquidity_line_vals, counterpart_line_vals]
@@ -861,6 +896,9 @@ class AccountBankStatementLine(models.Model):
@api.constrains('amount', 'amount_currency', 'currency_id', 'foreign_currency_id', 'journal_id')
def _check_amounts_currencies(self):
''' Ensure the consistency the specified amounts and the currencies. '''
if self._context.get('skip_check_amounts_currencies'):
return
for st_line in self:
if st_line.journal_id != st_line.statement_id.journal_id:
raise ValidationError(_('The journal of a statement line must always be the same as the bank statement one.'))
@@ -518,6 +518,150 @@ class TestAccountBankStatementLine(TestAccountBankStatementCommon):
{'debit': 0.0, 'credit': 80.0, 'amount_currency': 0.0, 'currency_id': False},
)
def test_zero_amount_journal_curr_1_statement_curr_2(self):
self.bank_journal_2.currency_id = self.currency_1
statement = self.env['account.bank.statement'].with_context(skip_check_amounts_currencies=True).create({
'name': 'test_statement',
'date': '2019-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,
'foreign_currency_id': self.currency_2.id,
'amount': 0.0,
'amount_currency': 10.0,
}),
],
})
self.assertRecordValues(statement.line_ids.move_id.line_ids, [
{'debit': 0.0, 'credit': 0.0, 'amount_currency': 10.0, 'currency_id': self.currency_2.id},
{'debit': 0.0, 'credit': 0.0, 'amount_currency': -10.0, 'currency_id': self.currency_2.id},
])
def test_zero_amount_currency_journal_curr_1_statement_curr_2(self):
self.bank_journal_2.currency_id = self.currency_1
statement = self.env['account.bank.statement'].with_context(skip_check_amounts_currencies=True).create({
'name': 'test_statement',
'date': '2019-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,
'foreign_currency_id': self.currency_2.id,
'amount': 10.0,
'amount_currency': 0.0,
}),
],
})
self.assertRecordValues(statement.line_ids.move_id.line_ids, [
{'debit': 10.0, 'credit': 0.0, 'amount_currency': 0.0, 'currency_id': self.currency_2.id},
{'debit': 0.0, 'credit': 10.0, 'amount_currency': 0.0, 'currency_id': self.currency_2.id},
])
def test_zero_amount_journal_curr_2_statement_curr_1(self):
self.bank_journal_2.currency_id = self.currency_2
statement = self.env['account.bank.statement'].with_context(skip_check_amounts_currencies=True).create({
'name': 'test_statement',
'date': '2019-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,
'foreign_currency_id': self.currency_1.id,
'amount': 0.0,
'amount_currency': 10.0,
}),
],
})
self.assertRecordValues(statement.line_ids.move_id.line_ids, [
{'debit': 10.0, 'credit': 0.0, 'amount_currency': 0.0, 'currency_id': self.currency_2.id},
{'debit': 0.0, 'credit': 10.0, 'amount_currency': 0.0, 'currency_id': False},
])
def test_zero_amount_currency_journal_curr_2_statement_curr_1(self):
self.bank_journal_2.currency_id = self.currency_2
statement = self.env['account.bank.statement'].with_context(skip_check_amounts_currencies=True).create({
'name': 'test_statement',
'date': '2019-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,
'foreign_currency_id': self.currency_1.id,
'amount': 10.0,
'amount_currency': 0.0,
}),
],
})
self.assertRecordValues(statement.line_ids.move_id.line_ids, [
{'debit': 0.0, 'credit': 0.0, 'amount_currency': 10.0, 'currency_id': self.currency_2.id},
{'debit': 0.0, 'credit': 0.0, 'amount_currency': 0.0, 'currency_id': False},
])
def test_zero_amount_journal_curr_2_statement_curr_3(self):
self.bank_journal_2.currency_id = self.currency_2
statement = self.env['account.bank.statement'].with_context(skip_check_amounts_currencies=True).create({
'name': 'test_statement',
'date': '2019-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,
'foreign_currency_id': self.currency_3.id,
'amount': 0.0,
'amount_currency': 10.0,
}),
],
})
self.assertRecordValues(statement.line_ids.move_id.line_ids, [
{'debit': 0.0, 'credit': 0.0, 'amount_currency': 0.0, 'currency_id': self.currency_2.id},
{'debit': 0.0, 'credit': 0.0, 'amount_currency': -10.0, 'currency_id': self.currency_3.id},
])
def test_zero_amount_currency_journal_curr_2_statement_curr_3(self):
self.bank_journal_2.currency_id = self.currency_2
statement = self.env['account.bank.statement'].with_context(skip_check_amounts_currencies=True).create({
'name': 'test_statement',
'date': '2019-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,
'foreign_currency_id': self.currency_3.id,
'amount': 10.0,
'amount_currency': 0.0,
}),
],
})
self.assertRecordValues(statement.line_ids.move_id.line_ids, [
{'debit': 5.0, 'credit': 0.0, 'amount_currency': 10.0, 'currency_id': self.currency_2.id},
{'debit': 0.0, 'credit': 5.0, 'amount_currency': 0.0, 'currency_id': self.currency_3.id},
])
def test_constraints(self):
def assertStatementLineConstraint(statement_vals, statement_line_vals):
with self.assertRaises(Exception), self.cr.savepoint():