Files
enterprise-addons/account_accountant_batch_payment/tests/test_batch_payment.py
T

856 lines
42 KiB
Python

# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import time
from unittest.mock import patch
from odoo import Command
from odoo.addons.account_accountant.tests.test_account_bank_statement import TestAccountBankStatement
from odoo.tests import Form, tagged
from odoo.exceptions import ValidationError
@tagged('post_install', '-at_install')
class TestBatchPayment(TestAccountBankStatement):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.env.user.group_ids |= cls.env.ref('account.group_validate_bank_account')
# Create a bank journal
cls.journal = cls.company_data['default_journal_bank']
cls.batch_deposit_method = cls.env.ref('account_batch_payment.account_payment_method_batch_deposit')
cls.batch_deposit = cls.journal.inbound_payment_method_line_ids.filtered(lambda l: l.code == 'batch_payment')
cls.other_currency = cls.setup_other_currency('EUR')
cls.partner_bank_account = cls.env['res.partner.bank'].create({
'acc_number': 'BE32707171912447',
'partner_id': cls.partner_a.id,
'allow_out_payment': True,
'acc_type': 'bank',
})
@classmethod
def create_payment(cls, partner, amount, **kwargs):
""" Create a batch deposit payment """
payment = cls.env['account.payment'].create({
'journal_id': cls.journal.id,
'payment_type': 'inbound',
'date': time.strftime('%Y') + '-07-15',
'amount': amount,
'partner_id': partner.id,
'partner_type': 'customer',
**kwargs,
})
payment.action_post()
return payment
@classmethod
def _create_st_line(cls, amount=1000.0, date='2019-01-01', payment_ref='turlututu', **kwargs):
return cls.env['account.bank.statement.line'].create({
'journal_id': cls.journal.id,
'amount': amount,
'date': date,
'payment_ref': payment_ref,
'partner_id': cls.partner_a.id,
**kwargs,
})
def test_zero_amount_payment(self):
zero_payment = self.create_payment(self.partner_a, 0, payment_method_line_id=self.batch_deposit.id)
batch_vals = {
'journal_id': self.journal.id,
'payment_ids': [(4, zero_payment.id, None)],
'payment_method_id': self.batch_deposit_method.id,
}
self.assertRaises(ValidationError, self.env['account.batch.payment'].create, batch_vals)
def test_exchange_diff_batch_payment(self):
"""
This test will do a basic case where the company is in US Dollars but the st_line and the payment are in
another currencies. Between the moment where we created the batch payment and the st_line a difference of
rates happens and so an exchange diff is created.
"""
self.other_currency = self.setup_other_currency('EUR', rates=[('2016-01-03', 2.0), ('2017-01-03', 1.0)])
payment = self.create_payment(
partner=self.partner_a,
amount=100,
date='2017-01-02',
journal_id=self.company_data['default_journal_bank'].id,
currency_id=self.other_currency.id,
)
payment.create_batch_payment()
st_line = self._create_st_line(
100.0,
date='2017-01-05',
)
st_line.set_batch_payment_bank_statement_line(payment.batch_payment_id.id)
self.assertRecordValues(st_line.line_ids, [
{
'account_id': st_line.journal_id.default_account_id.id,
'amount_currency': 100.0,
'currency_id': self.company_data['currency'].id,
'balance': 100.0,
'reconciled': False,
},
{
'account_id': payment.outstanding_account_id.id,
'amount_currency': -100.0,
'currency_id': self.other_currency.id,
'balance': -100.0,
'reconciled': True,
},
])
exchange_move = st_line.line_ids[1].matched_debit_ids.exchange_move_id
self.assertRecordValues(exchange_move.line_ids, [
{
'account_id': payment.outstanding_account_id.id,
'currency_id': self.other_currency.id,
'balance': 50.0,
},
{
'account_id': self.env.company.income_currency_exchange_account_id.id,
'currency_id': self.other_currency.id,
'balance': -50.0,
},
])
def test_partner_account_batch_payments_with_journal_entry(self):
""" Test the account for batch payments with a linked journal entry """
for payment_type, account_a, account_b in [
('inbound', self.partner_a.property_account_receivable_id, self.partner_b.property_account_receivable_id),
('outbound', self.partner_a.property_account_payable_id, self.partner_b.property_account_payable_id),
]:
outstanding_account = self.env['account.payment']._get_outstanding_account(payment_type)
self.batch_deposit.payment_account_id = outstanding_account
payment_1 = self.env['account.payment'].create({
'date': '2015-01-01',
'payment_type': payment_type,
'partner_type': 'customer' if payment_type == 'inbound' else 'supplier',
'partner_id': self.partner_a.id,
'payment_method_line_id': self.batch_deposit.id,
'amount': 100.0,
})
payment_2 = self.env['account.payment'].create({
'date': '2015-01-01',
'payment_type': payment_type,
'partner_type': 'customer' if payment_type == 'inbound' else 'supplier',
'partner_id': self.partner_b.id,
'payment_method_line_id': self.batch_deposit.id,
'amount': 200.0,
})
payments = payment_1 + payment_2
payments.action_post()
batch = self.env['account.batch.payment'].create({
'batch_type': payment_type,
'journal_id': self.journal.id,
'payment_ids': [Command.set(payments.ids)],
'payment_method_id': self.batch_deposit_method.id,
})
batch.validate_batch()
st_line_amount = 300.0 if payment_type == 'inbound' else -300.0
st_line = self.env['account.bank.statement.line'].create({
'journal_id': self.journal.id,
'amount': st_line_amount,
'date': '2015-01-01',
'payment_ref': batch.name,
})
st_line.set_batch_payment_bank_statement_line(batch.id)
bank_account = self.journal.default_account_id
if payment_type == 'inbound':
self.assertRecordValues(payments.move_id.line_ids.sorted('balance'), [
{'account_id': account_b.id, 'partner_id': self.partner_b.id, 'balance': -200.0},
{'account_id': account_a.id, 'partner_id': self.partner_a.id, 'balance': -100.0},
{'account_id': outstanding_account.id, 'partner_id': self.partner_a.id, 'balance': 100.0},
{'account_id': outstanding_account.id, 'partner_id': self.partner_b.id, 'balance': 200.0},
])
self.assertRecordValues(st_line.move_id.line_ids.sorted('balance'), [
{'account_id': outstanding_account.id, 'partner_id': self.partner_b.id, 'balance': -200.0},
{'account_id': outstanding_account.id, 'partner_id': self.partner_a.id, 'balance': -100.0},
{'account_id': bank_account.id, 'partner_id': False, 'balance': 300.0},
])
else:
self.assertRecordValues(payments.move_id.line_ids.sorted('balance'), [
{'account_id': outstanding_account.id, 'partner_id': self.partner_b.id, 'balance': -200.0},
{'account_id': outstanding_account.id, 'partner_id': self.partner_a.id, 'balance': -100.0},
{'account_id': account_a.id, 'partner_id': self.partner_a.id, 'balance': 100.0},
{'account_id': account_b.id, 'partner_id': self.partner_b.id, 'balance': 200.0},
])
self.assertRecordValues(st_line.move_id.line_ids.sorted('balance'), [
{'account_id': bank_account.id, 'partner_id': False, 'balance': -300.0},
{'account_id': outstanding_account.id, 'partner_id': self.partner_a.id, 'balance': 100.0},
{'account_id': outstanding_account.id, 'partner_id': self.partner_b.id, 'balance': 200.0},
])
def test_bank_rec_widget_batch_payment_with_entries(self):
payment = self.create_payment(self.partner_a, 100, journal_id=self.company_data['default_journal_bank'].id)
payment.create_batch_payment()
st_line = self._create_st_line(amount=100)
st_line.set_batch_payment_bank_statement_line(payment.batch_payment_id.id)
self.assertRecordValues(st_line.line_ids, [
{'account_id': st_line.journal_id.default_account_id.id, 'name': st_line.payment_ref, 'amount_currency': 100.0, 'currency_id': self.company_data['currency'].id, 'balance': 100.0, 'reconciled': False},
{'account_id': payment.journal_id.inbound_payment_method_line_ids.payment_account_id.id, 'name': payment.journal_id.inbound_payment_method_line_ids[0].name, 'amount_currency': -100.0, 'currency_id': self.company_data['currency'].id, 'balance': -100.0, 'reconciled': True},
])
self.assertEqual(st_line.line_ids.reconciled_lines_ids, payment.move_id.line_ids.filtered(lambda x: x.account_id.account_type == 'asset_current'))
def test_bank_rec_widget_batch_payment_delete_payment(self):
payment = self.create_payment(self.partner_a, 100, payment_method_line_id=self.batch_deposit.id)
payment.create_batch_payment()
st_line = self._create_st_line(amount=100)
st_line.set_batch_payment_bank_statement_line(payment.batch_payment_id.id)
# When removing the payment line, the payment should go back to in_process but the batch remains untouched
st_line.delete_reconciled_line(st_line.line_ids[-1].id)
self.assertEqual(payment.state, 'in_process')
def test_unreconcile_keeps_invoice_posted_when_post_is_blocked(self):
""" Ensure that unreconciling a batch payment from a bank statement line keeps
the linked invoice posted even if the internal repost is blocked by a
third-party module (ex: Studio Approval).
"""
invoice = self._create_invoice_one_line(price_unit=100, post=True)
payment = self.create_payment(
self.partner_a,
invoice.amount_total,
payment_method_line_id=self.batch_deposit.id,
invoice_ids=[Command.set(invoice.ids)],
)
payment.create_batch_payment()
st_line = self._create_st_line(amount=invoice.amount_total)
st_line.set_batch_payment_bank_statement_line(payment.batch_payment_id.id)
# Simulate an approval rule that silently rejects action_post
AccountMove = self.env.registry['account.move']
original_action_post = AccountMove.action_post
def gated_action_post(records, *args, **kwargs):
if records.env.su:
return original_action_post(records, *args, **kwargs)
return {'type': 'ir.actions.client', 'tag': 'display_notification', 'params': {}}
with patch.object(AccountMove, 'action_post', gated_action_post):
st_line.delete_reconciled_line(st_line.line_ids[-1].id)
self.assertEqual(invoice.state, 'posted')
self.assertEqual(payment.state, 'in_process')
def test_unreconcile_sepa_ct_batch_with_pending_online_status(self):
""" Ensure that delete_reconciled_line does not raise error when un-reconciling
a SEPA CT batch payment whose payment_online_status = 'pending'.
"""
if self.env['ir.module.module']._get('account_online_payment').state != 'installed':
self.skipTest("account_online_payment not installed")
# Create a bank account for the company and a SEPA CT journal
company_bank = self.env['res.partner.bank'].create({
'partner_id': self.company_data['company'].partner_id.id,
'acc_number': 'BE48363523682327',
})
sepa_journal = self.env['account.journal'].create({
'name': 'SEPA CT Test',
'type': 'bank',
'code': 'SEPA',
'bank_account_id': company_bank.id,
'currency_id': self.other_currency.id,
})
sepa_ct_method = sepa_journal.outbound_payment_method_line_ids.filtered(
lambda l: l.code == 'sepa_ct'
)
invoice = self._create_invoice_one_line(
move_type='in_invoice',
currency_id=self.other_currency.id,
price_unit=100.0,
post=True,
)
payment = self.env['account.payment'].create({
'journal_id': sepa_journal.id,
'currency_id': self.other_currency.id,
'payment_method_line_id': sepa_ct_method.id,
'payment_type': 'outbound',
'partner_type': 'supplier',
'partner_id': self.partner_a.id,
'partner_bank_id': self.partner_bank_account.id,
'amount': invoice.amount_total,
'invoice_ids': [Command.set(invoice.ids)],
})
payment.action_post()
batch = self.env['account.batch.payment'].create({
'journal_id': sepa_journal.id,
'payment_ids': [Command.set(payment.ids)],
'payment_method_id': self.env.ref('account_iso20022.account_payment_method_sepa_ct').id,
'batch_type': 'outbound',
})
# Simulate the batch being sent to the bank online.
batch.payment_online_status = 'pending'
st_line = self._create_st_line(amount=-payment.amount, journal_id=sepa_journal.id, partner_id=False)
st_line.set_batch_payment_bank_statement_line(batch.id)
st_line.delete_reconciled_line(st_line.line_ids[-1].id)
self.assertEqual(payment.state, 'in_process')
self.assertEqual(invoice.state, 'posted')
def test_batch_reconciliation_multiple_installments_payment_term(self):
""" Test reconciliation of payments for multiple installments payment term lines """
payment_term = self.env['account.payment.term'].create({
'name': "20-80_payment_term",
'company_id': self.company_data['company'].id,
'line_ids': [
Command.create({'value': 'percent', 'value_amount': 20, 'nb_days': 0}),
Command.create({'value': 'percent', 'value_amount': 80, 'nb_days': 20}),
],
})
invoice = self.init_invoice('out_invoice', partner=self.partner_a, amounts=[1000.0])
invoice.invoice_payment_term_id = payment_term
invoice.action_post()
# register payment for the first installment
payment_1 = self.env['account.payment.register'].with_context(
active_model='account.move',
active_ids=invoice.ids,
).create({
'amount': 200.0,
'payment_date': '2015-01-01',
'payment_method_line_id': self.batch_deposit.id,
})._create_payments()
payment_1.create_batch_payment()
st_line_1 = self._create_st_line(amount=200.0, date='2015-01-01', partner_id=False)
st_line_1.set_batch_payment_bank_statement_line(payment_1.batch_payment_id.id)
self.assertRecordValues(st_line_1.move_id.line_ids.sorted('balance'), [
{'balance': -200.0},
{'balance': 200.0},
])
# register payment for the second installment
payment_2 = self.env['account.payment.register'].with_context(
active_model='account.move',
active_ids=invoice.ids,
).create({
'amount': 800.0,
'payment_date': '2015-01-01',
'payment_method_line_id': self.batch_deposit.id,
})._create_payments()
payment_2.create_batch_payment()
st_line_2 = self._create_st_line(amount=800.0, date='2015-01-01', partner_id=False)
st_line_2.set_batch_payment_bank_statement_line(payment_2.batch_payment_id.id)
self.assertRecordValues(st_line_2.move_id.line_ids.sorted('balance'), [
{'balance': -800.0},
{'balance': 800.0},
])
self.assertRecordValues(invoice.line_ids.filtered(lambda l: l.display_type == 'payment_term').sorted('balance'), [
{'balance': 200.0, 'amount_residual': 0.0, 'reconciled': True},
{'balance': 800.0, 'amount_residual': 0.0, 'reconciled': True},
])
@tagged('post_install', '-at_install')
class TestBatchPaymentAccountingOnly(TestBatchPayment):
@classmethod
def setUpClass(cls):
super().setUpClass()
if cls.env['ir.module.module']._get('accountant').state != 'installed':
cls.skipTest(cls, "This class tests payment without entries, which happens only when Accounting is installed")
def test_partner_account_batch_payments_without_journal_entry(self):
""" Test that account receivable is used for inbound payments and account payable for outbound ones
when no journal entry is linked to the payment
"""
for payment_type, account_a, account_b in [
('inbound', self.partner_a.property_account_receivable_id, self.partner_b.property_account_receivable_id),
('outbound', self.partner_a.property_account_payable_id, self.partner_b.property_account_payable_id),
]:
payment_1 = self.env['account.payment'].create({
'date': '2015-01-01',
'payment_type': payment_type,
'partner_type': 'customer' if payment_type == 'inbound' else 'supplier',
'partner_id': self.partner_a.id,
'payment_method_line_id': self.batch_deposit.id,
'amount': 100.0,
})
payment_2 = self.env['account.payment'].create({
'date': '2015-01-01',
'payment_type': payment_type,
'partner_type': 'customer' if payment_type == 'inbound' else 'supplier',
'partner_id': self.partner_b.id,
'payment_method_line_id': self.batch_deposit.id,
'amount': 200.0,
})
payments = payment_1 + payment_2
payments.action_post()
batch = self.env['account.batch.payment'].create({
'batch_type': payment_type,
'journal_id': self.journal.id,
'payment_ids': [Command.set(payments.ids)],
'payment_method_id': self.batch_deposit_method.id,
})
batch.validate_batch()
st_line_amount = 300.0 if payment_type == 'inbound' else -300.0
st_line = self.env['account.bank.statement.line'].create({
'journal_id': self.journal.id,
'amount': st_line_amount,
'date': '2015-01-01',
'payment_ref': batch.name,
})
st_line.set_batch_payment_bank_statement_line(batch.id)
bank_account = self.journal.default_account_id
if payment_type == 'inbound':
self.assertRecordValues(st_line.move_id.line_ids.sorted('balance'), [
{'account_id': account_b.id, 'partner_id': self.partner_b.id, 'balance': -200.0},
{'account_id': account_a.id, 'partner_id': self.partner_a.id, 'balance': -100.0},
{'account_id': bank_account.id, 'partner_id': False, 'balance': 300.0},
])
else:
self.assertRecordValues(st_line.move_id.line_ids.sorted('balance'), [
{'account_id': bank_account.id, 'partner_id': False, 'balance': -300.0},
{'account_id': account_a.id, 'partner_id': self.partner_a.id, 'balance': 100.0},
{'account_id': account_b.id, 'partner_id': self.partner_b.id, 'balance': 200.0},
])
def test_bank_rec_widget_batch_with_epd_without_entries(self):
st_line = self._create_st_line(180.0, date='2019-01-05')
early_pay_acc = self.env.company.account_journal_early_pay_discount_loss_account_id
invoice_lines_with_epd = self._create_invoice_line(
'out_invoice',
invoice_date='2019-01-01',
invoice_payment_term_id=self.early_payment_term.id,
invoice_line_ids=[{'price_unit': 100.0}],
) + self._create_invoice_line(
'out_invoice',
invoice_date='2019-01-01',
invoice_payment_term_id=self.early_payment_term.id,
invoice_line_ids=[{'price_unit': 100.0}],
)
payments = self.env['account.payment.register'].with_context(
active_model='account.move',
active_ids=invoice_lines_with_epd.move_id.ids,
).create({
'payment_date': '2019-01-01',
'payment_method_line_id': self.batch_deposit.id,
})._create_payments()
batch = self.env['account.batch.payment'].create({
'batch_type': payments[0].payment_type,
'journal_id': self.journal.id,
'payment_ids': [Command.set(payments.ids)],
'payment_method_id': self.batch_deposit_method.id,
})
batch.validate_batch()
st_line.set_batch_payment_bank_statement_line(payments.batch_payment_id.id)
self.assertRecordValues(st_line.line_ids, [
{'account_id': st_line.journal_id.default_account_id.id, 'amount_currency': 180.0, 'balance': 180.0, 'reconciled': False},
{'account_id': invoice_lines_with_epd[0].account_id.id, 'amount_currency': -100.0, 'balance': -100.0, 'reconciled': True},
{'account_id': early_pay_acc.id, 'amount_currency': 10.0, 'balance': 10.0, 'reconciled': False},
{'account_id': invoice_lines_with_epd[1].account_id.id, 'amount_currency': -100.0, 'balance': -100.0, 'reconciled': True},
{'account_id': early_pay_acc.id, 'amount_currency': 10.0, 'balance': 10.0, 'reconciled': False},
])
self.assertEqual(payments.mapped('state'), ['paid', 'paid'])
self.assertEqual(batch.state, 'reconciled')
st_line.delete_reconciled_line(st_line.line_ids[1].id)
self.assertEqual(payments[0].state, 'in_process')
self.assertEqual(batch.state, 'sent')
def test_bank_rec_widget_batch_payment_without_entries(self):
payment = self.create_payment(self.partner_a, 100, payment_method_line_id=self.batch_deposit.id)
payment.create_batch_payment()
st_line = self._create_st_line(amount=100)
st_line.set_batch_payment_bank_statement_line(payment.batch_payment_id.id)
self.assertRecordValues(st_line.line_ids, [
{'account_id': st_line.journal_id.default_account_id.id, 'name': st_line.payment_ref, 'amount_currency': 100.0, 'currency_id': self.company_data['currency'].id, 'balance': 100.0, 'reconciled': False},
{'account_id': self.partner_a.property_account_receivable_id.id, 'name': payment.name, 'amount_currency': -100.0, 'currency_id': self.company_data['currency'].id, 'balance': -100.0, 'reconciled': False},
])
def test_bank_rec_widget_batch_payment_without_entries_link_to_move(self):
invoice = self.env['account.move'].create({
'move_type': 'out_invoice',
'partner_id': self.partner_a.id,
'invoice_date': '2017-01-01',
'invoice_line_ids': [
Command.create({
'name': 'Line',
'price_unit': 100,
}),
],
})
invoice.action_post()
payment = self.env['account.payment.register'].with_context(
active_model='account.move',
active_ids=invoice.ids
).create({
'payment_date': '2019-01-01',
'payment_method_line_id': self.batch_deposit.id,
})._create_payments()
payment.create_batch_payment()
st_line = self._create_st_line(amount=100)
st_line.set_batch_payment_bank_statement_line(payment.batch_payment_id.id)
self.assertRecordValues(st_line.line_ids, [
{'account_id': st_line.journal_id.default_account_id.id, 'amount_currency': 100.0, 'balance': 100.0, 'reconciled': False},
{'account_id': invoice.line_ids[-1].account_id.id, 'amount_currency': -100.0, 'balance': -100.0, 'reconciled': True},
])
self.assertEqual(st_line.line_ids.reconciled_lines_ids, payment.invoice_ids.line_ids.filtered(lambda x: x.account_id.account_type == 'asset_receivable'))
st_line.delete_reconciled_line(st_line.line_ids[-1].id)
self.assertEqual(payment.state, 'in_process')
self.assertEqual(invoice.payment_state, 'in_payment')
def test_bank_rec_widget_batch_move_link_to_multiple_payment_without_entries(self):
invoice = self.env['account.move'].create({
'move_type': 'out_invoice',
'partner_id': self.partner_a.id,
'invoice_date': '2017-01-01',
'invoice_line_ids': [
Command.create({
'name': 'Line',
'price_unit': 1000,
}),
],
})
invoice.action_post()
payment_1 = self.env['account.payment.register'].with_context(
active_model='account.move',
active_ids=invoice.ids,
).create({
'amount': 400,
'payment_date': '2019-01-01',
'payment_method_line_id': self.batch_deposit.id,
})._create_payments()
payment_2 = self.env['account.payment.register'].with_context(
active_model='account.move',
active_ids=invoice.ids,
).create({
'amount': 600,
'payment_date': '2019-01-01',
'payment_method_line_id': self.batch_deposit.id,
})._create_payments()
(payment_1 + payment_2).create_batch_payment()
st_line = self._create_st_line(amount=1000)
st_line.set_batch_payment_bank_statement_line(payment_1.batch_payment_id.id)
self.assertRecordValues(st_line.line_ids, [
{'account_id': st_line.journal_id.default_account_id.id, 'amount_currency': 1000.0, 'balance': 1000.0, 'reconciled': False},
{'account_id': invoice.line_ids[-1].account_id.id, 'amount_currency': -400.0, 'balance': -400.0, 'reconciled': True},
{'account_id': invoice.line_ids[-1].account_id.id, 'amount_currency': -600.0, 'balance': -600.0, 'reconciled': True},
])
st_line.delete_reconciled_line(st_line.line_ids[-1].id)
self.assertEqual(payment_1.state, 'paid')
self.assertEqual(payment_2.state, 'in_process')
self.assertEqual(invoice.payment_state, 'in_payment')
def test_bank_rec_widget_batch_one_move_multiple_payment_without_entries(self):
invoice_1 = self.env['account.move'].create({
'move_type': 'out_invoice',
'partner_id': self.partner_a.id,
'invoice_date': '2017-01-01',
'invoice_line_ids': [
Command.create({
'name': 'Line',
'price_unit': 1000,
}),
],
})
invoice_1.action_post()
invoice_2 = self.env['account.move'].create({
'move_type': 'out_invoice',
'partner_id': self.partner_a.id,
'invoice_date': '2017-01-01',
'invoice_line_ids': [
Command.create({
'name': 'Line',
'price_unit': 1000,
}),
],
})
invoice_2.action_post()
payments = self.env['account.payment.register'].with_context(
active_model='account.move',
active_ids=(invoice_1 + invoice_2).ids,
).create({
'amount': 2000,
'payment_date': '2019-01-01',
'payment_method_line_id': self.batch_deposit.id,
})._create_payments()
payments.create_batch_payment()
st_line = self._create_st_line(amount=2000)
st_line.set_batch_payment_bank_statement_line(payments.batch_payment_id.id)
self.assertRecordValues(st_line.line_ids, [
{'account_id': st_line.journal_id.default_account_id.id, 'amount_currency': 2000.0, 'balance': 2000.0, 'reconciled': False},
{'account_id': invoice_1.line_ids[-1].account_id.id, 'amount_currency': -1000.0, 'balance': -1000.0, 'reconciled': True},
{'account_id': invoice_2.line_ids[-1].account_id.id, 'amount_currency': -1000.0, 'balance': -1000.0, 'reconciled': True},
])
def test_bank_rec_widget_batch_one_move_multiple_payment_without_entries_grouped(self):
invoice_1 = self.env['account.move'].create({
'move_type': 'out_invoice',
'partner_id': self.partner_a.id,
'invoice_date': '2017-01-01',
'invoice_line_ids': [
Command.create({
'name': 'Line',
'price_unit': 1000,
}),
],
})
invoice_1.action_post()
invoice_2 = self.env['account.move'].create({
'move_type': 'out_invoice',
'partner_id': self.partner_a.id,
'invoice_date': '2017-01-01',
'invoice_line_ids': [
Command.create({
'name': 'Line',
'price_unit': 1000,
}),
],
})
invoice_2.action_post()
payments = self.env['account.payment.register'].with_context(
active_model='account.move',
active_ids=(invoice_1 + invoice_2).ids,
).create({
'amount': 2000,
'payment_date': '2019-01-01',
'payment_method_line_id': self.batch_deposit.id,
'group_payment': True,
})._create_payments()
payments.create_batch_payment()
st_line = self._create_st_line(amount=2000)
st_line.set_batch_payment_bank_statement_line(payments.batch_payment_id.id)
self.assertRecordValues(st_line.line_ids, [
{'account_id': st_line.journal_id.default_account_id.id, 'amount_currency': 2000.0, 'balance': 2000.0, 'reconciled': False},
{'account_id': invoice_1.line_ids[-1].account_id.id, 'amount_currency': -1000.0, 'balance': -1000.0, 'reconciled': True},
{'account_id': invoice_2.line_ids[-1].account_id.id, 'amount_currency': -1000.0, 'balance': -1000.0, 'reconciled': True},
])
def test_bank_rec_widget_batch_without_entries_grouped_with_bills(self):
bills_1 = self.env['account.move'].create({
'move_type': 'in_invoice',
'partner_id': self.partner_a.id,
'invoice_date': '2017-01-01',
'invoice_line_ids': [
Command.create({
'name': 'Line',
'price_unit': 1000,
}),
],
})
bills_1.action_post()
bills_2 = self.env['account.move'].create({
'move_type': 'in_invoice',
'partner_id': self.partner_a.id,
'invoice_date': '2017-01-01',
'invoice_line_ids': [
Command.create({
'name': 'Line',
'price_unit': 1000,
}),
],
})
bills_2.action_post()
payments = self.env['account.payment.register'].with_context(
active_model='account.move',
active_ids=(bills_1 + bills_2).ids,
).create({
'amount': 2000,
'payment_date': '2019-01-01',
'payment_method_line_id': self.batch_deposit.id,
'group_payment': True,
})._create_payments()
payments.create_batch_payment()
st_line = self._create_st_line(amount=-2000)
st_line.set_batch_payment_bank_statement_line(payments.batch_payment_id.id)
self.assertRecordValues(st_line.line_ids, [
{'account_id': st_line.journal_id.default_account_id.id, 'amount_currency': -2000.0, 'balance': -2000.0, 'reconciled': False},
{'account_id': bills_1.line_ids[-1].account_id.id, 'amount_currency': 1000.0, 'balance': 1000.0, 'reconciled': True},
{'account_id': bills_2.line_ids[-1].account_id.id, 'amount_currency': 1000.0, 'balance': 1000.0, 'reconciled': True},
])
def test_bank_rec_widget_batch_with_epd_with_exch_diff_without_entries(self):
""" Tests a batch payment of a grouped payment with an amount too large for:
- 1 invoice with an early payment discount AND exchange diff
- 1 invoice with an early payment discount
During reconciliation, a payment with move should be created for the first invoice (to correctly handle the EPD),
the second invoice should correctly be added to the widget, and the surplus should be added as a payment.
"""
chf_currency = self.setup_other_currency('CHF', rates=[('2016-01-01', 2.0), ('2019-01-03', 4.0)])
st_line = self._create_st_line(200.0, date='2019-01-05', foreign_currency_id=chf_currency.id)
early_pay_acc = self.env.company.account_journal_early_pay_discount_loss_account_id
invoice_with_exch_diff = self._create_invoice_line(
'out_invoice',
invoice_date='2019-01-01',
invoice_payment_term_id=self.early_payment_term.id,
invoice_line_ids=[{'price_unit': 100.0}],
currency_id=chf_currency.id,
)
invoice_without_exch_diff = self._create_invoice_line(
'out_invoice',
invoice_date='2019-01-04',
invoice_payment_term_id=self.early_payment_term.id,
invoice_line_ids=[{'price_unit': 100.0}],
currency_id=chf_currency.id,
)
payment = self.env['account.payment.register'].with_context(
active_model='account.move',
active_ids=(invoice_with_exch_diff + invoice_without_exch_diff).move_id.ids,
).create({
'group_payment': True,
'amount': 200,
'payment_date': '2019-01-04',
'payment_method_line_id': self.batch_deposit.id,
})._create_payments()
outstanding_account = self.env['account.payment']._get_outstanding_account(payment.payment_type)
batch = self.env['account.batch.payment'].create({
'batch_type': payment.payment_type,
'journal_id': self.journal.id,
'payment_ids': [Command.set(payment.ids)],
'payment_method_id': self.batch_deposit_method.id,
})
batch.validate_batch()
self.assertEqual(batch.amount, 50.0)
st_line.set_batch_payment_bank_statement_line(payment.batch_payment_id.id)
self.assertRecordValues(st_line.line_ids, [
{'account_id': st_line.journal_id.default_account_id.id, 'amount_currency': 200.0, 'balance': 200.0, 'reconciled': False},
# The first invoice and payment have been changed into a payment with move to handle the exchange diff. The next line comes from that move.
{'account_id': outstanding_account.id, 'amount_currency': -90.0, 'balance': -22.5, 'reconciled': True},
# The 2 following lines correspond to the second invoice + EPD.
{'account_id': invoice_without_exch_diff.account_id.id, 'amount_currency': -100.0, 'balance': -25.0, 'reconciled': True},
{'account_id': early_pay_acc.id, 'amount_currency': 10.0, 'balance': 2.5, 'reconciled': False},
# The remaining amount from the payment is added as is.
{'account_id': payment.partner_id.property_account_receivable_id.id, 'amount_currency': -20.0, 'balance': -5.0, 'reconciled': False},
{'account_id': st_line.journal_id.suspense_account_id.id, 'amount_currency': -600.0, 'balance': -150.0, 'reconciled': False},
])
self.assertEqual(payment.state, 'paid')
self.assertEqual(batch.state, 'reconciled')
self.assertEqual(payment.amount, 110.0, "The creation of the payment with move during reconciliation should have diminished the grouped payment amount.")
def test_bank_rec_widget_batch_foreign_currency_journal_without_entries(self):
""" Tests a batch payment of payments recorded in another journal with
foreign currency and no outstanding account set.
- 2 invoices in company currency paid in foreign currency
- 1 bank transaction in foreign currency
"""
chf_currency = self.setup_other_currency('CHF', rates=[('2019-01-01', 1.5)])
foreign_journal = self.env['account.journal'].create({'name': 'CHF journal', 'type': 'bank', 'code': 'BNKX', 'currency_id': chf_currency.id})
invoice_1 = self._create_invoice_line(
'out_invoice',
invoice_date='2019-01-01',
invoice_line_ids=[{'price_unit': 100.0}],
)
invoice_2 = self._create_invoice_line(
'out_invoice',
invoice_date='2019-01-01',
invoice_line_ids=[{'price_unit': 200.0}],
)
payment_1 = self.env['account.payment.register'].with_context(
active_model='account.move',
active_ids=invoice_1.move_id.ids,
).create({
'amount': 150,
'payment_date': '2019-01-01',
'journal_id': foreign_journal.id,
})._create_payments()
payment_2 = self.env['account.payment.register'].with_context(
active_model='account.move',
active_ids=invoice_2.move_id.ids,
).create({
'amount': 300,
'payment_date': '2019-01-01',
'journal_id': foreign_journal.id,
})._create_payments()
batch = self.env['account.batch.payment'].create({
'batch_type': payment_1.payment_type,
'journal_id': foreign_journal.id,
'payment_ids': [Command.set((payment_1 | payment_2).ids)],
})
batch.validate_batch()
st_line = self._create_st_line(450.0, date='2019-01-05', foreign_currency_id=chf_currency.id, journal_id=foreign_journal.id)
st_line.set_batch_payment_bank_statement_line(batch.id)
if self.env['account.move']._get_invoice_in_payment_state() == 'paid':
expected_account = self.env['account.payment']._get_outstanding_account(payment_1.payment_type).id
else:
expected_account = self.partner_a.property_account_receivable_id.id
self.assertRecordValues(st_line.line_ids, [
{'account_id': st_line.journal_id.default_account_id.id, 'amount_currency': 450.0, 'balance': 300.0, 'reconciled': False},
{'account_id': expected_account, 'amount_currency': -150.0, 'balance': -100.0, 'reconciled': True},
{'account_id': expected_account, 'amount_currency': -300.0, 'balance': -200.0, 'reconciled': True},
])
self.assertEqual(invoice_1.move_id.payment_state, 'paid')
self.assertEqual(invoice_2.move_id.payment_state, 'paid')
self.assertEqual(batch.state, 'reconciled')
def test_payment_state_after_invoice_edition_without_journal_entry(self):
""" Test that a bank statement reconciled with a batch payment is unreconciled and the state of all the payments
is set to "In Process" when the amount of one of the invoices is modified.
"""
self.partner_b.property_payment_term_id = self.pay_terms_a
invoice_1 = self.init_invoice('out_invoice', partner=self.partner_a, amounts=[90.0], post=True)
invoice_2 = self.init_invoice('out_invoice', partner=self.partner_a, amounts=[10.0], post=True)
invoice_3 = self.init_invoice('out_invoice', partner=self.partner_b, amounts=[50.0], post=True)
invoice_4 = self.init_invoice('out_invoice', partner=self.partner_b, amounts=[40.0], post=True)
# create a group payment for invoice 1 and 2
active_ids = (invoice_1 + invoice_2).ids
group_payment = self.env['account.payment.register'].with_context(active_model='account.move', active_ids=active_ids).create({
'amount': 100.0,
'group_payment': True,
'payment_method_line_id': self.batch_deposit.id,
})._create_payments()
# create a simple payment for invoice 3
payment_3 = self.env['account.payment.register'].with_context(active_model='account.move', active_ids=invoice_3.ids).create({
'amount': 50.0,
'payment_method_line_id': self.batch_deposit.id,
})._create_payments()
# create a simple payment for invoice 4
payment_4 = self.env['account.payment.register'].with_context(active_model='account.move', active_ids=invoice_4.ids).create({
'amount': 40.0,
'payment_method_line_id': self.batch_deposit.id,
})._create_payments()
payments = group_payment + payment_3 + payment_4
payments.action_post()
# create a batch payment for the 3 payments
batch_payment_action = payments.create_batch_payment()
batch_payment = self.env['account.batch.payment'].browse(batch_payment_action.get('res_id'))
batch_payment.validate_batch()
# create a statement line and reconcile it with the batch payment
st_line = self._create_st_line(190.0, payment_ref=batch_payment.name)
st_line.set_batch_payment_bank_statement_line(batch_payment.id)
self.assertTrue(st_line.is_reconciled)
for payment in payments:
self.assertEqual(payment.state, 'paid')
# edit the price of invoice 3
invoice_3.button_draft()
with Form(invoice_3) as form:
with form.invoice_line_ids.edit(0) as line_form:
line_form.price_unit = 30.0
self.assertFalse(st_line.is_reconciled)
for payment in payments:
self.assertEqual(payment.state, 'in_process')