Skip to content
Permalink
Browse files

[FIX] account: cash basis reconciliation almost all amount

In multicurrency

Do an invoice with cash basis lines in the foreign currency
Make a payment for almost all the invoice
"almost" refers to the point where virtually all taxes will be paid

i.e., paying 90 over 100, that contains a tax of 5%
The tax paid will be an amount almost equal (to a few cents) to the
total amount of the tax
It is not negligible, but if the currency rates are in the right configuration
(i.e. 0.005888)

Before this commit: the Cash Basis reconciliation will be considered as full and will trigger
the creation of the Exchange Diff Entry.
In turn, paying the rest of the invoice will pop up an error saying that some entries are already reconciled
(with the Exchange Diff entry)
It is not *that* that an exchange rate entry has been created the first time
after all, a percentage sufficiently close to 100 has been paid
But it blocks subsequent reconciliation, hence this fix

After this commit, if the cash basis entry doesn't match at least 100% of the paid move
then, we force to not check for full reconciliation

OPW 1953027
closes #31168
  • Loading branch information...
kebeclibre committed Mar 25, 2019
1 parent 24f7c72 commit aad74fd3870256442493c338a5864e0a3634f80f
Showing with 62 additions and 1 deletion.
  1. +4 −1 addons/account/models/account_move.py
  2. +58 −0 addons/account/tests/test_reconciliation.py
@@ -952,7 +952,8 @@ def reconcile(self, writeoff_acc_id=False, writeoff_journal_id=False):
#add writeoff line to reconcile algorithm and finish the reconciliation
remaining_moves = (remaining_moves + writeoff_to_reconcile).auto_reconcile_lines()
# Check if reconciliation is total or needs an exchange rate entry to be created
(self + writeoff_to_reconcile).check_full_reconcile()
if not self._context.get('skip_full_reconcile_check'):
(self + writeoff_to_reconcile).check_full_reconcile()
return True

def _create_writeoff(self, writeoff_vals):
@@ -1602,6 +1603,8 @@ def create_tax_cash_basis_entry(self, percentage_before_rec):
if line.account_id.reconcile:
#setting the account to allow reconciliation will help to fix rounding errors
to_clear_aml |= line
if percentage_after < 1.0:
to_clear_aml = to_clear_aml.with_context(skip_full_reconcile_check=True)
to_clear_aml.reconcile()

if any([tax.tax_exigibility == 'on_payment' for tax in line.tax_ids]):
@@ -1883,3 +1883,61 @@ def test_reconciliation_cash_basis_revert(self):
reverted_expected = reverted.line_ids.filtered(lambda l: l.account_id == inv_line.account_id)
self.assertEqual(len(reverted_expected), 1)
self.assertEqual(reverted_expected.full_reconcile_id, inv_line.full_reconcile_id)


class LPE(TestReconciliation):

def test_reconciliation_cash_basis_foreign_currency_low_values(self):
journal = self.env['account.journal'].create({
'name': 'Bank', 'type': 'bank', 'code': 'THE',
'currency_id': self.currency_usd_id,
})
usd = self.env['res.currency'].browse(self.currency_usd_id)
usd.rate_ids.unlink()
self.env['res.currency.rate'].create({
'name': time.strftime('%Y-01-01'),
'rate': 1/17.0,
'currency_id': self.currency_usd_id,
'company_id': self.env.ref('base.main_company').id,
})
invoice = self.create_invoice(
type='out_invoice', invoice_amount=50,
currency_id=self.currency_usd_id)
invoice.journal_id.update_posted = True
invoice.action_cancel()
invoice.state = 'draft'
invoice.invoice_line_ids.write({
'invoice_line_tax_ids': [(6, 0, [self.tax_cash_basis.id])]})
invoice.compute_taxes()
invoice.action_invoice_open()

self.assertTrue(invoice.currency_id != self.env.user.company_id.currency_id)

# First Payment
payment0 = self.make_payment(invoice, journal, invoice.amount_total - 0.01)
self.assertEqual(invoice.residual, 0.01)

tax_waiting_line = invoice.move_id.line_ids.filtered(lambda l: l.account_id == self.tax_waiting_account)
self.assertFalse(tax_waiting_line.reconciled)

move_caba0 = tax_waiting_line.matched_debit_ids.debit_move_id.move_id
self.assertTrue(move_caba0.exists())
self.assertEqual(move_caba0.journal_id, self.env.user.company_id.tax_cash_basis_journal_id)

pay_receivable_line0 = payment0.move_line_ids.filtered(lambda l: l.account_id == self.account_rcv)
self.assertTrue(pay_receivable_line0.reconciled)
self.assertEqual(pay_receivable_line0.matched_debit_ids, move_caba0.tax_cash_basis_rec_id)

# Second Payment
payment1 = self.make_payment(invoice, journal, 0.01)
self.assertEqual(invoice.residual, 0)
self.assertEqual(invoice.state, 'paid')

self.assertTrue(tax_waiting_line.reconciled)
move_caba1 = tax_waiting_line.matched_debit_ids.mapped('debit_move_id').mapped('move_id').filtered(lambda m: m != move_caba0)
self.assertEqual(len(move_caba1.exists()), 1)
self.assertEqual(move_caba1.journal_id, self.env.user.company_id.tax_cash_basis_journal_id)

pay_receivable_line1 = payment1.move_line_ids.filtered(lambda l: l.account_id == self.account_rcv)
self.assertTrue(pay_receivable_line1.reconciled)
self.assertEqual(pay_receivable_line1.matched_debit_ids, move_caba1.tax_cash_basis_rec_id)

0 comments on commit aad74fd

Please sign in to comment.
You can’t perform that action at this time.