forked from Mapan/odoo17e
3024 lines
155 KiB
Python
3024 lines
155 KiB
Python
# -*- coding: utf-8 -*-
|
|
from odoo.addons.account_accountant.tests.test_bank_rec_widget_common import TestBankRecWidgetCommon
|
|
from odoo.tests import tagged
|
|
from odoo.tools import html2plaintext
|
|
from odoo import fields, Command
|
|
|
|
from freezegun import freeze_time
|
|
from unittest.mock import patch
|
|
import re
|
|
|
|
|
|
@tagged('post_install', '-at_install')
|
|
class TestBankRecWidget(TestBankRecWidgetCommon):
|
|
|
|
@classmethod
|
|
def setUpClass(cls, chart_template_ref=None):
|
|
super().setUpClass(chart_template_ref=chart_template_ref)
|
|
|
|
cls.early_payment_term = cls.env['account.payment.term'].create({
|
|
'name': "early_payment_term",
|
|
'company_id': cls.company_data['company'].id,
|
|
'discount_percentage': 10,
|
|
'discount_days': 10,
|
|
'early_discount': True,
|
|
'line_ids': [
|
|
Command.create({
|
|
'value': 'percent',
|
|
'value_amount': 100,
|
|
'nb_days': 20,
|
|
}),
|
|
],
|
|
})
|
|
|
|
cls.account_revenue1 = cls.company_data['default_account_revenue']
|
|
cls.account_revenue2 = cls.copy_account(cls.account_revenue1)
|
|
|
|
def assert_form_extra_text_value(self, wizard, regex):
|
|
line = wizard.line_ids.filtered(lambda x: x.index == wizard.form_index)
|
|
value = line.suggestion_html
|
|
if regex:
|
|
cleaned_value = html2plaintext(value).replace('\n', '')
|
|
if not re.match(regex, cleaned_value):
|
|
self.fail(f"The following 'form_extra_text':\n\n'{cleaned_value}'\n\n...doesn't match the provided regex:\n\n'{regex}'")
|
|
else:
|
|
self.assertFalse(value)
|
|
|
|
def test_retrieve_partner_from_account_number(self):
|
|
st_line = self._create_st_line(1000.0, partner_id=None, account_number="014 474 8555")
|
|
bank_account = self.env['res.partner.bank'].create({
|
|
'acc_number': '0144748555',
|
|
'partner_id': self.partner_a.id,
|
|
})
|
|
self.assertEqual(st_line._retrieve_partner(), bank_account.partner_id)
|
|
|
|
# Can't retrieve the partner since the bank account is used by multiple partners.
|
|
self.env['res.partner.bank'].create({
|
|
'acc_number': '0144748555',
|
|
'partner_id': self.partner_b.id,
|
|
})
|
|
self.assertEqual(st_line._retrieve_partner(), self.env['res.partner'])
|
|
|
|
def test_retrieve_partner_from_account_number_in_other_company(self):
|
|
st_line = self._create_st_line(1000.0, partner_id=None, account_number="014 474 8555")
|
|
self.env['res.partner.bank'].create({
|
|
'acc_number': '0144748555',
|
|
'partner_id': self.partner_a.id,
|
|
})
|
|
|
|
# Bank account is owned by another company.
|
|
new_company = self.env['res.company'].create({'name': "test_retrieve_partner_from_account_number_in_other_company"})
|
|
self.partner_a.company_id = new_company
|
|
self.assertEqual(st_line._retrieve_partner(), self.env['res.partner'])
|
|
|
|
def test_retrieve_partner_from_partner_name(self):
|
|
""" Ensure the partner having a name fitting exactly the 'partner_name' is retrieved first.
|
|
This test create two partners that will be ordered in the lexicographic order when performing
|
|
a search. So:
|
|
row1: "Turlututu tsoin tsoin"
|
|
row2: "turlututu"
|
|
|
|
Since "turlututu" matches exactly (case insensitive) the partner_name of the statement line,
|
|
it should be suggested first.
|
|
|
|
However if we have two partners called turlututu, we should not suggest any or we risk selecting
|
|
the wrong one.
|
|
"""
|
|
_partner_a, partner_b = self.env['res.partner'].create([
|
|
{'name': "Turlututu tsoin tsoin"},
|
|
{'name': "turlututu"},
|
|
])
|
|
|
|
st_line = self._create_st_line(1000.0, partner_id=None, partner_name="Turlututu")
|
|
self.assertEqual(st_line._retrieve_partner(), partner_b)
|
|
|
|
self.env['res.partner'].create({'name': "turlututu"})
|
|
self.assertFalse(st_line._retrieve_partner())
|
|
|
|
def test_retrieve_partner_suggested_account_from_rank(self):
|
|
""" Ensure a retrieved partner is proposing his receivable/payable according his customer/supplier rank. """
|
|
partner = self.env['res.partner'].create({'name': "turlututu"})
|
|
rec_account_id = partner.property_account_receivable_id.id
|
|
pay_account_id = partner.property_account_payable_id.id
|
|
|
|
st_line = self._create_st_line(1000.0, partner_id=None, partner_name="turlututu")
|
|
liq_account_id = st_line.journal_id.default_account_id.id
|
|
wizard = self.env['bank.rec.widget'].with_context(default_st_line_id=st_line.id).new({})
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'account_id': liq_account_id, 'balance': 1000.0},
|
|
{'flag': 'auto_balance', 'account_id': rec_account_id, 'balance': -1000.0},
|
|
])
|
|
|
|
partner._increase_rank('supplier_rank', 1)
|
|
wizard = self.env['bank.rec.widget'].with_context(default_st_line_id=st_line.id).new({})
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'account_id': liq_account_id, 'balance': 1000.0},
|
|
{'flag': 'auto_balance', 'account_id': pay_account_id, 'balance': -1000.0},
|
|
])
|
|
|
|
def test_res_partner_bank_find_create_when_archived(self):
|
|
""" Test we don't get the "The combination Account Number/Partner must be unique." error with archived
|
|
bank account.
|
|
"""
|
|
partner = self.env['res.partner'].create({
|
|
'name': "Zitycard",
|
|
'bank_ids': [Command.create({
|
|
'acc_number': "123456789",
|
|
'active': False,
|
|
})],
|
|
})
|
|
|
|
st_line = self._create_st_line(
|
|
100.0,
|
|
partner_name="Zeumat Zitycard",
|
|
account_number="123456789",
|
|
)
|
|
inv_line = self._create_invoice_line(
|
|
'out_invoice',
|
|
partner_id=partner.id,
|
|
invoice_line_ids=[{'price_unit': 100.0, 'tax_ids': []}],
|
|
)
|
|
wizard = self.env['bank.rec.widget'].with_context(default_st_line_id=st_line.id).new({})
|
|
wizard._action_add_new_amls(inv_line)
|
|
wizard._action_validate()
|
|
|
|
# Should not trigger the error.
|
|
self.env['res.partner.bank'].flush_model()
|
|
|
|
def test_res_partner_bank_find_create_multi_company(self):
|
|
""" Test we don't get the "The combination Account Number/Partner must be unique." error when the bank account
|
|
already exists on another company.
|
|
"""
|
|
partner = self.env['res.partner'].create({
|
|
'name': "Zitycard",
|
|
'bank_ids': [Command.create({'acc_number': "123456789"})],
|
|
})
|
|
partner.bank_ids.company_id = self.company_data_2['company']
|
|
self.env.user.company_ids = self.env.company
|
|
|
|
st_line = self._create_st_line(
|
|
100.0,
|
|
partner_name="Zeumat Zitycard",
|
|
account_number="123456789",
|
|
)
|
|
inv_line = self._create_invoice_line(
|
|
'out_invoice',
|
|
partner_id=partner.id,
|
|
invoice_line_ids=[{'price_unit': 100.0, 'tax_ids': []}],
|
|
)
|
|
wizard = self.env['bank.rec.widget'].with_context(default_st_line_id=st_line.id).new({})
|
|
wizard._action_add_new_amls(inv_line)
|
|
wizard._action_validate()
|
|
|
|
# Should not trigger the error.
|
|
self.env['res.partner.bank'].flush_model()
|
|
|
|
def test_validation_base_case(self):
|
|
st_line = self._create_st_line(
|
|
1000.0,
|
|
date='2017-01-01',
|
|
)
|
|
|
|
wizard = self.env['bank.rec.widget'].with_context(default_st_line_id=st_line.id).new({})
|
|
line = wizard.line_ids.filtered(lambda x: x.flag == 'auto_balance')
|
|
wizard._js_action_mount_line_in_edit(line.index)
|
|
line.account_id = self.account_revenue1
|
|
wizard._line_value_changed_account_id(line)
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'amount_currency': 1000.0, 'currency_id': self.company_data['currency'].id, 'balance': 1000.0},
|
|
{'flag': 'manual', 'amount_currency': -1000.0, 'currency_id': self.company_data['currency'].id, 'balance': -1000.0},
|
|
])
|
|
self.assertRecordValues(wizard, [{'state': 'valid'}])
|
|
|
|
# The amount is the same, no message under the 'amount' field.
|
|
self.assert_form_extra_text_value(wizard, False)
|
|
|
|
wizard._action_validate()
|
|
self.assertRecordValues(st_line.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'account_id': st_line.journal_id.default_account_id.id, 'amount_currency': 1000.0, 'currency_id': self.company_data['currency'].id, 'balance': 1000.0, 'reconciled': False},
|
|
{'account_id': self.account_revenue1.id, 'amount_currency': -1000.0, 'currency_id': self.company_data['currency'].id, 'balance': -1000.0, 'reconciled': False},
|
|
])
|
|
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'account_id': st_line.journal_id.default_account_id.id, 'amount_currency': 1000.0, 'currency_id': self.company_data['currency'].id, 'balance': 1000.0},
|
|
{'flag': 'aml', 'account_id': self.account_revenue1.id, 'amount_currency': -1000.0, 'currency_id': self.company_data['currency'].id, 'balance': -1000.0},
|
|
])
|
|
|
|
def test_validation_exchange_difference(self):
|
|
# 240.0 curr2 == 120.0 comp_curr
|
|
st_line = self._create_st_line(
|
|
120.0,
|
|
date='2017-01-01',
|
|
foreign_currency_id=self.currency_data['currency'].id,
|
|
amount_currency=240.0,
|
|
)
|
|
# 240.0 curr2 == 80.0 comp_curr
|
|
inv_line = self._create_invoice_line(
|
|
'out_invoice',
|
|
currency_id=self.currency_data['currency'].id,
|
|
invoice_date='2016-01-01',
|
|
invoice_line_ids=[{'price_unit': 240.0}],
|
|
)
|
|
|
|
wizard = self.env['bank.rec.widget'].with_context(default_st_line_id=st_line.id).new({})
|
|
wizard._action_add_new_amls(inv_line)
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'amount_currency': 120.0, 'currency_id': self.company_data['currency'].id, 'balance': 120.0},
|
|
{'flag': 'new_aml', 'amount_currency': -240.0, 'currency_id': self.currency_data['currency'].id, 'balance': -80.0},
|
|
{'flag': 'exchange_diff', 'amount_currency': 0.0, 'currency_id': self.currency_data['currency'].id, 'balance': -40.0},
|
|
])
|
|
self.assertRecordValues(wizard, [{'state': 'valid'}])
|
|
|
|
wizard._action_validate()
|
|
|
|
# Check the statement line.
|
|
self.assertRecordValues(st_line.line_ids.sorted(), [
|
|
# pylint: disable=C0326
|
|
{'account_id': st_line.journal_id.default_account_id.id, 'amount_currency': 120.0, 'currency_id': self.company_data['currency'].id, 'balance': 120.0, 'reconciled': False},
|
|
{'account_id': inv_line.account_id.id, 'amount_currency': -240.0, 'currency_id': self.currency_data['currency'].id, 'balance': -120.0, 'reconciled': True},
|
|
])
|
|
|
|
# Check the partials.
|
|
partials = st_line.line_ids.matched_debit_ids
|
|
exchange_move = partials.exchange_move_id
|
|
_liquidity_line, _suspense_line, other_line = st_line._seek_for_lines()
|
|
self.assertRecordValues(partials.sorted(), [
|
|
# pylint: disable=C0326
|
|
{
|
|
'amount': 40.0,
|
|
'debit_amount_currency': 0.0,
|
|
'credit_amount_currency': 0.0,
|
|
'debit_move_id': exchange_move.line_ids.sorted()[0].id,
|
|
'credit_move_id': other_line.id,
|
|
'exchange_move_id': False,
|
|
},
|
|
{
|
|
'amount': 80.0,
|
|
'debit_amount_currency': 240.0,
|
|
'credit_amount_currency': 240.0,
|
|
'debit_move_id': inv_line.id,
|
|
'credit_move_id': other_line.id,
|
|
'exchange_move_id': exchange_move.id,
|
|
},
|
|
])
|
|
|
|
# Check the exchange diff journal entry.
|
|
self.assertRecordValues(exchange_move.line_ids.sorted(), [
|
|
# pylint: disable=C0326
|
|
{'account_id': inv_line.account_id.id, 'amount_currency': 0.0, 'currency_id': self.currency_data['currency'].id, 'balance': 40.0, 'reconciled': True},
|
|
{'account_id': self.env.company.income_currency_exchange_account_id.id, 'amount_currency': 0.0, 'currency_id': self.currency_data['currency'].id, 'balance': -40.0, 'reconciled': False},
|
|
])
|
|
|
|
def test_validation_new_aml_same_foreign_currency(self):
|
|
income_exchange_account = self.env.company.income_currency_exchange_account_id
|
|
|
|
# 6000.0 curr2 == 1200.0 comp_curr (bank rate 5:1 instead of the odoo rate 4:1)
|
|
st_line = self._create_st_line(
|
|
1200.0,
|
|
date='2017-01-01',
|
|
foreign_currency_id=self.currency_data_2['currency'].id,
|
|
amount_currency=6000.0,
|
|
)
|
|
# 6000.0 curr2 == 1000.0 comp_curr (rate 6:1)
|
|
inv_line = self._create_invoice_line(
|
|
'out_invoice',
|
|
currency_id=self.currency_data_2['currency'].id,
|
|
invoice_date='2016-01-01',
|
|
invoice_line_ids=[{'price_unit': 6000.0}],
|
|
)
|
|
|
|
wizard = self.env['bank.rec.widget'].with_context(default_st_line_id=st_line.id).new({})
|
|
wizard._action_add_new_amls(inv_line)
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'amount_currency': 1200.0, 'currency_id': self.company_data['currency'].id, 'balance': 1200.0},
|
|
{'flag': 'new_aml', 'amount_currency': -6000.0, 'currency_id': self.currency_data_2['currency'].id, 'balance': -1000.0},
|
|
{'flag': 'exchange_diff', 'amount_currency': 0.0, 'currency_id': self.currency_data_2['currency'].id, 'balance': -200.0},
|
|
])
|
|
self.assertRecordValues(wizard, [{'state': 'valid'}])
|
|
|
|
# The amount is the same, no message under the 'amount' field.
|
|
self.assert_form_extra_text_value(wizard, False)
|
|
|
|
wizard._action_validate()
|
|
self.assertRecordValues(st_line.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'account_id': st_line.journal_id.default_account_id.id, 'amount_currency': 1200.0, 'currency_id': self.company_data['currency'].id, 'balance': 1200.0, 'reconciled': False},
|
|
{'account_id': inv_line.account_id.id, 'amount_currency': -6000.0, 'currency_id': self.currency_data_2['currency'].id, 'balance': -1200.0, 'reconciled': True},
|
|
])
|
|
self.assertRecordValues(st_line, [{'is_reconciled': True}])
|
|
self.assertRecordValues(inv_line.move_id, [{'payment_state': 'paid'}])
|
|
self.assertRecordValues(inv_line.matched_credit_ids.exchange_move_id.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'account_id': inv_line.account_id.id, 'amount_currency': 0.0, 'currency_id': self.currency_data_2['currency'].id, 'balance': 200.0, 'reconciled': True, 'date': fields.Date.from_string('2017-01-31')},
|
|
{'account_id': income_exchange_account.id, 'amount_currency': 0.0, 'currency_id': self.currency_data_2['currency'].id, 'balance': -200.0, 'reconciled': False, 'date': fields.Date.from_string('2017-01-31')},
|
|
])
|
|
|
|
# Reset the wizard.
|
|
wizard._js_action_reset()
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'amount_currency': 1200.0, 'currency_id': self.company_data['currency'].id, 'balance': 1200.0},
|
|
{'flag': 'auto_balance', 'amount_currency': -6000.0, 'currency_id': self.currency_data_2['currency'].id, 'balance': -1200.0},
|
|
])
|
|
|
|
# Create the same invoice with a higher amount to check the partial flow.
|
|
# 9000.0 curr2 == 1500.0 comp_curr (rate 6:1)
|
|
inv_line = self._create_invoice_line(
|
|
'out_invoice',
|
|
currency_id=self.currency_data_2['currency'].id,
|
|
invoice_date='2016-01-01',
|
|
invoice_line_ids=[{'price_unit': 9000.0}],
|
|
)
|
|
wizard._action_add_new_amls(inv_line)
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'amount_currency': 1200.0, 'currency_id': self.company_data['currency'].id, 'balance': 1200.0},
|
|
{'flag': 'new_aml', 'amount_currency': -6000.0, 'currency_id': self.currency_data_2['currency'].id, 'balance': -1000.0},
|
|
{'flag': 'exchange_diff', 'amount_currency': 0.0, 'currency_id': self.currency_data_2['currency'].id, 'balance': -200.0},
|
|
])
|
|
|
|
# Check the message under the 'amount' field.
|
|
line = wizard.line_ids.filtered(lambda x: x.flag == 'new_aml')
|
|
wizard._js_action_mount_line_in_edit(line.index)
|
|
self.assert_form_extra_text_value(
|
|
wizard,
|
|
r".+open amount of 9,000.000.+ reduced by 6,000.000.+ set the invoice as fully paid .",
|
|
)
|
|
self.assertRecordValues(line, [{
|
|
'suggestion_amount_currency': -9000.0,
|
|
'suggestion_balance': -1500.0,
|
|
}])
|
|
|
|
# Switch to a full reconciliation.
|
|
wizard._js_action_apply_line_suggestion(line.index)
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'amount_currency': 1200.0, 'currency_id': self.company_data['currency'].id, 'balance': 1200.0},
|
|
{'flag': 'new_aml', 'amount_currency': -9000.0, 'currency_id': self.currency_data_2['currency'].id, 'balance': -1500.0},
|
|
{'flag': 'exchange_diff', 'amount_currency': 0.0, 'currency_id': self.currency_data_2['currency'].id, 'balance': -300.0},
|
|
{'flag': 'auto_balance', 'amount_currency': 3000.0, 'currency_id': self.currency_data_2['currency'].id, 'balance': 600.0},
|
|
])
|
|
|
|
# Check the message under the 'amount' field.
|
|
line = wizard.line_ids.filtered(lambda x: x.flag == 'new_aml')
|
|
wizard._js_action_mount_line_in_edit(line.index)
|
|
self.assert_form_extra_text_value(
|
|
wizard,
|
|
r".+open amount of 9,000.000.+ paid .+ record a partial payment .",
|
|
)
|
|
self.assertRecordValues(line, [{
|
|
'suggestion_amount_currency': -6000.0,
|
|
'suggestion_balance': -1000.0,
|
|
}])
|
|
|
|
# Switch back to a partial reconciliation.
|
|
wizard._js_action_apply_line_suggestion(line.index)
|
|
self.assertRecordValues(wizard, [{'state': 'valid'}])
|
|
|
|
# Reconcile
|
|
wizard._action_validate()
|
|
self.assertRecordValues(st_line.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'account_id': st_line.journal_id.default_account_id.id, 'amount_currency': 1200.0, 'currency_id': self.company_data['currency'].id, 'balance': 1200.0, 'reconciled': False},
|
|
{'account_id': inv_line.account_id.id, 'amount_currency': -6000.0, 'currency_id': self.currency_data_2['currency'].id, 'balance': -1200.0, 'reconciled': True},
|
|
])
|
|
self.assertRecordValues(st_line, [{'is_reconciled': True}])
|
|
self.assertRecordValues(inv_line.move_id, [{
|
|
'payment_state': 'partial',
|
|
'amount_residual': 3000.0,
|
|
}])
|
|
self.assertRecordValues(inv_line.matched_credit_ids.exchange_move_id.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'account_id': inv_line.account_id.id, 'amount_currency': 0.0, 'currency_id': self.currency_data_2['currency'].id, 'balance': 200.0, 'reconciled': True, 'date': fields.Date.from_string('2017-01-31')},
|
|
{'account_id': income_exchange_account.id, 'amount_currency': 0.0, 'currency_id': self.currency_data_2['currency'].id, 'balance': -200.0, 'reconciled': False, 'date': fields.Date.from_string('2017-01-31')},
|
|
])
|
|
|
|
def test_validation_expense_exchange_difference(self):
|
|
expense_exchange_account = self.env.company.expense_currency_exchange_account_id
|
|
|
|
# 1200.0 comp_curr = 3600.0 foreign_curr in 2016 (rate 1:3)
|
|
st_line = self._create_st_line(
|
|
1200.0,
|
|
date='2016-01-01',
|
|
)
|
|
# 1800.0 comp_curr = 3600.0 foreign_curr in 2017 (rate 1:2)
|
|
inv_line = self._create_invoice_line(
|
|
'out_invoice',
|
|
currency_id=self.currency_data['currency'].id,
|
|
invoice_date='2017-01-01',
|
|
invoice_line_ids=[{'price_unit': 3600.0}],
|
|
)
|
|
|
|
wizard = self.env['bank.rec.widget'].with_context(default_st_line_id=st_line.id).new({})
|
|
wizard._action_add_new_amls(inv_line)
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'amount_currency': 1200.0, 'currency_id': self.company_data['currency'].id, 'balance': 1200.0},
|
|
{'flag': 'new_aml', 'amount_currency': -3600.0, 'currency_id': self.currency_data['currency'].id, 'balance': -1800.0},
|
|
{'flag': 'exchange_diff', 'amount_currency': 0.0, 'currency_id': self.currency_data['currency'].id, 'balance': 600.0},
|
|
])
|
|
self.assertRecordValues(wizard, [{'state': 'valid'}])
|
|
|
|
wizard._action_validate()
|
|
self.assertRecordValues(st_line.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'account_id': st_line.journal_id.default_account_id.id, 'amount_currency': 1200.0, 'currency_id': self.company_data['currency'].id, 'balance': 1200.0, 'reconciled': False},
|
|
{'account_id': inv_line.account_id.id, 'amount_currency': -3600.0, 'currency_id': self.currency_data['currency'].id, 'balance': -1200.0, 'reconciled': True},
|
|
])
|
|
self.assertRecordValues(st_line, [{'is_reconciled': True}])
|
|
self.assertRecordValues(inv_line.move_id, [{'payment_state': 'paid'}])
|
|
self.assertRecordValues(inv_line.matched_credit_ids.exchange_move_id.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'account_id': inv_line.account_id.id, 'amount_currency': 0.0, 'currency_id': self.currency_data['currency'].id, 'balance': -600.0, 'reconciled': True, 'date': fields.Date.from_string('2017-01-31')},
|
|
{'account_id': expense_exchange_account.id, 'amount_currency': 0.0, 'currency_id': self.currency_data['currency'].id, 'balance': 600.0, 'reconciled': False, 'date': fields.Date.from_string('2017-01-31')},
|
|
])
|
|
# Checks that the wizard still display the 3 initial lines
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'amount_currency': 1200.0, 'currency_id': self.company_data['currency'].id, 'balance': 1200.0},
|
|
{'flag': 'aml', 'amount_currency': -3600.0, 'currency_id': self.currency_data['currency'].id, 'balance': -1800.0},
|
|
{'flag': 'aml', 'amount_currency': 0.0, 'currency_id': self.currency_data['currency'].id, 'balance': 600.0},
|
|
])
|
|
|
|
def test_validation_income_exchange_difference(self):
|
|
income_exchange_account = self.env.company.income_currency_exchange_account_id
|
|
|
|
# 1800.0 comp_curr = 3600.0 foreign_curr in 2017 (rate 1:2)
|
|
st_line = self._create_st_line(
|
|
1800.0,
|
|
date='2017-01-01',
|
|
)
|
|
# 1200.0 comp_curr = 3600.0 foreign_curr in 2016 (rate 1:3)
|
|
inv_line = self._create_invoice_line(
|
|
'out_invoice',
|
|
currency_id=self.currency_data['currency'].id,
|
|
invoice_date='2016-01-01',
|
|
invoice_line_ids=[{'price_unit': 3600.0}],
|
|
)
|
|
|
|
wizard = self.env['bank.rec.widget'].with_context(default_st_line_id=st_line.id).new({})
|
|
wizard._action_add_new_amls(inv_line)
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'amount_currency': 1800.0, 'currency_id': self.company_data['currency'].id, 'balance': 1800.0},
|
|
{'flag': 'new_aml', 'amount_currency': -3600.0, 'currency_id': self.currency_data['currency'].id, 'balance': -1200.0},
|
|
{'flag': 'exchange_diff', 'amount_currency': 0.0, 'currency_id': self.currency_data['currency'].id, 'balance': -600.0},
|
|
])
|
|
self.assertRecordValues(wizard, [{'state': 'valid'}])
|
|
|
|
wizard._action_validate()
|
|
self.assertRecordValues(st_line.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'account_id': st_line.journal_id.default_account_id.id, 'amount_currency': 1800.0, 'currency_id': self.company_data['currency'].id, 'balance': 1800.0, 'reconciled': False},
|
|
{'account_id': inv_line.account_id.id, 'amount_currency': -3600.0, 'currency_id': self.currency_data['currency'].id, 'balance': -1800.0, 'reconciled': True},
|
|
])
|
|
self.assertRecordValues(st_line, [{'is_reconciled': True}])
|
|
self.assertRecordValues(inv_line.move_id, [{'payment_state': 'paid'}])
|
|
self.assertRecordValues(inv_line.matched_credit_ids.exchange_move_id.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'account_id': inv_line.account_id.id, 'amount_currency': 0.0, 'currency_id': self.currency_data['currency'].id, 'balance': 600.0, 'reconciled': True, 'date': fields.Date.from_string('2017-01-31')},
|
|
{'account_id': income_exchange_account.id, 'amount_currency': 0.0, 'currency_id': self.currency_data['currency'].id, 'balance': -600.0, 'reconciled': False, 'date': fields.Date.from_string('2017-01-31')},
|
|
])
|
|
# Checks that the wizard still display the 3 initial lines
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'amount_currency': 1800.0, 'currency_id': self.company_data['currency'].id, 'balance': 1800.0},
|
|
{'flag': 'aml', 'amount_currency': -3600.0, 'currency_id': self.currency_data['currency'].id, 'balance': -1200.0},
|
|
{'flag': 'aml', 'amount_currency': 0.0, 'currency_id': self.currency_data['currency'].id, 'balance': -600.0},
|
|
])
|
|
|
|
def test_validation_income_exchange_difference_with_rounding(self):
|
|
# 1000.0 comp_curr = 3000.0 foreign_curr in 2016 (rate 1:3)
|
|
# However divided in 3 invoices + rounding we have 333.33333 ≃ 333.33 comp_curr = 1000.0 foreign_curr
|
|
# this implies that the full amount has been used in foreign_curr but there is 0.01 in comp_curr
|
|
st_line = self._create_st_line(
|
|
1000.0,
|
|
date='2016-01-01',
|
|
)
|
|
|
|
# 1500 comp_curr = 3000.0 foreign_curr in 2017 (rate 1:2)
|
|
inv_line_1 = self._create_invoice_line(
|
|
'out_invoice',
|
|
currency_id=self.currency_data['currency'].id,
|
|
invoice_date='2017-01-01',
|
|
invoice_line_ids=[{'price_unit': 1000.0}],
|
|
)
|
|
|
|
inv_line_2 = self._create_invoice_line(
|
|
'out_invoice',
|
|
currency_id=self.currency_data['currency'].id,
|
|
invoice_date='2017-01-01',
|
|
invoice_line_ids=[{'price_unit': 1000.0}],
|
|
)
|
|
|
|
inv_line_3 = self._create_invoice_line(
|
|
'out_invoice',
|
|
currency_id=self.currency_data['currency'].id,
|
|
invoice_date='2017-01-01',
|
|
invoice_line_ids=[{'price_unit': 1000.0}],
|
|
)
|
|
|
|
wizard = self.env['bank.rec.widget'].with_context(default_st_line_id=st_line.id).new({})
|
|
wizard._action_add_new_amls(inv_line_1 + inv_line_2 + inv_line_3)
|
|
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'amount_currency': 1000.0, 'currency_id': self.company_data['currency'].id, 'balance': 1000.0},
|
|
{'flag': 'new_aml', 'amount_currency': -1000.0, 'currency_id': self.currency_data['currency'].id, 'balance': -500.0},
|
|
{'flag': 'exchange_diff', 'amount_currency': 0.0, 'currency_id': self.currency_data['currency'].id, 'balance': 166.67},
|
|
{'flag': 'new_aml', 'amount_currency': -1000.0, 'currency_id': self.currency_data['currency'].id, 'balance': -500.0},
|
|
{'flag': 'exchange_diff', 'amount_currency': 0.0, 'currency_id': self.currency_data['currency'].id, 'balance': 166.67},
|
|
{'flag': 'new_aml', 'amount_currency': -1000.0, 'currency_id': self.currency_data['currency'].id, 'balance': -500.0},
|
|
{'flag': 'exchange_diff', 'amount_currency': 0.0, 'currency_id': self.currency_data['currency'].id, 'balance': 166.67},
|
|
{'flag': 'auto_balance', 'amount_currency': -0.01, 'currency_id': self.company_data['currency'].id, 'balance': -0.01},
|
|
])
|
|
|
|
# Remove 0.01 cent in the balance of first exchange line
|
|
first_exchange_line = wizard.line_ids.filtered(lambda x: x.flag == 'exchange_diff')[:1]
|
|
wizard._js_action_mount_line_in_edit(first_exchange_line.index)
|
|
first_exchange_line.balance = 166.66
|
|
wizard._line_value_changed_balance(first_exchange_line)
|
|
|
|
# Every line balance so no 'auto_balance' is generated
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'amount_currency': 1000.0, 'currency_id': self.company_data['currency'].id, 'balance': 1000.0},
|
|
{'flag': 'new_aml', 'amount_currency': -1000.0, 'currency_id': self.currency_data['currency'].id, 'balance': -500.0},
|
|
{'flag': 'exchange_diff', 'amount_currency': 0.0, 'currency_id': self.currency_data['currency'].id, 'balance': 166.66},
|
|
{'flag': 'new_aml', 'amount_currency': -1000.0, 'currency_id': self.currency_data['currency'].id, 'balance': -500.0},
|
|
{'flag': 'exchange_diff', 'amount_currency': 0.0, 'currency_id': self.currency_data['currency'].id, 'balance': 166.67},
|
|
{'flag': 'new_aml', 'amount_currency': -1000.0, 'currency_id': self.currency_data['currency'].id, 'balance': -500.0},
|
|
{'flag': 'exchange_diff', 'amount_currency': 0.0, 'currency_id': self.currency_data['currency'].id, 'balance': 166.67},
|
|
])
|
|
|
|
self.assertRecordValues(wizard, [{'state': 'valid'}])
|
|
|
|
wizard._action_validate()
|
|
|
|
# Check that the first line with exchange has -0.01 compared to others
|
|
self.assertRecordValues(st_line.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'account_id': st_line.journal_id.default_account_id.id, 'amount_currency': 1000.0, 'currency_id': self.company_data['currency'].id, 'balance': 1000.0, 'reconciled': False},
|
|
{'account_id': inv_line_1.account_id.id, 'amount_currency': -1000.0, 'currency_id': self.currency_data['currency'].id, 'balance': -333.34, 'reconciled': True},
|
|
{'account_id': inv_line_2.account_id.id, 'amount_currency': -1000.0, 'currency_id': self.currency_data['currency'].id, 'balance': -333.33, 'reconciled': True},
|
|
{'account_id': inv_line_3.account_id.id, 'amount_currency': -1000.0, 'currency_id': self.currency_data['currency'].id, 'balance': -333.33, 'reconciled': True},
|
|
])
|
|
|
|
self.assertRecordValues(st_line, [{'is_reconciled': True}])
|
|
self.assertRecordValues(inv_line_1.move_id, [{'payment_state': 'paid'}])
|
|
self.assertRecordValues(inv_line_2.move_id, [{'payment_state': 'paid'}])
|
|
self.assertRecordValues(inv_line_3.move_id, [{'payment_state': 'paid'}])
|
|
|
|
def test_validation_exchange_diff_multiple(self):
|
|
income_exchange_account = self.env.company.income_currency_exchange_account_id
|
|
foreign_currency = self.setup_multi_currency_data(default_values={
|
|
'name': 'Diamond',
|
|
'symbol': '💎',
|
|
'currency_unit_label': 'Diamond',
|
|
'currency_subunit_label': 'Carbon',
|
|
}, rate2016=6.0, rate2017=5.0)['currency']
|
|
|
|
# 6000.0 curr2 == 1200.0 comp_curr (bank rate 5:1 instead of the odoo rate 6:1)
|
|
st_line = self._create_st_line(
|
|
1200.0,
|
|
date='2016-01-01',
|
|
foreign_currency_id=foreign_currency.id,
|
|
amount_currency=6000.0,
|
|
)
|
|
# 1000.0 foreign_curr == 166.67 comp_curr (rate 6:1)
|
|
inv_line_1 = self._create_invoice_line(
|
|
'out_invoice',
|
|
currency_id=foreign_currency.id,
|
|
invoice_date='2016-01-01',
|
|
invoice_line_ids=[{'price_unit': 1000.0}],
|
|
)
|
|
# 2000.00 foreign_curr == 400.0 comp_curr (rate 5:1)
|
|
inv_line_2 = self._create_invoice_line(
|
|
'out_invoice',
|
|
currency_id=foreign_currency.id,
|
|
invoice_date='2017-01-01',
|
|
invoice_line_ids=[{'price_unit': 2000.0}],
|
|
)
|
|
# 3000.0 foreign_curr == 500.0 comp_curr (rate 6:1)
|
|
inv_line_3 = self._create_invoice_line(
|
|
'out_invoice',
|
|
currency_id=foreign_currency.id,
|
|
invoice_date='2016-01-01',
|
|
invoice_line_ids=[{'price_unit': 3000.0}],
|
|
)
|
|
|
|
wizard = self.env['bank.rec.widget'].with_context(default_st_line_id=st_line.id).new({})
|
|
wizard._action_add_new_amls(inv_line_1 + inv_line_2 + inv_line_3)
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'amount_currency': 1200.0, 'currency_id': self.company_data['currency'].id, 'balance': 1200.0},
|
|
{'flag': 'new_aml', 'amount_currency': -1000.0, 'currency_id': foreign_currency.id, 'balance': -166.67},
|
|
{'flag': 'exchange_diff', 'amount_currency': 0.0, 'currency_id': foreign_currency.id, 'balance': -33.33},
|
|
{'flag': 'new_aml', 'amount_currency': -2000.0, 'currency_id': foreign_currency.id, 'balance': -400.0},
|
|
{'flag': 'new_aml', 'amount_currency': -3000.0, 'currency_id': foreign_currency.id, 'balance': -500.0},
|
|
{'flag': 'exchange_diff', 'amount_currency': 0.0, 'currency_id': foreign_currency.id, 'balance': -100.0},
|
|
])
|
|
self.assertRecordValues(wizard, [{'state': 'valid'}])
|
|
|
|
# The amount is the same, no message under the 'amount' field.
|
|
self.assert_form_extra_text_value(wizard, False)
|
|
|
|
wizard._action_validate()
|
|
self.assertRecordValues(st_line.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'account_id': st_line.journal_id.default_account_id.id, 'amount_currency': 1200.0, 'currency_id': self.company_data['currency'].id, 'balance': 1200.0, 'reconciled': False},
|
|
{'account_id': inv_line_1.account_id.id, 'amount_currency': -1000.0, 'currency_id': foreign_currency.id, 'balance': -200.0, 'reconciled': True},
|
|
{'account_id': inv_line_2.account_id.id, 'amount_currency': -2000.0, 'currency_id': foreign_currency.id, 'balance': -400.0, 'reconciled': True},
|
|
{'account_id': inv_line_3.account_id.id, 'amount_currency': -3000.0, 'currency_id': foreign_currency.id, 'balance': -600.0, 'reconciled': True},
|
|
])
|
|
self.assertRecordValues(st_line, [{'is_reconciled': True}])
|
|
self.assertRecordValues(inv_line_1.move_id, [{'payment_state': 'paid'}])
|
|
self.assertRecordValues(inv_line_2.move_id, [{'payment_state': 'paid'}])
|
|
self.assertRecordValues(inv_line_3.move_id, [{'payment_state': 'paid'}])
|
|
self.assertRecordValues((inv_line_1 + inv_line_2 + inv_line_3).matched_credit_ids.exchange_move_id.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'account_id': inv_line_1.account_id.id, 'amount_currency': 0.0, 'currency_id': foreign_currency.id, 'balance': 33.33, 'reconciled': True},
|
|
{'account_id': income_exchange_account.id, 'amount_currency': 0.0, 'currency_id': foreign_currency.id, 'balance': -33.33, 'reconciled': False},
|
|
{'account_id': inv_line_3.account_id.id, 'amount_currency': 0.0, 'currency_id': foreign_currency.id, 'balance': 100.0, 'reconciled': True},
|
|
{'account_id': income_exchange_account.id, 'amount_currency': 0.0, 'currency_id': foreign_currency.id, 'balance': -100.0, 'reconciled': False},
|
|
])
|
|
|
|
def test_validation_foreign_curr_st_line_comp_curr_payment_partial_exchange_difference(self):
|
|
comp_curr = self.env.company.currency_id
|
|
foreign_curr = self.currency_data['currency']
|
|
|
|
st_line = self._create_st_line(
|
|
650.0,
|
|
date='2017-01-01',
|
|
foreign_currency_id=foreign_curr.id,
|
|
amount_currency=800,
|
|
)
|
|
|
|
payment = self.env['account.payment'].create({
|
|
'partner_id': self.partner_a.id,
|
|
'payment_type': 'inbound',
|
|
'partner_type': 'customer',
|
|
'date': '2017-01-01',
|
|
'amount': 725.0,
|
|
})
|
|
payment.action_post()
|
|
pay_line, _counterpart_lines, _writeoff_lines = payment._seek_for_lines()
|
|
|
|
wizard = self.env['bank.rec.widget'].with_context(default_st_line_id=st_line.id).new({})
|
|
wizard._action_add_new_amls(pay_line)
|
|
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'amount_currency': 650.0, 'currency_id': comp_curr.id, 'balance': 650.0},
|
|
{'flag': 'new_aml', 'amount_currency': -650.0, 'currency_id': comp_curr.id, 'balance': -650.0},
|
|
])
|
|
|
|
# Switch to a full reconciliation.
|
|
line = wizard.line_ids.filtered(lambda x: x.flag == 'new_aml')
|
|
wizard._js_action_mount_line_in_edit(line.index)
|
|
wizard._js_action_apply_line_suggestion(line.index)
|
|
|
|
# 725 * 800 / 650 = 892.308
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'amount_currency': 650.0, 'currency_id': comp_curr.id, 'balance': 650.0},
|
|
{'flag': 'new_aml', 'amount_currency': -725.0, 'currency_id': comp_curr.id, 'balance': -725.0},
|
|
{'flag': 'auto_balance', 'amount_currency': 92.308, 'currency_id': foreign_curr.id, 'balance': 75.0},
|
|
])
|
|
|
|
# Switch to a partial reconciliation.
|
|
wizard._js_action_apply_line_suggestion(line.index)
|
|
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'amount_currency': 650.0, 'currency_id': comp_curr.id, 'balance': 650.0},
|
|
{'flag': 'new_aml', 'amount_currency': -650.0, 'currency_id': comp_curr.id, 'balance': -650.0},
|
|
])
|
|
|
|
wizard._action_validate()
|
|
self.assertRecordValues(pay_line, [{'amount_residual': 75.0}])
|
|
|
|
def test_validation_remove_exchange_difference(self):
|
|
""" Test the case when the foreign currency is missing on the statement line.
|
|
In that case, the user can remove the exchange difference in order to fully reconcile both items without additional
|
|
write-off/exchange difference.
|
|
"""
|
|
# 1200.0 comp_curr = 2400.0 foreign_curr in 2017 (rate 1:2)
|
|
st_line = self._create_st_line(
|
|
1200.0,
|
|
date='2017-01-01',
|
|
)
|
|
# 1200.0 comp_curr = 3600.0 foreign_curr in 2016 (rate 1:3)
|
|
inv_line = self._create_invoice_line(
|
|
'out_invoice',
|
|
currency_id=self.currency_data['currency'].id,
|
|
invoice_date='2016-01-01',
|
|
invoice_line_ids=[{'price_unit': 3600.0}],
|
|
)
|
|
|
|
wizard = self.env['bank.rec.widget'].with_context(default_st_line_id=st_line.id).new({})
|
|
wizard._action_add_new_amls(inv_line)
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'amount_currency': 1200.0, 'currency_id': self.company_data['currency'].id, 'balance': 1200.0},
|
|
{'flag': 'new_aml', 'amount_currency': -2400.0, 'currency_id': self.currency_data['currency'].id, 'balance': -800.0},
|
|
{'flag': 'exchange_diff', 'amount_currency': 0.0, 'currency_id': self.currency_data['currency'].id, 'balance': -400.0},
|
|
])
|
|
self.assertRecordValues(wizard, [{'state': 'valid'}])
|
|
|
|
# Remove the partial.
|
|
line_index = wizard.line_ids.filtered(lambda x: x.flag == 'new_aml').index
|
|
wizard._js_action_mount_line_in_edit(line_index)
|
|
wizard._js_action_apply_line_suggestion(line_index)
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'amount_currency': 1200.0, 'currency_id': self.company_data['currency'].id, 'balance': 1200.0},
|
|
{'flag': 'new_aml', 'amount_currency': -3600.0, 'currency_id': self.currency_data['currency'].id, 'balance': -1200.0},
|
|
{'flag': 'exchange_diff', 'amount_currency': 0.0, 'currency_id': self.currency_data['currency'].id, 'balance': -600.0},
|
|
{'flag': 'auto_balance', 'amount_currency': 600.0, 'currency_id': self.company_data['currency'].id, 'balance': 600.0},
|
|
])
|
|
|
|
exchange_diff_index = wizard.line_ids.filtered(lambda x: x.flag == 'exchange_diff').index
|
|
wizard._js_action_remove_line(exchange_diff_index)
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'amount_currency': 1200.0, 'currency_id': self.company_data['currency'].id, 'balance': 1200.0},
|
|
{'flag': 'new_aml', 'amount_currency': -3600.0, 'currency_id': self.currency_data['currency'].id, 'balance': -1200.0},
|
|
])
|
|
|
|
wizard._action_validate()
|
|
self.assertRecordValues(st_line.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'account_id': st_line.journal_id.default_account_id.id, 'amount_currency': 1200.0, 'currency_id': self.company_data['currency'].id, 'balance': 1200.0, 'reconciled': False},
|
|
{'account_id': inv_line.account_id.id, 'amount_currency': -3600.0, 'currency_id': self.currency_data['currency'].id, 'balance': -1200.0, 'reconciled': True},
|
|
])
|
|
self.assertRecordValues(st_line, [{'is_reconciled': True}])
|
|
self.assertRecordValues(inv_line.move_id, [{'payment_state': 'paid'}])
|
|
|
|
def test_validation_new_aml_one_foreign_currency_on_st_line(self):
|
|
income_exchange_account = self.env.company.income_currency_exchange_account_id
|
|
|
|
# 4800.0 curr2 == 1200.0 comp_curr (rate 4:1)
|
|
st_line = self._create_st_line(
|
|
1200.0,
|
|
date='2017-01-01',
|
|
)
|
|
# 4800.0 curr2 in 2016 (rate 6:1)
|
|
inv_line = self._create_invoice_line(
|
|
'out_invoice',
|
|
invoice_date='2016-01-01',
|
|
currency_id=self.currency_data_2['currency'].id,
|
|
invoice_line_ids=[{'price_unit': 4800.0}],
|
|
)
|
|
|
|
wizard = self.env['bank.rec.widget'].with_context(default_st_line_id=st_line.id).new({})
|
|
wizard._action_add_new_amls(inv_line)
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'amount_currency': 1200.0, 'currency_id': self.company_data['currency'].id, 'balance': 1200.0},
|
|
{'flag': 'new_aml', 'amount_currency': -4800.0, 'currency_id': self.currency_data_2['currency'].id, 'balance': -800.0},
|
|
{'flag': 'exchange_diff', 'amount_currency': 0.0, 'currency_id': self.currency_data_2['currency'].id, 'balance': -400.0},
|
|
])
|
|
self.assertRecordValues(wizard, [{'state': 'valid'}])
|
|
|
|
# The amount is the same, no message under the 'amount' field.
|
|
self.assert_form_extra_text_value(wizard, False)
|
|
|
|
wizard._action_validate()
|
|
self.assertRecordValues(st_line.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'account_id': st_line.journal_id.default_account_id.id, 'amount_currency': 1200.0, 'currency_id': self.company_data['currency'].id, 'balance': 1200.0, 'reconciled': False},
|
|
{'account_id': inv_line.account_id.id, 'amount_currency': -4800.0, 'currency_id': self.currency_data_2['currency'].id, 'balance': -1200.0, 'reconciled': True},
|
|
])
|
|
self.assertRecordValues(st_line, [{'is_reconciled': True}])
|
|
self.assertRecordValues(inv_line.move_id, [{'payment_state': 'paid'}])
|
|
self.assertRecordValues(inv_line.matched_credit_ids.exchange_move_id.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'account_id': inv_line.account_id.id, 'amount_currency': 0.0, 'currency_id': self.currency_data_2['currency'].id, 'balance': 400.0, 'reconciled': True, 'date': fields.Date.from_string('2017-01-31')},
|
|
{'account_id': income_exchange_account.id, 'amount_currency': 0.0, 'currency_id': self.currency_data_2['currency'].id, 'balance': -400.0, 'reconciled': False, 'date': fields.Date.from_string('2017-01-31')},
|
|
])
|
|
|
|
# Checks that the wizard still display the 3 initial lines
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'amount_currency': 1200.0, 'currency_id': self.company_data['currency'].id, 'balance': 1200.0},
|
|
{'flag': 'aml', 'amount_currency': -4800.0, 'currency_id': self.currency_data_2['currency'].id, 'balance': -800.0},
|
|
{'flag': 'aml', 'amount_currency': 0.0, 'currency_id': self.currency_data_2['currency'].id, 'balance': -400.0}, # represents the exchange diff
|
|
])
|
|
|
|
# Reset the wizard.
|
|
wizard._js_action_reset()
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'amount_currency': 1200.0, 'currency_id': self.company_data['currency'].id, 'balance': 1200.0},
|
|
{'flag': 'auto_balance', 'amount_currency': -1200.0, 'currency_id': self.company_data['currency'].id, 'balance': -1200.0},
|
|
])
|
|
|
|
# Create the same invoice with a higher amount to check the partial flow.
|
|
# 4800.0 curr2 in 2016 (rate 6:1)
|
|
inv_line = self._create_invoice_line(
|
|
'out_invoice',
|
|
invoice_date='2016-01-01',
|
|
currency_id=self.currency_data_2['currency'].id,
|
|
invoice_line_ids=[{'price_unit': 9600.0}],
|
|
)
|
|
wizard._action_add_new_amls(inv_line)
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'amount_currency': 1200.0, 'currency_id': self.company_data['currency'].id, 'balance': 1200.0},
|
|
{'flag': 'new_aml', 'amount_currency': -4800.0, 'currency_id': self.currency_data_2['currency'].id, 'balance': -800.0},
|
|
{'flag': 'exchange_diff', 'amount_currency': 0.0, 'currency_id': self.currency_data_2['currency'].id, 'balance': -400.0},
|
|
])
|
|
|
|
# Check the message under the 'amount' field.
|
|
line = wizard.line_ids.filtered(lambda x: x.flag == 'new_aml')
|
|
wizard._js_action_mount_line_in_edit(line.index)
|
|
self.assert_form_extra_text_value(
|
|
wizard,
|
|
r".+open amount of 9,600.000.+ reduced by 4,800.000.+ set the invoice as fully paid .",
|
|
)
|
|
self.assertRecordValues(line, [{
|
|
'suggestion_amount_currency': -9600.0,
|
|
'suggestion_balance': -1600.0,
|
|
}])
|
|
|
|
# Switch to a full reconciliation.
|
|
wizard._js_action_apply_line_suggestion(line.index)
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'amount_currency': 1200.0, 'currency_id': self.company_data['currency'].id, 'balance': 1200.0},
|
|
{'flag': 'new_aml', 'amount_currency': -9600.0, 'currency_id': self.currency_data_2['currency'].id, 'balance': -1600.0},
|
|
{'flag': 'exchange_diff', 'amount_currency': 0.0, 'currency_id': self.currency_data_2['currency'].id, 'balance': -800.0},
|
|
{'flag': 'auto_balance', 'amount_currency': 1200.0, 'currency_id': self.company_data['currency'].id, 'balance': 1200.0},
|
|
])
|
|
|
|
# Check the message under the 'amount' field.
|
|
line = wizard.line_ids.filtered(lambda x: x.flag == 'new_aml')
|
|
wizard._js_action_mount_line_in_edit(line.index)
|
|
self.assert_form_extra_text_value(
|
|
wizard,
|
|
r".+open amount of 9,600.000.+ paid .+ record a partial payment .",
|
|
)
|
|
self.assertRecordValues(line, [{
|
|
'suggestion_amount_currency': -4800.0,
|
|
'suggestion_balance': -800.0,
|
|
}])
|
|
|
|
# Switch back to a partial reconciliation.
|
|
wizard._js_action_apply_line_suggestion(line.index)
|
|
self.assertRecordValues(wizard, [{'state': 'valid'}])
|
|
|
|
# Reconcile
|
|
wizard._action_validate()
|
|
self.assertRecordValues(st_line.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'account_id': st_line.journal_id.default_account_id.id, 'amount_currency': 1200.0, 'currency_id': self.company_data['currency'].id, 'balance': 1200.0, 'reconciled': False},
|
|
{'account_id': inv_line.account_id.id, 'amount_currency': -4800.0, 'currency_id': self.currency_data_2['currency'].id, 'balance': -1200.0, 'reconciled': True},
|
|
])
|
|
self.assertRecordValues(st_line, [{'is_reconciled': True}])
|
|
self.assertRecordValues(inv_line.move_id, [{
|
|
'payment_state': 'partial',
|
|
'amount_residual': 4800.0,
|
|
}])
|
|
self.assertRecordValues(inv_line, [{
|
|
'amount_residual_currency': 4800.0,
|
|
'amount_residual': 800.0,
|
|
'reconciled': False,
|
|
}])
|
|
self.assertRecordValues(inv_line.matched_credit_ids.exchange_move_id.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'account_id': inv_line.account_id.id, 'amount_currency': 0.0, 'currency_id': self.currency_data_2['currency'].id, 'balance': 400.0, 'reconciled': True, 'date': fields.Date.from_string('2017-01-31')},
|
|
{'account_id': income_exchange_account.id, 'amount_currency': 0.0, 'currency_id': self.currency_data_2['currency'].id, 'balance': -400.0, 'reconciled': False, 'date': fields.Date.from_string('2017-01-31')},
|
|
])
|
|
|
|
def test_validation_new_aml_one_foreign_currency_on_inv_line(self):
|
|
income_exchange_account = self.env.company.income_currency_exchange_account_id
|
|
|
|
# 1200.0 comp_curr is equals to 4800.0 curr2 in 2017 (rate 4:1)
|
|
st_line = self._create_st_line(
|
|
1200.0,
|
|
date='2017-01-01',
|
|
)
|
|
# 4800.0 curr2 == 800.0 comp_curr (rate 6:1)
|
|
inv_line = self._create_invoice_line(
|
|
'out_invoice',
|
|
currency_id=self.currency_data_2['currency'].id,
|
|
invoice_date='2016-01-01',
|
|
invoice_line_ids=[{'price_unit': 4800.0}],
|
|
)
|
|
|
|
wizard = self.env['bank.rec.widget'].with_context(default_st_line_id=st_line.id).new({})
|
|
wizard._action_add_new_amls(inv_line)
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'amount_currency': 1200.0, 'currency_id': self.company_data['currency'].id, 'balance': 1200.0},
|
|
{'flag': 'new_aml', 'amount_currency': -4800.0, 'currency_id': self.currency_data_2['currency'].id, 'balance': -800.0},
|
|
{'flag': 'exchange_diff', 'amount_currency': 0.0, 'currency_id': self.currency_data_2['currency'].id, 'balance': -400.0},
|
|
])
|
|
self.assertRecordValues(wizard, [{'state': 'valid'}])
|
|
|
|
# The amount is the same, no message under the 'amount' field.
|
|
self.assert_form_extra_text_value(wizard, False)
|
|
|
|
# Remove the line to see if the exchange difference is well removed.
|
|
wizard._action_remove_new_amls(inv_line)
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'amount_currency': 1200.0, 'currency_id': self.company_data['currency'].id, 'balance': 1200.0},
|
|
{'flag': 'auto_balance', 'amount_currency': -1200.0, 'currency_id': self.company_data['currency'].id, 'balance': -1200.0},
|
|
])
|
|
self.assertRecordValues(wizard, [{'state': 'invalid'}])
|
|
|
|
# Mount the line again and validate.
|
|
wizard._action_add_new_amls(inv_line)
|
|
wizard._action_validate()
|
|
self.assertRecordValues(st_line.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'account_id': st_line.journal_id.default_account_id.id, 'amount_currency': 1200.0, 'currency_id': self.company_data['currency'].id, 'balance': 1200.0, 'reconciled': False},
|
|
{'account_id': inv_line.account_id.id, 'amount_currency': -4800.0, 'currency_id': self.currency_data_2['currency'].id, 'balance': -1200.0, 'reconciled': True},
|
|
])
|
|
self.assertRecordValues(st_line, [{'is_reconciled': True}])
|
|
self.assertRecordValues(inv_line.move_id, [{'payment_state': 'paid'}])
|
|
self.assertRecordValues(inv_line.matched_credit_ids.exchange_move_id.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'account_id': inv_line.account_id.id, 'amount_currency': 0.0, 'currency_id': self.currency_data_2['currency'].id, 'balance': 400.0, 'reconciled': True, 'date': fields.Date.from_string('2017-01-31')},
|
|
{'account_id': income_exchange_account.id, 'amount_currency': 0.0, 'currency_id': self.currency_data_2['currency'].id, 'balance': -400.0, 'reconciled': False, 'date': fields.Date.from_string('2017-01-31')},
|
|
])
|
|
|
|
# Reset the wizard.
|
|
wizard._js_action_reset()
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'amount_currency': 1200.0, 'currency_id': self.company_data['currency'].id, 'balance': 1200.0},
|
|
{'flag': 'auto_balance', 'amount_currency': -1200.0, 'currency_id': self.company_data['currency'].id, 'balance': -1200.0},
|
|
])
|
|
|
|
# Create the same invoice with a higher amount to check the partial flow.
|
|
# 7200.0 curr2 == 1200.0 comp_curr (rate 6:1)
|
|
inv_line = self._create_invoice_line(
|
|
'out_invoice',
|
|
currency_id=self.currency_data_2['currency'].id,
|
|
invoice_date='2016-01-01',
|
|
invoice_line_ids=[{'price_unit': 7200.0}],
|
|
)
|
|
wizard._action_add_new_amls(inv_line)
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'amount_currency': 1200.0, 'currency_id': self.company_data['currency'].id, 'balance': 1200.0},
|
|
{'flag': 'new_aml', 'amount_currency': -4800.0, 'currency_id': self.currency_data_2['currency'].id, 'balance': -800.0},
|
|
{'flag': 'exchange_diff', 'amount_currency': 0.0, 'currency_id': self.currency_data_2['currency'].id, 'balance': -400.0},
|
|
])
|
|
|
|
# Check the message under the 'amount' field.
|
|
line = wizard.line_ids.filtered(lambda x: x.flag == 'new_aml')
|
|
wizard._js_action_mount_line_in_edit(line.index)
|
|
self.assert_form_extra_text_value(
|
|
wizard,
|
|
r".+open amount of 7,200.000.+ reduced by 4,800.000.+ set the invoice as fully paid .",
|
|
)
|
|
self.assertRecordValues(line, [{
|
|
'suggestion_amount_currency': -7200.0,
|
|
'suggestion_balance': -1200.0,
|
|
}])
|
|
|
|
# Switch to a full reconciliation.
|
|
wizard._js_action_apply_line_suggestion(line.index)
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'amount_currency': 1200.0, 'currency_id': self.company_data['currency'].id, 'balance': 1200.0},
|
|
{'flag': 'new_aml', 'amount_currency': -7200.0, 'currency_id': self.currency_data_2['currency'].id, 'balance': -1200.0},
|
|
{'flag': 'exchange_diff', 'amount_currency': 0.0, 'currency_id': self.currency_data_2['currency'].id, 'balance': -600.0},
|
|
{'flag': 'auto_balance', 'amount_currency': 600.0, 'currency_id': self.company_data['currency'].id, 'balance': 600.0},
|
|
])
|
|
|
|
# Check the message under the 'amount' field.
|
|
line = wizard.line_ids.filtered(lambda x: x.flag == 'new_aml')
|
|
wizard._js_action_mount_line_in_edit(line.index)
|
|
self.assert_form_extra_text_value(
|
|
wizard,
|
|
r".+open amount of 7,200.000.+ paid .+ record a partial payment .",
|
|
)
|
|
self.assertRecordValues(line, [{
|
|
'suggestion_amount_currency': -4800.0,
|
|
'suggestion_balance': -800.0,
|
|
}])
|
|
|
|
# Switch back to a partial reconciliation.
|
|
wizard._js_action_apply_line_suggestion(line.index)
|
|
self.assertRecordValues(wizard, [{'state': 'valid'}])
|
|
|
|
# Reconcile
|
|
wizard._action_validate()
|
|
self.assertRecordValues(st_line.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'account_id': st_line.journal_id.default_account_id.id, 'amount_currency': 1200.0, 'currency_id': self.company_data['currency'].id, 'balance': 1200.0, 'reconciled': False},
|
|
{'account_id': inv_line.account_id.id, 'amount_currency': -4800.0, 'currency_id': self.currency_data_2['currency'].id, 'balance': -1200.0, 'reconciled': True},
|
|
])
|
|
self.assertRecordValues(st_line, [{'is_reconciled': True}])
|
|
self.assertRecordValues(inv_line.move_id, [{
|
|
'payment_state': 'partial',
|
|
'amount_residual': 2400.0,
|
|
}])
|
|
self.assertRecordValues(inv_line.matched_credit_ids.exchange_move_id.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'account_id': inv_line.account_id.id, 'amount_currency': 0.0, 'currency_id': self.currency_data_2['currency'].id, 'balance': 400.0, 'reconciled': True, 'date': fields.Date.from_string('2017-01-31')},
|
|
{'account_id': income_exchange_account.id, 'amount_currency': 0.0, 'currency_id': self.currency_data_2['currency'].id, 'balance': -400.0, 'reconciled': False, 'date': fields.Date.from_string('2017-01-31')},
|
|
])
|
|
|
|
def test_validation_new_aml_multi_currencies(self):
|
|
# 6300.0 curr2 == 1800.0 comp_curr (bank rate 3.5:1 instead of the odoo rate 4:1)
|
|
st_line = self._create_st_line(
|
|
1800.0,
|
|
date='2017-01-01',
|
|
foreign_currency_id=self.currency_data_2['currency'].id,
|
|
amount_currency=6300.0,
|
|
)
|
|
# 21600.0 curr3 == 1800.0 comp_curr (rate 12:1)
|
|
inv_line = self._create_invoice_line(
|
|
'out_invoice',
|
|
currency_id=self.currency_data_3['currency'].id,
|
|
invoice_date='2016-01-01',
|
|
invoice_line_ids=[{'price_unit': 21600.0}],
|
|
)
|
|
|
|
wizard = self.env['bank.rec.widget'].with_context(default_st_line_id=st_line.id).new({})
|
|
wizard._action_add_new_amls(inv_line)
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'amount_currency': 1800.0, 'currency_id': self.company_data['currency'].id, 'balance': 1800.0},
|
|
{'flag': 'new_aml', 'amount_currency': -21600.0, 'currency_id': self.currency_data_3['currency'].id, 'balance': -1800.0},
|
|
])
|
|
self.assertRecordValues(wizard, [{'state': 'valid'}])
|
|
|
|
# The amount is the same, no message under the 'amount' field.
|
|
self.assert_form_extra_text_value(wizard, False)
|
|
|
|
wizard._action_validate()
|
|
self.assertRecordValues(st_line.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'account_id': st_line.journal_id.default_account_id.id, 'amount_currency': 1800.0, 'currency_id': self.company_data['currency'].id, 'balance': 1800.0, 'reconciled': False},
|
|
{'account_id': inv_line.account_id.id, 'amount_currency': -21600.0, 'currency_id': self.currency_data_3['currency'].id, 'balance': -1800.0, 'reconciled': True},
|
|
])
|
|
self.assertRecordValues(st_line, [{'is_reconciled': True}])
|
|
self.assertRecordValues(inv_line.move_id, [{'payment_state': 'paid'}])
|
|
|
|
# Reset the wizard.
|
|
wizard._js_action_reset()
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'amount_currency': 1800.0, 'currency_id': self.company_data['currency'].id, 'balance': 1800.0},
|
|
{'flag': 'auto_balance', 'amount_currency': -6300.0, 'currency_id': self.currency_data_2['currency'].id, 'balance': -1800.0},
|
|
])
|
|
|
|
# Create the same invoice with a higher amount to check the partial flow.
|
|
# 32400.0 curr3 == 2700.0 comp_curr (rate 12:1)
|
|
inv_line = self._create_invoice_line(
|
|
'out_invoice',
|
|
currency_id=self.currency_data_3['currency'].id,
|
|
invoice_date='2016-01-01',
|
|
invoice_line_ids=[{'price_unit': 32400.0}],
|
|
)
|
|
wizard._action_add_new_amls(inv_line)
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'amount_currency': 1800.0, 'currency_id': self.company_data['currency'].id, 'balance': 1800.0},
|
|
{'flag': 'new_aml', 'amount_currency': -21600.0, 'currency_id': self.currency_data_3['currency'].id, 'balance': -1800.0},
|
|
])
|
|
|
|
# Check the message under the 'amount' field.
|
|
line = wizard.line_ids.filtered(lambda x: x.flag == 'new_aml')
|
|
wizard._js_action_mount_line_in_edit(line.index)
|
|
self.assert_form_extra_text_value(
|
|
wizard,
|
|
r".+open amount of 32,400.000.+ reduced by 21,600.000.+ set the invoice as fully paid .",
|
|
)
|
|
self.assertRecordValues(line, [{
|
|
'suggestion_amount_currency': -32400.0,
|
|
'suggestion_balance': -2700.0,
|
|
}])
|
|
|
|
# Switch to a full reconciliation.
|
|
wizard._js_action_apply_line_suggestion(line.index)
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'amount_currency': 1800.0, 'currency_id': self.company_data['currency'].id, 'balance': 1800.0},
|
|
{'flag': 'new_aml', 'amount_currency': -32400.0, 'currency_id': self.currency_data_3['currency'].id, 'balance': -2700.0},
|
|
{'flag': 'auto_balance', 'amount_currency': 3150.0, 'currency_id': self.currency_data_2['currency'].id, 'balance': 900.0},
|
|
])
|
|
|
|
# Check the message under the 'amount' field.
|
|
line = wizard.line_ids.filtered(lambda x: x.flag == 'new_aml')
|
|
wizard._js_action_mount_line_in_edit(line.index)
|
|
self.assert_form_extra_text_value(
|
|
wizard,
|
|
r".+open amount of 32,400.000.+ paid .+ record a partial payment .",
|
|
)
|
|
self.assertRecordValues(line, [{
|
|
'suggestion_amount_currency': -21600.0,
|
|
'suggestion_balance': -1800.0,
|
|
}])
|
|
|
|
# Switch back to a partial reconciliation.
|
|
wizard._js_action_apply_line_suggestion(line.index)
|
|
self.assertRecordValues(wizard, [{'state': 'valid'}])
|
|
|
|
# Reconcile
|
|
wizard._action_validate()
|
|
self.assertRecordValues(st_line.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'account_id': st_line.journal_id.default_account_id.id, 'amount_currency': 1800.0, 'currency_id': self.company_data['currency'].id, 'balance': 1800.0, 'reconciled': False},
|
|
{'account_id': inv_line.account_id.id, 'amount_currency': -21600.0, 'currency_id': self.currency_data_3['currency'].id, 'balance': -1800.0, 'reconciled': True},
|
|
])
|
|
self.assertRecordValues(st_line, [{'is_reconciled': True}])
|
|
self.assertRecordValues(inv_line.move_id, [{
|
|
'payment_state': 'partial',
|
|
'amount_residual': 10800.0,
|
|
}])
|
|
|
|
def test_validation_new_aml_multi_currencies_exchange_diff_custom_rates(self):
|
|
self.company_data['default_journal_bank'].currency_id = self.currency_data['currency']
|
|
|
|
self.env['res.currency.rate'].create([
|
|
{
|
|
'name': '2017-02-01',
|
|
'rate': 1.0683,
|
|
'currency_id': self.currency_data['currency'].id,
|
|
'company_id': self.env.company.id,
|
|
},
|
|
{
|
|
'name': '2017-03-01',
|
|
'rate': 1.0812,
|
|
'currency_id': self.currency_data['currency'].id,
|
|
'company_id': self.env.company.id,
|
|
},
|
|
])
|
|
|
|
# 960.14 curr1 = 888.03 comp_curr
|
|
st_line = self._create_st_line(
|
|
-960.14,
|
|
date='2017-03-01',
|
|
)
|
|
# 112.7 curr1 == 105.49 comp_curr
|
|
inv_line1 = self._create_invoice_line(
|
|
'in_invoice',
|
|
currency_id=self.currency_data['currency'].id,
|
|
invoice_date='2017-02-01',
|
|
invoice_line_ids=[{'price_unit': 112.7}],
|
|
)
|
|
# 847.44 curr1 == 793.26 comp_curr
|
|
inv_line2 = self._create_invoice_line(
|
|
'in_invoice',
|
|
currency_id=self.currency_data['currency'].id,
|
|
invoice_date='2017-02-01',
|
|
invoice_line_ids=[{'price_unit': 847.44}],
|
|
)
|
|
|
|
wizard = self.env['bank.rec.widget'].with_context(default_st_line_id=st_line.id).new({})
|
|
wizard._action_add_new_amls(inv_line1)
|
|
wizard._action_add_new_amls(inv_line2)
|
|
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'amount_currency': -960.14, 'balance': -888.03},
|
|
{'flag': 'new_aml', 'amount_currency': 112.7, 'balance': 105.49},
|
|
{'flag': 'exchange_diff', 'amount_currency': 0.0, 'balance': -1.25},
|
|
{'flag': 'new_aml', 'amount_currency': 847.44, 'balance': 793.26},
|
|
{'flag': 'exchange_diff', 'amount_currency': 0.0, 'balance': -9.47},
|
|
])
|
|
wizard._action_remove_new_amls(inv_line1 + inv_line2)
|
|
wizard._action_add_new_amls(inv_line2)
|
|
wizard._action_add_new_amls(inv_line1)
|
|
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'amount_currency': -960.14, 'balance': -888.03},
|
|
{'flag': 'new_aml', 'amount_currency': 847.44, 'balance': 793.26},
|
|
{'flag': 'exchange_diff', 'amount_currency': 0.0, 'balance': -9.47},
|
|
{'flag': 'new_aml', 'amount_currency': 112.7, 'balance': 105.49},
|
|
{'flag': 'exchange_diff', 'amount_currency': 0.0, 'balance': -1.25},
|
|
])
|
|
|
|
def test_validation_with_partner(self):
|
|
partner = self.partner_a.copy()
|
|
|
|
st_line = self._create_st_line(1000.0, partner_id=self.partner_a.id)
|
|
|
|
# The wizard can be validated directly thanks to the receivable account set on the partner.
|
|
wizard = self.env['bank.rec.widget'].with_context(default_st_line_id=st_line.id).new({})
|
|
self.assertRecordValues(wizard, [{'state': 'valid'}])
|
|
|
|
# Validate and check the statement line.
|
|
wizard._action_validate()
|
|
self.assertRecordValues(st_line, [{'partner_id': self.partner_a.id}])
|
|
liquidity_line, _suspense_line, other_line = st_line._seek_for_lines()
|
|
account = self.partner_a.property_account_receivable_id
|
|
self.assertRecordValues(liquidity_line + other_line, [
|
|
# pylint: disable=C0326
|
|
{'account_id': liquidity_line.account_id.id, 'balance': 1000.0},
|
|
{'account_id': account.id, 'balance': -1000.0},
|
|
])
|
|
self.assertRecordValues(wizard, [{'state': 'reconciled'}])
|
|
|
|
# Match an invoice with a different partner.
|
|
wizard._js_action_reset()
|
|
inv_line = self._create_invoice_line(
|
|
'out_invoice',
|
|
partner_id=partner.id,
|
|
invoice_line_ids=[{'price_unit': 1000.0}],
|
|
)
|
|
wizard._action_add_new_amls(inv_line)
|
|
wizard._action_validate()
|
|
liquidity_line, suspense_line, other_line = st_line._seek_for_lines()
|
|
self.assertRecordValues(st_line, [{'partner_id': partner.id}])
|
|
self.assertRecordValues(st_line.move_id, [{'partner_id': partner.id}])
|
|
self.assertRecordValues(liquidity_line + other_line, [
|
|
# pylint: disable=C0326
|
|
{'account_id': liquidity_line.account_id.id, 'partner_id': partner.id, 'balance': 1000.0},
|
|
{'account_id': inv_line.account_id.id, 'partner_id': partner.id, 'balance': -1000.0},
|
|
])
|
|
self.assertRecordValues(wizard, [{'state': 'reconciled'}])
|
|
|
|
# Reset the wizard and match invoices with different partners.
|
|
wizard._js_action_reset()
|
|
partner1 = self.partner_a.copy()
|
|
inv_line1 = self._create_invoice_line(
|
|
'out_invoice',
|
|
partner_id=partner1.id,
|
|
invoice_line_ids=[{'price_unit': 300.0}],
|
|
)
|
|
partner2 = self.partner_a.copy()
|
|
inv_line2 = self._create_invoice_line(
|
|
'out_invoice',
|
|
partner_id=partner2.id,
|
|
invoice_line_ids=[{'price_unit': 300.0}],
|
|
)
|
|
wizard._action_add_new_amls(inv_line1 + inv_line2)
|
|
wizard._action_validate()
|
|
liquidity_line, _suspense_line, other_line = st_line._seek_for_lines()
|
|
self.assertRecordValues(st_line, [{'partner_id': False}])
|
|
self.assertRecordValues(st_line.move_id, [{'partner_id': False}])
|
|
self.assertRecordValues(liquidity_line + other_line, [
|
|
# pylint: disable=C0326
|
|
{'account_id': liquidity_line.account_id.id, 'partner_id': False, 'balance': 1000.0},
|
|
{'account_id': inv_line1.account_id.id, 'partner_id': partner1.id, 'balance': -300.0},
|
|
{'account_id': inv_line2.account_id.id, 'partner_id': partner2.id, 'balance': -300.0},
|
|
{'account_id': account.id, 'partner_id': False, 'balance': -400.0},
|
|
])
|
|
self.assertRecordValues(wizard, [{'state': 'reconciled'}])
|
|
|
|
# Clear the accounts set on the partner and reset the widget.
|
|
# The wizard should be invalid since we are not able to set an open balance.
|
|
partner.property_account_receivable_id = None
|
|
wizard._js_action_reset()
|
|
liquidity_line, suspense_line, other_line = st_line._seek_for_lines()
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'account_id': liquidity_line.account_id.id},
|
|
{'flag': 'auto_balance', 'account_id': suspense_line.account_id.id},
|
|
])
|
|
self.assertRecordValues(wizard, [{'state': 'invalid'}])
|
|
|
|
def test_partner_receivable_payable_account(self):
|
|
self.partner_a.write({'customer_rank': 1, 'supplier_rank': 0}) # always receivable
|
|
self.partner_b.write({'customer_rank': 0, 'supplier_rank': 1}) # always payable
|
|
partner_c = self.partner_b.copy({'customer_rank': 3, 'supplier_rank': 2}) # no preference
|
|
|
|
positive_st_line = self._create_st_line(1000)
|
|
journal_account = positive_st_line.journal_id.default_account_id
|
|
|
|
wizard = self.env['bank.rec.widget'].with_context(default_st_line_id=positive_st_line.id).new({})
|
|
suspense_line = wizard.line_ids.filtered(lambda l: l.flag != "liquidity")
|
|
wizard._js_action_mount_line_in_edit(suspense_line.index)
|
|
|
|
suspense_line.partner_id = self.partner_a
|
|
wizard._line_value_changed_partner_id(suspense_line)
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'partner_id': False, 'account_id': journal_account.id},
|
|
{'partner_id': self.partner_a.id, 'account_id': self.partner_a.property_account_receivable_id.id},
|
|
])
|
|
|
|
suspense_line.partner_id = self.partner_b
|
|
wizard._line_value_changed_partner_id(suspense_line)
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'partner_id': False, 'account_id': journal_account.id},
|
|
{'partner_id': self.partner_b.id, 'account_id': self.partner_b.property_account_payable_id.id},
|
|
])
|
|
|
|
suspense_line.partner_id = partner_c
|
|
wizard._line_value_changed_partner_id(suspense_line)
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'partner_id': False, 'account_id': journal_account.id},
|
|
{'partner_id': partner_c.id, 'account_id': partner_c.property_account_receivable_id.id},
|
|
])
|
|
|
|
negative_st_line = self._create_st_line(-1000)
|
|
wizard = self.env['bank.rec.widget'].with_context(default_st_line_id=negative_st_line.id).new({})
|
|
suspense_line = wizard.line_ids.filtered(lambda l: l.flag != "liquidity")
|
|
wizard._js_action_mount_line_in_edit(suspense_line.index)
|
|
|
|
suspense_line.partner_id = self.partner_a
|
|
wizard._line_value_changed_partner_id(suspense_line)
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'partner_id': False, 'account_id': journal_account.id},
|
|
{'partner_id': self.partner_a.id, 'account_id': self.partner_a.property_account_receivable_id.id},
|
|
])
|
|
|
|
suspense_line.partner_id = self.partner_b
|
|
wizard._line_value_changed_partner_id(suspense_line)
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'partner_id': False, 'account_id': journal_account.id},
|
|
{'partner_id': self.partner_b.id, 'account_id': self.partner_b.property_account_payable_id.id},
|
|
])
|
|
|
|
suspense_line.partner_id = partner_c
|
|
wizard._line_value_changed_partner_id(suspense_line)
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'partner_id': False, 'account_id': journal_account.id},
|
|
{'partner_id': partner_c.id, 'account_id': partner_c.property_account_payable_id.id},
|
|
])
|
|
|
|
def test_validation_using_custom_account(self):
|
|
st_line = self._create_st_line(1000.0)
|
|
|
|
# By default, the wizard can't be validated directly due to the suspense account.
|
|
wizard = self.env['bank.rec.widget'].with_context(default_st_line_id=st_line.id).new({})
|
|
self.assertRecordValues(wizard, [{'state': 'invalid'}])
|
|
|
|
# Mount the auto-balance line in edit mode.
|
|
line = wizard.line_ids.filtered(lambda x: x.flag == 'auto_balance')
|
|
wizard._js_action_mount_line_in_edit(line.index)
|
|
liquidity_line, suspense_line, _other_lines = st_line._seek_for_lines()
|
|
self.assertRecordValues(line, [{
|
|
'account_id': suspense_line.account_id.id,
|
|
'balance': -1000.0,
|
|
}])
|
|
|
|
# Switch to a custom account.
|
|
account = self.env['account.account'].create({
|
|
'name': "test_validation_using_custom_account",
|
|
'code': "424242",
|
|
'account_type': "asset_current",
|
|
})
|
|
line.account_id = account
|
|
wizard._line_value_changed_account_id(line)
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'account_id': liquidity_line.account_id.id, 'balance': 1000.0},
|
|
{'flag': 'manual', 'account_id': account.id, 'balance': -1000.0},
|
|
])
|
|
|
|
# The wizard can be validated.
|
|
self.assertRecordValues(wizard, [{'state': 'valid'}])
|
|
|
|
# Validate and check the statement line.
|
|
wizard._action_validate()
|
|
liquidity_line, _suspense_line, other_line = st_line._seek_for_lines()
|
|
self.assertRecordValues(liquidity_line + other_line, [
|
|
# pylint: disable=C0326
|
|
{'account_id': liquidity_line.account_id.id, 'balance': 1000.0},
|
|
{'account_id': account.id, 'balance': -1000.0},
|
|
])
|
|
self.assertRecordValues(wizard, [{'state': 'reconciled'}])
|
|
|
|
def test_validation_with_taxes(self):
|
|
st_line = self._create_st_line(1000.0)
|
|
|
|
tax_tags = self.env['account.account.tag'].create({
|
|
'name': f'tax_tag_{i}',
|
|
'applicability': 'taxes',
|
|
'country_id': self.env.company.account_fiscal_country_id.id,
|
|
} for i in range(4))
|
|
|
|
tax_21 = self.env['account.tax'].create({
|
|
'name': "tax_21",
|
|
'amount': 21,
|
|
'invoice_repartition_line_ids': [
|
|
Command.create({
|
|
'factor_percent': 100,
|
|
'repartition_type': 'base',
|
|
'tag_ids': [Command.set(tax_tags[0].ids)],
|
|
}),
|
|
Command.create({
|
|
'factor_percent': 100,
|
|
'repartition_type': 'tax',
|
|
'tag_ids': [Command.set(tax_tags[1].ids)],
|
|
}),
|
|
],
|
|
'refund_repartition_line_ids': [
|
|
Command.create({
|
|
'factor_percent': 100,
|
|
'repartition_type': 'base',
|
|
'tag_ids': [Command.set(tax_tags[2].ids)],
|
|
}),
|
|
Command.create({
|
|
'factor_percent': 100,
|
|
'repartition_type': 'tax',
|
|
'tag_ids': [Command.set(tax_tags[3].ids)],
|
|
}),
|
|
],
|
|
})
|
|
|
|
wizard = self.env['bank.rec.widget'].with_context(default_st_line_id=st_line.id).new({})
|
|
line = wizard.line_ids.filtered(lambda x: x.flag == 'auto_balance')
|
|
wizard._js_action_mount_line_in_edit(line.index)
|
|
line.tax_ids = [Command.link(tax_21.id)]
|
|
wizard._line_value_changed_tax_ids(line)
|
|
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'balance': 1000.0, 'tax_tag_ids': []},
|
|
{'flag': 'manual', 'balance': -826.45, 'tax_tag_ids': tax_tags[0].ids},
|
|
{'flag': 'tax_line', 'balance': -173.55, 'tax_tag_ids': tax_tags[1].ids},
|
|
])
|
|
|
|
# Remove the tax directly.
|
|
line.tax_ids = [Command.clear()]
|
|
wizard._line_value_changed_tax_ids(line)
|
|
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'balance': 1000.0, 'tax_tag_ids': []},
|
|
{'flag': 'manual', 'balance': -1000.0, 'tax_tag_ids': []},
|
|
])
|
|
|
|
# Edit the base line. The tax tags should be the refund ones.
|
|
line = wizard.line_ids.filtered(lambda x: x.flag == 'manual')
|
|
wizard._js_action_mount_line_in_edit(line.index)
|
|
line.tax_ids = [Command.link(tax_21.id)]
|
|
wizard._line_value_changed_tax_ids(line)
|
|
line.balance = 500.0
|
|
wizard._line_value_changed_balance(line)
|
|
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'balance': 1000.0, 'tax_tag_ids': []},
|
|
{'flag': 'manual', 'balance': 500.0, 'tax_tag_ids': tax_tags[2].ids},
|
|
{'flag': 'tax_line', 'balance': 105.0, 'tax_tag_ids': tax_tags[3].ids},
|
|
{'flag': 'auto_balance', 'balance': -1605.0, 'tax_tag_ids': []},
|
|
])
|
|
|
|
# Edit the base line.
|
|
line = wizard.line_ids.filtered(lambda x: x.flag == 'manual')
|
|
wizard._js_action_mount_line_in_edit(line.index)
|
|
line.balance = -500.0
|
|
wizard._line_value_changed_balance(line)
|
|
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'balance': 1000.0, 'tax_tag_ids': []},
|
|
{'flag': 'manual', 'balance': -500.0, 'tax_tag_ids': tax_tags[0].ids},
|
|
{'flag': 'tax_line', 'balance': -105.0, 'tax_tag_ids': tax_tags[1].ids},
|
|
{'flag': 'auto_balance', 'balance': -395.0, 'tax_tag_ids': []},
|
|
])
|
|
|
|
# Edit the tax line.
|
|
line = wizard.line_ids.filtered(lambda x: x.flag == 'tax_line')
|
|
wizard._js_action_mount_line_in_edit(line.index)
|
|
line.balance = -100.0
|
|
wizard._line_value_changed_balance(line)
|
|
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'balance': 1000.0, 'tax_tag_ids': []},
|
|
{'flag': 'manual', 'balance': -500.0, 'tax_tag_ids': tax_tags[0].ids},
|
|
{'flag': 'tax_line', 'balance': -100.0, 'tax_tag_ids': tax_tags[1].ids},
|
|
{'flag': 'auto_balance', 'balance': -400.0, 'tax_tag_ids': []},
|
|
])
|
|
|
|
# Add a new tax.
|
|
tax_10 = self.env['account.tax'].create({
|
|
'name': "tax_10",
|
|
'amount': 10,
|
|
})
|
|
|
|
line = wizard.line_ids.filtered(lambda x: x.flag == 'manual')
|
|
wizard._js_action_mount_line_in_edit(line.index)
|
|
line.tax_ids = [Command.link(tax_10.id)]
|
|
wizard._line_value_changed_tax_ids(line)
|
|
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'balance': 1000.0},
|
|
{'flag': 'manual', 'balance': -500.0},
|
|
{'flag': 'tax_line', 'balance': -105.0},
|
|
{'flag': 'tax_line', 'balance': -50.0},
|
|
{'flag': 'auto_balance', 'balance': -345.0},
|
|
])
|
|
|
|
# Remove the taxes.
|
|
line = wizard.line_ids.filtered(lambda x: x.flag == 'manual')
|
|
wizard._js_action_mount_line_in_edit(line.index)
|
|
line.tax_ids = [Command.clear()]
|
|
wizard._line_value_changed_tax_ids(line)
|
|
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'balance': 1000.0},
|
|
{'flag': 'manual', 'balance': -500.0},
|
|
{'flag': 'auto_balance', 'balance': -500.0},
|
|
])
|
|
|
|
# Reset the amount.
|
|
line = wizard.line_ids.filtered(lambda x: x.flag == 'manual')
|
|
wizard._js_action_mount_line_in_edit(line.index)
|
|
line.balance = -1000.0
|
|
wizard._line_value_changed_balance(line)
|
|
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'balance': 1000.0},
|
|
{'flag': 'manual', 'balance': -1000.0},
|
|
])
|
|
|
|
# Add taxes. We should be back into the "price included taxes" mode.
|
|
line = wizard.line_ids.filtered(lambda x: x.flag == 'manual')
|
|
wizard._js_action_mount_line_in_edit(line.index)
|
|
line.tax_ids = [Command.link(tax_21.id)]
|
|
wizard._line_value_changed_tax_ids(line)
|
|
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'balance': 1000.0},
|
|
{'flag': 'manual', 'balance': -826.45},
|
|
{'flag': 'tax_line', 'balance': -173.55},
|
|
])
|
|
|
|
line = wizard.line_ids.filtered(lambda x: x.flag == 'manual')
|
|
wizard._js_action_mount_line_in_edit(line.index)
|
|
line.tax_ids = [Command.link(tax_10.id)]
|
|
wizard._line_value_changed_tax_ids(line)
|
|
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'balance': 1000.0},
|
|
{'flag': 'manual', 'balance': -763.36},
|
|
{'flag': 'tax_line', 'balance': -160.31},
|
|
{'flag': 'tax_line', 'balance': -76.33},
|
|
])
|
|
|
|
# Changing the account should recompute the taxes but preserve the "price included taxes" mode.
|
|
line = wizard.line_ids.filtered(lambda x: x.flag == 'manual')
|
|
wizard._js_action_mount_line_in_edit(line.index)
|
|
line.account_id = self.account_revenue1
|
|
wizard._line_value_changed_account_id(line)
|
|
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'balance': 1000.0},
|
|
{'flag': 'manual', 'balance': -763.36},
|
|
{'flag': 'tax_line', 'balance': -160.31},
|
|
{'flag': 'tax_line', 'balance': -76.33},
|
|
])
|
|
|
|
# The wizard can be validated.
|
|
self.assertRecordValues(wizard, [{'state': 'valid'}])
|
|
|
|
# Validate and check the statement line.
|
|
wizard._action_validate()
|
|
self.assertRecordValues(st_line.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'balance': 1000.0},
|
|
{'balance': -763.36},
|
|
{'balance': -160.31},
|
|
{'balance': -76.33},
|
|
])
|
|
self.assertRecordValues(wizard, [{'state': 'reconciled'}])
|
|
|
|
def test_validation_caba_tax_account(self):
|
|
""" Cash basis taxes usually put their tax lines on a transition account, and the cash basis entries then move those amounts
|
|
to the regular tax accounts. When using a cash basis tax in the bank reconciliation widget, their won't be any cash basis
|
|
entry and the lines will directly be exigible, so we want to use the final tax account directly.
|
|
"""
|
|
tax_account = self.company_data['default_account_tax_sale']
|
|
|
|
caba_tax = self.env['account.tax'].create({
|
|
'name': "CABA",
|
|
'amount_type': 'percent',
|
|
'amount': 20.0,
|
|
'tax_exigibility': 'on_payment',
|
|
'cash_basis_transition_account_id': self.safe_copy(tax_account).id,
|
|
'invoice_repartition_line_ids': [
|
|
(0, 0, {
|
|
'repartition_type': 'base',
|
|
}),
|
|
(0, 0, {
|
|
'repartition_type': 'tax',
|
|
'account_id': tax_account.id,
|
|
}),
|
|
],
|
|
'refund_repartition_line_ids': [
|
|
(0, 0, {
|
|
'repartition_type': 'base',
|
|
}),
|
|
(0, 0, {
|
|
'repartition_type': 'tax',
|
|
'account_id': tax_account.id,
|
|
}),
|
|
],
|
|
})
|
|
|
|
st_line = self._create_st_line(120.0)
|
|
|
|
wizard = self.env['bank.rec.widget'].with_context(default_st_line_id=st_line.id).new({})
|
|
line = wizard.line_ids.filtered(lambda x: x.flag == 'auto_balance')
|
|
wizard._js_action_mount_line_in_edit(line.index)
|
|
line.account_id = self.account_revenue1
|
|
line.tax_ids = [Command.link(caba_tax.id)]
|
|
wizard._line_value_changed_tax_ids(line)
|
|
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'balance': 120.0, 'account_id': st_line.journal_id.default_account_id.id},
|
|
{'flag': 'manual', 'balance': -100.0, 'account_id': self.account_revenue1.id},
|
|
{'flag': 'tax_line', 'balance': -20.0, 'account_id': tax_account.id},
|
|
])
|
|
|
|
self.assertRecordValues(wizard, [{'state': 'valid'}])
|
|
|
|
wizard._action_validate()
|
|
self.assertRecordValues(st_line.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'balance': 120.0, 'tax_ids': [], 'tax_line_id': False, 'account_id': st_line.journal_id.default_account_id.id},
|
|
{'balance': -100.0, 'tax_ids': caba_tax.ids, 'tax_line_id': False, 'account_id': self.account_revenue1.id},
|
|
{'balance': -20.0, 'tax_ids': [], 'tax_line_id': caba_tax.id, 'account_id': tax_account.id},
|
|
])
|
|
self.assertRecordValues(wizard, [{'state': 'reconciled'}])
|
|
|
|
def test_validation_changed_default_account(self):
|
|
st_line = self._create_st_line(100.0, partner_id=self.partner_a.id)
|
|
original_journal_account_id = st_line.journal_id.default_account_id
|
|
# Change the default account of the journal (exceptional case)
|
|
st_line.journal_id.default_account_id = self.company_data['default_journal_cash'].default_account_id
|
|
wizard = self.env['bank.rec.widget'].with_context(default_st_line_id=st_line.id).new({})
|
|
self.assertRecordValues(wizard, [{'state': 'valid'}])
|
|
# Validate and check the statement line.
|
|
wizard._action_validate()
|
|
liquidity_line, _suspense_line, _other_line = st_line._seek_for_lines()
|
|
self.assertRecordValues(liquidity_line, [
|
|
{'account_id': original_journal_account_id.id, 'balance': 100.0},
|
|
])
|
|
self.assertRecordValues(wizard, [{'state': 'reconciled'}])
|
|
|
|
def test_apply_taxes_with_reco_model(self):
|
|
st_line = self._create_st_line(1000.0)
|
|
|
|
tax_21 = self.env['account.tax'].create({
|
|
'name': "tax_21",
|
|
'amount': 21,
|
|
})
|
|
|
|
reco_model = self.env['account.reconcile.model'].create({
|
|
'name': "test_apply_taxes_with_reco_model",
|
|
'rule_type': 'writeoff_button',
|
|
'line_ids': [Command.create({
|
|
'account_id': self.account_revenue1.id,
|
|
'tax_ids': [Command.set(tax_21.ids)],
|
|
})],
|
|
})
|
|
|
|
wizard = self.env['bank.rec.widget'].with_context(default_st_line_id=st_line.id).new({})
|
|
wizard._action_select_reconcile_model(reco_model)
|
|
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'balance': 1000.0},
|
|
{'flag': 'manual', 'balance': -826.45},
|
|
{'flag': 'tax_line', 'balance': -173.55},
|
|
])
|
|
|
|
def test_percentage_st_line_with_reco_model(self):
|
|
journal_curr = self.currency_data['currency']
|
|
foreign_curr = self.currency_data_2['currency']
|
|
self.company_data['default_journal_bank'].currency_id = journal_curr
|
|
|
|
# Setup triple currency.
|
|
st_line = self._create_st_line(
|
|
1000.0,
|
|
date='2018-01-01',
|
|
foreign_currency_id=foreign_curr.id,
|
|
amount_currency=4000.0,
|
|
)
|
|
|
|
reco_model = self.env['account.reconcile.model'].create({
|
|
'name': "test_percentage_st_line_with_reco_model",
|
|
'rule_type': 'writeoff_button',
|
|
'line_ids': [
|
|
Command.create({
|
|
'amount_type': 'percentage_st_line',
|
|
'amount_string': str(percentage),
|
|
'label': str(i),
|
|
'account_id': self.account_revenue1.id,
|
|
})
|
|
for i, percentage in enumerate((74.0, 24.0, 12.0, -10.0))
|
|
],
|
|
})
|
|
|
|
wizard = self.env['bank.rec.widget'].with_context(default_st_line_id=st_line.id).new({})
|
|
wizard._action_select_reconcile_model(reco_model)
|
|
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
{'flag': 'liquidity', 'currency_id': journal_curr.id, 'amount_currency': 1000.0, 'balance': 500.0},
|
|
{'flag': 'manual', 'currency_id': journal_curr.id, 'amount_currency': -740.0, 'balance': -370.0},
|
|
{'flag': 'manual', 'currency_id': journal_curr.id, 'amount_currency': -240.0, 'balance': -120.0},
|
|
{'flag': 'manual', 'currency_id': journal_curr.id, 'amount_currency': -120.0, 'balance': -60.0},
|
|
{'flag': 'manual', 'currency_id': journal_curr.id, 'amount_currency': 100.0, 'balance': 50.0},
|
|
])
|
|
|
|
def test_manual_edits_not_replaced(self):
|
|
""" 2 partial payments should keep the edited balance """
|
|
st_line = self._create_st_line(
|
|
1200.0,
|
|
date='2017-02-01',
|
|
)
|
|
inv_line_1 = self._create_invoice_line(
|
|
'out_invoice',
|
|
invoice_date='2016-01-01',
|
|
invoice_line_ids=[{'price_unit': 3000.0}],
|
|
)
|
|
inv_line_2 = self._create_invoice_line(
|
|
'out_invoice',
|
|
invoice_date='2017-01-01',
|
|
invoice_line_ids=[{'price_unit': 4000.0}],
|
|
)
|
|
|
|
wizard = self.env['bank.rec.widget'].with_context(default_st_line_id=st_line.id).new({})
|
|
wizard._action_add_new_amls(inv_line_1)
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'balance': 1200.0},
|
|
{'flag': 'new_aml', 'balance':-1200.0},
|
|
])
|
|
|
|
line = wizard.line_ids.filtered(lambda x: x.flag == 'new_aml')
|
|
wizard._js_action_mount_line_in_edit(line.index)
|
|
line.balance = -600.0
|
|
wizard._line_value_changed_balance(line)
|
|
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'balance': 1200.0},
|
|
{'flag': 'new_aml', 'balance': -600.0},
|
|
{'flag': 'auto_balance', 'balance': -600.0},
|
|
])
|
|
|
|
wizard._action_add_new_amls(inv_line_2)
|
|
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'balance': 1200.0},
|
|
{'flag': 'new_aml', 'balance': -600.0},
|
|
{'flag': 'new_aml', 'balance': -600.0},
|
|
])
|
|
|
|
def test_manual_edits_not_replaced_multicurrency(self):
|
|
""" 2 partial payments should keep the edited amount_currency """
|
|
st_line = self._create_st_line(
|
|
1200.0,
|
|
date='2018-01-01',
|
|
foreign_currency_id=self.currency_data_2['currency'].id,
|
|
amount_currency=6000.0, # rate 5:1
|
|
)
|
|
|
|
inv_line_1 = self._create_invoice_line(
|
|
'out_invoice',
|
|
invoice_date='2016-01-01',
|
|
currency_id=self.currency_data_2['currency'].id,
|
|
invoice_line_ids=[{'price_unit': 6000.0}], # 1000 company curr (rate 6:1)
|
|
)
|
|
inv_line_2 = self._create_invoice_line(
|
|
'out_invoice',
|
|
invoice_date='2017-01-01',
|
|
currency_id=self.currency_data_2['currency'].id,
|
|
invoice_line_ids=[{'price_unit': 4000.0}], # 1000 company curr (rate 4:1)
|
|
)
|
|
|
|
wizard = self.env['bank.rec.widget'].with_context(default_st_line_id=st_line.id).new({})
|
|
wizard._action_add_new_amls(inv_line_1)
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'amount_currency': 1200.0, 'balance': 1200.0},
|
|
{'flag': 'new_aml', 'amount_currency':-6000.0, 'balance':-1000.0},
|
|
{'flag': 'exchange_diff', 'amount_currency': 0.0, 'balance': -200.0},
|
|
])
|
|
|
|
line = wizard.line_ids.filtered(lambda x: x.flag == 'new_aml')
|
|
wizard._js_action_mount_line_in_edit(line.index)
|
|
line.amount_currency = -3000.0
|
|
wizard._line_value_changed_amount_currency(line)
|
|
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'amount_currency': 1200.0, 'balance': 1200.0},
|
|
{'flag': 'new_aml', 'amount_currency':-3000.0, 'balance': -500.0},
|
|
{'flag': 'exchange_diff', 'amount_currency': 0.0, 'balance': -100.0},
|
|
{'flag': 'auto_balance', 'amount_currency':-3000.0, 'balance': -600.0},
|
|
])
|
|
|
|
wizard._action_add_new_amls(inv_line_2)
|
|
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'amount_currency': 1200.0, 'balance': 1200.0},
|
|
{'flag': 'new_aml', 'amount_currency':-3000.0, 'balance': -500.0},
|
|
{'flag': 'exchange_diff', 'amount_currency': 0.0, 'balance': -100.0},
|
|
{'flag': 'new_aml', 'amount_currency':-3000.0, 'balance': -750.0},
|
|
{'flag': 'exchange_diff', 'amount_currency': 0.0, 'balance': 150.0},
|
|
])
|
|
|
|
def test_creating_manual_line_multi_currencies(self):
|
|
# 6300.0 curr2 == 1800.0 comp_curr (bank rate 3.5:1 instead of the odoo rate 4:1)
|
|
st_line = self._create_st_line(
|
|
1800.0,
|
|
date='2017-01-01',
|
|
foreign_currency_id=self.currency_data_2['currency'].id,
|
|
amount_currency=6300.0,
|
|
)
|
|
|
|
wizard = self.env['bank.rec.widget'].with_context(default_st_line_id=st_line.id).new({})
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'amount_currency': 1800.0, 'currency_id': self.company_data['currency'].id, 'balance': 1800.0},
|
|
{'flag': 'auto_balance', 'amount_currency': -6300.0, 'currency_id': self.currency_data_2['currency'].id, 'balance': -1800.0},
|
|
])
|
|
|
|
# Custom balance.
|
|
line = wizard.line_ids.filtered(lambda x: x.flag == 'auto_balance')
|
|
wizard._js_action_mount_line_in_edit(line.index)
|
|
line.balance = -1500.0
|
|
wizard._line_value_changed_balance(line)
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'amount_currency': 1800.0, 'currency_id': self.company_data['currency'].id, 'balance': 1800.0},
|
|
{'flag': 'manual', 'amount_currency': -6300.0, 'currency_id': self.currency_data_2['currency'].id, 'balance': -1500.0},
|
|
{'flag': 'auto_balance', 'amount_currency': 0.0, 'currency_id': self.currency_data_2['currency'].id, 'balance': -300.0},
|
|
])
|
|
|
|
# Custom amount_currency.
|
|
line = wizard.line_ids.filtered(lambda x: x.flag == 'manual')
|
|
wizard._js_action_mount_line_in_edit(line.index)
|
|
line.amount_currency = -4200.0
|
|
wizard._line_value_changed_amount_currency(line)
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'amount_currency': 1800.0, 'currency_id': self.company_data['currency'].id, 'balance': 1800.0},
|
|
{'flag': 'manual', 'amount_currency': -4200.0, 'currency_id': self.currency_data_2['currency'].id, 'balance': -1200.0},
|
|
{'flag': 'auto_balance', 'amount_currency': -2100.0, 'currency_id': self.currency_data_2['currency'].id, 'balance': -600.0},
|
|
])
|
|
|
|
# Custom currency_id.
|
|
line = wizard.line_ids.filtered(lambda x: x.flag == 'manual')
|
|
wizard._js_action_mount_line_in_edit(line.index)
|
|
line.currency_id = self.currency_data['currency']
|
|
wizard._line_value_changed_currency_id(line)
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'amount_currency': 1800.0, 'currency_id': self.company_data['currency'].id, 'balance': 1800.0},
|
|
{'flag': 'manual', 'amount_currency': -4200.0, 'currency_id': self.currency_data['currency'].id, 'balance': -2100.0},
|
|
{'flag': 'auto_balance', 'amount_currency': 1050.0, 'currency_id': self.currency_data_2['currency'].id, 'balance': 300.0},
|
|
])
|
|
|
|
# Custom balance.
|
|
line = wizard.line_ids.filtered(lambda x: x.flag == 'manual')
|
|
wizard._js_action_mount_line_in_edit(line.index)
|
|
line.balance = -1800.0
|
|
wizard._line_value_changed_balance(line)
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'amount_currency': 1800.0, 'currency_id': self.company_data['currency'].id, 'balance': 1800.0},
|
|
{'flag': 'manual', 'amount_currency': -4200.0, 'currency_id': self.currency_data['currency'].id, 'balance': -1800.0},
|
|
])
|
|
|
|
def test_auto_reconcile_cron(self):
|
|
self.env['account.reconcile.model'].search([('company_id', '=', self.company_data['company'].id)]).unlink()
|
|
cron = self.env.ref('account_accountant.auto_reconcile_bank_statement_line')
|
|
self.env['ir.cron.trigger'].search([('cron_id', '=', cron.id)]).unlink()
|
|
|
|
st_line = self._create_st_line(1234.0, partner_id=self.partner_a.id, date='2017-01-01')
|
|
self.assertEqual(len(self.env['ir.cron.trigger'].search([('cron_id', '=', cron.id)])), 1)
|
|
|
|
self._create_invoice_line(
|
|
'out_invoice',
|
|
invoice_date='2017-01-01',
|
|
invoice_line_ids=[{'price_unit': 1234.0}],
|
|
)
|
|
|
|
rule = self.env['account.reconcile.model'].create({
|
|
'name': "test_auto_reconcile_cron",
|
|
'rule_type': 'writeoff_suggestion',
|
|
'auto_reconcile': False,
|
|
'line_ids': [Command.create({'account_id': self.account_revenue1.id})],
|
|
})
|
|
|
|
# The CRON is not doing anything since the model is not auto reconcile.
|
|
with freeze_time('2017-01-01'):
|
|
self.env['account.bank.statement.line']._cron_try_auto_reconcile_statement_lines()
|
|
self.assertRecordValues(st_line, [{'is_reconciled': False, 'cron_last_check': False}])
|
|
self.assertEqual(len(self.env['ir.cron.trigger'].search([('cron_id', '=', cron.id)])), 1)
|
|
|
|
rule.auto_reconcile = True
|
|
|
|
# The CRON don't consider old statement lines.
|
|
with freeze_time('2017-06-01'):
|
|
self.env['account.bank.statement.line']._cron_try_auto_reconcile_statement_lines()
|
|
self.assertRecordValues(st_line, [{'is_reconciled': False, 'cron_last_check': False}])
|
|
self.assertEqual(len(self.env['ir.cron.trigger'].search([('cron_id', '=', cron.id)])), 1)
|
|
|
|
# The CRON will auto-reconcile the line.
|
|
with freeze_time('2017-01-02'):
|
|
self.env['account.bank.statement.line']._cron_try_auto_reconcile_statement_lines()
|
|
self.assertRecordValues(st_line, [{'is_reconciled': True, 'cron_last_check': fields.Datetime.from_string('2017-01-02 00:00:00')}])
|
|
self.assertEqual(len(self.env['ir.cron.trigger'].search([('cron_id', '=', cron.id)])), 1)
|
|
|
|
st_line1 = self._create_st_line(1234.0, partner_id=self.partner_a.id, date='2018-01-01')
|
|
self.assertEqual(len(self.env['ir.cron.trigger'].search([('cron_id', '=', cron.id)])), 2)
|
|
self._create_invoice_line(
|
|
'out_invoice',
|
|
invoice_date='2018-01-01',
|
|
invoice_line_ids=[{'price_unit': 1234.0}],
|
|
)
|
|
st_line2 = self._create_st_line(1234.0, partner_id=self.partner_a.id, date='2018-01-01')
|
|
self.assertEqual(len(self.env['ir.cron.trigger'].search([('cron_id', '=', cron.id)])), 3)
|
|
self._create_invoice_line(
|
|
'out_invoice',
|
|
invoice_date='2018-01-01',
|
|
invoice_line_ids=[{'price_unit': 1234.0}],
|
|
)
|
|
|
|
# Simulate the cron already tried to process 'st_line1' before.
|
|
with freeze_time('2017-12-31'):
|
|
st_line1.cron_last_check = fields.Datetime.now()
|
|
|
|
# The statement line with no 'cron_last_check' must be processed before others.
|
|
with freeze_time('2018-01-02'):
|
|
self.env['account.bank.statement.line']._cron_try_auto_reconcile_statement_lines(batch_size=1)
|
|
|
|
self.assertRecordValues(st_line1 + st_line2, [
|
|
{'is_reconciled': False, 'cron_last_check': fields.Datetime.from_string('2017-12-31 00:00:00')},
|
|
{'is_reconciled': True, 'cron_last_check': fields.Datetime.from_string('2018-01-02 00:00:00')},
|
|
])
|
|
self.assertEqual(len(self.env['ir.cron.trigger'].search([('cron_id', '=', cron.id)])), 4)
|
|
|
|
with freeze_time('2018-01-03'):
|
|
self.env['account.bank.statement.line']._cron_try_auto_reconcile_statement_lines(batch_size=1)
|
|
|
|
self.assertRecordValues(st_line1, [{'is_reconciled': True, 'cron_last_check': fields.Datetime.from_string('2018-01-03 00:00:00')}])
|
|
self.assertEqual(len(self.env['ir.cron.trigger'].search([('cron_id', '=', cron.id)])), 4)
|
|
|
|
st_line3 = self._create_st_line(1234.0, date='2018-01-01')
|
|
self.assertEqual(len(self.env['ir.cron.trigger'].search([('cron_id', '=', cron.id)])), 5)
|
|
self._create_invoice_line(
|
|
'out_invoice',
|
|
invoice_date='2018-01-01',
|
|
invoice_line_ids=[{'price_unit': 1234.0}],
|
|
)
|
|
st_line4 = self._create_st_line(1234.0, date='2018-01-01')
|
|
self.assertEqual(len(self.env['ir.cron.trigger'].search([('cron_id', '=', cron.id)])), 6)
|
|
self._create_invoice_line(
|
|
'out_invoice',
|
|
invoice_date='2018-01-01',
|
|
invoice_line_ids=[{'price_unit': 1234.0}],
|
|
)
|
|
|
|
# Make sure the CRON is no longer applicable.
|
|
rule.match_partner = True
|
|
rule.match_partner_ids = [Command.set(self.partner_a.ids)]
|
|
with freeze_time('2018-01-01'):
|
|
self.env['account.bank.statement.line']._cron_try_auto_reconcile_statement_lines(batch_size=1)
|
|
|
|
self.assertRecordValues(st_line3 + st_line4, [
|
|
{'is_reconciled': False, 'cron_last_check': fields.Datetime.from_string('2018-01-01 00:00:00')},
|
|
{'is_reconciled': False, 'cron_last_check': False},
|
|
])
|
|
self.assertEqual(len(self.env['ir.cron.trigger'].search([('cron_id', '=', cron.id)])), 7)
|
|
|
|
# Make sure the statement lines are reconciled by the cron in the right order.
|
|
self.assertRecordValues(st_line3 + st_line4, [
|
|
{'is_reconciled': False, 'cron_last_check': fields.Datetime.from_string('2018-01-01 00:00:00')},
|
|
{'is_reconciled': False, 'cron_last_check': False},
|
|
])
|
|
|
|
# st_line4 is processed because cron_last_check is null.
|
|
with freeze_time('2018-01-02'):
|
|
self.env['account.bank.statement.line']._cron_try_auto_reconcile_statement_lines(batch_size=1)
|
|
|
|
self.assertRecordValues(st_line3 + st_line4, [
|
|
{'is_reconciled': False, 'cron_last_check': fields.Datetime.from_string('2018-01-01 00:00:00')},
|
|
{'is_reconciled': False, 'cron_last_check': fields.Datetime.from_string('2018-01-02 00:00:00')},
|
|
])
|
|
self.assertEqual(len(self.env['ir.cron.trigger'].search([('cron_id', '=', cron.id)])), 7)
|
|
|
|
# st_line3 is processed because it has the oldest cron_last_check.
|
|
with freeze_time('2018-01-03'):
|
|
self.env['account.bank.statement.line']._cron_try_auto_reconcile_statement_lines(batch_size=1)
|
|
|
|
self.assertRecordValues(st_line3 + st_line4, [
|
|
{'is_reconciled': False, 'cron_last_check': fields.Datetime.from_string('2018-01-03 00:00:00')},
|
|
{'is_reconciled': False, 'cron_last_check': fields.Datetime.from_string('2018-01-02 00:00:00')},
|
|
])
|
|
self.assertEqual(len(self.env['ir.cron.trigger'].search([('cron_id', '=', cron.id)])), 7)
|
|
|
|
def test_duplicate_amls_constraint(self):
|
|
st_line = self._create_st_line(1000.0)
|
|
inv_line = self._create_invoice_line(
|
|
'out_invoice',
|
|
invoice_line_ids=[{'price_unit': 1000.0}],
|
|
)
|
|
|
|
wizard = self.env['bank.rec.widget'].with_context(default_st_line_id=st_line.id).new({})
|
|
wizard._action_add_new_amls(inv_line)
|
|
self.assertTrue(len(wizard.line_ids), 2)
|
|
|
|
wizard._action_add_new_amls(inv_line)
|
|
self.assertTrue(len(wizard.line_ids), 2)
|
|
|
|
@freeze_time('2017-01-01')
|
|
def test_reconcile_model_with_payment_tolerance(self):
|
|
self.env['account.reconcile.model'].search([('company_id', '=', self.company_data['company'].id)]).unlink()
|
|
|
|
invoice_line = self._create_invoice_line(
|
|
'out_invoice',
|
|
invoice_date='2017-01-01',
|
|
invoice_line_ids=[{'price_unit': 1000.0}],
|
|
)
|
|
st_line = self._create_st_line(998.0, partner_id=self.partner_a.id, date='2017-01-01', payment_ref=invoice_line.move_id.name)
|
|
|
|
rule = self.env['account.reconcile.model'].create({
|
|
'name': "test_reconcile_model_with_payment_tolerance",
|
|
'rule_type': 'invoice_matching',
|
|
'allow_payment_tolerance': True,
|
|
'payment_tolerance_type': 'percentage',
|
|
'payment_tolerance_param': 2.0,
|
|
'line_ids': [Command.create({'account_id': self.account_revenue1.id})],
|
|
})
|
|
|
|
wizard = self.env['bank.rec.widget'].with_context(default_st_line_id=st_line.id).new({})
|
|
wizard._action_trigger_matching_rules()
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'balance': 998.0, 'reconcile_model_id': False},
|
|
{'flag': 'new_aml', 'balance': -1000.0, 'reconcile_model_id': rule.id},
|
|
{'flag': 'manual', 'balance': 2.0, 'reconcile_model_id': rule.id},
|
|
])
|
|
|
|
def test_early_payment_included_multi_currency(self):
|
|
self.env['account.reconcile.model'].search([('company_id', '=', self.company_data['company'].id)]).unlink()
|
|
self.early_payment_term.early_pay_discount_computation = 'included'
|
|
income_exchange_account = self.env.company.income_currency_exchange_account_id
|
|
expense_exchange_account = self.env.company.expense_currency_exchange_account_id
|
|
|
|
inv_line1_with_epd = self._create_invoice_line(
|
|
'out_invoice',
|
|
currency_id=self.currency_data_2['currency'].id,
|
|
partner_id=self.partner_a.id,
|
|
invoice_payment_term_id=self.early_payment_term.id,
|
|
invoice_date='2016-12-01',
|
|
invoice_line_ids=[
|
|
{
|
|
'price_unit': 4800.0,
|
|
'account_id': self.account_revenue1.id,
|
|
'tax_ids': [Command.set(self.company_data['default_tax_sale'].ids)],
|
|
},
|
|
{
|
|
'price_unit': 9600.0,
|
|
'account_id': self.account_revenue2.id,
|
|
'tax_ids': [Command.set(self.company_data['default_tax_sale'].ids)],
|
|
},
|
|
],
|
|
)
|
|
inv_line1_with_epd_rec_lines = inv_line1_with_epd.move_id.line_ids\
|
|
.filtered(lambda x: x.account_type == 'asset_receivable')\
|
|
.sorted(lambda x: x.discount_date or x.date_maturity)
|
|
self.assertRecordValues(
|
|
inv_line1_with_epd_rec_lines,
|
|
[
|
|
{
|
|
'amount_currency': 16560.0,
|
|
'balance': 2760.0,
|
|
'discount_amount_currency': 14904.0,
|
|
'discount_balance': 2484.0,
|
|
'discount_date': fields.Date.from_string('2016-12-11'),
|
|
'date_maturity': fields.Date.from_string('2016-12-21'),
|
|
},
|
|
],
|
|
)
|
|
|
|
inv_line2_with_epd = self._create_invoice_line(
|
|
'out_invoice',
|
|
currency_id=self.currency_data_2['currency'].id,
|
|
partner_id=self.partner_a.id,
|
|
invoice_payment_term_id=self.early_payment_term.id,
|
|
invoice_date='2017-01-20',
|
|
invoice_line_ids=[
|
|
{
|
|
'price_unit': 480.0,
|
|
'account_id': self.account_revenue1.id,
|
|
'tax_ids': [Command.set(self.company_data['default_tax_sale'].ids)],
|
|
},
|
|
{
|
|
'price_unit': 960.0,
|
|
'account_id': self.account_revenue2.id,
|
|
'tax_ids': [Command.set(self.company_data['default_tax_sale'].ids)],
|
|
},
|
|
],
|
|
)
|
|
inv_line2_with_epd_rec_lines = inv_line2_with_epd.move_id.line_ids\
|
|
.filtered(lambda x: x.account_type == 'asset_receivable')\
|
|
.sorted(lambda x: x.discount_date or x.date_maturity)
|
|
self.assertRecordValues(
|
|
inv_line2_with_epd_rec_lines,
|
|
[
|
|
{
|
|
'amount_currency': 1656.0,
|
|
'balance': 414.0,
|
|
'discount_amount_currency': 1490.4,
|
|
'discount_balance': 372.6,
|
|
'discount_date': fields.Date.from_string('2017-01-30'),
|
|
'date_maturity': fields.Date.from_string('2017-02-09'),
|
|
},
|
|
],
|
|
)
|
|
|
|
# inv1: 16560.0 (no epd)
|
|
# inv2: 1490.4 (epd)
|
|
st_line = self._create_st_line(
|
|
4512.0, # instead of 4512.6 (rate 1:4)
|
|
date='2017-01-04',
|
|
foreign_currency_id=self.currency_data_2['currency'].id,
|
|
amount_currency=18050.4,
|
|
)
|
|
|
|
wizard = self.env['bank.rec.widget'].with_context(default_st_line_id=st_line.id).new({})
|
|
|
|
# Add all lines from the first invoice plus the first one from the second one.
|
|
wizard._action_add_new_amls(inv_line1_with_epd_rec_lines + inv_line2_with_epd_rec_lines)
|
|
liquidity_acc = st_line.journal_id.default_account_id
|
|
receivable_acc = self.company_data['default_account_receivable']
|
|
early_pay_acc = self.env.company.account_journal_early_pay_discount_loss_account_id
|
|
tax_acc = self.company_data['default_tax_sale'].invoice_repartition_line_ids.account_id
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'amount_currency': 4512.0, 'balance': 4512.0, 'account_id': liquidity_acc.id},
|
|
{'flag': 'new_aml', 'amount_currency': -16560.0, 'balance': -2760.0, 'account_id': receivable_acc.id},
|
|
{'flag': 'exchange_diff', 'amount_currency': 0.0, 'balance': -1379.45, 'account_id': income_exchange_account.id},
|
|
{'flag': 'new_aml', 'amount_currency': -1656.0, 'balance': -414.0, 'account_id': receivable_acc.id},
|
|
{'flag': 'exchange_diff', 'amount_currency': 0.0, 'balance': 0.06, 'account_id': expense_exchange_account.id},
|
|
{'flag': 'early_payment', 'amount_currency': 144.0, 'balance': 36.0, 'account_id': early_pay_acc.id},
|
|
{'flag': 'early_payment', 'amount_currency': 21.6, 'balance': 5.4, 'account_id': tax_acc.id},
|
|
{'flag': 'early_payment', 'amount_currency': 0.0, 'balance': -0.01, 'account_id': income_exchange_account.id},
|
|
])
|
|
|
|
def test_early_payment_excluded_multi_currency(self):
|
|
self.env['account.reconcile.model'].search([('company_id', '=', self.company_data['company'].id)]).unlink()
|
|
self.early_payment_term.early_pay_discount_computation = 'excluded'
|
|
income_exchange_account = self.env.company.income_currency_exchange_account_id
|
|
expense_exchange_account = self.env.company.expense_currency_exchange_account_id
|
|
|
|
inv_line1_with_epd = self._create_invoice_line(
|
|
'out_invoice',
|
|
currency_id=self.currency_data_2['currency'].id,
|
|
partner_id=self.partner_a.id,
|
|
invoice_payment_term_id=self.early_payment_term.id,
|
|
invoice_date='2016-12-01',
|
|
invoice_line_ids=[
|
|
{
|
|
'price_unit': 4800.0,
|
|
'account_id': self.account_revenue1.id,
|
|
'tax_ids': [Command.set(self.company_data['default_tax_sale'].ids)],
|
|
},
|
|
{
|
|
'price_unit': 9600.0,
|
|
'account_id': self.account_revenue2.id,
|
|
'tax_ids': [Command.set(self.company_data['default_tax_sale'].ids)],
|
|
},
|
|
],
|
|
)
|
|
inv_line1_with_epd_rec_lines = inv_line1_with_epd.move_id.line_ids\
|
|
.filtered(lambda x: x.account_type == 'asset_receivable')\
|
|
.sorted(lambda x: x.discount_date or x.date_maturity)
|
|
self.assertRecordValues(
|
|
inv_line1_with_epd_rec_lines,
|
|
[
|
|
{
|
|
'amount_currency': 16560.0,
|
|
'balance': 2760.0,
|
|
'discount_amount_currency': 15120.0,
|
|
'discount_balance': 2520.0,
|
|
'discount_date': fields.Date.from_string('2016-12-11'),
|
|
'date_maturity': fields.Date.from_string('2016-12-21'),
|
|
},
|
|
],
|
|
)
|
|
|
|
inv_line2_with_epd = self._create_invoice_line(
|
|
'out_invoice',
|
|
currency_id=self.currency_data_2['currency'].id,
|
|
partner_id=self.partner_a.id,
|
|
invoice_payment_term_id=self.early_payment_term.id,
|
|
invoice_date='2017-01-20',
|
|
invoice_line_ids=[
|
|
{
|
|
'price_unit': 480.0,
|
|
'account_id': self.account_revenue1.id,
|
|
'tax_ids': [Command.set(self.company_data['default_tax_sale'].ids)],
|
|
},
|
|
{
|
|
'price_unit': 960.0,
|
|
'account_id': self.account_revenue2.id,
|
|
'tax_ids': [Command.set(self.company_data['default_tax_sale'].ids)],
|
|
},
|
|
],
|
|
)
|
|
inv_line2_with_epd_rec_lines = inv_line2_with_epd.move_id.line_ids\
|
|
.filtered(lambda x: x.account_type == 'asset_receivable')\
|
|
.sorted(lambda x: x.discount_date or x.date_maturity)
|
|
self.assertRecordValues(
|
|
inv_line2_with_epd_rec_lines,
|
|
[
|
|
{
|
|
'amount_currency': 1656.0,
|
|
'balance': 414.0,
|
|
'discount_amount_currency': 1512.0,
|
|
'discount_balance': 378.0,
|
|
'discount_date': fields.Date.from_string('2017-01-30'),
|
|
'date_maturity': fields.Date.from_string('2017-02-09'),
|
|
},
|
|
],
|
|
)
|
|
|
|
# inv1: 16560.0 (no epd)
|
|
# inv2: 1512.0 (epd)
|
|
st_line = self._create_st_line(
|
|
4515.0, # instead of 4518.0 (rate 1:4)
|
|
date='2017-01-04',
|
|
foreign_currency_id=self.currency_data_2['currency'].id,
|
|
amount_currency=18072.0,
|
|
)
|
|
|
|
wizard = self.env['bank.rec.widget'].with_context(default_st_line_id=st_line.id).new({})
|
|
|
|
# Add all lines from the first invoice plus the first one from the second one.
|
|
wizard._action_add_new_amls(inv_line1_with_epd_rec_lines + inv_line2_with_epd_rec_lines[:2])
|
|
liquidity_acc = st_line.journal_id.default_account_id
|
|
receivable_acc = self.company_data['default_account_receivable']
|
|
early_pay_acc = self.env.company.account_journal_early_pay_discount_loss_account_id
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'amount_currency': 4515.0, 'balance': 4515.0, 'account_id': liquidity_acc.id},
|
|
{'flag': 'new_aml', 'amount_currency': -16560.0, 'balance': -2760.0, 'account_id': receivable_acc.id},
|
|
{'flag': 'exchange_diff', 'amount_currency': 0.0, 'balance': -1377.25, 'account_id': income_exchange_account.id},
|
|
{'flag': 'new_aml', 'amount_currency': -1656.0, 'balance': -414.0, 'account_id': receivable_acc.id},
|
|
{'flag': 'exchange_diff', 'amount_currency': 0.0, 'balance': 0.27, 'account_id': expense_exchange_account.id},
|
|
{'flag': 'early_payment', 'amount_currency': 144.0, 'balance': 36.0, 'account_id': early_pay_acc.id},
|
|
{'flag': 'early_payment', 'amount_currency': 0.0, 'balance': -0.02, 'account_id': income_exchange_account.id},
|
|
])
|
|
|
|
def test_early_payment_mixed_multi_currency(self):
|
|
self.env['account.reconcile.model'].search([('company_id', '=', self.company_data['company'].id)]).unlink()
|
|
self.early_payment_term.early_pay_discount_computation = 'mixed'
|
|
income_exchange_account = self.env.company.income_currency_exchange_account_id
|
|
expense_exchange_account = self.env.company.expense_currency_exchange_account_id
|
|
|
|
inv_line1_with_epd = self._create_invoice_line(
|
|
'out_invoice',
|
|
currency_id=self.currency_data_2['currency'].id,
|
|
partner_id=self.partner_a.id,
|
|
invoice_payment_term_id=self.early_payment_term.id,
|
|
invoice_date='2016-12-01',
|
|
invoice_line_ids=[
|
|
{
|
|
'price_unit': 4800.0,
|
|
'account_id': self.account_revenue1.id,
|
|
'tax_ids': [Command.set(self.company_data['default_tax_sale'].ids)],
|
|
},
|
|
{
|
|
'price_unit': 9600.0,
|
|
'account_id': self.account_revenue2.id,
|
|
'tax_ids': [Command.set(self.company_data['default_tax_sale'].ids)],
|
|
},
|
|
],
|
|
)
|
|
inv_line1_with_epd_rec_lines = inv_line1_with_epd.move_id.line_ids\
|
|
.filtered(lambda x: x.account_type == 'asset_receivable')\
|
|
.sorted(lambda x: x.discount_date or x.date_maturity)
|
|
self.assertRecordValues(
|
|
inv_line1_with_epd_rec_lines,
|
|
[
|
|
{
|
|
'amount_currency': 16344.0,
|
|
'balance': 2724.0,
|
|
'discount_amount_currency': 14904.0,
|
|
'discount_balance': 2484.0,
|
|
'discount_date': fields.Date.from_string('2016-12-11'),
|
|
'date_maturity': fields.Date.from_string('2016-12-21'),
|
|
},
|
|
],
|
|
)
|
|
|
|
inv_line2_with_epd = self._create_invoice_line(
|
|
'out_invoice',
|
|
currency_id=self.currency_data_2['currency'].id,
|
|
partner_id=self.partner_a.id,
|
|
invoice_payment_term_id=self.early_payment_term.id,
|
|
invoice_date='2017-01-20',
|
|
invoice_line_ids=[
|
|
{
|
|
'price_unit': 480.0,
|
|
'account_id': self.account_revenue1.id,
|
|
'tax_ids': [Command.set(self.company_data['default_tax_sale'].ids)],
|
|
},
|
|
{
|
|
'price_unit': 960.0,
|
|
'account_id': self.account_revenue2.id,
|
|
'tax_ids': [Command.set(self.company_data['default_tax_sale'].ids)],
|
|
},
|
|
],
|
|
)
|
|
inv_line2_with_epd_rec_lines = inv_line2_with_epd.move_id.line_ids\
|
|
.filtered(lambda x: x.account_type == 'asset_receivable')\
|
|
.sorted(lambda x: x.discount_date or x.date_maturity)
|
|
self.assertRecordValues(
|
|
inv_line2_with_epd_rec_lines,
|
|
[
|
|
{
|
|
'amount_currency': 1634.4,
|
|
'balance': 408.6,
|
|
'discount_amount_currency': 1490.4,
|
|
'discount_balance': 372.6,
|
|
'discount_date': fields.Date.from_string('2017-01-30'),
|
|
'date_maturity': fields.Date.from_string('2017-02-09'),
|
|
},
|
|
],
|
|
)
|
|
|
|
# inv1: 16344.0 (no epd)
|
|
# inv2: 1490.4 (epd)
|
|
st_line = self._create_st_line(
|
|
4458.0, # instead of 4458.6 (rate 1:4)
|
|
date='2017-01-04',
|
|
foreign_currency_id=self.currency_data_2['currency'].id,
|
|
amount_currency=17834.4,
|
|
)
|
|
|
|
wizard = self.env['bank.rec.widget'].with_context(default_st_line_id=st_line.id).new({})
|
|
|
|
# Add all lines from the first invoice plus the first one from the second one.
|
|
wizard._action_add_new_amls(inv_line1_with_epd_rec_lines + inv_line2_with_epd_rec_lines[:2])
|
|
liquidity_acc = st_line.journal_id.default_account_id
|
|
receivable_acc = self.company_data['default_account_receivable']
|
|
early_pay_acc = self.env.company.account_journal_early_pay_discount_loss_account_id
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'amount_currency': 4458.0, 'balance': 4458.0, 'account_id': liquidity_acc.id},
|
|
{'flag': 'new_aml', 'amount_currency': -16344.0, 'balance': -2724.0, 'account_id': receivable_acc.id},
|
|
{'flag': 'exchange_diff', 'amount_currency': 0.0, 'balance': -1361.45, 'account_id': income_exchange_account.id},
|
|
{'flag': 'new_aml', 'amount_currency': -1634.4, 'balance': -408.6, 'account_id': receivable_acc.id},
|
|
{'flag': 'exchange_diff', 'amount_currency': 0.0, 'balance': 0.05, 'account_id': expense_exchange_account.id},
|
|
{'flag': 'early_payment', 'amount_currency': 144.0, 'balance': 36.0, 'account_id': early_pay_acc.id},
|
|
])
|
|
|
|
def test_early_payment_included_intracomm_bill(self):
|
|
tax_tags = self.env['account.account.tag'].create({
|
|
'name': f'tax_tag_{i}',
|
|
'applicability': 'taxes',
|
|
'country_id': self.env.company.account_fiscal_country_id.id,
|
|
} for i in range(6))
|
|
|
|
intracomm_tax = self.env['account.tax'].create({
|
|
'name': 'tax20',
|
|
'amount_type': 'percent',
|
|
'amount': 20,
|
|
'type_tax_use': 'purchase',
|
|
'invoice_repartition_line_ids': [
|
|
# pylint: disable=bad-whitespace
|
|
Command.create({'repartition_type': 'base', 'factor_percent': 100.0, 'tag_ids': [Command.set(tax_tags[0].ids)]}),
|
|
Command.create({'repartition_type': 'tax', 'factor_percent': 100.0, 'tag_ids': [Command.set(tax_tags[1].ids)]}),
|
|
Command.create({'repartition_type': 'tax', 'factor_percent': -100.0, 'tag_ids': [Command.set(tax_tags[2].ids)]}),
|
|
],
|
|
'refund_repartition_line_ids': [
|
|
# pylint: disable=bad-whitespace
|
|
Command.create({'repartition_type': 'base', 'factor_percent': 100.0, 'tag_ids': [Command.set(tax_tags[3].ids)]}),
|
|
Command.create({'repartition_type': 'tax', 'factor_percent': 100.0, 'tag_ids': [Command.set(tax_tags[4].ids)]}),
|
|
Command.create({'repartition_type': 'tax', 'factor_percent': -100.0, 'tag_ids': [Command.set(tax_tags[5].ids)]}),
|
|
],
|
|
})
|
|
|
|
early_payment_term = self.env['account.payment.term'].create({
|
|
'name': "early_payment_term",
|
|
'company_id': self.company_data['company'].id,
|
|
'early_pay_discount_computation': 'included',
|
|
'early_discount': True,
|
|
'discount_percentage': 2,
|
|
'discount_days': 7,
|
|
'line_ids': [
|
|
Command.create({
|
|
'value': 'percent',
|
|
'value_amount': 100.0,
|
|
'nb_days': 30,
|
|
}),
|
|
],
|
|
})
|
|
|
|
bill = self.env['account.move'].create({
|
|
'move_type': 'in_invoice',
|
|
'partner_id': self.partner_a.id,
|
|
'invoice_payment_term_id': early_payment_term.id,
|
|
'invoice_date': '2019-01-01',
|
|
'date': '2019-01-01',
|
|
'invoice_line_ids': [
|
|
Command.create({
|
|
'name': 'line',
|
|
'price_unit': 1000.0,
|
|
'tax_ids': [Command.set(intracomm_tax.ids)],
|
|
}),
|
|
],
|
|
})
|
|
bill.action_post()
|
|
|
|
st_line = self._create_st_line(
|
|
-980.0,
|
|
date='2017-01-01',
|
|
)
|
|
|
|
wizard = self.env['bank.rec.widget'].with_context(default_st_line_id=st_line.id).new({})
|
|
wizard._action_add_new_amls(bill.line_ids.filtered(lambda x: x.account_type == 'liability_payable'))
|
|
wizard._action_validate()
|
|
|
|
self.assertRecordValues(st_line.line_ids.sorted('balance'), [
|
|
# pylint: disable=bad-whitespace
|
|
{'amount_currency': -980.0, 'tax_ids': [], 'tax_tag_ids': [], 'tax_tag_invert': False},
|
|
{'amount_currency': -20.0, 'tax_ids': intracomm_tax.ids, 'tax_tag_ids': tax_tags[3].ids, 'tax_tag_invert': True},
|
|
{'amount_currency': -4.0, 'tax_ids': [], 'tax_tag_ids': tax_tags[4].ids, 'tax_tag_invert': True},
|
|
{'amount_currency': 4.0, 'tax_ids': [], 'tax_tag_ids': tax_tags[5].ids, 'tax_tag_invert': True},
|
|
{'amount_currency': 1000.0, 'tax_ids': [], 'tax_tag_ids': [], 'tax_tag_invert': False},
|
|
])
|
|
|
|
def test_multi_currencies_with_custom_rate(self):
|
|
self.company_data['default_journal_bank'].currency_id = self.currency_data['currency']
|
|
st_line = self._create_st_line(1200.0) # rate 1:2
|
|
self.assertRecordValues(st_line.move_id.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'amount_currency': 1200.0, 'balance': 600.0},
|
|
{'amount_currency': -1200.0, 'balance': -600.0},
|
|
])
|
|
|
|
# invoice with currency_data and rate 1:2
|
|
invoice_line1 = self._create_invoice_line(
|
|
'out_invoice',
|
|
currency_id=self.currency_data['currency'].id,
|
|
invoice_date='2017-01-01',
|
|
invoice_line_ids=[{'price_unit': 300.0}], # = 150 USD
|
|
)
|
|
|
|
# Remove all rates.
|
|
self.currency_data['rates'].unlink()
|
|
|
|
wizard = self.env['bank.rec.widget'].with_context(default_st_line_id=st_line.id).new({})
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'amount_currency': 1200.0, 'balance': 600.0},
|
|
{'flag': 'auto_balance', 'amount_currency': -1200.0, 'balance': -600.0},
|
|
])
|
|
|
|
# invoice with currency_data_2 and rate 1:6
|
|
invoice_line2 = self._create_invoice_line(
|
|
'out_invoice',
|
|
currency_id=self.currency_data_2['currency'].id,
|
|
invoice_date='2016-01-01',
|
|
invoice_line_ids=[{'price_unit': 600.0}], # = 100 USD
|
|
)
|
|
# invoice with currency_data_2 and rate 1:4
|
|
invoice_line3 = self._create_invoice_line(
|
|
'out_invoice',
|
|
currency_id=self.currency_data_2['currency'].id,
|
|
invoice_date='2017-01-01',
|
|
invoice_line_ids=[{'price_unit': 400.0}], # = 100 USD
|
|
)
|
|
|
|
# Remove all rates.
|
|
self.currency_data_2['rates'].unlink()
|
|
|
|
# Ensure no conversion rate has been made.
|
|
wizard._action_add_new_amls(invoice_line1 + invoice_line2 + invoice_line3)
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'amount_currency': 1200.0, 'balance': 600.0},
|
|
{'flag': 'new_aml', 'amount_currency': -300.0, 'balance': -150.0},
|
|
{'flag': 'new_aml', 'amount_currency': -600.0, 'balance': -100.0},
|
|
{'flag': 'new_aml', 'amount_currency': -400.0, 'balance': -100.0},
|
|
{'flag': 'auto_balance', 'amount_currency': -500.0, 'balance': -250.0},
|
|
])
|
|
|
|
def test_partial_reconciliation_suggestion_with_mixed_invoice_and_refund(self):
|
|
""" Test the partial reconciliation suggestion is well recomputed when adding another
|
|
line. For example, when adding 2 invoices having an higher amount then a refund. In that
|
|
case, the partial on the second invoice should be removed since the difference is filled
|
|
by the newly added refund.
|
|
"""
|
|
st_line = self._create_st_line(
|
|
1800.0,
|
|
date='2017-01-01',
|
|
foreign_currency_id=self.currency_data['currency'].id,
|
|
amount_currency=3600.0,
|
|
)
|
|
|
|
inv1 = self._create_invoice_line(
|
|
'out_invoice',
|
|
currency_id=self.currency_data['currency'].id,
|
|
invoice_date='2016-01-01',
|
|
invoice_line_ids=[{'price_unit': 2400.0}],
|
|
)
|
|
inv2 = self._create_invoice_line(
|
|
'out_invoice',
|
|
currency_id=self.currency_data['currency'].id,
|
|
invoice_date='2016-01-01',
|
|
invoice_line_ids=[{'price_unit': 2400.0}],
|
|
)
|
|
refund = self._create_invoice_line(
|
|
'out_refund',
|
|
currency_id=self.currency_data['currency'].id,
|
|
invoice_date='2016-01-01',
|
|
invoice_line_ids=[{'price_unit': 1200.0}],
|
|
)
|
|
|
|
wizard = self.env['bank.rec.widget'].with_context(default_st_line_id=st_line.id).new({})
|
|
wizard._action_add_new_amls(inv1 + inv2)
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'amount_currency': 1800.0, 'balance': 1800.0},
|
|
{'flag': 'new_aml', 'amount_currency': -2400.0, 'balance': -800.0},
|
|
{'flag': 'exchange_diff', 'amount_currency': 0.0, 'balance': -400.0},
|
|
{'flag': 'new_aml', 'amount_currency': -1200.0, 'balance': -400.0},
|
|
{'flag': 'exchange_diff', 'amount_currency': 0.0, 'balance': -200.0},
|
|
])
|
|
wizard._action_add_new_amls(refund)
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'amount_currency': 1800.0, 'balance': 1800.0},
|
|
{'flag': 'new_aml', 'amount_currency': -2400.0, 'balance': -800.0},
|
|
{'flag': 'exchange_diff', 'amount_currency': 0.0, 'balance': -400.0},
|
|
{'flag': 'new_aml', 'amount_currency': -2400.0, 'balance': -800.0},
|
|
{'flag': 'exchange_diff', 'amount_currency': 0.0, 'balance': -400.0},
|
|
{'flag': 'new_aml', 'amount_currency': 1200.0, 'balance': 400.0},
|
|
{'flag': 'exchange_diff', 'amount_currency': 0.0, 'balance': 200.0},
|
|
])
|
|
|
|
def test_auto_reconcile_cron_with_time_limit(self):
|
|
self.env['account.reconcile.model'].search([('company_id', '=', self.company_data['company'].id)]).unlink()
|
|
cron = self.env.ref('account_accountant.auto_reconcile_bank_statement_line')
|
|
self.env['ir.cron.trigger'].search([('cron_id', '=', cron.id)]).unlink()
|
|
|
|
st_line1 = self._create_st_line(1234.0, partner_id=self.partner_a.id, date='2017-01-01')
|
|
self.assertEqual(len(self.env['ir.cron.trigger'].search([('cron_id', '=', cron.id)])), 1)
|
|
st_line2 = self._create_st_line(5678.0, partner_id=self.partner_a.id, date='2017-01-02')
|
|
self.assertEqual(len(self.env['ir.cron.trigger'].search([('cron_id', '=', cron.id)])), 2)
|
|
|
|
self._create_invoice_line(
|
|
'out_invoice',
|
|
invoice_date='2017-01-01',
|
|
invoice_line_ids=[{'price_unit': 1234.0}],
|
|
)
|
|
self._create_invoice_line(
|
|
'out_invoice',
|
|
invoice_date='2017-01-01',
|
|
invoice_line_ids=[{'price_unit': 5678.0}],
|
|
)
|
|
self.env['account.reconcile.model'].create({
|
|
'name': "test_auto_reconcile_cron_with_time_limit",
|
|
'rule_type': 'writeoff_suggestion',
|
|
'auto_reconcile': True,
|
|
'line_ids': [Command.create({'account_id': self.account_revenue1.id})],
|
|
})
|
|
|
|
with freeze_time('2017-01-01 00:00:00') as frozen_time:
|
|
def datetime_now_override():
|
|
frozen_time.tick()
|
|
return frozen_time()
|
|
with patch('odoo.fields.Datetime.now', side_effect=datetime_now_override):
|
|
# we simulate that the time limit is reached after first loop
|
|
self.env['account.bank.statement.line']._cron_try_auto_reconcile_statement_lines(limit_time=1)
|
|
# after first loop, only one statement should be reconciled
|
|
self.assertRecordValues(st_line1, [{'is_reconciled': True, 'cron_last_check': fields.Datetime.from_string('2017-01-01 00:00:01')}])
|
|
# the other one should be in queue for regular cron tigger
|
|
self.assertRecordValues(st_line2, [{'is_reconciled': False, 'cron_last_check': False}])
|
|
self.assertEqual(len(self.env['ir.cron.trigger'].search([('cron_id', '=', cron.id)])), 3)
|
|
|
|
def test_auto_reconcile_cron_with_provided_statements_lines(self):
|
|
self.env['account.reconcile.model'].search([('company_id', '=', self.company_data['company'].id)]).unlink()
|
|
|
|
st_line1 = self._create_st_line(1234.0, partner_id=self.partner_a.id, date='2017-01-01')
|
|
st_line2 = self._create_st_line(5678.0, partner_id=self.partner_a.id, date='2017-01-02')
|
|
self._create_invoice_line(
|
|
'out_invoice',
|
|
invoice_date='2017-01-01',
|
|
invoice_line_ids=[{'price_unit': 1234.0}],
|
|
)
|
|
self._create_invoice_line(
|
|
'out_invoice',
|
|
invoice_date='2017-01-01',
|
|
invoice_line_ids=[{'price_unit': 5678.0}],
|
|
)
|
|
self.env['account.reconcile.model'].create({
|
|
'name': "test_auto_reconcile_cron_with_time_limit",
|
|
'rule_type': 'writeoff_suggestion',
|
|
'auto_reconcile': True,
|
|
'line_ids': [Command.create({'account_id': self.account_revenue1.id})],
|
|
})
|
|
with freeze_time('2017-01-01 00:00:00'):
|
|
# we call auto reconcile on st_lines1 **only**
|
|
st_line1._cron_try_auto_reconcile_statement_lines()
|
|
self.assertRecordValues(st_line1, [{'is_reconciled': True, 'cron_last_check': fields.Datetime.from_string('2017-01-01 00:00:00')}])
|
|
self.assertRecordValues(st_line2, [{'is_reconciled': False, 'cron_last_check': False}])
|
|
|
|
@freeze_time('2019-01-01')
|
|
def test_button_apply_reco_model(self):
|
|
st_line = self._create_st_line(-1000.0, partner_id=self.partner_a.id)
|
|
inv_line = self._create_invoice_line(
|
|
'in_invoice',
|
|
invoice_date=st_line.date,
|
|
invoice_line_ids=[{'price_unit': 980.0}],
|
|
)
|
|
|
|
reco_model = self.env['account.reconcile.model'].create({
|
|
'name': "test_apply_taxes_with_reco_model",
|
|
'rule_type': 'writeoff_button',
|
|
'line_ids': [Command.create({
|
|
'account_id': self.account_revenue1.copy().id,
|
|
'label': 'Bank Fees'
|
|
})],
|
|
})
|
|
|
|
wizard = self.env['bank.rec.widget'].with_context(default_st_line_id=st_line.id).new({})
|
|
wizard._action_trigger_matching_rules()
|
|
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'account_id': st_line.journal_id.default_account_id.id, 'balance': -1000.0},
|
|
{'flag': 'new_aml', 'account_id': inv_line.account_id.id, 'balance': 980.0},
|
|
{'flag': 'auto_balance', 'account_id': self.company_data['default_account_payable'].id, 'balance': 20.0},
|
|
])
|
|
|
|
wizard._action_select_reconcile_model(reco_model)
|
|
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'account_id': st_line.journal_id.default_account_id.id, 'balance': -1000.0},
|
|
{'flag': 'new_aml', 'account_id': inv_line.account_id.id, 'balance': 980.0},
|
|
{'flag': 'manual', 'account_id': reco_model.line_ids[0].account_id.id, 'balance': 20.0},
|
|
])
|
|
|
|
def test_exchange_diff_on_partial_aml_multi_currency(self):
|
|
self.company_data['default_journal_bank'].currency_id = self.currency_data['currency']
|
|
st_line = self._create_st_line(-36000.0) # rate 1:2
|
|
inv_line = self._create_invoice_line(
|
|
'in_invoice',
|
|
invoice_date='2016-01-01', # rate 1:3
|
|
currency_id=self.currency_data['currency'].id,
|
|
invoice_line_ids=[{'price_unit': 38000.0}],
|
|
)
|
|
|
|
wizard = self.env['bank.rec.widget'].with_context(default_st_line_id=st_line.id).new({})
|
|
wizard._action_add_new_amls(inv_line)
|
|
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'amount_currency': -36000.0, 'currency_id': self.currency_data['currency'].id, 'balance': -18000.0},
|
|
{'flag': 'new_aml', 'amount_currency': 36000.0, 'currency_id': self.currency_data['currency'].id, 'balance': 12000.0},
|
|
{'flag': 'exchange_diff', 'amount_currency': 0.0, 'currency_id': self.currency_data['currency'].id, 'balance': 6000.0},
|
|
])
|
|
|
|
def test_exchange_diff_on_partial_aml_multi_currency_close_amount(self):
|
|
self.currency_data['rates'].rate = 0.9839
|
|
self.company_data['default_journal_bank'].currency_id = self.currency_data['currency']
|
|
|
|
st_line = self._create_st_line(-37436.50)
|
|
self.assertRecordValues(st_line.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'amount_currency': -37436.50, 'balance': -38049.09},
|
|
{'amount_currency': 37436.50, 'balance': 38049.09},
|
|
])
|
|
|
|
inv_line = self._create_invoice_line(
|
|
'in_invoice',
|
|
invoice_date=st_line.date,
|
|
currency_id=self.currency_data['currency'].id,
|
|
invoice_line_ids=[{'price_unit': 37436.52}],
|
|
)
|
|
self.assertRecordValues(inv_line, [{
|
|
'amount_currency': -37436.52,
|
|
'balance': -38049.11,
|
|
}])
|
|
|
|
wizard = self.env['bank.rec.widget'].with_context(default_st_line_id=st_line.id).new({})
|
|
wizard._action_add_new_amls(inv_line)
|
|
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'amount_currency': -37436.50, 'currency_id': self.currency_data['currency'].id, 'balance': -38049.09},
|
|
{'flag': 'new_aml', 'amount_currency': 37436.50, 'currency_id': self.currency_data['currency'].id, 'balance': 38049.09},
|
|
])
|
|
|
|
def test_matching_zero_amount_misc_entry(self):
|
|
""" Check for division by zero with foreign currencies and some 0 making a broken rate. """
|
|
self.company_data['default_journal_bank'].currency_id = self.currency_data['currency']
|
|
st_line = self._create_st_line(0.0, amount_currency=10.0, foreign_currency_id=self.company_data['currency'].id)
|
|
|
|
entry = self.env['account.move'].create({
|
|
'date': '2019-01-01',
|
|
'line_ids': [
|
|
Command.create({
|
|
'account_id': self.company_data['default_account_receivable'].id,
|
|
'currency_id': self.currency_data['currency'].id,
|
|
'debit': 1.0,
|
|
'credit': 0.0,
|
|
}),
|
|
Command.create({
|
|
'account_id': self.company_data['default_account_revenue'].id,
|
|
'currency_id': self.currency_data['currency'].id,
|
|
'debit': 0.0,
|
|
'credit': 1.0,
|
|
}),
|
|
]
|
|
})
|
|
entry.action_post()
|
|
|
|
wizard = self.env['bank.rec.widget'].with_context(default_st_line_id=st_line.id).new({})
|
|
aml = entry.line_ids.filtered('debit')
|
|
wizard._action_add_new_amls(aml)
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'balance': 10.0},
|
|
{'flag': 'new_aml', 'balance': -1.0},
|
|
{'flag': 'exchange_diff', 'balance': 1.0},
|
|
{'flag': 'auto_balance', 'balance': -10.0},
|
|
])
|
|
|
|
def test_amls_order_with_matching_amount(self):
|
|
""" AML's with a matching amount_residual should be displayed first when the order is not specified. """
|
|
|
|
foreign_st_line = self._create_st_line(
|
|
500.0,
|
|
date='2016-01-01',
|
|
foreign_currency_id=self.currency_data['currency'].id,
|
|
amount_currency=1500.0,
|
|
)
|
|
st_line = self._create_st_line(
|
|
66.66,
|
|
date='2016-01-01',
|
|
)
|
|
wizard = self.env['bank.rec.widget'].with_context(default_st_line_id=foreign_st_line.id).new({})
|
|
|
|
aml1_id = self._create_invoice_line(
|
|
'out_invoice',
|
|
invoice_date='2017-01-30',
|
|
invoice_line_ids=[{'price_unit': 1000.0}],
|
|
).id
|
|
aml2_id = self._create_invoice_line(
|
|
'out_invoice',
|
|
invoice_date='2017-01-29',
|
|
currency_id=self.currency_data['currency'].id,
|
|
invoice_line_ids=[{'price_unit': 1500.0}], # = 100 USD
|
|
).id
|
|
aml3_id = self._create_invoice_line(
|
|
'out_invoice',
|
|
invoice_date='2017-01-28',
|
|
invoice_line_ids=[{'price_unit': 500.0}],
|
|
).id
|
|
aml4_id = self._create_invoice_line(
|
|
'out_invoice',
|
|
invoice_date='2017-01-27',
|
|
invoice_line_ids=[{'price_unit': 55.55}], # = 55.550000000000004
|
|
).id
|
|
aml5_id = self._create_invoice_line(
|
|
'out_invoice',
|
|
invoice_date='2017-01-26',
|
|
invoice_line_ids=[{'price_unit': 66.66}],
|
|
).id
|
|
|
|
# Check the lines without the context key.
|
|
wizard._js_action_mount_st_line(foreign_st_line.id)
|
|
domain = wizard.return_todo_command['amls']['domain']
|
|
amls_list = self.env['account.move.line'].search_fetch(domain=domain, field_names=['id'])
|
|
self.assertEqual(
|
|
[x['id'] for x in amls_list],
|
|
[aml1_id, aml2_id, aml3_id, aml4_id, aml5_id],
|
|
)
|
|
|
|
# Check the lines with the context key.
|
|
suspense_line = wizard.line_ids.filtered(lambda l: l.flag == 'auto_balance')
|
|
amls_list = self.env['account.move.line']\
|
|
.with_context(preferred_aml_value=suspense_line.amount_currency * -1, preferred_aml_currency_id=suspense_line.currency_id.id)\
|
|
.search_fetch(domain=domain, field_names=['id'])
|
|
self.assertEqual(
|
|
[x['id'] for x in amls_list],
|
|
[aml2_id, aml1_id, aml3_id, aml4_id, aml5_id],
|
|
)
|
|
|
|
# Check the order with limits and offsets
|
|
amls_list = self.env['account.move.line']\
|
|
.with_context(preferred_aml_value=suspense_line.amount_currency * -1, preferred_aml_currency_id=suspense_line.currency_id.id)\
|
|
.search_fetch(domain=domain, field_names=['id'], limit=2)
|
|
self.assertEqual(
|
|
[x['id'] for x in amls_list],
|
|
[aml2_id, aml1_id],
|
|
)
|
|
amls_list = self.env['account.move.line']\
|
|
.with_context(preferred_aml_value=suspense_line.amount_currency * -1, preferred_aml_currency_id=suspense_line.currency_id.id)\
|
|
.search_fetch(domain=domain, field_names=['id'], offset=2, limit=3)
|
|
self.assertEqual(
|
|
[x['id'] for x in amls_list],
|
|
[aml3_id, aml4_id, aml5_id],
|
|
)
|
|
|
|
# Check rounding and new suspense line
|
|
wizard._js_action_mount_st_line(st_line.id)
|
|
suspense_line = wizard.line_ids.filtered(lambda l: l.flag == 'auto_balance')
|
|
amls_list = self.env['account.move.line']\
|
|
.with_context(preferred_aml_value=suspense_line.amount_currency * -1, preferred_aml_currency_id=suspense_line.currency_id.id)\
|
|
.search_fetch(domain=domain, field_names=['id'])
|
|
self.assertEqual(
|
|
[x['id'] for x in amls_list],
|
|
[aml5_id, aml1_id, aml2_id, aml3_id, aml4_id],
|
|
)
|
|
wizard._js_action_mount_line_in_edit(suspense_line.index)
|
|
suspense_line.balance = -11.11
|
|
wizard._line_value_changed_balance(suspense_line)
|
|
suspense_line = wizard.line_ids.filtered(lambda l: l.flag == 'auto_balance')
|
|
self.assertEqual(suspense_line.balance, -55.55)
|
|
self.env.cr.execute(f"""
|
|
UPDATE account_move_line SET amount_residual_currency = 55.550000001 WHERE id = {aml4_id};
|
|
""")
|
|
amls_list = self.env['account.move.line']\
|
|
.with_context(preferred_aml_value=55.550003, preferred_aml_currency_id=suspense_line.currency_id.id)\
|
|
.search_fetch(domain=domain, field_names=['id'])
|
|
self.assertEqual(
|
|
[x['id'] for x in amls_list],
|
|
[aml4_id, aml1_id, aml2_id, aml3_id, aml5_id],
|
|
)
|
|
|
|
# Check that context keys are not propagated
|
|
action = amls_list[0].action_open_business_doc()
|
|
self.assertFalse(action['context'].get('preferred_aml_value'))
|
|
|
|
@freeze_time('2023-12-25')
|
|
def test_analtyic_distribution_model_exchange_diff_line(self):
|
|
"""Test that the analytic distribution model is present on the exchange diff line."""
|
|
expense_exchange_account = self.env.company.expense_currency_exchange_account_id
|
|
analytic_plan = self.env['account.analytic.plan'].create({
|
|
'name': 'Plan 1',
|
|
'default_applicability': 'unavailable',
|
|
})
|
|
analytic_account_1 = self.env['account.analytic.account'].create({'name': 'Account 1', 'plan_id': analytic_plan.id})
|
|
analytic_account_2 = self.env['account.analytic.account'].create({'name': 'Account 1', 'plan_id': analytic_plan.id})
|
|
distribution_model = self.env['account.analytic.distribution.model'].create({
|
|
'account_prefix': expense_exchange_account.code,
|
|
'partner_id': self.partner_a.id,
|
|
'analytic_distribution': {analytic_account_1.id: 100},
|
|
})
|
|
|
|
# 1200.0 comp_curr = 3600.0 foreign_curr in 2016 (rate 1:3)
|
|
st_line = self._create_st_line(
|
|
1200.0,
|
|
date='2016-01-01',
|
|
)
|
|
# 1800.0 comp_curr = 3600.0 foreign_curr in 2017 (rate 1:2)
|
|
inv_line = self._create_invoice_line(
|
|
'out_invoice',
|
|
currency_id=self.currency_data['currency'].id,
|
|
invoice_date='2017-01-01',
|
|
invoice_line_ids=[{'price_unit': 3600.0}],
|
|
)
|
|
|
|
wizard = self.env['bank.rec.widget'].with_context(default_st_line_id=st_line.id).new({})
|
|
wizard._action_add_new_amls(inv_line)
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'amount_currency': 1200.0, 'currency_id': self.company_data['currency'].id, 'balance': 1200.0, 'analytic_distribution': False},
|
|
{'flag': 'new_aml', 'amount_currency': -3600.0, 'currency_id': self.currency_data['currency'].id, 'balance': -1800.0, 'analytic_distribution': False},
|
|
{'flag': 'exchange_diff', 'amount_currency': 0.0, 'currency_id': self.currency_data['currency'].id, 'balance': 600.0, 'analytic_distribution': distribution_model.analytic_distribution},
|
|
])
|
|
|
|
# Test that the analytic distribution is kept on the creation of the exchange diff move
|
|
new_distribution = {**distribution_model.analytic_distribution, str(analytic_account_2.id): 100}
|
|
|
|
line = wizard.line_ids.filtered(lambda x: x.flag == 'exchange_diff')
|
|
line.analytic_distribution = new_distribution
|
|
wizard._action_validate()
|
|
|
|
self.assertRecordValues(inv_line.matched_credit_ids.exchange_move_id.line_ids, [
|
|
{'analytic_distribution': False},
|
|
{'analytic_distribution': new_distribution},
|
|
])
|
|
|
|
def test_access_child_bank_with_user_set_on_child(self):
|
|
"""
|
|
Demo user with a Child Company as default company/allowed companies
|
|
should be able to access the Bank set on this same Child Company
|
|
"""
|
|
child_company = self.env['res.company'].create({
|
|
'name': 'Childest Company',
|
|
'parent_id': self.env.company.id,
|
|
})
|
|
child_bank_journal = self.env['account.journal'].create({
|
|
'name': 'Child Bank',
|
|
'type': 'bank',
|
|
'company_id': child_company.id,
|
|
})
|
|
self.user.write({
|
|
'company_ids': [Command.set(child_company.ids)],
|
|
'company_id': child_company.id,
|
|
'groups_id': [
|
|
Command.set(self.env.ref('account.group_account_user').ids),
|
|
]
|
|
})
|
|
res = self.env['bank.rec.widget'].with_user(self.user).collect_global_info_data(child_bank_journal.id)
|
|
self.assertTrue(res, "Journal should be accessible")
|
|
|
|
def test_collect_global_info_data_other_company_bank_journal_with_user_on_main_company(self):
|
|
""" The aim of this test is checking that a user who having
|
|
access to 2 companies will have values even when he's
|
|
calling collect_global_info_data function if
|
|
it's current company it's not the one on the journal
|
|
but is still available.
|
|
To do that, we add 2 companies to the user, and try to
|
|
call collect_global_info_data on the journal of the second
|
|
company, even if the main company it's the first one.
|
|
"""
|
|
self.user.write({
|
|
'company_ids': [Command.set((self.company_data['company'] + self.company_data_2['company']).ids)],
|
|
'company_id': self.company_data['company'].id,
|
|
})
|
|
|
|
result = self.env['bank.rec.widget'].with_user(self.user).collect_global_info_data(self.company_data_2['default_journal_bank'].id)
|
|
self.assertTrue(result['balance_amount'], "Balance amount shouldn't be False value")
|
|
|
|
def test_collect_global_info_data_non_existing_bank_journal(self):
|
|
""" The aim of this test is checking that we receive an empty
|
|
string when we call collect_global_info_data function
|
|
with a non-existing journal. This use case could happen
|
|
when we try to open the bank rec widget on a journal that
|
|
is not actually existing. As this function is callable by
|
|
rpc, this usecase could happen.
|
|
"""
|
|
result = self.env['bank.rec.widget'].with_user(self.user).collect_global_info_data(99999999)
|
|
self.assertEqual(result['balance_amount'], "", "If no value, the function should return an empty string")
|
|
|
|
def test_res_partner_bank_find_create_multi_account(self):
|
|
""" Make sure that we can save multiple bank accounts for a partner. """
|
|
partner = self.env['res.partner'].create({'name': "Zitycard"})
|
|
|
|
for acc_number in ("123456789", "123456780"):
|
|
st_line = self._create_st_line(100.0, account_number=acc_number)
|
|
inv_line = self._create_invoice_line(
|
|
'out_invoice',
|
|
partner_id=partner.id,
|
|
invoice_line_ids=[{'price_unit': 100.0, 'tax_ids': []}],
|
|
)
|
|
wizard = self.env['bank.rec.widget'].with_context(default_st_line_id=st_line.id).new({})
|
|
wizard._action_add_new_amls(inv_line)
|
|
wizard._action_validate()
|
|
|
|
bank_accounts = self.env['res.partner.bank'].sudo().with_context(active_test=False).search([
|
|
('partner_id', '=', partner.id),
|
|
])
|
|
self.assertEqual(len(bank_accounts), 2, "Second bank account was not registered!")
|
|
|
|
def test_unreconciled_with_other_lines(self):
|
|
"""Test that other lines are shown in the widget if they exist."""
|
|
st_line = self._create_st_line(
|
|
1000.0,
|
|
date='2017-01-01',
|
|
)
|
|
|
|
# Edit the associated move to partially reconcile some of the suspense amount; i.e. we add another line
|
|
liquidity_line, suspense_line, other_line = st_line._seek_for_lines()
|
|
other_account = st_line.journal_id.company_id.default_cash_difference_income_account_id
|
|
self.assertFalse(other_line)
|
|
st_line.move_id.write({'line_ids': [
|
|
Command.create({'account_id': other_account.id, 'credit': 100.0}),
|
|
Command.update(suspense_line.id, {'credit': 900.0}),
|
|
]})
|
|
liquidity_line, suspense_line, other_line = st_line._seek_for_lines()
|
|
self.assertTrue(other_line)
|
|
|
|
# Check that the wizard displays the new line
|
|
wizard = self.env['bank.rec.widget'].with_context(default_st_line_id=st_line.id).new({})
|
|
self.assertRecordValues(wizard.line_ids, [
|
|
# pylint: disable=C0326
|
|
{'flag': 'liquidity', 'account_id': liquidity_line.account_id.id, 'amount_currency': 1000.0},
|
|
{'flag': 'aml', 'account_id': other_line.account_id.id, 'amount_currency': -100.0},
|
|
{'flag': 'auto_balance', 'account_id': suspense_line.account_id.id, 'amount_currency': -900.0},
|
|
])
|