account-reconcile/account_reconcile_oca/tests/test_bank_account_reconcile.py

1395 lines
52 KiB
Python

import time
from odoo import Command
from odoo.tests import Form, tagged
from odoo.addons.account_reconcile_model_oca.tests.common import (
TestAccountReconciliationCommon,
)
@tagged("post_install", "-at_install")
class TestReconciliationWidget(TestAccountReconciliationCommon):
@classmethod
def _setup_context(cls):
return {**cls.env.context, "_test_account_reconcile_oca": True}
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.env = cls.env(context=cls._setup_context())
# Auto-disable reconciliation model created automatically with
# generate_account_reconcile_model() to avoid side effects in tests
cls.invoice_matching_models = cls.env["account.reconcile.model"].search(
[
("rule_type", "=", "invoice_matching"),
("auto_reconcile", "=", True),
("company_id", "=", cls.company.id),
]
)
cls.invoice_matching_models.active = False
cls.acc_bank_stmt_model = cls.env["account.bank.statement"]
cls.acc_bank_stmt_line_model = cls.env["account.bank.statement.line"]
cls.bank_journal_usd.suspense_account_id = (
cls.env.company.account_journal_suspense_account_id
)
cls.bank_journal_euro.suspense_account_id = (
cls.env.company.account_journal_suspense_account_id
)
cls.current_assets_account = cls.env["account.account"].search(
[
("account_type", "=", "asset_current"),
("company_ids", "in", cls.env.company.id),
],
limit=1,
)
cls.current_assets_account.reconcile = True
cls.rule = cls.env["account.reconcile.model"].create(
{
"name": "write-off model",
"rule_type": "writeoff_button",
"match_partner": True,
"match_partner_ids": [],
"line_ids": [
Command.create({"account_id": cls.current_assets_account.id})
],
}
)
cls.tax_10 = cls.env["account.tax"].create(
{
"name": "tax_10",
"amount_type": "percent",
"amount": 10.0,
}
)
# We need to make some fields visible in order to make the tests work
cls.env["ir.ui.view"].create(
{
"name": "DEMO Account bank statement",
"model": "account.bank.statement.line",
"inherit_id": cls.env.ref(
"account_reconcile_oca.bank_statement_line_form_reconcile_view"
).id,
"arch": """
<data>
<field name="manual_reference" position="attributes">
<attribute name="invisible">0</attribute>
</field>
<field name="manual_delete" position="attributes">
<attribute name="invisible">0</attribute>
</field>
<field name="partner_id" position="attributes">
<attribute name="invisible">0</attribute>
</field>
</data>
""",
}
)
# Testing reconcile action
def test_reconcile_invoice_currency(self):
inv1 = self.create_invoice(currency_id=self.currency_usd_id, invoice_amount=100)
bank_stmt = self.acc_bank_stmt_model.create(
{
"journal_id": self.bank_journal_euro.id,
"date": time.strftime("%Y-07-15"),
"name": "test",
}
)
bank_stmt_line = self.acc_bank_stmt_line_model.create(
{
"name": "testLine",
"journal_id": self.bank_journal_euro.id,
"statement_id": bank_stmt.id,
"amount": 50,
"amount_currency": 100,
"foreign_currency_id": self.currency_usd_id,
"date": time.strftime("%Y-07-15"),
}
)
with Form(
bank_stmt_line,
view="account_reconcile_oca.bank_statement_line_form_reconcile_view",
) as f:
self.assertFalse(f.can_reconcile)
f.add_account_move_line_id = inv1.line_ids.filtered(
lambda line: line.account_id.account_type == "asset_receivable"
)
self.assertFalse(f.add_account_move_line_id)
self.assertTrue(f.can_reconcile)
def test_manual_line_with_currency(self):
bank_stmt = self.acc_bank_stmt_model.create(
{
"journal_id": self.bank_journal_euro.id,
"date": time.strftime("%Y-07-15"),
"name": "test",
}
)
bank_stmt_line = self.acc_bank_stmt_line_model.create(
{
"name": "testLine",
"journal_id": self.bank_journal_euro.id,
"statement_id": bank_stmt.id,
"amount": 50,
"amount_currency": 100,
"foreign_currency_id": self.currency_usd_id,
"date": time.strftime("%Y-07-15"),
}
)
receivable_acc = self.company_data["default_account_receivable"]
with Form(
bank_stmt_line,
view="account_reconcile_oca.bank_statement_line_form_reconcile_view",
) as f:
self.assertFalse(f.can_reconcile)
f.manual_reference = "reconcile_auxiliary;1"
f.manual_account_id = receivable_acc
self.assertTrue(f.can_reconcile)
bank_stmt_line.reconcile_bank_line()
receivable_line = bank_stmt_line.line_ids.filtered(
lambda line: line.account_id == receivable_acc
)
self.assertEqual(receivable_line.currency_id.id, self.currency_usd_id)
self.assertEqual(receivable_line.amount_currency, -100)
self.assertEqual(receivable_line.balance, -50)
def test_reconcile_invoice_reconcile_full(self):
"""
We want to test the reconcile widget for bank statements on invoices.
As we use edit mode by default, we will also check what happens when
we press unreconcile
"""
inv1 = self.create_invoice(
currency_id=self.currency_euro_id, invoice_amount=100
)
bank_stmt = self.acc_bank_stmt_model.create(
{
"journal_id": self.bank_journal_euro.id,
"date": time.strftime("%Y-07-15"),
"name": "test",
}
)
bank_stmt_line = self.acc_bank_stmt_line_model.create(
{
"name": "testLine",
"journal_id": self.bank_journal_euro.id,
"statement_id": bank_stmt.id,
"amount": 50,
"date": time.strftime("%Y-07-15"),
}
)
receivable1 = inv1.line_ids.filtered(
lambda line: line.account_id.account_type == "asset_receivable"
)
with Form(
bank_stmt_line,
view="account_reconcile_oca.bank_statement_line_form_reconcile_view",
) as f:
self.assertFalse(f.can_reconcile)
f.add_account_move_line_id = receivable1
self.assertFalse(f.add_account_move_line_id)
self.assertTrue(f.can_reconcile)
f.manual_reference = f"account.move.line;{receivable1.id}"
self.assertEqual(-50, f.manual_amount)
self.assertEqual(2, len(bank_stmt_line.reconcile_data_info["data"]))
bank_stmt_line.button_manual_reference_full_paid()
self.assertEqual(3, len(bank_stmt_line.reconcile_data_info["data"]))
with Form(
bank_stmt_line,
view="account_reconcile_oca.bank_statement_line_form_reconcile_view",
) as f:
f.manual_reference = f"account.move.line;{receivable1.id}"
self.assertEqual(-100, f.manual_amount)
def test_reconcile_invoice_unreconcile(self):
"""
We want to test the reconcile widget for bank statements on invoices.
As we use edit mode by default, we will also check what happens when
we press unreconcile
"""
inv1 = self.create_invoice(
currency_id=self.currency_euro_id, invoice_amount=100
)
bank_stmt = self.acc_bank_stmt_model.create(
{
"journal_id": self.bank_journal_euro.id,
"date": time.strftime("%Y-07-15"),
"name": "test",
}
)
bank_stmt_line = self.acc_bank_stmt_line_model.create(
{
"name": "testLine",
"journal_id": self.bank_journal_euro.id,
"statement_id": bank_stmt.id,
"amount": 100,
"date": time.strftime("%Y-07-15"),
}
)
with Form(
bank_stmt_line,
view="account_reconcile_oca.bank_statement_line_form_reconcile_view",
) as f:
self.assertFalse(f.can_reconcile)
f.add_account_move_line_id = inv1.line_ids.filtered(
lambda line: line.account_id.account_type == "asset_receivable"
)
self.assertFalse(f.add_account_move_line_id)
self.assertTrue(f.can_reconcile)
self.assertFalse(bank_stmt_line.is_reconciled)
self.assertTrue(
bank_stmt_line.move_id.line_ids.filtered(
lambda r: r.account_id == self.bank_journal_euro.suspense_account_id
)
)
number_of_lines = len(bank_stmt_line.reconcile_data_info["data"])
bank_stmt_line.reconcile_bank_line()
self.assertEqual(
number_of_lines, len(bank_stmt_line.reconcile_data_info["data"])
)
self.assertTrue(bank_stmt_line.is_reconciled)
self.assertFalse(
bank_stmt_line.move_id.line_ids.filtered(
lambda r: r.account_id == self.bank_journal_euro.suspense_account_id
)
)
bank_stmt_line.unreconcile_bank_line()
self.assertFalse(bank_stmt_line.is_reconciled)
self.assertTrue(
bank_stmt_line.move_id.line_ids.filtered(
lambda r: r.account_id == self.bank_journal_euro.suspense_account_id
)
)
def test_reconcile_invoice_partial(self):
"""
We want to partially reconcile two invoices from a single payment.
As a result, both invoices must be partially reconciled
"""
inv1 = self.create_invoice(
currency_id=self.currency_euro_id, invoice_amount=100
)
inv2 = self.create_invoice(
currency_id=self.currency_euro_id, invoice_amount=100
)
bank_stmt = self.acc_bank_stmt_model.create(
{
"journal_id": self.bank_journal_euro.id,
"date": time.strftime("%Y-07-15"),
"name": "test",
}
)
bank_stmt_line = self.acc_bank_stmt_line_model.create(
{
"name": "testLine",
"journal_id": self.bank_journal_euro.id,
"statement_id": bank_stmt.id,
"amount": 100,
"date": time.strftime("%Y-07-15"),
}
)
receivable1 = inv1.line_ids.filtered(
lambda line: line.account_id.account_type == "asset_receivable"
)
receivable2 = inv2.line_ids.filtered(
lambda line: line.account_id.account_type == "asset_receivable"
)
with Form(
bank_stmt_line,
view="account_reconcile_oca.bank_statement_line_form_reconcile_view",
) as f:
self.assertFalse(f.can_reconcile)
f.add_account_move_line_id = receivable1
self.assertFalse(f.add_account_move_line_id)
self.assertTrue(f.can_reconcile)
f.manual_reference = f"account.move.line;{receivable1.id}"
self.assertEqual(f.manual_amount, -100)
f.manual_amount = -70
self.assertFalse(f.can_reconcile)
f.add_account_move_line_id = receivable2
f.manual_reference = f"account.move.line;{receivable2.id}"
self.assertEqual(f.manual_amount, -30)
self.assertTrue(f.can_reconcile)
self.assertEqual(inv1.amount_residual_signed, 100)
self.assertEqual(inv2.amount_residual_signed, 100)
number_of_lines = len(bank_stmt_line.reconcile_data_info["data"])
bank_stmt_line.reconcile_bank_line()
self.assertEqual(
number_of_lines, len(bank_stmt_line.reconcile_data_info["data"])
)
self.assertEqual(inv1.amount_residual_signed, 30)
self.assertEqual(inv2.amount_residual_signed, 70)
def test_reconcile_invoice_partial_supplier(self):
"""
We want to partially reconcile two invoices from a single payment.
As a result, both invoices must be partially reconciled
"""
inv1 = self.create_invoice(
currency_id=self.currency_euro_id,
invoice_amount=100,
move_type="in_invoice",
)
inv2 = self.create_invoice(
currency_id=self.currency_euro_id,
invoice_amount=100,
move_type="in_invoice",
)
bank_stmt = self.acc_bank_stmt_model.create(
{
"journal_id": self.bank_journal_euro.id,
"date": time.strftime("%Y-07-15"),
"name": "test",
}
)
bank_stmt_line = self.acc_bank_stmt_line_model.create(
{
"name": "testLine",
"journal_id": self.bank_journal_euro.id,
"statement_id": bank_stmt.id,
"amount": -100,
"date": time.strftime("%Y-07-15"),
}
)
receivable1 = inv1.line_ids.filtered(
lambda line: line.account_id.account_type == "liability_payable"
)
receivable2 = inv2.line_ids.filtered(
lambda line: line.account_id.account_type == "liability_payable"
)
with Form(
bank_stmt_line,
view="account_reconcile_oca.bank_statement_line_form_reconcile_view",
) as f:
self.assertFalse(f.can_reconcile)
f.add_account_move_line_id = receivable1
self.assertFalse(f.add_account_move_line_id)
self.assertTrue(f.can_reconcile)
f.manual_reference = f"account.move.line;{receivable1.id}"
self.assertEqual(f.manual_amount, 100)
f.manual_amount = 70
self.assertFalse(f.can_reconcile)
f.add_account_move_line_id = receivable2
f.manual_reference = f"account.move.line;{receivable2.id}"
self.assertEqual(f.manual_amount, 30)
self.assertTrue(f.can_reconcile)
self.assertEqual(inv1.amount_residual_signed, -100)
self.assertEqual(inv2.amount_residual_signed, -100)
number_of_lines = len(bank_stmt_line.reconcile_data_info["data"])
bank_stmt_line.reconcile_bank_line()
self.assertEqual(
number_of_lines, len(bank_stmt_line.reconcile_data_info["data"])
)
self.assertEqual(inv1.amount_residual_signed, -30)
self.assertEqual(inv2.amount_residual_signed, -70)
def test_reconcile_model(self):
"""
We want to test what happens when we select an reconcile model to fill a
bank statement.
"""
bank_stmt = self.acc_bank_stmt_model.create(
{
"journal_id": self.bank_journal_euro.id,
"date": time.strftime("%Y-07-15"),
"name": "test",
}
)
bank_stmt_line = self.acc_bank_stmt_line_model.create(
{
"name": "testLine",
"journal_id": self.bank_journal_euro.id,
"statement_id": bank_stmt.id,
"amount": 100,
"date": time.strftime("%Y-07-15"),
}
)
with Form(
bank_stmt_line,
view="account_reconcile_oca.bank_statement_line_form_reconcile_view",
) as f:
self.assertFalse(f.can_reconcile)
f.manual_model_id = self.rule
self.assertTrue(f.can_reconcile)
number_of_lines = len(bank_stmt_line.reconcile_data_info["data"])
bank_stmt_line.reconcile_bank_line()
self.assertEqual(
number_of_lines, len(bank_stmt_line.reconcile_data_info["data"])
)
self.assertEqual(2, len(bank_stmt_line.move_id.line_ids))
self.assertTrue(
bank_stmt_line.move_id.line_ids.filtered(
lambda r: r.account_id == self.current_assets_account
)
)
def test_reconcile_model_tax_included(self):
"""
We want to test what happens when we select an reconcile model to fill a
bank statement.
"""
self.rule.line_ids.write(
{"tax_ids": [Command.link(self.tax_10.id)], "force_tax_included": True}
)
bank_stmt = self.acc_bank_stmt_model.create(
{
"journal_id": self.bank_journal_euro.id,
"date": time.strftime("%Y-07-15"),
"name": "test",
}
)
bank_stmt_line = self.acc_bank_stmt_line_model.create(
{
"name": "testLine",
"journal_id": self.bank_journal_euro.id,
"statement_id": bank_stmt.id,
"amount": 100,
"date": time.strftime("%Y-07-15"),
}
)
with Form(
bank_stmt_line,
view="account_reconcile_oca.bank_statement_line_form_reconcile_view",
) as f:
self.assertFalse(f.can_reconcile)
f.manual_model_id = self.rule
self.assertTrue(f.can_reconcile)
number_of_lines = len(bank_stmt_line.reconcile_data_info["data"])
bank_stmt_line.reconcile_bank_line()
self.assertEqual(
number_of_lines, len(bank_stmt_line.reconcile_data_info["data"])
)
self.assertEqual(3, len(bank_stmt_line.move_id.line_ids))
self.assertTrue(
bank_stmt_line.move_id.line_ids.filtered(
lambda r: r.account_id == self.current_assets_account
and r.tax_ids == self.tax_10
)
)
self.assertTrue(
bank_stmt_line.move_id.line_ids.filtered(
lambda r: r.tax_line_id == self.tax_10
)
)
def test_reconcile_invoice_model(self):
"""
We want to test what happens when we select a reconcile model to fill a
bank statement prefilled with an invoice.
The result should be the reconcile of the invoice, and the rest set to the model
"""
inv1 = self.create_invoice(currency_id=self.currency_euro_id)
receivable1 = inv1.line_ids.filtered(
lambda line: line.account_id.account_type == "asset_receivable"
)
bank_stmt = self.acc_bank_stmt_model.create(
{
"journal_id": self.bank_journal_euro.id,
"date": time.strftime("%Y-07-15"),
"name": "test",
}
)
bank_stmt_line = self.acc_bank_stmt_line_model.create(
{
"name": "testLine",
"journal_id": self.bank_journal_euro.id,
"statement_id": bank_stmt.id,
"amount": 100,
"date": time.strftime("%Y-07-15"),
}
)
with Form(
bank_stmt_line,
view="account_reconcile_oca.bank_statement_line_form_reconcile_view",
) as f:
self.assertFalse(f.can_reconcile)
f.add_account_move_line_id = receivable1
self.assertFalse(f.can_reconcile)
f.manual_model_id = self.rule
self.assertTrue(f.can_reconcile)
number_of_lines = len(bank_stmt_line.reconcile_data_info["data"])
bank_stmt_line.reconcile_bank_line()
self.assertEqual(
number_of_lines, len(bank_stmt_line.reconcile_data_info["data"])
)
self.assertNotEqual(self.current_assets_account, receivable1.account_id)
self.assertTrue(
bank_stmt_line.move_id.line_ids.filtered(
lambda r: r.account_id == self.current_assets_account
)
)
self.assertTrue(
bank_stmt_line.move_id.line_ids.filtered(
lambda r: r.account_id == receivable1.account_id
)
)
self.assertEqual(0, inv1.amount_residual)
def test_reconcile_rule_on_create(self):
"""
Testing the fill of the bank statment line with
writeoff suggestion reconcile model with auto_reconcile
"""
self.env["account.reconcile.model"].create(
{
"name": "write-off model suggestion",
"rule_type": "writeoff_suggestion",
"match_label": "contains",
"match_label_param": "DEMO WRITEOFF",
"auto_reconcile": True,
"line_ids": [
Command.create({"account_id": self.current_assets_account.id})
],
}
)
bank_stmt = self.acc_bank_stmt_model.create(
{
"journal_id": self.bank_journal_euro.id,
"date": time.strftime("%Y-07-15"),
"name": "test",
}
)
bank_stmt_line = self.acc_bank_stmt_line_model.create(
{
"name": "DEMO WRITEOFF",
"payment_ref": "DEMO WRITEOFF",
"journal_id": self.bank_journal_euro.id,
"statement_id": bank_stmt.id,
"amount": 100,
"date": time.strftime("%Y-07-15"),
}
)
self.assertTrue(bank_stmt_line.is_reconciled)
def test_reconcile_invoice_keep(self):
"""
We want to test how the keep mode works, keeping the original move lines.
When unreconciling, the entry created for the reconciliation is reversed.
"""
self.bank_journal_euro.reconcile_mode = "keep"
self.bank_journal_euro.suspense_account_id.reconcile = True
inv1 = self.create_invoice(
currency_id=self.currency_euro_id, invoice_amount=100
)
bank_stmt = self.acc_bank_stmt_model.create(
{
"journal_id": self.bank_journal_euro.id,
"date": time.strftime("%Y-07-15"),
"name": "test",
}
)
bank_stmt_line = self.acc_bank_stmt_line_model.create(
{
"name": "testLine",
"journal_id": self.bank_journal_euro.id,
"statement_id": bank_stmt.id,
"amount": 100,
"date": time.strftime("%Y-07-15"),
}
)
receivable1 = inv1.line_ids.filtered(
lambda line: line.account_id.account_type == "asset_receivable"
)
with Form(
bank_stmt_line,
view="account_reconcile_oca.bank_statement_line_form_reconcile_view",
) as f:
self.assertFalse(f.can_reconcile)
f.add_account_move_line_id = receivable1
self.assertFalse(f.add_account_move_line_id)
self.assertTrue(bank_stmt_line.can_reconcile)
number_of_lines = len(bank_stmt_line.reconcile_data_info["data"])
bank_stmt_line.reconcile_bank_line()
self.assertEqual(
number_of_lines, len(bank_stmt_line.reconcile_data_info["data"])
)
self.assertIn(
self.bank_journal_euro.suspense_account_id,
bank_stmt_line.mapped("move_id.line_ids.account_id"),
)
# Reset reconciliation
reconcile_move = (
bank_stmt_line.line_ids._all_reconciled_lines()
.filtered(lambda line: line.move_id != bank_stmt_line.move_id)
.move_id
)
bank_stmt_line.unreconcile_bank_line()
self.assertTrue(reconcile_move.reversal_move_ids)
self.assertFalse(bank_stmt_line.is_reconciled)
def test_reconcile_model_with_foreign_currency(self):
"""
We want to test what happens when we select a reconcile model to fill a
bank statement with a foreign currency.
"""
bank_stmt = self.acc_bank_stmt_model.create(
{
"journal_id": self.bank_journal_usd.id,
"date": time.strftime("%Y-07-15"),
"name": "test",
}
)
bank_stmt_line = self.acc_bank_stmt_line_model.create(
{
"name": "testLine",
"journal_id": self.bank_journal_usd.id,
"statement_id": bank_stmt.id,
"amount": 100,
"date": time.strftime("%Y-07-15"),
}
)
with Form(
bank_stmt_line,
view="account_reconcile_oca.bank_statement_line_form_reconcile_view",
) as f:
self.assertFalse(f.can_reconcile)
f.manual_model_id = self.rule
self.assertTrue(f.can_reconcile)
number_of_lines = len(bank_stmt_line.reconcile_data_info["data"])
bank_stmt_line.reconcile_bank_line()
self.assertEqual(
number_of_lines, len(bank_stmt_line.reconcile_data_info["data"])
)
self.assertEqual(2, len(bank_stmt_line.move_id.line_ids))
self.assertTrue(
bank_stmt_line.move_id.line_ids.filtered(
lambda r: r.account_id == self.current_assets_account
)
)
expected_amount = bank_stmt_line._get_reconcile_currency()._convert(
bank_stmt_line.amount,
bank_stmt_line.company_id.currency_id,
bank_stmt_line.company_id,
bank_stmt_line.date,
)
self.assertEqual(
bank_stmt_line.move_id.line_ids[0].amount_currency, bank_stmt_line.amount
)
self.assertEqual(bank_stmt_line.move_id.line_ids[0].debit, expected_amount)
self.assertEqual(bank_stmt_line.move_id.line_ids[1].credit, expected_amount)
# Testing to check functionality
def test_reconcile_invoice_to_check_reconciled(self):
"""
We want to test the reconcile widget for bank statements on invoices.
As we use edit mode by default, we will also check what happens when
we press unreconcile
"""
inv1 = self.create_invoice(
currency_id=self.currency_euro_id, invoice_amount=100
)
bank_stmt = self.acc_bank_stmt_model.create(
{
"journal_id": self.bank_journal_euro.id,
"date": time.strftime("%Y-07-15"),
"name": "test",
}
)
bank_stmt_line = self.acc_bank_stmt_line_model.create(
{
"name": "testLine",
"journal_id": self.bank_journal_euro.id,
"statement_id": bank_stmt.id,
"amount": 100,
"date": time.strftime("%Y-07-15"),
}
)
receivable1 = inv1.line_ids.filtered(
lambda line: line.account_id.account_type == "asset_receivable"
)
with Form(
bank_stmt_line,
view="account_reconcile_oca.bank_statement_line_form_reconcile_view",
) as f:
self.assertFalse(f.can_reconcile)
f.add_account_move_line_id = receivable1
self.assertTrue(f.can_reconcile)
self.assertFalse(bank_stmt_line.is_reconciled)
self.assertTrue(bank_stmt_line.checked)
bank_stmt_line.action_to_check()
self.assertTrue(bank_stmt_line.is_reconciled)
self.assertFalse(bank_stmt_line.checked)
bank_stmt_line.action_checked()
self.assertTrue(bank_stmt_line.is_reconciled)
self.assertTrue(bank_stmt_line.checked)
def test_reconcile_invoice_to_check_not_reconciled(self):
"""
We want to test the reconcile widget for bank statements on invoices.
As we use edit mode by default, we will also check what happens when
we press unreconcile
"""
bank_stmt = self.acc_bank_stmt_model.create(
{
"journal_id": self.bank_journal_euro.id,
"date": time.strftime("%Y-07-15"),
"name": "test",
}
)
bank_stmt_line = self.acc_bank_stmt_line_model.create(
{
"name": "testLine",
"journal_id": self.bank_journal_euro.id,
"statement_id": bank_stmt.id,
"amount": 100,
"date": time.strftime("%Y-07-15"),
}
)
self.assertFalse(bank_stmt_line.is_reconciled)
self.assertTrue(bank_stmt_line.checked)
bank_stmt_line.action_to_check()
self.assertFalse(bank_stmt_line.is_reconciled)
self.assertFalse(bank_stmt_line.checked)
bank_stmt_line.action_checked()
self.assertFalse(bank_stmt_line.is_reconciled)
self.assertTrue(bank_stmt_line.checked)
# Testing widget
def test_widget_invoice_clean(self):
"""
We want to test how the clean works on an already defined bank statement
"""
inv1 = self.create_invoice(
currency_id=self.currency_euro_id, invoice_amount=100
)
bank_stmt = self.acc_bank_stmt_model.create(
{
"journal_id": self.bank_journal_euro.id,
"date": time.strftime("%Y-07-15"),
"name": "test",
}
)
bank_stmt_line = self.acc_bank_stmt_line_model.create(
{
"name": "testLine",
"journal_id": self.bank_journal_euro.id,
"statement_id": bank_stmt.id,
"amount": 100,
"date": time.strftime("%Y-07-15"),
}
)
receivable1 = inv1.line_ids.filtered(
lambda line: line.account_id.account_type == "asset_receivable"
)
with Form(
bank_stmt_line,
view="account_reconcile_oca.bank_statement_line_form_reconcile_view",
) as f:
self.assertFalse(f.can_reconcile)
f.add_account_move_line_id = receivable1
self.assertFalse(f.add_account_move_line_id)
self.assertTrue(bank_stmt_line.can_reconcile)
bank_stmt_line.clean_reconcile()
self.assertFalse(bank_stmt_line.can_reconcile)
def test_widget_invoice_delete(self):
"""
We need to test the possibility to remove a line from the reconcile widget
"""
inv1 = self.create_invoice(
currency_id=self.currency_euro_id, invoice_amount=100
)
bank_stmt = self.acc_bank_stmt_model.create(
{
"journal_id": self.bank_journal_euro.id,
"date": time.strftime("%Y-07-15"),
"name": "test",
}
)
bank_stmt_line = self.acc_bank_stmt_line_model.create(
{
"name": "testLine",
"journal_id": self.bank_journal_euro.id,
"statement_id": bank_stmt.id,
"amount": 100,
"date": time.strftime("%Y-07-15"),
}
)
receivable1 = inv1.line_ids.filtered(
lambda line: line.account_id.account_type == "asset_receivable"
)
with Form(
bank_stmt_line,
view="account_reconcile_oca.bank_statement_line_form_reconcile_view",
) as f:
self.assertFalse(f.can_reconcile)
f.add_account_move_line_id = receivable1
self.assertFalse(f.add_account_move_line_id)
self.assertTrue(f.can_reconcile)
f.manual_reference = f"account.move.line;{receivable1.id}"
self.assertEqual(f.manual_amount, -100)
f.manual_delete = True
self.assertFalse(f.can_reconcile)
def test_widget_invoice_unselect(self):
"""
We want to test how selection and unselection of an account move lines is
managed by the system.
"""
inv1 = self.create_invoice(
currency_id=self.currency_euro_id, invoice_amount=100
)
bank_stmt = self.acc_bank_stmt_model.create(
{
"journal_id": self.bank_journal_euro.id,
"date": time.strftime("%Y-07-15"),
"name": "test",
}
)
bank_stmt_line = self.acc_bank_stmt_line_model.create(
{
"name": "testLine",
"journal_id": self.bank_journal_euro.id,
"statement_id": bank_stmt.id,
"amount": 100,
"date": time.strftime("%Y-07-15"),
}
)
with Form(
bank_stmt_line,
view="account_reconcile_oca.bank_statement_line_form_reconcile_view",
) as f:
self.assertFalse(f.can_reconcile)
f.add_account_move_line_id = inv1.line_ids.filtered(
lambda line: line.account_id.account_type == "asset_receivable"
)
self.assertFalse(f.add_account_move_line_id)
self.assertTrue(f.can_reconcile)
f.add_account_move_line_id = inv1.line_ids.filtered(
lambda line: line.account_id.account_type == "asset_receivable"
)
self.assertFalse(f.add_account_move_line_id)
self.assertFalse(f.can_reconcile)
def test_widget_invoice_change_partner(self):
"""
We want to know how the change of partner of
a bank statement line is managed
"""
inv1 = self.create_invoice(
currency_id=self.currency_euro_id, invoice_amount=100
)
bank_stmt = self.acc_bank_stmt_model.create(
{
"journal_id": self.bank_journal_euro.id,
"date": time.strftime("%Y-07-15"),
"name": "test",
}
)
bank_stmt_line = self.acc_bank_stmt_line_model.create(
{
"name": "testLine",
"journal_id": self.bank_journal_euro.id,
"statement_id": bank_stmt.id,
"amount": 100,
"date": time.strftime("%Y-07-15"),
}
)
liquidity_lines, suspense_lines, other_lines = bank_stmt_line._seek_for_lines()
with Form(
bank_stmt_line,
view="account_reconcile_oca.bank_statement_line_form_reconcile_view",
) as f:
self.assertFalse(f.can_reconcile)
self.assertFalse(f.partner_id)
f.manual_reference = f"account.move.line;{liquidity_lines.id}"
f.manual_partner_id = inv1.partner_id
f.save()
self.assertEqual(f.partner_id, inv1.partner_id)
bank_stmt_line.clean_reconcile()
# As we have set a partner, the cleaning should assign the invoice automatically
self.assertTrue(bank_stmt_line.can_reconcile)
def test_widget_model_clean(self):
"""
We want to test what happens when we select an reconcile model to fill a
bank statement.
"""
bank_stmt = self.acc_bank_stmt_model.create(
{
"journal_id": self.bank_journal_euro.id,
"date": time.strftime("%Y-07-15"),
"name": "test",
}
)
bank_stmt_line = self.acc_bank_stmt_line_model.create(
{
"name": "testLine",
"journal_id": self.bank_journal_euro.id,
"statement_id": bank_stmt.id,
"amount": 100,
"date": time.strftime("%Y-07-15"),
}
)
with Form(
bank_stmt_line,
view="account_reconcile_oca.bank_statement_line_form_reconcile_view",
) as f:
self.assertFalse(f.can_reconcile)
f.manual_model_id = self.rule
self.assertTrue(f.can_reconcile)
# We need to check what happens when we uncheck it too
f.manual_model_id = self.env["account.reconcile.model"]
self.assertFalse(f.can_reconcile)
f.manual_model_id = self.rule
self.assertTrue(f.can_reconcile)
# Testing actions
def test_bank_statement_rainbowman(self):
message = self.bank_journal_euro.get_rainbowman_message()
self.assertTrue(message)
self.acc_bank_stmt_line_model.create(
{
"name": "testLine",
"journal_id": self.bank_journal_euro.id,
"amount": 100,
"date": time.strftime("%Y-07-15"),
}
)
self.env.flush_all()
message = self.bank_journal_euro.get_rainbowman_message()
self.assertFalse(message)
def test_bank_statement_line_actions(self):
"""
Testing the actions of bank statement
"""
bank_stmt = self.acc_bank_stmt_model.create(
{
"journal_id": self.bank_journal_euro.id,
"date": time.strftime("%Y-07-15"),
"name": "test",
}
)
bank_stmt_line = self.acc_bank_stmt_line_model.create(
{
"name": "testLine",
"journal_id": self.bank_journal_euro.id,
"statement_id": bank_stmt.id,
"amount": 100,
"date": time.strftime("%Y-07-15"),
}
)
move_action = bank_stmt_line.action_show_move()
self.assertEqual(
bank_stmt_line.move_id,
self.env[move_action["res_model"]].browse(move_action["res_id"]),
)
# Testing filters
def test_filter_partner(self):
"""
When a partner is set, the system might try to define an existent
invoice automatically
"""
inv1 = self.create_invoice(currency_id=self.currency_euro_id)
inv2 = self.create_invoice(currency_id=self.currency_euro_id)
partner = inv1.partner_id
receivable1 = inv1.line_ids.filtered(
lambda line: line.account_id.account_type == "asset_receivable"
)
self.assertTrue(receivable1)
receivable2 = inv2.line_ids.filtered(
lambda line: line.account_id.account_type == "asset_receivable"
)
self.assertTrue(receivable2)
bank_stmt = self.acc_bank_stmt_model.create(
{
"journal_id": self.bank_journal_euro.id,
"date": time.strftime("%Y-07-15"),
"name": "test",
}
)
bank_stmt_line = self.acc_bank_stmt_line_model.create(
{
"name": "testLine",
"journal_id": self.bank_journal_euro.id,
"statement_id": bank_stmt.id,
"amount": 100,
"date": time.strftime("%Y-07-15"),
}
)
# Without a partner set, No default data
bkstmt_data = bank_stmt_line.reconcile_data_info
mv_lines_ids = bkstmt_data["counterparts"]
self.assertNotIn(receivable1.id, mv_lines_ids)
self.assertNotIn(receivable2.id, mv_lines_ids)
# This is like input a partner in the widget
bank_stmt_line.partner_id = partner
bank_stmt_line.flush_recordset()
bank_stmt_line.invalidate_recordset()
bkstmt_data = bank_stmt_line.reconcile_data_info
mv_lines_ids = bkstmt_data["counterparts"]
self.assertIn(receivable1.id, mv_lines_ids)
self.assertIn(receivable2.id, mv_lines_ids)
# With a partner set, type the invoice reference in the filter
bank_stmt_line.payment_ref = inv1.payment_reference
bank_stmt_line.flush_recordset()
bank_stmt_line.invalidate_recordset()
bkstmt_data = bank_stmt_line.reconcile_data_info
mv_lines_ids = bkstmt_data["counterparts"]
self.assertIn(receivable1.id, mv_lines_ids)
self.assertNotIn(receivable2.id, mv_lines_ids)
def test_partner_name_with_parent(self):
parent_partner = self.env["res.partner"].create(
{
"name": "test_account_reconcile_oca",
}
)
child_partner = self.env["res.partner"].create(
{
"name": "test_account_reconcile_oca",
"parent_id": parent_partner.id,
"type": "delivery",
}
)
self.create_invoice_partner(
currency_id=self.currency_euro_id, partner_id=child_partner.id
)
bank_stmt = self.acc_bank_stmt_model.create(
{
"journal_id": self.bank_journal_euro.id,
"date": time.strftime("%Y-07-15"),
"name": "test",
}
)
self.invoice_matching_models.active = True
self.invoice_matching_models.match_text_location_label = False
bank_stmt_line = self.acc_bank_stmt_line_model.create(
{
"name": "testLine",
"statement_id": bank_stmt.id,
"journal_id": self.bank_journal_euro.id,
"amount": 100,
"date": time.strftime("%Y-07-15"),
"payment_ref": "test",
"partner_name": "test_account_reconcile_oca",
}
)
bkstmt_data = bank_stmt_line.reconcile_data_info
self.assertEqual(len(bkstmt_data["counterparts"]), 1)
self.assertEqual(
self.env["account.move.line"]
.browse(bkstmt_data["counterparts"])
.partner_id,
parent_partner,
)
def test_journal_foreign_currency(self):
inv1 = self.create_invoice(currency_id=self.currency_usd_id, invoice_amount=100)
bank_stmt = self.acc_bank_stmt_model.create(
{
"journal_id": self.bank_journal_usd.id,
"date": time.strftime("%Y-07-15"),
"name": "test",
}
)
bank_stmt_line = self.acc_bank_stmt_line_model.create(
{
"name": "testLine",
"journal_id": self.bank_journal_usd.id,
"statement_id": bank_stmt.id,
"amount": 100,
"date": time.strftime("%Y-07-15"),
}
)
with Form(
bank_stmt_line,
view="account_reconcile_oca.bank_statement_line_form_reconcile_view",
) as f:
self.assertFalse(f.can_reconcile)
f.add_account_move_line_id = inv1.line_ids.filtered(
lambda line: line.account_id.account_type == "asset_receivable"
)
self.assertFalse(f.add_account_move_line_id)
self.assertTrue(f.can_reconcile)
self.assertTrue(bank_stmt_line.can_reconcile)
number_of_lines = len(bank_stmt_line.reconcile_data_info["data"])
bank_stmt_line.reconcile_bank_line()
self.assertEqual(
number_of_lines, len(bank_stmt_line.reconcile_data_info["data"])
)
self.assertEqual(0, inv1.amount_residual)
self.assertTrue(
inv1.line_ids.filtered(
lambda line: line.account_id.account_type == "asset_receivable"
).full_reconcile_id
)
def test_journal_foreign_currency_change(self):
cny = self.env.ref("base.CNY")
cny.write({"active": True})
cny_journal = self.env["account.journal"].create(
{
"name": "Bank CNY",
"type": "bank",
"currency_id": cny.id,
}
)
self.env["res.currency.rate"].create(
{
"name": time.strftime("%Y-09-10"),
"currency_id": cny.id,
"inverse_company_rate": 0.125989013758,
}
)
self.env["res.currency.rate"].create(
{
"name": time.strftime("%Y-09-09"),
"currency_id": cny.id,
"inverse_company_rate": 0.126225969731,
}
)
bank_stmt = self.acc_bank_stmt_model.create(
{
"journal_id": cny_journal.id,
"date": time.strftime("%Y-09-10"),
"name": "test",
}
)
bank_stmt_line = self.acc_bank_stmt_line_model.create(
{
"name": "testLine",
"journal_id": cny_journal.id,
"statement_id": bank_stmt.id,
"amount": 259200,
"date": time.strftime("%Y-09-10"),
}
)
inv1 = self._create_invoice(
currency_id=cny.id,
invoice_amount=259200,
date_invoice=time.strftime("%Y-09-09"),
auto_validate=True,
)
with Form(
bank_stmt_line,
view="account_reconcile_oca.bank_statement_line_form_reconcile_view",
) as f:
line = f.reconcile_data_info["data"][0]
self.assertEqual(
line["currency_amount"],
259200,
)
f.add_account_move_line_id = inv1.line_ids.filtered(
lambda line: line.account_id.account_type == "asset_receivable"
)
self.assertTrue(f.can_reconcile)
self.assertEqual(len(bank_stmt_line.reconcile_data_info["data"]), 3)
exchange_line = bank_stmt_line.reconcile_data_info["data"][-1]
self.assertEqual(exchange_line["amount"], 61.42)
bank_stmt_line.reconcile_bank_line()
self.assertEqual(inv1.payment_state, "paid")
def test_invoice_foreign_currency_change(self):
self.env["res.currency.rate"].create(
{
"currency_id": self.env.ref("base.EUR").id,
"name": time.strftime("%Y-07-14"),
"rate": 1.15,
}
)
self.env["res.currency.rate"].create(
{
"currency_id": self.env.ref("base.EUR").id,
"name": time.strftime("%Y-07-15"),
"rate": 1.2,
}
)
inv1 = self._create_invoice(
currency_id=self.currency_usd_id,
invoice_amount=100,
date_invoice="2021-07-14",
auto_validate=True,
)
bank_stmt = self.acc_bank_stmt_model.create(
{
"journal_id": self.bank_journal_usd.id,
"date": time.strftime("%Y-07-15"),
"name": "test",
}
)
bank_stmt_line = self.acc_bank_stmt_line_model.create(
{
"name": "testLine",
"journal_id": self.bank_journal_usd.id,
"statement_id": bank_stmt.id,
"amount": 100,
"date": time.strftime("%Y-07-15"),
}
)
with Form(
bank_stmt_line,
view="account_reconcile_oca.bank_statement_line_form_reconcile_view",
) as f:
line = f.reconcile_data_info["data"][0]
self.assertEqual(
line["currency_amount"],
100,
)
f.add_account_move_line_id = inv1.line_ids.filtered(
lambda line: line.account_id.account_type == "asset_receivable"
)
self.assertFalse(f.add_account_move_line_id)
self.assertTrue(f.can_reconcile)
self.assertEqual(3, len(f.reconcile_data_info["data"]))
def test_receivable_line(self):
bank_stmt_line = self.acc_bank_stmt_line_model.create(
{
"name": "testLine",
"journal_id": self.bank_journal_euro.id,
"partner_id": self.partner_agrolait_id,
"amount": 100,
"date": time.strftime("%Y-07-15"),
}
)
self.assertTrue(bank_stmt_line.can_reconcile)
suspense_line = False
for line in bank_stmt_line.reconcile_data_info["data"]:
if line["kind"] == "suspense":
suspense_line = line
break
self.assertTrue(suspense_line)
self.assertEqual(
self.env["account.account"]
.browse(suspense_line["account_id"][0])
.account_type,
"asset_receivable",
)
def test_payable_line(self):
bank_stmt_line = self.acc_bank_stmt_line_model.create(
{
"name": "testLine",
"journal_id": self.bank_journal_euro.id,
"partner_id": self.partner_agrolait_id,
"amount": -100,
"date": time.strftime("%Y-07-15"),
}
)
self.assertTrue(bank_stmt_line.can_reconcile)
suspense_line = False
for line in bank_stmt_line.reconcile_data_info["data"]:
if line["kind"] == "suspense":
suspense_line = line
break
self.assertTrue(suspense_line)
self.assertEqual(
self.env["account.account"]
.browse(suspense_line["account_id"][0])
.account_type,
"liability_payable",
)
def test_invoice_foreign_currency_late_change_of_rate(self):
# Test we can reconcile lines in foreign currency even if the rate was updated
# late in odoo, meaning the statement line was created and the rate was updated
# in odoo after that.
self.env["res.currency.rate"].create(
{
"currency_id": self.env.ref("base.USD").id,
"name": time.strftime("%Y-07-14"),
"rate": 1.15,
}
)
self.env["res.currency.rate"].create(
{
"currency_id": self.env.ref("base.USD").id,
"name": time.strftime("%Y-07-15"),
"rate": 1.2,
}
)
inv1 = self._create_invoice(
currency_id=self.currency_usd_id,
invoice_amount=100,
date_invoice=time.strftime("%Y-07-14"),
auto_validate=True,
)
bank_stmt = self.acc_bank_stmt_model.create(
{
"journal_id": self.bank_journal_usd.id,
"date": time.strftime("%Y-07-15"),
"name": "test",
}
)
bank_stmt_line = self.acc_bank_stmt_line_model.create(
{
"name": "testLine",
"journal_id": self.bank_journal_usd.id,
"statement_id": bank_stmt.id,
"amount": 100,
"date": time.strftime("%Y-07-16"),
}
)
# rate of 07-16 is create after the statement line, meaning the rate of the
# statement line is the one of the 07-15
self.env["res.currency.rate"].create(
{
"currency_id": self.env.ref("base.USD").id,
"name": time.strftime("%Y-07-16"),
"rate": 1.25,
}
)
liquidity_lines, suspense_lines, other_lines = bank_stmt_line._seek_for_lines()
with Form(
bank_stmt_line,
view="account_reconcile_oca.bank_statement_line_form_reconcile_view",
) as f:
line = f.reconcile_data_info["data"][0]
self.assertEqual(
line["currency_amount"],
100,
)
self.assertEqual(
line["amount"],
83.33,
)
# check that adding a partner does not recompute the amounts on accounting
# entries, but is still synchronized with accounting entries
f.manual_reference = "account.move.line;%s" % liquidity_lines.id
f.manual_partner_id = inv1.partner_id
self.assertEqual(f.partner_id, inv1.partner_id)
self.assertEqual(liquidity_lines.debit, 83.33)
f.save()
# check liquidity line did not recompute debit with the new rate with
# partner change
self.assertEqual(liquidity_lines.debit, 83.33)
self.assertEqual(liquidity_lines.partner_id, inv1.partner_id)
f.manual_reference = "account.move.line;%s" % line["id"]
# simulate click on statement line, check amount does not recompute
f.manual_partner_id = inv1.partner_id
self.assertEqual(f.manual_amount, 83.33)
# check currency amount is still fine
self.assertEqual(f.reconcile_data_info["data"][0]["currency_amount"], 100)
f.add_account_move_line_id = inv1.line_ids.filtered(
lambda line: line.account_id.account_type == "asset_receivable"
)
self.assertEqual(3, len(f.reconcile_data_info["data"]))
self.assertTrue(f.can_reconcile)
self.assertEqual(f.reconcile_data_info["data"][-1]["amount"], 3.63)