Skip to content

Commit

Permalink
[FIX] account: reconcile payments against min date_maturity journal item
Browse files Browse the repository at this point in the history
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.

opw-1906665
  • Loading branch information
jorenvo authored and qdp-odoo committed Nov 7, 2018
1 parent dc35de9 commit b9e6adc
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 2 deletions.
4 changes: 2 additions & 2 deletions addons/account/models/account_move.py
Original file line number Diff line number Diff line change
Expand Up @@ -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: r.credit != 0 or r.amount_currency < 0)
debit_moves.sorted(key=lambda a: (a.date, a.currency_id))
credit_moves.sorted(key=lambda a: (a.date, a.currency_id))
debit_moves = debit_moves.sorted(key=lambda a: (a.date_maturity or a.date, a.currency_id))
credit_moves = credit_moves.sorted(key=lambda a: (a.date_maturity or a.date, 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
Expand Down
60 changes: 60 additions & 0 deletions addons/account/tests/test_reconciliation.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
'payment_term_id': payment_term.id,
'reference_type': 'none',
'currency_id': self.currency_usd_id,
'name': 'Multiple payment terms',
'account_id': self.account_rcv.id,
'type': 'out_invoice',
'date_invoice': time.strftime('%Y') + '-07-01',
})
self.account_invoice_line_model.create({
'product_id': self.product.id,
'quantity': 1,
'price_unit': 50,
'invoice_id': invoice.id,
'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,
})

invoice.action_invoice_open()

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,
'journal_id': self.bank_journal_usd.id,
})
payment.post()

invoice.assign_outstanding_credit(payment.move_line_ids.filtered('credit').id)

receivable_lines = invoice.move_id.line_ids.filtered(lambda line: line.account_id == self.account_rcv).sorted('date_maturity')[0]
self.assertTrue(receivable_lines.matched_credit_ids)

0 comments on commit b9e6adc

Please sign in to comment.