Browse files

[FIX] account: reconcile payments against min date_maturity journal item

1. Create a payment term with:
   - 50% due now
   - balance due in 14 days
2. Validate an invoice with this payment term and partner Agrolait
3. Create a payment from Agrolait with the 50% due
4. Add this outstanding credit to the invoice

It is reconciled with the balance due in 14 days instead of what is
due now. Because of this e.g. the Aged Receivable report will show the
customer being overdue with a payment.

This issue was first fixed in 9.0 at
adad192. It was then reintroduced in
saas-11.4 at d3d2612. This commit
adds a test to avoid regressions like this.

To fix the issue this sorts journal items by their Due Date if there
is one. Otherwise we use the date from the journal entry as before.

Note that before this commit journal items were not sorted at all by
the two 'sorted' statements. sorted returns a sorted recordset, it
doesn't modify the recordset it's called on.

  • Loading branch information...
jorenvo authored and qdp-odoo committed Nov 5, 2018
1 parent dc35de9 commit b9e6adcaf7dd87f8a625588a03690e4a9f9cbc02
Showing with 62 additions and 2 deletions.
  1. +2 −2 addons/account/models/
  2. +60 −0 addons/account/tests/
@@ -862,8 +862,8 @@ def auto_reconcile_lines(self):
# Create list of debit and list of credit move ordered by date-currency
debit_moves = self.filtered(lambda r: r.debit != 0 or r.amount_currency > 0)
credit_moves = self.filtered(lambda r: != 0 or r.amount_currency < 0)
debit_moves.sorted(key=lambda a: (, a.currency_id))
credit_moves.sorted(key=lambda a: (, a.currency_id))
debit_moves = debit_moves.sorted(key=lambda a: (a.date_maturity or, a.currency_id))
credit_moves = credit_moves.sorted(key=lambda a: (a.date_maturity or, a.currency_id))
# Compute on which field reconciliation should be based upon:
field = self[0].account_id.currency_id and 'amount_residual_currency' or 'amount_residual'
#if all lines share the same currency, use amount_residual_currency to avoid currency rounding error
@@ -974,3 +974,63 @@ def test_partial_reconcile_currencies_02(self):
# because they owe us still 50 CC.
self.assertEqual(invoice_cust_1.state, 'open',
'Invoice is in status %s' % invoice_cust_1.state)
def test_multiple_term_reconciliation_opw_1906665(self):
'''Test that when registering a payment to an invoice with multiple
payment term lines the reconciliation happens against the line
with the earliest date_maturity
payment_term = self.env['account.payment.term'].create({
'name': 'Pay in 2 installments',
'line_ids': [
# Pay 50% immediately
(0, 0, {
'value': 'percent',
'value_amount': 50,
# Pay the rest after 14 days
(0, 0, {
'value': 'balance',
'days': 14,
# can't use self.create_invoice because it validates and we need to set payment_term_id
invoice = self.account_invoice_model.create({
'partner_id': self.partner_agrolait_id,
'reference_type': 'none',
'currency_id': self.currency_usd_id,
'name': 'Multiple payment terms',
'type': 'out_invoice',
'date_invoice': time.strftime('%Y') + '-07-01',
'quantity': 1,
'price_unit': 50,
'name': self.product.display_name,
'account_id': self.env['account.account'].search([('user_type_id', '=', self.env.ref('account.data_account_type_revenue').id)], limit=1).id,
payment = self.env['account.payment'].create({
'payment_type': 'inbound',
'payment_method_id': self.env.ref('account.account_payment_method_manual_in').id,
'partner_type': 'customer',
'partner_id': self.partner_agrolait_id,
'amount': 25,
'currency_id': self.currency_usd_id,
receivable_lines = invoice.move_id.line_ids.filtered(lambda line: line.account_id == self.account_rcv).sorted('date_maturity')[0]

0 comments on commit b9e6adc

Please sign in to comment.