Permalink
Browse files

[FIX] account: fix "post at bank reconciliation" option of bank journals

Before that, with "post at bank reconciliation option" activated on bank journal, the following scenarii did not work as expected:

1. When creating an invoice, making two payments for it, and then matching only one of them with a bank statement
=> the invoice was marked as 'paid' while it should have staid 'in payment' until the second payment gets a bank statement.

2. When directly reconciling a bank statement with an invoice for its full amount
=> the invoice staid in "in payment" state, while it should have been "paid"

[IMP] account: add tests for the aforementioned cases

closes #28428
  • Loading branch information...
oco-odoo committed Nov 6, 2018
1 parent e1c9efb commit 7754416cd8a6484dd7d449f302909d7ef70ffe0f
@@ -550,7 +550,8 @@ def process_reconciliation(self, counterpart_aml_dicts=None, payment_aml_rec=Non
aml_rec.payment_id.payment_date = self.date
aml_rec.move_id.post()
# We check the paid status of the invoices reconciled with this payment
aml_rec.payment_id.reconciled_invoice_ids.filtered(lambda x: x.state == 'in_payment').write({'state': 'paid'})
for invoice in aml_rec.payment_id.reconciled_invoice_ids:
self._check_invoice_state(invoice)
# Create move line(s). Either matching an existing journal entry (eg. invoice), in which
# case we reconcile the existing and the new move lines together, or being a write-off.
@@ -639,6 +640,8 @@ def process_reconciliation(self, counterpart_aml_dicts=None, payment_aml_rec=Non
(new_aml | counterpart_move_line).reconcile()
self._check_invoice_state(counterpart_move_line.invoice_id)
# Balance the move
st_line_amount = -sum([x.balance for x in move.line_ids])
aml_dict = self._prepare_reconciliation_move_line(move, st_line_amount)
@@ -658,3 +661,7 @@ def process_reconciliation(self, counterpart_aml_dicts=None, payment_aml_rec=Non
counterpart_moves.assert_balanced()
return counterpart_moves
def _check_invoice_state(self, invoice):
if invoice.state == 'in_payment' and all([payment.state == 'reconciled' for payment in invoice.mapped('payment_move_line_ids.payment_id')]):
invoice.write({'state': 'paid'})
@@ -26,6 +26,19 @@ def test_reconciliation_proposition(self):
self.assertEqual(prop[0]['id'], rcv_mv_line.id)
def test_full_reconcile(self):
self._reconcile_invoice_with_statement(False)
def test_post_at_bank_rec_full_reconcile(self):
""" Test the full reconciliation of a bank statement directly with an invoice.
"""
self._reconcile_invoice_with_statement(True)
def _reconcile_invoice_with_statement(self, post_at_bank_rec):
""" Tests the reconciliation of an invoice with a bank statement, using
the provided 'post at bank reconciliation' value for the bank journal
where to generate the statement.
"""
self.bs_model.with_context(journal_type='bank')._default_journal().post_at_bank_reconciliation = post_at_bank_rec
rcv_mv_line = self.create_invoice(100)
st_line = self.create_statement_line(100)
# reconcile
@@ -47,6 +60,7 @@ def test_full_reconcile(self):
self.assertTrue(rcv_mv_line.reconciled)
self.assertTrue(counterpart_mv_line.reconciled)
self.assertEqual(counterpart_mv_line.matched_credit_ids, rcv_mv_line.matched_debit_ids)
self.assertEqual(rcv_mv_line.invoice_id.state, 'paid', "The related invoice's state should now be 'paid'")
def test_reconcile_with_write_off(self):
pass
@@ -507,14 +507,14 @@ def test_payment_and_writeoff_in_other_currency_3(self):
self.assertTrue(invoice.move_id.line_ids.filtered(lambda l: l.account_id == self.account_receivable)[0].full_reconcile_id)
def test_post_at_bank_reconciliation_payment(self):
# Create a new payment in a journal requiring the journal entries to be posted at bank reconciliation
# Create two new payments in a journal requiring the journal entries to be posted at bank reconciliation
post_at_bank_rec_journal = bank_journal_euro = self.env['account.journal'].create({
'name': 'Bank',
'type': 'bank',
'code': 'COUCOU',
'post_at_bank_rec': True,
})
payment = self.payment_model.create({'payment_type': 'inbound',
payment_one = self.payment_model.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,
@@ -524,17 +524,48 @@ def test_post_at_bank_reconciliation_payment(self):
'writeoff_account_id': self.account_receivable.id,
'journal_id': post_at_bank_rec_journal.id,
})
payment.post()
payment_one.post()
payment_two = self.payment_model.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': 11,
'payment_date': time.strftime('%Y') + '-12-15',
'payment_difference_handling': 'reconcile',
'writeoff_account_id': self.account_receivable.id,
'journal_id': post_at_bank_rec_journal.id,
})
payment_two.post()
# Check the payments and their move state
self.assertEqual(payment_one.state, 'posted', "Payment one shoud be in posted state.")
self.assertEqual(payment_one.mapped('move_line_ids.move_id.state'), ['draft'], "A posted payment (payment_one) in a bank journal with the 'post at bank reconciliation' option activated should correspond to a draft account.move")
self.assertEqual(payment_two.state, 'posted', "Payment two shoud be in posted state.")
self.assertEqual(payment_two.mapped('move_line_ids.move_id.state'), ['draft'], "A posted payment (payment_two) in a bank journal with the 'post at bank reconciliation' option activated should correspond to a draft account.move")
# Reconcile the two payments with an invoice, whose full amount is equal to their sum
invoice = self.create_invoice(amount=53, partner=self.partner_agrolait.id)
(payment_one.move_line_ids + payment_two.move_line_ids + invoice.move_id.line_ids).filtered(lambda x: x.account_id.user_type_id.type == 'receivable').reconcile()
self.assertTrue(invoice.reconciled, "Invoice should have been reconciled with the payments")
self.assertEqual(invoice.state, 'in_payment', "Invoice should be in 'in payment' state")
# Match the first payment with a bank statement line
bank_statement_one = self.reconcile(payment_one.move_line_ids.filtered(lambda x: x.account_id.user_type_id.type == 'liquidity'), 42)
stmt_line_date_one = bank_statement_one.mapped('line_ids.date')
self.assertEqual(payment_one.mapped('move_line_ids.move_id.state'), ['posted'], "After bank reconciliation, payment one's account.move should be posted.")
self.assertEqual(payment_one.mapped('move_line_ids.move_id.date'), stmt_line_date_one, "After bank reconciliation, payment one's account.move should share the same date as the bank statement.")
self.assertEqual([payment_one.payment_date], stmt_line_date_one, "After bank reconciliation, payment one should share the same date as the bank statement.")
self.assertEqual(invoice.state, 'in_payment', "The invoice should still be 'in payment', not all its payments are reconciled with a statement")
# Check the payment and move state
self.assertEqual(payment.state, 'posted', "Payment shoud be in posted state.")
self.assertEqual(payment.mapped('move_line_ids.move_id.state'), ['draft'], "A posted payment in a bank journal with the 'post at bank reconciliation' option activated should correspond to a draft account.move")
# Match the second payment with a bank statement line
bank_statement_two = self.reconcile(payment_two.move_line_ids.filtered(lambda x: x.account_id.user_type_id.type == 'liquidity'), 42)
stmt_line_date_two = bank_statement_two.mapped('line_ids.date')
# Match the payment with a bank statement line
bank_statement = self.reconcile(payment.move_line_ids.filtered(lambda x: x.account_id == post_at_bank_rec_journal.default_debit_account_id), 42)
stmt_line_date = bank_statement.mapped('line_ids.date')
self.assertEqual(payment_two.mapped('move_line_ids.move_id.state'), ['posted'], "After bank reconciliation, payment two's account.move should be posted.")
self.assertEqual(payment_two.mapped('move_line_ids.move_id.date'), stmt_line_date_two, "After bank reconciliation, payment two's account.move should share the same date as the bank statement.")
self.assertEqual([payment_two.payment_date], stmt_line_date_two, "After bank reconciliation, payment two should share the same date as the bank statement.")
# Check the move has been posted properly
self.assertEqual(payment.mapped('move_line_ids.move_id.state'), ['posted'], "After bank reconciliation, the payment's account.move should be posted.")
self.assertEqual(payment.mapped('move_line_ids.move_id.date'), stmt_line_date, "After bank reconciliation, the payment's account.move should share the same date as the bank statement.")
self.assertEqual([payment.payment_date], stmt_line_date, "After bank reconciliation, the payment should share the same date as the bank statement.")
# The invoice should now be paid
self.assertEqual(invoice.state, 'paid', "Invoice should be in 'paid' state after having reconciled the two payments with a bank statement")

0 comments on commit 7754416

Please sign in to comment.