[FIX] account: compute of amount residual in foreign currency

When having an invoice in foreign currency and a partial payment in
domestic currency (in a different date with a different exchange rate),
the computed amount due is incorrect. When computing the
amount_residual_currency the payment (in domestic currency) is converted
to the foreign currency using the exchange rate of the invoice date, and
not the one of the payment date (see 56d92213b8).

If the account.partial.reconcile line will have a currency_id and a
amount_currency the amount_residual_currency will not be converted but
simply added.

This behaviour was introduced with e130606602
and backported to version 11.0 with 3363d7235137f286458c734a1a0417beeb1f66bb.
In version 12.0 this behaviour was partially reverted in d3d2612061.

opw-2156001

closes odoo/odoo#44181

X-original-commit: 94d34e052f3757c21884fd5a57cc68ea8c51aafb
Signed-off-by: Jorge Pinna Puissant (jpp) <jpp@odoo.com>
This commit is contained in:
Jorge Pinna Puissant
2020-01-29 12:24:08 +00:00
parent c5e5e97888
commit cb2d8943ea
3 changed files with 73 additions and 7 deletions
+8
View File
@@ -3653,6 +3653,14 @@ class AccountMoveLine(models.Model):
currency = credit_move.currency_id.id
amount_reconcile_currency = temp_amount_residual_currency
amount_reconcile = temp_amount_residual
elif bool(debit_move.currency_id) != bool(credit_move.currency_id):
# If only one of debit_move or credit_move has a secondary currency, also record the converted amount
# in that secondary currency in the partial reconciliation. That allows the exchange difference entry
# to be created, in case it is needed. It also allows to compute the amount residual in foreign currency.
currency = debit_move.currency_id or credit_move.currency_id
currency_date = debit_move.currency_id and credit_move.date or debit_move.date
amount_reconcile_currency = company_currency._convert(amount_reconcile, currency, debit_move.company_id, currency_date)
currency = currency.id
if cash_basis:
tmp_set = debit_move | credit_move
+59
View File
@@ -568,3 +568,62 @@ class TestPayment(AccountTestCommon):
self.assertEqual(name, move.name)
self.assertTrue(transfer_move.name)
self.assertNotEqual(name, transfer_move.name)
def test_partial_payment_inv_foreign_payment_domestic(self):
"""
Invoice of 1000$ (foreign $) at 01/01 with foreign exchange rate of 0.50000
Payment of 500 (domestic €) at 15/01 with foreign exchange rate of 1.00000
The residuals should be 500 in foreign and 1500 in domestic.
"""
company = self.env.ref('base.main_company')
self.env['res.currency.rate'].search([]).unlink()
self.env['res.currency.rate'].create({
'name': time.strftime('%Y') + '-01-01',
'rate': 1.0,
'currency_id': self.currency_eur_id,
'company_id': company.id
})
self.env['res.currency.rate'].create({
'name': time.strftime('%Y') + '-01-01',
'rate': 0.5, # Don't change this !
'currency_id': self.currency_usd_id,
'company_id': self.env.ref('base.main_company').id
})
self.env['res.currency.rate'].create({
'name': time.strftime('%Y') + '-01-15',
'rate': 1.0, # Don't change this !
'currency_id': self.currency_usd_id,
'company_id': self.env.ref('base.main_company').id
})
inv1 = self.env['account.move'].create({
'type': 'out_invoice',
'partner_id': self.partner_agrolait.id,
'currency_id': self.currency_usd_id,
'invoice_date': time.strftime('%Y') + '-01-01',
'date': time.strftime('%Y') + '-01-01',
'invoice_line_ids': [
(0, 0, {'product_id': self.product.id, 'quantity': 1, 'price_unit': 1000})
],
})
inv1.post()
payment = self.payment_model.create({
'payment_date': time.strftime('%Y') + '-01-15',
'payment_method_id': self.payment_method_manual_in.id,
'payment_type': 'inbound',
'partner_type': 'customer',
'partner_id': inv1.partner_id.id,
'amount': 500,
'journal_id': self.bank_journal_euro.id,
'company_id': company.id,
'currency_id': self.currency_eur_id,
})
payment.post()
inv1_receivable = inv1.line_ids.filtered(lambda l: l.account_id.internal_type == 'receivable')
pay_receivable = payment.move_line_ids.filtered(lambda l: l.account_id.internal_type == 'receivable')
self.assertEqual(inv1_receivable.balance, 2000)
self.assertEqual(pay_receivable.balance, -500)
(inv1_receivable + pay_receivable).reconcile()
self.assertEqual(inv1.amount_residual, 500)
self.assertEqual(inv1.amount_residual_signed, 1500)
+6 -7
View File
@@ -1855,6 +1855,7 @@ class TestReconciliationExec(TestAccountReconciliationCommon):
'partner_type': 'customer',
'partner_id': inv1.partner_id.id,
'amount': 372.10,
'payment_date': time.strftime('%Y') + '-07-01',
'journal_id': self.bank_journal_euro.id,
'company_id': company.id,
})
@@ -1884,9 +1885,7 @@ class TestReconciliationExec(TestAccountReconciliationCommon):
self.assertEqual(inv1_receivable.full_reconcile_id, pay_receivable.full_reconcile_id)
self.assertEqual(inv1_receivable.full_reconcile_id, move_balance_receiv.full_reconcile_id)
# This one may be due rounding errors
exchange_rcv = inv1_receivable.full_reconcile_id.exchange_move_id.line_ids.filtered(lambda l: l.account_id.internal_type == 'receivable')
self.assertEqual(exchange_rcv.amount_currency, 0.01)
self.assertFalse(inv1_receivable.full_reconcile_id.exchange_move_id)
self.assertEqual(inv1.payment_state, 'paid')
self.assertEqual(inv2.payment_state, 'paid')
@@ -1967,8 +1966,6 @@ class TestReconciliationExec(TestAccountReconciliationCommon):
self.assertEqual(inv1_receivable.full_reconcile_id, pay_receivable.full_reconcile_id)
self.assertEqual(inv1_receivable.full_reconcile_id, move_balance_receiv.full_reconcile_id)
self.assertFalse(inv1_receivable.full_reconcile_id.exchange_move_id)
self.assertEqual(inv1.payment_state, 'paid')
self.assertEqual(inv2.payment_state, 'paid')
@@ -2099,7 +2096,8 @@ class TestReconciliationExec(TestAccountReconciliationCommon):
self.assertEqual(inv1_receivable.full_reconcile_id, inv2_receivable.full_reconcile_id)
self.assertEqual(inv1_receivable.full_reconcile_id, payment_receivable.full_reconcile_id)
self.assertFalse(inv1_receivable.full_reconcile_id.exchange_move_id)
exchange_rcv = inv1_receivable.full_reconcile_id.exchange_move_id.line_ids.filtered(lambda l: l.account_id.internal_type == 'receivable')
self.assertEqual(exchange_rcv.amount_currency, 0.01)
self.assertEqual(inv1.payment_state, 'paid')
self.assertEqual(inv2.payment_state, 'paid')
@@ -2296,6 +2294,7 @@ class TestReconciliationExec(TestAccountReconciliationCommon):
self.assertEqual(inv1_receivable.full_reconcile_id, payment_receivable.full_reconcile_id)
self.assertEqual(move_balance_receiv.full_reconcile_id, inv1_receivable.full_reconcile_id)
self.assertFalse(inv1_receivable.full_reconcile_id.exchange_move_id)
exchange_rcv = inv1_receivable.full_reconcile_id.exchange_move_id.line_ids.filtered(lambda l: l.account_id.internal_type == 'receivable')
self.assertEqual(exchange_rcv.amount_currency, 0.01)
self.assertEqual(inv1.payment_state, 'paid')