4853 lines
224 KiB
Python
4853 lines
224 KiB
Python
|
# -*- coding: utf-8 -*-
|
||
|
# pylint: disable=C0326
|
||
|
from contextlib import contextmanager
|
||
|
|
||
|
from odoo.addons.account.tests.common import AccountTestInvoicingCommon
|
||
|
from odoo.tests import tagged
|
||
|
from odoo.tests.common import Form
|
||
|
from odoo import fields, Command
|
||
|
|
||
|
|
||
|
@tagged('post_install', '-at_install')
|
||
|
class TestAccountMoveReconcile(AccountTestInvoicingCommon):
|
||
|
''' Tests about the account.partial.reconcile model, not the reconciliation itself but mainly the computation of
|
||
|
the residual amounts on account.move.line.
|
||
|
'''
|
||
|
|
||
|
@classmethod
|
||
|
def setUpClass(cls, chart_template_ref=None):
|
||
|
super().setUpClass(chart_template_ref=chart_template_ref)
|
||
|
|
||
|
cls.receivable_account = cls.company_data['default_account_receivable']
|
||
|
cls.payable_account = cls.company_data['default_account_payable']
|
||
|
cls.expense_account = cls.company_data['default_account_expense']
|
||
|
cls.revenue_account = cls.company_data['default_account_revenue']
|
||
|
|
||
|
cls.extra_receivable_account_1 = cls.copy_account(cls.receivable_account)
|
||
|
cls.extra_receivable_account_2 = cls.copy_account(cls.receivable_account)
|
||
|
cls.extra_payable_account_1 = cls.copy_account(cls.company_data['default_account_payable'])
|
||
|
cls.extra_payable_account_2 = cls.copy_account(cls.company_data['default_account_payable'])
|
||
|
|
||
|
cls.exch_income_account = cls.env.company.income_currency_exchange_account_id
|
||
|
cls.exch_expense_account = cls.env.company.expense_currency_exchange_account_id
|
||
|
|
||
|
|
||
|
# ==== Multi-currency setup ====
|
||
|
|
||
|
cls.currency_data_2 = cls.setup_multi_currency_data(default_values={
|
||
|
'name': 'Diamond',
|
||
|
'symbol': '💎',
|
||
|
'currency_unit_label': 'Diamond',
|
||
|
'currency_subunit_label': 'Carbon',
|
||
|
}, rate2016=6.0, rate2017=4.0)
|
||
|
cls.currency_data_3 = cls.setup_multi_currency_data(default_values={
|
||
|
'name': 'Sand',
|
||
|
'symbol': 'S',
|
||
|
'currency_unit_label': 'Sand',
|
||
|
'currency_subunit_label': 'Sand',
|
||
|
}, rate2016=0.0001, rate2017=0.00001)
|
||
|
|
||
|
# ==== Cash Basis Taxes setup ====
|
||
|
|
||
|
cls.cash_basis_base_account = cls.env['account.account'].create({
|
||
|
'code': 'cash.basis.base.account',
|
||
|
'name': 'cash_basis_base_account',
|
||
|
'account_type': 'income',
|
||
|
'company_id': cls.company_data['company'].id,
|
||
|
})
|
||
|
cls.company_data['company'].account_cash_basis_base_account_id = cls.cash_basis_base_account
|
||
|
|
||
|
cls.cash_basis_transfer_account = cls.env['account.account'].create({
|
||
|
'code': 'cash.basis.transfer.account',
|
||
|
'name': 'cash_basis_transfer_account',
|
||
|
'account_type': 'income',
|
||
|
'reconcile': True,
|
||
|
'company_id': cls.company_data['company'].id,
|
||
|
})
|
||
|
|
||
|
cls.tax_account_1 = cls.env['account.account'].create({
|
||
|
'code': 'tax.account.1',
|
||
|
'name': 'tax_account_1',
|
||
|
'account_type': 'income',
|
||
|
'company_id': cls.company_data['company'].id,
|
||
|
})
|
||
|
|
||
|
cls.tax_account_2 = cls.env['account.account'].create({
|
||
|
'code': 'tax.account.2',
|
||
|
'name': 'tax_account_2',
|
||
|
'account_type': 'income',
|
||
|
'company_id': cls.company_data['company'].id,
|
||
|
})
|
||
|
|
||
|
cls.fake_country = cls.env['res.country'].create({
|
||
|
'name': "The Island of the Fly",
|
||
|
'code': 'YY',
|
||
|
})
|
||
|
|
||
|
cls.tax_tags = cls.env['account.account.tag'].create({
|
||
|
'name': 'tax_tag_%s' % str(i),
|
||
|
'applicability': 'taxes',
|
||
|
'country_id': cls.company_data['company'].account_fiscal_country_id.id,
|
||
|
} for i in range(8))
|
||
|
|
||
|
cls.cash_basis_tax_a_third_amount = cls.env['account.tax'].create({
|
||
|
'name': 'tax_1',
|
||
|
'amount': 33.3333,
|
||
|
'company_id': cls.company_data['company'].id,
|
||
|
'cash_basis_transition_account_id': cls.cash_basis_transfer_account.id,
|
||
|
'tax_exigibility': 'on_payment',
|
||
|
'invoice_repartition_line_ids': [
|
||
|
(0, 0, {
|
||
|
'repartition_type': 'base',
|
||
|
'tag_ids': [(6, 0, cls.tax_tags[0].ids)],
|
||
|
}),
|
||
|
|
||
|
(0, 0, {
|
||
|
'repartition_type': 'tax',
|
||
|
'account_id': cls.tax_account_1.id,
|
||
|
'tag_ids': [(6, 0, cls.tax_tags[1].ids)],
|
||
|
}),
|
||
|
],
|
||
|
'refund_repartition_line_ids': [
|
||
|
(0, 0, {
|
||
|
'repartition_type': 'base',
|
||
|
'tag_ids': [(6, 0, cls.tax_tags[2].ids)],
|
||
|
}),
|
||
|
|
||
|
(0, 0, {
|
||
|
'repartition_type': 'tax',
|
||
|
'account_id': cls.tax_account_1.id,
|
||
|
'tag_ids': [(6, 0, cls.tax_tags[3].ids)],
|
||
|
}),
|
||
|
],
|
||
|
})
|
||
|
|
||
|
cls.cash_basis_tax_tiny_amount = cls.env['account.tax'].create({
|
||
|
'name': 'cash_basis_tax_tiny_amount',
|
||
|
'amount': 0.0001,
|
||
|
'company_id': cls.company_data['company'].id,
|
||
|
'cash_basis_transition_account_id': cls.cash_basis_transfer_account.id,
|
||
|
'tax_exigibility': 'on_payment',
|
||
|
'invoice_repartition_line_ids': [
|
||
|
(0, 0, {
|
||
|
'repartition_type': 'base',
|
||
|
'tag_ids': [(6, 0, cls.tax_tags[4].ids)],
|
||
|
}),
|
||
|
|
||
|
(0, 0, {
|
||
|
'repartition_type': 'tax',
|
||
|
'account_id': cls.tax_account_2.id,
|
||
|
'tag_ids': [(6, 0, cls.tax_tags[5].ids)],
|
||
|
}),
|
||
|
],
|
||
|
'refund_repartition_line_ids': [
|
||
|
(0, 0, {
|
||
|
'repartition_type': 'base',
|
||
|
'tag_ids': [(6, 0, cls.tax_tags[6].ids)],
|
||
|
}),
|
||
|
|
||
|
(0, 0, {
|
||
|
'repartition_type': 'tax',
|
||
|
'account_id': cls.tax_account_2.id,
|
||
|
'tag_ids': [(6, 0, cls.tax_tags[7].ids)],
|
||
|
}),
|
||
|
],
|
||
|
})
|
||
|
|
||
|
# -------------------------------------------------------------------------
|
||
|
# HELPERS
|
||
|
# -------------------------------------------------------------------------
|
||
|
|
||
|
def assertFullReconcile(self, full_reconcile, lines):
|
||
|
exchange_difference_move = full_reconcile.exchange_move_id
|
||
|
partials = lines.mapped('matched_debit_ids') + lines.mapped('matched_credit_ids')
|
||
|
|
||
|
if full_reconcile.exchange_move_id:
|
||
|
lines += exchange_difference_move.line_ids.filtered(lambda line: line.account_id == lines[0].account_id)
|
||
|
|
||
|
# Use sets to not depend of the order.
|
||
|
self.assertEqual(set(full_reconcile.partial_reconcile_ids), set(partials))
|
||
|
self.assertEqual(set(full_reconcile.reconciled_line_ids), set(lines))
|
||
|
|
||
|
# Ensure there is no residual amount left.
|
||
|
self.assertRecordValues(lines, [{
|
||
|
'amount_residual': 0.0,
|
||
|
'amount_residual_currency': 0.0,
|
||
|
'reconciled': bool(line.account_id.reconcile),
|
||
|
} for line in lines])
|
||
|
|
||
|
def assertFullReconcileAccount(self, full_reconcile, account):
|
||
|
self.assertFullReconcile(full_reconcile, self.env['account.move.line'].search([('account_id', '=', account.id)]))
|
||
|
|
||
|
def assertAmountsGroupByAccount(self, amount_per_account):
|
||
|
expected_values = {account.id: (account, balance, amount_currency) for account, balance, amount_currency in amount_per_account}
|
||
|
|
||
|
if not expected_values:
|
||
|
return
|
||
|
|
||
|
self.cr.execute('''
|
||
|
SELECT
|
||
|
line.account_id,
|
||
|
COALESCE(SUM(line.balance), 0.0) AS total_balance,
|
||
|
COALESCE(SUM(line.amount_currency), 0.0) AS total_amount_currency
|
||
|
FROM account_move_line line
|
||
|
WHERE line.account_id IN %s
|
||
|
GROUP BY line.account_id
|
||
|
''', [tuple(expected_values.keys())])
|
||
|
for account_id, total_balance, total_amount_currency in self.cr.fetchall():
|
||
|
account, expected_balance, expected_amount_currency = expected_values[account_id]
|
||
|
self.assertEqual(
|
||
|
total_balance,
|
||
|
expected_balance,
|
||
|
"Balance of %s is incorrect" % account.name,
|
||
|
)
|
||
|
self.assertEqual(
|
||
|
total_amount_currency,
|
||
|
expected_amount_currency,
|
||
|
"Amount currency of %s is incorrect" % account.name,
|
||
|
)
|
||
|
|
||
|
# -------------------------------------------------------------------------
|
||
|
# Test creation of account.partial.reconcile/account.full.reconcile
|
||
|
# during the reconciliation.
|
||
|
# -------------------------------------------------------------------------
|
||
|
|
||
|
def _get_partials(self, amls):
|
||
|
return (amls.matched_debit_ids | amls.matched_credit_ids).sorted()
|
||
|
|
||
|
def _get_caba_moves(self, moves):
|
||
|
return moves.search([('tax_cash_basis_origin_move_id', 'in', moves.ids)])
|
||
|
|
||
|
def test_full_reconcile_bunch_lines(self):
|
||
|
""" Test the reconciliation with multiple lines at the same time and ensure the result is always a full
|
||
|
reconcile whatever the number of involved currencies.
|
||
|
"""
|
||
|
comp_curr = self.company_data['currency']
|
||
|
foreign_curr1 = self.currency_data['currency']
|
||
|
foreign_curr2 = self.currency_data_2['currency']
|
||
|
|
||
|
line_1 = self.create_line_for_reconciliation(1000.0, 1000.0, comp_curr, '2016-01-01')
|
||
|
line_2 = self.create_line_for_reconciliation(-300.0, -300.0, comp_curr, '2016-01-01')
|
||
|
line_3 = self.create_line_for_reconciliation(-400.0, -400.0, comp_curr, '2016-01-01')
|
||
|
line_4 = self.create_line_for_reconciliation(-500.0, -500.0, comp_curr, '2016-01-01')
|
||
|
line_5 = self.create_line_for_reconciliation(200.0, 200.0, comp_curr, '2016-01-01')
|
||
|
comp_curr_batch = line_1 + line_2 + line_3 + line_4 + line_5
|
||
|
|
||
|
line_1 = self.create_line_for_reconciliation(1200.0, 3600.0, foreign_curr1, '2016-01-01')
|
||
|
line_2 = self.create_line_for_reconciliation(-240.0, -480.0, foreign_curr1, '2017-01-01')
|
||
|
line_3 = self.create_line_for_reconciliation(-720.0, -1440.0, foreign_curr1, '2017-01-01')
|
||
|
line_4 = self.create_line_for_reconciliation(-1020.0, -2040.0, foreign_curr1, '2017-01-01')
|
||
|
line_5 = self.create_line_for_reconciliation(120.0, 360.0, foreign_curr1, '2016-01-01')
|
||
|
same_curr_batch = line_1 + line_2 + line_3 + line_4 + line_5
|
||
|
|
||
|
line_1 = self.create_line_for_reconciliation(1200.0, 3600.0, foreign_curr1, '2016-01-01')
|
||
|
line_2 = self.create_line_for_reconciliation(780.0, 2340.0, foreign_curr1, '2016-01-01')
|
||
|
line_3 = self.create_line_for_reconciliation(-240.0, -960.0, foreign_curr2, '2017-01-01')
|
||
|
line_4 = self.create_line_for_reconciliation(-720.0, -2880.0, foreign_curr2, '2017-01-01')
|
||
|
line_5 = self.create_line_for_reconciliation(-1020.0, -4080.0, foreign_curr2, '2017-01-01')
|
||
|
multi_curr_batch = line_1 + line_2 + line_3 + line_4 + line_5
|
||
|
|
||
|
for batch, sub_test_name in (
|
||
|
(comp_curr_batch, "Batch in company currency"),
|
||
|
(same_curr_batch, "Batch in foreign currency"),
|
||
|
(multi_curr_batch, "Batch with multiple currencies"),
|
||
|
(comp_curr_batch + same_curr_batch + multi_curr_batch, "All batches"),
|
||
|
):
|
||
|
with self.subTest(sub_test_name=sub_test_name):
|
||
|
|
||
|
batch.reconcile()
|
||
|
self.assertTrue(batch.full_reconcile_id)
|
||
|
self.assertRecordValues(
|
||
|
batch,
|
||
|
[{'amount_residual': 0.0, 'amount_residual_currency': 0.0, 'reconciled': True}] * len(batch),
|
||
|
)
|
||
|
batch.remove_move_reconcile()
|
||
|
|
||
|
def test_reconcile_lines_multiple_in_foreign_currency(self):
|
||
|
currency = self.currency_data['currency']
|
||
|
|
||
|
rates = (1/3, 1/2)
|
||
|
for rate1 in rates:
|
||
|
for rate2 in rates:
|
||
|
for rate3 in rates:
|
||
|
with self.subTest(rate1=rate1, rate2=rate2, rate3=rate3):
|
||
|
line_1 = self.create_line_for_reconciliation(120.0 * rate1, 120.0, currency, '2017-01-01')
|
||
|
line_2 = self.create_line_for_reconciliation(120.0 * rate2, 120.0, currency, '2017-01-01')
|
||
|
line_3 = self.create_line_for_reconciliation(-240.0 * rate3, -240.0, currency, '2017-01-01')
|
||
|
|
||
|
(line_1 + line_2 + line_3).reconcile()
|
||
|
self.assertTrue(line_1.full_reconcile_id)
|
||
|
|
||
|
def test_reverse_exchange_difference(self):
|
||
|
""" Test the reversing of the exchange difference to ensure there is no unexpected recursion inside the
|
||
|
'reconcile' method.
|
||
|
"""
|
||
|
comp_curr = self.company_data['currency']
|
||
|
foreign_curr = self.currency_data['currency']
|
||
|
|
||
|
for line1_vals, line2_vals in (
|
||
|
((60.0, 120.0, foreign_curr, '2017-01-01'), (-40.0, -120.0, foreign_curr, '2016-01-01')),
|
||
|
((-60.0, -120.0, foreign_curr, '2017-01-01'), (40.0, 120.0, foreign_curr, '2016-01-01')),
|
||
|
((60.0, 60.0, comp_curr, '2017-01-01'), (-40.0, -120.0, foreign_curr, '2016-01-01')),
|
||
|
((-60.0, -60.0, comp_curr, '2017-01-01'), (40.0, 120.0, foreign_curr, '2016-01-01')),
|
||
|
):
|
||
|
line1 = self.create_line_for_reconciliation(*line1_vals)
|
||
|
line2 = self.create_line_for_reconciliation(*line2_vals)
|
||
|
with self.subTest(line1_vals=line1_vals, line2_vals=line2_vals):
|
||
|
(line1 + line2).reconcile()
|
||
|
|
||
|
# Reconcile.
|
||
|
# Don't check the result since this is already checked by another tests.
|
||
|
partials = self._get_partials(line1 + line2)
|
||
|
exchange_diff = partials.exchange_move_id
|
||
|
self.assertTrue(exchange_diff)
|
||
|
|
||
|
# Unreconcile.
|
||
|
# A reversal is created to cancel the exchange difference journal entry.
|
||
|
line1.remove_move_reconcile()
|
||
|
reverse_exchange_diff_lines = exchange_diff.line_ids.matched_debit_ids.debit_move_id \
|
||
|
+ exchange_diff.line_ids.matched_credit_ids.credit_move_id
|
||
|
reverse_exchange_diff = reverse_exchange_diff_lines.move_id
|
||
|
self.assertTrue(reverse_exchange_diff)
|
||
|
|
||
|
self.assertRecordValues(exchange_diff.line_ids + reverse_exchange_diff.line_ids, [
|
||
|
{'reconciled': True},
|
||
|
{'reconciled': False},
|
||
|
{'reconciled': True},
|
||
|
{'reconciled': False},
|
||
|
])
|
||
|
|
||
|
def test_invoice_draft_fully_paid_if_zero(self):
|
||
|
""" Tests that Invoices with zero balance are marked as paid and reconciled
|
||
|
"""
|
||
|
zero_invoice = self.env['account.move'].create({
|
||
|
'move_type': 'out_invoice',
|
||
|
'partner_id': self.partner_a.id,
|
||
|
'invoice_date': fields.Date.from_string('2019-01-01'),
|
||
|
'invoice_line_ids': [Command.create({'name': 'Nope', 'price_unit': 0})],
|
||
|
})
|
||
|
payment_term_line = zero_invoice.line_ids.filtered(lambda l: l.display_type == 'payment_term')
|
||
|
self.assertRecordValues(zero_invoice, [{
|
||
|
'state': 'draft',
|
||
|
'payment_state': 'not_paid',
|
||
|
'amount_total': 0.0,
|
||
|
}])
|
||
|
self.assertTrue(payment_term_line.reconciled)
|
||
|
|
||
|
zero_invoice.action_post()
|
||
|
self.assertRecordValues(zero_invoice, [{
|
||
|
'state': 'posted',
|
||
|
'payment_state': 'paid',
|
||
|
'amount_total': 0.0,
|
||
|
}])
|
||
|
self.assertTrue(payment_term_line.reconciled)
|
||
|
|
||
|
def test_reconcile_lines_corner_case_1_zero_balance_same_foreign_currency(self):
|
||
|
""" Test the reconciliation of lines having a zero balance in different currencies. In that case, the reconciliation should not be full until
|
||
|
an additional move is added with the right foreign currency amount. """
|
||
|
currency = self.currency_data['currency']
|
||
|
|
||
|
line_1 = self.create_line_for_reconciliation(0.0, -0.02, currency, '2017-01-01')
|
||
|
line_2 = self.create_line_for_reconciliation(0.0, 0.01, currency, '2017-01-01')
|
||
|
(line_1 + line_2).reconcile()
|
||
|
|
||
|
self.assertFalse(line_1.full_reconcile_id + line_2.full_reconcile_id, "The reconciliation should not be considered full, as 0.01 still remain open in foreign currency.")
|
||
|
|
||
|
line_3 = self.create_line_for_reconciliation(0.0, 0.01, currency, '2017-01-01')
|
||
|
(line_1 + line_3).reconcile()
|
||
|
|
||
|
self.assertTrue(line_1.full_reconcile_id)
|
||
|
self.assertEqual(line_1.full_reconcile_id, line_2.full_reconcile_id)
|
||
|
self.assertEqual(line_2.full_reconcile_id, line_3.full_reconcile_id)
|
||
|
|
||
|
def test_reconcile_lines_corner_case_1_zero_balance_different_foreign_currency(self):
|
||
|
""" Test the reconciliation of lines having a zero balance in different currencies.
|
||
|
In that case, we don't reconcile anything.
|
||
|
"""
|
||
|
currency_1 = self.currency_data['currency']
|
||
|
currency_2 = self.setup_multi_currency_data({
|
||
|
'name': 'Bretonnian Ecu',
|
||
|
'symbol': '👑',
|
||
|
'currency_unit_label': 'Ecu',
|
||
|
'currency_subunit_label': 'Bretonnian Denier',
|
||
|
})['currency']
|
||
|
|
||
|
line_1 = self.create_line_for_reconciliation(0.0, -0.01, currency_1, '2017-01-01')
|
||
|
line_2 = self.create_line_for_reconciliation(0.0, 0.02, currency_2, '2016-01-01')
|
||
|
amls = line_1 + line_2
|
||
|
|
||
|
amls.reconcile()
|
||
|
partials = self._get_partials(amls)
|
||
|
|
||
|
self.assertFalse(partials)
|
||
|
|
||
|
def test_reconcile_lines_corner_case_2_zero_amount_currency_same_foreign_currency(self):
|
||
|
""" Test a corner case when both lines have something to reconcile in company currency but nothing
|
||
|
in foreign currency. It could be due to:
|
||
|
- a bad usage of the `no_exchange_difference` context key
|
||
|
- a partial reconciliation made before migrating to this version
|
||
|
- some rounding error when dealing with currencies having != decimal places
|
||
|
- strange journal items made by the user
|
||
|
"""
|
||
|
currency = self.currency_data['currency']
|
||
|
|
||
|
line_1 = self.create_line_for_reconciliation(-0.01, 0.0, currency, '2017-01-01')
|
||
|
line_2 = self.create_line_for_reconciliation(0.02, 0.0, currency, '2016-01-01')
|
||
|
amls = line_1 + line_2
|
||
|
|
||
|
amls.reconcile()
|
||
|
partials = self._get_partials(amls)
|
||
|
full_reconcile = amls.full_reconcile_id
|
||
|
|
||
|
self.assertTrue(full_reconcile)
|
||
|
self.assertRecordValues(partials, [
|
||
|
{
|
||
|
'amount': 0.01,
|
||
|
'debit_amount_currency': 0.0,
|
||
|
'credit_amount_currency': 0.0,
|
||
|
'debit_move_id': line_2.id,
|
||
|
'credit_move_id': line_1.id,
|
||
|
},
|
||
|
{
|
||
|
'amount': 0.01,
|
||
|
'debit_amount_currency': 0.0,
|
||
|
'credit_amount_currency': 0.0,
|
||
|
'debit_move_id': line_2.id,
|
||
|
'credit_move_id': full_reconcile.exchange_move_id.line_ids[0].id,
|
||
|
},
|
||
|
])
|
||
|
self.assertRecordValues(full_reconcile.exchange_move_id, [{'date': fields.Date.from_string('2017-01-31')}])
|
||
|
self.assertRecordValues(full_reconcile.exchange_move_id.line_ids, [
|
||
|
{
|
||
|
'debit': 0.0,
|
||
|
'credit': 0.01,
|
||
|
'amount_currency': 0.0,
|
||
|
'currency_id': currency.id,
|
||
|
'account_id': line_1.account_id.id,
|
||
|
},
|
||
|
{
|
||
|
'debit': 0.01,
|
||
|
'credit': 0.0,
|
||
|
'amount_currency': 0.0,
|
||
|
'currency_id': currency.id,
|
||
|
'account_id': self.exch_expense_account.id,
|
||
|
},
|
||
|
])
|
||
|
self.assertRecordValues(amls, [
|
||
|
{'amount_residual': 0.0, 'amount_residual_currency': 0.0, 'reconciled': True},
|
||
|
{'amount_residual': 0.0, 'amount_residual_currency': 0.0, 'reconciled': True},
|
||
|
])
|
||
|
|
||
|
def test_reconcile_lines_corner_case_3_zero_balance_one_foreign_currency(self):
|
||
|
""" Test the special case when one line (credit) has a zero residual amount in company currency probably due to
|
||
|
some rounding issues or accumulated rounding due to multiple reconciliations.
|
||
|
This line is matched with another line (debit) using the company currency.
|
||
|
"""
|
||
|
comp_curr = self.company_data['currency']
|
||
|
foreign_curr = self.currency_data['currency']
|
||
|
|
||
|
line_1 = self.create_line_for_reconciliation(-0.01, -0.01, comp_curr, '2017-01-01')
|
||
|
line_2 = self.create_line_for_reconciliation(0.0, 0.03, foreign_curr, '2016-01-01')
|
||
|
amls = line_1 + line_2
|
||
|
|
||
|
amls.reconcile()
|
||
|
partials = self._get_partials(amls)
|
||
|
full_reconcile = amls.full_reconcile_id
|
||
|
|
||
|
self.assertTrue(full_reconcile)
|
||
|
self.assertRecordValues(partials, [
|
||
|
{
|
||
|
'amount': 0.0,
|
||
|
'debit_amount_currency': 0.02,
|
||
|
'credit_amount_currency': 0.0,
|
||
|
'debit_move_id': line_2.id,
|
||
|
'credit_move_id': line_1.id,
|
||
|
},
|
||
|
{
|
||
|
'amount': 0.01,
|
||
|
'debit_amount_currency': 0.01,
|
||
|
'credit_amount_currency': 0.01,
|
||
|
'debit_move_id': partials.exchange_move_id.line_ids[0].id,
|
||
|
'credit_move_id': line_1.id,
|
||
|
},
|
||
|
{
|
||
|
'amount': 0.0,
|
||
|
'debit_amount_currency': 0.01,
|
||
|
'credit_amount_currency': 0.01,
|
||
|
'debit_move_id': line_2.id,
|
||
|
'credit_move_id': full_reconcile.exchange_move_id.line_ids[0].id,
|
||
|
},
|
||
|
])
|
||
|
self.assertRecordValues(partials.exchange_move_id, [{'date': fields.Date.from_string('2017-01-31')}])
|
||
|
self.assertRecordValues(partials.exchange_move_id.line_ids, [
|
||
|
{
|
||
|
'debit': 0.01,
|
||
|
'credit': 0.0,
|
||
|
'amount_currency': 0.01,
|
||
|
'currency_id': comp_curr.id,
|
||
|
'account_id': line_1.account_id.id,
|
||
|
},
|
||
|
{
|
||
|
'debit': 0.0,
|
||
|
'credit': 0.01,
|
||
|
'amount_currency': -0.01,
|
||
|
'currency_id': comp_curr.id,
|
||
|
'account_id': self.exch_income_account.id,
|
||
|
},
|
||
|
])
|
||
|
self.assertRecordValues(full_reconcile.exchange_move_id, [{'date': fields.Date.from_string('2017-01-31')}])
|
||
|
self.assertRecordValues(full_reconcile.exchange_move_id.line_ids, [
|
||
|
{
|
||
|
'debit': 0.0,
|
||
|
'credit': 0.0,
|
||
|
'amount_currency': -0.01,
|
||
|
'currency_id': foreign_curr.id,
|
||
|
'account_id': line_2.account_id.id,
|
||
|
},
|
||
|
{
|
||
|
'debit': 0.0,
|
||
|
'credit': 0.0,
|
||
|
'amount_currency': 0.01,
|
||
|
'currency_id': foreign_curr.id,
|
||
|
'account_id': self.exch_expense_account.id,
|
||
|
},
|
||
|
])
|
||
|
self.assertRecordValues(amls, [
|
||
|
{'amount_residual': 0.0, 'amount_residual_currency': 0.0, 'reconciled': True},
|
||
|
{'amount_residual': 0.0, 'amount_residual_currency': 0.0, 'reconciled': True},
|
||
|
])
|
||
|
|
||
|
def test_reconcile_lines_corner_case_4_zero_amount_currency_multiple_currencies(self):
|
||
|
foreign_curr1 = self.currency_data['currency']
|
||
|
foreign_curr2 = self.currency_data_2['currency']
|
||
|
|
||
|
line_1 = self.create_line_for_reconciliation(-0.01, 0.0, foreign_curr2, '2017-01-01')
|
||
|
line_2 = self.create_line_for_reconciliation(0.01, 0.03, foreign_curr1, '2016-01-01')
|
||
|
amls = line_1 + line_2
|
||
|
|
||
|
amls.reconcile()
|
||
|
partials = self._get_partials(amls)
|
||
|
|
||
|
self.assertRecordValues(partials, [{
|
||
|
'amount': 0.01,
|
||
|
'debit_amount_currency': 0.03,
|
||
|
'credit_amount_currency': 0.0,
|
||
|
'debit_move_id': line_2.id,
|
||
|
'credit_move_id': line_1.id,
|
||
|
'exchange_move_id': None,
|
||
|
}])
|
||
|
self.assertRecordValues(amls, [
|
||
|
{'amount_residual': 0.0, 'amount_residual_currency': 0.0, 'reconciled': True},
|
||
|
{'amount_residual': 0.0, 'amount_residual_currency': 0.0, 'reconciled': True},
|
||
|
])
|
||
|
|
||
|
def test_reconcile_lines_corner_case_5_zero_balance_in_one_line_same_foreign_currency(self):
|
||
|
""" Test a corner case when both lines have something to reconcile in company currency but one has nothing
|
||
|
in foreign currency. It could be due to:
|
||
|
- a bad usage of the `no_exchange_difference` context key
|
||
|
- a partial reconciliation made before migrating to this version
|
||
|
- some rounding error when dealing with currencies having != decimal places
|
||
|
- strange journal items made by the user
|
||
|
"""
|
||
|
currency = self.currency_data['currency']
|
||
|
|
||
|
line_1 = self.create_line_for_reconciliation(-0.06, 0.0, currency, '2017-01-01')
|
||
|
line_2 = self.create_line_for_reconciliation(0.12, 0.24, currency, '2017-01-01')
|
||
|
amls = line_1 + line_2
|
||
|
|
||
|
amls.reconcile()
|
||
|
partials = self._get_partials(amls)
|
||
|
|
||
|
self.assertRecordValues(partials, [
|
||
|
{
|
||
|
'amount': 0.06,
|
||
|
'debit_amount_currency': 0.0,
|
||
|
'credit_amount_currency': 0.0,
|
||
|
'debit_move_id': line_2.id,
|
||
|
'credit_move_id': line_1.id,
|
||
|
},
|
||
|
])
|
||
|
self.assertRecordValues(amls, [
|
||
|
{'amount_residual': 0.0, 'amount_residual_currency': 0.0, 'reconciled': True},
|
||
|
{'amount_residual': 0.06, 'amount_residual_currency': 0.24, 'reconciled': False},
|
||
|
])
|
||
|
|
||
|
def test_reconcile_exchange_difference_on_partial_same_foreign_currency_debit_expense_partial_payment(self):
|
||
|
currency = self.currency_data['currency']
|
||
|
|
||
|
line_1 = self.create_line_for_reconciliation(60.0, 120.0, currency, '2017-01-01')
|
||
|
line_2 = self.create_line_for_reconciliation(-80.0, -240.0, currency, '2016-01-01')
|
||
|
amls = line_1 + line_2
|
||
|
|
||
|
amls.reconcile()
|
||
|
partials = self._get_partials(amls)
|
||
|
|
||
|
self.assertRecordValues(partials, [
|
||
|
{
|
||
|
'amount': 40.0,
|
||
|
'debit_amount_currency': 120.0,
|
||
|
'credit_amount_currency': 120.0,
|
||
|
'debit_move_id': line_1.id,
|
||
|
'credit_move_id': line_2.id,
|
||
|
},
|
||
|
{
|
||
|
'amount': 20.0,
|
||
|
'debit_amount_currency': 0.0,
|
||
|
'credit_amount_currency': 0.0,
|
||
|
'debit_move_id': line_1.id,
|
||
|
'credit_move_id': partials.exchange_move_id.line_ids[0].id,
|
||
|
},
|
||
|
])
|
||
|
self.assertRecordValues(partials.exchange_move_id, [{'date': fields.Date.from_string('2017-01-31')}])
|
||
|
self.assertRecordValues(partials.exchange_move_id.line_ids, [
|
||
|
{
|
||
|
'debit': 0.0,
|
||
|
'credit': 20.0,
|
||
|
'amount_currency': 0.0,
|
||
|
'currency_id': currency.id,
|
||
|
'account_id': line_1.account_id.id,
|
||
|
},
|
||
|
{
|
||
|
'debit': 20.0,
|
||
|
'credit': 0.0,
|
||
|
'amount_currency': 0.0,
|
||
|
'currency_id': currency.id,
|
||
|
'account_id': self.exch_expense_account.id,
|
||
|
},
|
||
|
])
|
||
|
self.assertRecordValues(amls, [
|
||
|
{'amount_residual': 0.0, 'amount_residual_currency': 0.0, 'reconciled': True},
|
||
|
{'amount_residual': -40.0, 'amount_residual_currency': -120.0, 'reconciled': False},
|
||
|
])
|
||
|
|
||
|
def test_reconcile_exchange_difference_on_partial_same_foreign_currency_debit_income_partial_payment(self):
|
||
|
currency = self.currency_data['currency']
|
||
|
|
||
|
line_1 = self.create_line_for_reconciliation(40.0, 120.0, currency, '2016-01-01')
|
||
|
line_2 = self.create_line_for_reconciliation(-120.0, -240.0, currency, '2017-01-01')
|
||
|
amls = line_1 + line_2
|
||
|
|
||
|
amls.reconcile()
|
||
|
partials = self._get_partials(amls)
|
||
|
|
||
|
self.assertRecordValues(partials, [
|
||
|
{
|
||
|
'amount': 40.0,
|
||
|
'debit_amount_currency': 120.0,
|
||
|
'credit_amount_currency': 120.0,
|
||
|
'debit_move_id': line_1.id,
|
||
|
'credit_move_id': line_2.id,
|
||
|
},
|
||
|
{
|
||
|
'amount': 20.0,
|
||
|
'debit_amount_currency': 0.0,
|
||
|
'credit_amount_currency': 0.0,
|
||
|
'debit_move_id': partials.exchange_move_id.line_ids[0].id,
|
||
|
'credit_move_id': line_2.id,
|
||
|
},
|
||
|
])
|
||
|
self.assertRecordValues(partials.exchange_move_id, [{'date': fields.Date.from_string('2017-01-31')}])
|
||
|
self.assertRecordValues(partials.exchange_move_id.line_ids, [
|
||
|
{
|
||
|
'debit': 20.0,
|
||
|
'credit': 0.0,
|
||
|
'amount_currency': 0.0,
|
||
|
'currency_id': currency.id,
|
||
|
'account_id': line_2.account_id.id,
|
||
|
},
|
||
|
{
|
||
|
'debit': 0.0,
|
||
|
'credit': 20.0,
|
||
|
'amount_currency': 0.0,
|
||
|
'currency_id': currency.id,
|
||
|
'account_id': self.exch_income_account.id,
|
||
|
},
|
||
|
])
|
||
|
self.assertRecordValues(amls, [
|
||
|
{'amount_residual': 0.0, 'amount_residual_currency': 0.0, 'reconciled': True},
|
||
|
{'amount_residual': -60.0, 'amount_residual_currency': -120.0, 'reconciled': False},
|
||
|
])
|
||
|
|
||
|
def test_reconcile_exchange_difference_on_partial_same_foreign_currency_credit_expense_partial_payment(self):
|
||
|
currency = self.currency_data['currency']
|
||
|
|
||
|
line_1 = self.create_line_for_reconciliation(-40.0, -120.0, currency, '2016-01-01')
|
||
|
line_2 = self.create_line_for_reconciliation(120.0, 240.0, currency, '2017-01-01')
|
||
|
amls = line_1 + line_2
|
||
|
|
||
|
amls.reconcile()
|
||
|
partials = self._get_partials(amls)
|
||
|
|
||
|
self.assertRecordValues(partials, [
|
||
|
{
|
||
|
'amount': 40.0,
|
||
|
'debit_amount_currency': 120.0,
|
||
|
'credit_amount_currency': 120.0,
|
||
|
'debit_move_id': line_2.id,
|
||
|
'credit_move_id': line_1.id,
|
||
|
},
|
||
|
{
|
||
|
'amount': 20.0,
|
||
|
'debit_amount_currency': 0.0,
|
||
|
'credit_amount_currency': 0.0,
|
||
|
'debit_move_id': line_2.id,
|
||
|
'credit_move_id': partials.exchange_move_id.line_ids[0].id,
|
||
|
},
|
||
|
])
|
||
|
self.assertRecordValues(partials.exchange_move_id, [{'date': fields.Date.from_string('2017-01-31')}])
|
||
|
self.assertRecordValues(partials.exchange_move_id.line_ids, [
|
||
|
{
|
||
|
'debit': 0.0,
|
||
|
'credit': 20.0,
|
||
|
'amount_currency': 0.0,
|
||
|
'currency_id': currency.id,
|
||
|
'account_id': line_2.account_id.id,
|
||
|
},
|
||
|
{
|
||
|
'debit': 20.0,
|
||
|
'credit': 0.0,
|
||
|
'amount_currency': 0.0,
|
||
|
'currency_id': currency.id,
|
||
|
'account_id': self.exch_expense_account.id,
|
||
|
},
|
||
|
])
|
||
|
self.assertRecordValues(amls, [
|
||
|
{'amount_residual': 0.0, 'amount_residual_currency': 0.0, 'reconciled': True},
|
||
|
{'amount_residual': 60.0, 'amount_residual_currency': 120.0, 'reconciled': False},
|
||
|
])
|
||
|
|
||
|
def test_reconcile_exchange_difference_on_partial_same_foreign_currency_credit_income_partial_payment(self):
|
||
|
currency = self.currency_data['currency']
|
||
|
|
||
|
line_1 = self.create_line_for_reconciliation(-60.0, -120.0, currency, '2017-01-01')
|
||
|
line_2 = self.create_line_for_reconciliation(80.0, 240.0, currency, '2016-01-01')
|
||
|
amls = line_1 + line_2
|
||
|
|
||
|
amls.reconcile()
|
||
|
partials = self._get_partials(amls)
|
||
|
|
||
|
self.assertRecordValues(partials, [
|
||
|
{
|
||
|
'amount': 40.0,
|
||
|
'debit_amount_currency': 120.0,
|
||
|
'credit_amount_currency': 120.0,
|
||
|
'debit_move_id': line_2.id,
|
||
|
'credit_move_id': line_1.id,
|
||
|
},
|
||
|
{
|
||
|
'amount': 20.0,
|
||
|
'debit_amount_currency': 0.0,
|
||
|
'credit_amount_currency': 0.0,
|
||
|
'debit_move_id': partials.exchange_move_id.line_ids[0].id,
|
||
|
'credit_move_id': line_1.id,
|
||
|
},
|
||
|
])
|
||
|
self.assertRecordValues(partials.exchange_move_id, [{'date': fields.Date.from_string('2017-01-31')}])
|
||
|
self.assertRecordValues(partials.exchange_move_id.line_ids, [
|
||
|
{
|
||
|
'debit': 20.0,
|
||
|
'credit': 0.0,
|
||
|
'amount_currency': 0.0,
|
||
|
'currency_id': currency.id,
|
||
|
'account_id': line_1.account_id.id,
|
||
|
},
|
||
|
{
|
||
|
'debit': 0.0,
|
||
|
'credit': 20.0,
|
||
|
'amount_currency': 0.0,
|
||
|
'currency_id': currency.id,
|
||
|
'account_id': self.exch_income_account.id,
|
||
|
},
|
||
|
])
|
||
|
self.assertRecordValues(amls, [
|
||
|
{'amount_residual': 0.0, 'amount_residual_currency': 0.0, 'reconciled': True},
|
||
|
{'amount_residual': 40.0, 'amount_residual_currency': 120.0, 'reconciled': False},
|
||
|
])
|
||
|
|
||
|
def test_reconcile_exchange_difference_on_partial_one_debit_foreign_currency_debit_expense_partial_payment(self):
|
||
|
comp_curr = self.company_data['currency']
|
||
|
foreign_curr = self.currency_data['currency']
|
||
|
|
||
|
line_1 = self.create_line_for_reconciliation(60.0, 120.0, foreign_curr, '2017-01-01')
|
||
|
line_2 = self.create_line_for_reconciliation(-80.0, -80.0, comp_curr, '2016-01-01')
|
||
|
amls = line_1 + line_2
|
||
|
|
||
|
amls.reconcile()
|
||
|
partials = self._get_partials(amls)
|
||
|
|
||
|
self.assertRecordValues(partials, [
|
||
|
{
|
||
|
'amount': 40.0,
|
||
|
'debit_amount_currency': 120.0,
|
||
|
'credit_amount_currency': 40.0,
|
||
|
'debit_move_id': line_1.id,
|
||
|
'credit_move_id': line_2.id,
|
||
|
},
|
||
|
{
|
||
|
'amount': 20.0,
|
||
|
'debit_amount_currency': 0.0,
|
||
|
'credit_amount_currency': 0.0,
|
||
|
'debit_move_id': line_1.id,
|
||
|
'credit_move_id': partials.exchange_move_id.line_ids[0].id,
|
||
|
},
|
||
|
])
|
||
|
self.assertRecordValues(partials.exchange_move_id, [{'date': fields.Date.from_string('2017-01-31')}])
|
||
|
self.assertRecordValues(partials.exchange_move_id.line_ids, [
|
||
|
{
|
||
|
'debit': 0.0,
|
||
|
'credit': 20.0,
|
||
|
'amount_currency': 0.0,
|
||
|
'currency_id': foreign_curr.id,
|
||
|
'account_id': line_1.account_id.id,
|
||
|
},
|
||
|
{
|
||
|
'debit': 20.0,
|
||
|
'credit': 0.0,
|
||
|
'amount_currency': 0.0,
|
||
|
'currency_id': foreign_curr.id,
|
||
|
'account_id': self.exch_expense_account.id,
|
||
|
},
|
||
|
])
|
||
|
self.assertRecordValues(amls, [
|
||
|
{'amount_residual': 0.0, 'amount_residual_currency': 0.0, 'reconciled': True},
|
||
|
{'amount_residual': -40.0, 'amount_residual_currency': -40.0, 'reconciled': False},
|
||
|
])
|
||
|
|
||
|
def test_reconcile_exchange_difference_on_partial_one_credit_foreign_currency_debit_expense_partial_payment(self):
|
||
|
comp_curr = self.company_data['currency']
|
||
|
foreign_curr = self.currency_data['currency']
|
||
|
|
||
|
line_1 = self.create_line_for_reconciliation(60.0, 60.0, comp_curr, '2017-01-01')
|
||
|
line_2 = self.create_line_for_reconciliation(-80.0, -240.0, foreign_curr, '2016-01-01')
|
||
|
amls = line_1 + line_2
|
||
|
|
||
|
amls.reconcile()
|
||
|
partials = self._get_partials(amls)
|
||
|
|
||
|
self.assertRecordValues(partials, [
|
||
|
{
|
||
|
'amount': 40.0,
|
||
|
'debit_amount_currency': 40.0,
|
||
|
'credit_amount_currency': 120.0,
|
||
|
'debit_move_id': line_1.id,
|
||
|
'credit_move_id': line_2.id,
|
||
|
},
|
||
|
{
|
||
|
'amount': 20.0,
|
||
|
'debit_amount_currency': 20.0,
|
||
|
'credit_amount_currency': 20.0,
|
||
|
'debit_move_id': line_1.id,
|
||
|
'credit_move_id': partials.exchange_move_id.line_ids[0].id,
|
||
|
},
|
||
|
])
|
||
|
self.assertRecordValues(partials.exchange_move_id, [{'date': fields.Date.from_string('2017-01-31')}])
|
||
|
self.assertRecordValues(partials.exchange_move_id.line_ids, [
|
||
|
{
|
||
|
'debit': 0.0,
|
||
|
'credit': 20.0,
|
||
|
'amount_currency': -20.0,
|
||
|
'currency_id': comp_curr.id,
|
||
|
'account_id': line_1.account_id.id,
|
||
|
},
|
||
|
{
|
||
|
'debit': 20.0,
|
||
|
'credit': 0.0,
|
||
|
'amount_currency': 20.0,
|
||
|
'currency_id': comp_curr.id,
|
||
|
'account_id': self.exch_expense_account.id,
|
||
|
},
|
||
|
])
|
||
|
self.assertRecordValues(amls, [
|
||
|
{'amount_residual': 0.0, 'amount_residual_currency': 0.0, 'reconciled': True},
|
||
|
{'amount_residual': -40.0, 'amount_residual_currency': -120.0, 'reconciled': False},
|
||
|
])
|
||
|
|
||
|
def test_reconcile_exchange_difference_on_partial_one_debit_foreign_currency_debit_income_partial_payment(self):
|
||
|
comp_curr = self.company_data['currency']
|
||
|
foreign_curr = self.currency_data['currency']
|
||
|
|
||
|
line_1 = self.create_line_for_reconciliation(40.0, 120.0, foreign_curr, '2016-01-01')
|
||
|
line_2 = self.create_line_for_reconciliation(-120.0, -120.0, comp_curr, '2017-01-01')
|
||
|
amls = line_1 + line_2
|
||
|
|
||
|
amls.reconcile()
|
||
|
partials = self._get_partials(amls)
|
||
|
|
||
|
self.assertRecordValues(partials, [
|
||
|
{
|
||
|
'amount': 40.0,
|
||
|
'debit_amount_currency': 120.0,
|
||
|
'credit_amount_currency': 40.0,
|
||
|
'debit_move_id': line_1.id,
|
||
|
'credit_move_id': line_2.id,
|
||
|
},
|
||
|
{
|
||
|
'amount': 20.0,
|
||
|
'debit_amount_currency': 20.0,
|
||
|
'credit_amount_currency': 20.0,
|
||
|
'debit_move_id': partials.exchange_move_id.line_ids[0].id,
|
||
|
'credit_move_id': line_2.id,
|
||
|
},
|
||
|
])
|
||
|
self.assertRecordValues(partials.exchange_move_id, [{'date': fields.Date.from_string('2017-01-31')}])
|
||
|
self.assertRecordValues(partials.exchange_move_id.line_ids, [
|
||
|
{
|
||
|
'debit': 20.0,
|
||
|
'credit': 0.0,
|
||
|
'amount_currency': 20.0,
|
||
|
'currency_id': comp_curr.id,
|
||
|
'account_id': line_2.account_id.id,
|
||
|
},
|
||
|
{
|
||
|
'debit': 0.0,
|
||
|
'credit': 20.0,
|
||
|
'amount_currency': -20.0,
|
||
|
'currency_id': comp_curr.id,
|
||
|
'account_id': self.exch_income_account.id,
|
||
|
},
|
||
|
])
|
||
|
self.assertRecordValues(amls, [
|
||
|
{'amount_residual': 0.0, 'amount_residual_currency': 0.0, 'reconciled': True},
|
||
|
{'amount_residual': -60.0, 'amount_residual_currency': -60.0, 'reconciled': False},
|
||
|
])
|
||
|
|
||
|
def test_reconcile_exchange_difference_on_partial_one_credit_foreign_currency_debit_income_partial_payment(self):
|
||
|
comp_curr = self.company_data['currency']
|
||
|
foreign_curr = self.currency_data['currency']
|
||
|
|
||
|
line_1 = self.create_line_for_reconciliation(40.0, 40.0, comp_curr, '2016-01-01')
|
||
|
line_2 = self.create_line_for_reconciliation(-120.0, -240.0, foreign_curr, '2017-01-01')
|
||
|
amls = line_1 + line_2
|
||
|
|
||
|
amls.reconcile()
|
||
|
partials = self._get_partials(amls)
|
||
|
|
||
|
self.assertRecordValues(partials, [
|
||
|
{
|
||
|
'amount': 40.0,
|
||
|
'debit_amount_currency': 40.0,
|
||
|
'credit_amount_currency': 120.0,
|
||
|
'debit_move_id': line_1.id,
|
||
|
'credit_move_id': line_2.id,
|
||
|
},
|
||
|
{
|
||
|
'amount': 20.0,
|
||
|
'debit_amount_currency': 0.0,
|
||
|
'credit_amount_currency': 0.0,
|
||
|
'debit_move_id': partials.exchange_move_id.line_ids[0].id,
|
||
|
'credit_move_id': line_2.id,
|
||
|
},
|
||
|
])
|
||
|
self.assertRecordValues(partials.exchange_move_id, [{'date': fields.Date.from_string('2017-01-31')}])
|
||
|
self.assertRecordValues(partials.exchange_move_id.line_ids, [
|
||
|
{
|
||
|
'debit': 20.0,
|
||
|
'credit': 0.0,
|
||
|
'amount_currency': 0.0,
|
||
|
'currency_id': foreign_curr.id,
|
||
|
'account_id': line_2.account_id.id,
|
||
|
},
|
||
|
{
|
||
|
'debit': 0.0,
|
||
|
'credit': 20.0,
|
||
|
'amount_currency': 0.0,
|
||
|
'currency_id': foreign_curr.id,
|
||
|
'account_id': self.exch_income_account.id,
|
||
|
},
|
||
|
])
|
||
|
self.assertRecordValues(amls, [
|
||
|
{'amount_residual': 0.0, 'amount_residual_currency': 0.0, 'reconciled': True},
|
||
|
{'amount_residual': -60.0, 'amount_residual_currency': -120.0, 'reconciled': False},
|
||
|
])
|
||
|
|
||
|
def test_reconcile_exchange_difference_on_partial_one_credit_foreign_currency_credit_expense_partial_payment(self):
|
||
|
comp_curr = self.company_data['currency']
|
||
|
foreign_curr = self.currency_data['currency']
|
||
|
|
||
|
line_1 = self.create_line_for_reconciliation(-40.0, -120.0, foreign_curr, '2016-01-01')
|
||
|
line_2 = self.create_line_for_reconciliation(120.0, 120.0, comp_curr, '2017-01-01')
|
||
|
amls = line_1 + line_2
|
||
|
|
||
|
amls.reconcile()
|
||
|
partials = self._get_partials(amls)
|
||
|
|
||
|
self.assertRecordValues(partials, [
|
||
|
{
|
||
|
'amount': 40.0,
|
||
|
'debit_amount_currency': 40.0,
|
||
|
'credit_amount_currency': 120.0,
|
||
|
'debit_move_id': line_2.id,
|
||
|
'credit_move_id': line_1.id,
|
||
|
},
|
||
|
{
|
||
|
'amount': 20.0,
|
||
|
'debit_amount_currency': 20.0,
|
||
|
'credit_amount_currency': 20.0,
|
||
|
'debit_move_id': line_2.id,
|
||
|
'credit_move_id': partials.exchange_move_id.line_ids[0].id,
|
||
|
},
|
||
|
])
|
||
|
self.assertRecordValues(partials.exchange_move_id, [{'date': fields.Date.from_string('2017-01-31')}])
|
||
|
self.assertRecordValues(partials.exchange_move_id.line_ids, [
|
||
|
{
|
||
|
'debit': 0.0,
|
||
|
'credit': 20.0,
|
||
|
'amount_currency': -20.0,
|
||
|
'currency_id': comp_curr.id,
|
||
|
'account_id': line_2.account_id.id,
|
||
|
},
|
||
|
{
|
||
|
'debit': 20.0,
|
||
|
'credit': 0.0,
|
||
|
'amount_currency': 20.0,
|
||
|
'currency_id': comp_curr.id,
|
||
|
'account_id': self.exch_expense_account.id,
|
||
|
},
|
||
|
])
|
||
|
self.assertRecordValues(amls, [
|
||
|
{'amount_residual': 0.0, 'amount_residual_currency': 0.0, 'reconciled': True},
|
||
|
{'amount_residual': 60.0, 'amount_residual_currency': 60.0, 'reconciled': False},
|
||
|
])
|
||
|
|
||
|
def test_reconcile_exchange_difference_on_partial_one_debit_foreign_currency_credit_expense_partial_payment(self):
|
||
|
comp_curr = self.company_data['currency']
|
||
|
foreign_curr = self.currency_data['currency']
|
||
|
|
||
|
line_1 = self.create_line_for_reconciliation(-40.0, -40.0, comp_curr, '2016-01-01')
|
||
|
line_2 = self.create_line_for_reconciliation(120.0, 240.0, foreign_curr, '2017-01-01')
|
||
|
amls = line_1 + line_2
|
||
|
|
||
|
amls.reconcile()
|
||
|
partials = self._get_partials(amls)
|
||
|
|
||
|
self.assertRecordValues(partials, [
|
||
|
{
|
||
|
'amount': 40.0,
|
||
|
'debit_amount_currency': 120.0,
|
||
|
'credit_amount_currency': 40.0,
|
||
|
'debit_move_id': line_2.id,
|
||
|
'credit_move_id': line_1.id,
|
||
|
},
|
||
|
{
|
||
|
'amount': 20.0,
|
||
|
'debit_amount_currency': 0.0,
|
||
|
'credit_amount_currency': 0.0,
|
||
|
'debit_move_id': line_2.id,
|
||
|
'credit_move_id': partials.exchange_move_id.line_ids[0].id,
|
||
|
},
|
||
|
])
|
||
|
self.assertRecordValues(partials.exchange_move_id, [{'date': fields.Date.from_string('2017-01-31')}])
|
||
|
self.assertRecordValues(partials.exchange_move_id.line_ids, [
|
||
|
{
|
||
|
'debit': 0.0,
|
||
|
'credit': 20.0,
|
||
|
'amount_currency': 0.0,
|
||
|
'currency_id': foreign_curr.id,
|
||
|
'account_id': line_2.account_id.id,
|
||
|
},
|
||
|
{
|
||
|
'debit': 20.0,
|
||
|
'credit': 0.0,
|
||
|
'amount_currency': 0.0,
|
||
|
'currency_id': foreign_curr.id,
|
||
|
'account_id': self.exch_expense_account.id,
|
||
|
},
|
||
|
])
|
||
|
self.assertRecordValues(amls, [
|
||
|
{'amount_residual': 0.0, 'amount_residual_currency': 0.0, 'reconciled': True},
|
||
|
{'amount_residual': 60.0, 'amount_residual_currency': 120.0, 'reconciled': False},
|
||
|
])
|
||
|
|
||
|
def test_reconcile_exchange_difference_on_partial_one_debit_foreign_currency_credit_income_partial_payment(self):
|
||
|
comp_curr = self.company_data['currency']
|
||
|
foreign_curr = self.currency_data['currency']
|
||
|
|
||
|
line_1 = self.create_line_for_reconciliation(-60.0, -60.0, comp_curr, '2017-01-01')
|
||
|
line_2 = self.create_line_for_reconciliation(80.0, 240.0, foreign_curr, '2016-01-01')
|
||
|
amls = line_1 + line_2
|
||
|
|
||
|
amls.reconcile()
|
||
|
partials = self._get_partials(amls)
|
||
|
|
||
|
self.assertRecordValues(partials, [
|
||
|
{
|
||
|
'amount': 40.0,
|
||
|
'debit_amount_currency': 120.0,
|
||
|
'credit_amount_currency': 40.0,
|
||
|
'debit_move_id': line_2.id,
|
||
|
'credit_move_id': line_1.id,
|
||
|
},
|
||
|
{
|
||
|
'amount': 20.0,
|
||
|
'debit_amount_currency': 20.0,
|
||
|
'credit_amount_currency': 20.0,
|
||
|
'debit_move_id': partials.exchange_move_id.line_ids[0].id,
|
||
|
'credit_move_id': line_1.id,
|
||
|
},
|
||
|
])
|
||
|
self.assertRecordValues(partials.exchange_move_id, [{'date': fields.Date.from_string('2017-01-31')}])
|
||
|
self.assertRecordValues(partials.exchange_move_id.line_ids, [
|
||
|
{
|
||
|
'debit': 20.0,
|
||
|
'credit': 0.0,
|
||
|
'amount_currency': 20.0,
|
||
|
'currency_id': comp_curr.id,
|
||
|
'account_id': line_1.account_id.id,
|
||
|
},
|
||
|
{
|
||
|
'debit': 0.0,
|
||
|
'credit': 20.0,
|
||
|
'amount_currency': -20.0,
|
||
|
'currency_id': comp_curr.id,
|
||
|
'account_id': self.exch_income_account.id,
|
||
|
},
|
||
|
])
|
||
|
self.assertRecordValues(amls, [
|
||
|
{'amount_residual': 0.0, 'amount_residual_currency': 0.0, 'reconciled': True},
|
||
|
{'amount_residual': 40.0, 'amount_residual_currency': 120.0, 'reconciled': False},
|
||
|
])
|
||
|
|
||
|
def test_reconcile_exchange_difference_on_partial_one_credit_foreign_currency_credit_income_partial_payment(self):
|
||
|
comp_curr = self.company_data['currency']
|
||
|
foreign_curr = self.currency_data['currency']
|
||
|
|
||
|
line_1 = self.create_line_for_reconciliation(-60.0, -120.0, foreign_curr, '2017-01-01')
|
||
|
line_2 = self.create_line_for_reconciliation(80.0, 80.0, comp_curr, '2016-01-01')
|
||
|
amls = line_1 + line_2
|
||
|
|
||
|
amls.reconcile()
|
||
|
partials = self._get_partials(amls)
|
||
|
|
||
|
self.assertRecordValues(partials, [
|
||
|
{
|
||
|
'amount': 40.0,
|
||
|
'debit_amount_currency': 40.0,
|
||
|
'credit_amount_currency': 120.0,
|
||
|
'debit_move_id': line_2.id,
|
||
|
'credit_move_id': line_1.id,
|
||
|
},
|
||
|
{
|
||
|
'amount': 20.0,
|
||
|
'debit_amount_currency': 0.0,
|
||
|
'credit_amount_currency': 0.0,
|
||
|
'debit_move_id': partials.exchange_move_id.line_ids[0].id,
|
||
|
'credit_move_id': line_1.id,
|
||
|
},
|
||
|
])
|
||
|
self.assertRecordValues(partials.exchange_move_id, [{'date': fields.Date.from_string('2017-01-31')}])
|
||
|
self.assertRecordValues(partials.exchange_move_id.line_ids, [
|
||
|
{
|
||
|
'debit': 20.0,
|
||
|
'credit': 0.0,
|
||
|
'amount_currency': 0.0,
|
||
|
'currency_id': foreign_curr.id,
|
||
|
'account_id': line_1.account_id.id,
|
||
|
},
|
||
|
{
|
||
|
'debit': 0.0,
|
||
|
'credit': 20.0,
|
||
|
'amount_currency': 0.0,
|
||
|
'currency_id': foreign_curr.id,
|
||
|
'account_id': self.exch_income_account.id,
|
||
|
},
|
||
|
])
|
||
|
self.assertRecordValues(amls, [
|
||
|
{'amount_residual': 0.0, 'amount_residual_currency': 0.0, 'reconciled': True},
|
||
|
{'amount_residual': 40.0, 'amount_residual_currency': 40.0, 'reconciled': False},
|
||
|
])
|
||
|
|
||
|
def test_reconcile_one_foreign_currency_fallback_company_currency(self):
|
||
|
comp_curr = self.company_data['currency']
|
||
|
foreign_curr = self.currency_data_3['currency']
|
||
|
|
||
|
line_1 = self.create_line_for_reconciliation(-10.0, -10.0, comp_curr, '2017-01-01')
|
||
|
line_2 = self.create_line_for_reconciliation(1000000.0, 100.0, foreign_curr, '2017-01-01')
|
||
|
amls = line_1 + line_2
|
||
|
|
||
|
amls.reconcile()
|
||
|
partials = self._get_partials(amls)
|
||
|
|
||
|
self.assertRecordValues(partials, [{
|
||
|
'amount': 10.0,
|
||
|
'debit_amount_currency': 0.001,
|
||
|
'credit_amount_currency': 10.0,
|
||
|
'debit_move_id': line_2.id,
|
||
|
'credit_move_id': line_1.id,
|
||
|
}])
|
||
|
self.assertFalse(partials.exchange_move_id)
|
||
|
self.assertRecordValues(line_1 + line_2, [
|
||
|
{'amount_residual': 0.0, 'amount_residual_currency': 0.0, 'reconciled': True},
|
||
|
{'amount_residual': 999990.0, 'amount_residual_currency': 99.999, 'reconciled': False},
|
||
|
])
|
||
|
|
||
|
def test_reconcile_exchange_difference_on_partial_same_foreign_currency_debit_expense_full_payment(self):
|
||
|
currency = self.currency_data['currency']
|
||
|
|
||
|
line_1 = self.create_line_for_reconciliation(60.0, 120.0, currency, '2017-01-01')
|
||
|
line_2 = self.create_line_for_reconciliation(-40.0, -120.0, currency, '2016-01-01')
|
||
|
amls = line_1 + line_2
|
||
|
|
||
|
amls.reconcile()
|
||
|
partials = self._get_partials(amls)
|
||
|
full_reconcile = amls.full_reconcile_id
|
||
|
|
||
|
self.assertTrue(full_reconcile)
|
||
|
self.assertRecordValues(full_reconcile, [{'exchange_move_id': False}])
|
||
|
self.assertRecordValues(partials, [
|
||
|
{
|
||
|
'amount': 40.0,
|
||
|
'debit_amount_currency': 120.0,
|
||
|
'credit_amount_currency': 120.0,
|
||
|
'debit_move_id': line_1.id,
|
||
|
'credit_move_id': line_2.id,
|
||
|
},
|
||
|
{
|
||
|
'amount': 20.0,
|
||
|
'debit_amount_currency': 0.0,
|
||
|
'credit_amount_currency': 0.0,
|
||
|
'debit_move_id': line_1.id,
|
||
|
'credit_move_id': partials.exchange_move_id.line_ids[0].id,
|
||
|
},
|
||
|
])
|
||
|
self.assertRecordValues(partials.exchange_move_id, [{'date': fields.Date.from_string('2017-01-31')}])
|
||
|
self.assertRecordValues(partials.exchange_move_id.line_ids, [
|
||
|
{
|
||
|
'debit': 0.0,
|
||
|
'credit': 20.0,
|
||
|
'amount_currency': 0.0,
|
||
|
'currency_id': currency.id,
|
||
|
'account_id': line_1.account_id.id,
|
||
|
},
|
||
|
{
|
||
|
'debit': 20.0,
|
||
|
'credit': 0.0,
|
||
|
'amount_currency': 0.0,
|
||
|
'currency_id': currency.id,
|
||
|
'account_id': self.exch_expense_account.id,
|
||
|
},
|
||
|
])
|
||
|
self.assertRecordValues(amls, [
|
||
|
{'amount_residual': 0.0, 'amount_residual_currency': 0.0, 'reconciled': True},
|
||
|
{'amount_residual': 0.0, 'amount_residual_currency': 0.0, 'reconciled': True},
|
||
|
])
|
||
|
|
||
|
def test_reconcile_exchange_difference_on_partial_same_foreign_currency_debit_income_full_payment(self):
|
||
|
currency = self.currency_data['currency']
|
||
|
|
||
|
line_1 = self.create_line_for_reconciliation(40.0, 120.0, currency, '2016-01-01')
|
||
|
line_2 = self.create_line_for_reconciliation(-60.0, -120.0, currency, '2017-01-01')
|
||
|
amls = line_1 + line_2
|
||
|
|
||
|
amls.reconcile()
|
||
|
partials = self._get_partials(amls)
|
||
|
full_reconcile = amls.full_reconcile_id
|
||
|
|
||
|
self.assertTrue(full_reconcile)
|
||
|
self.assertRecordValues(full_reconcile, [{'exchange_move_id': False}])
|
||
|
self.assertRecordValues(partials, [
|
||
|
{
|
||
|
'amount': 40.0,
|
||
|
'debit_amount_currency': 120.0,
|
||
|
'credit_amount_currency': 120.0,
|
||
|
'debit_move_id': line_1.id,
|
||
|
'credit_move_id': line_2.id,
|
||
|
},
|
||
|
{
|
||
|
'amount': 20.0,
|
||
|
'debit_amount_currency': 0.0,
|
||
|
'credit_amount_currency': 0.0,
|
||
|
'debit_move_id': partials.exchange_move_id.line_ids[0].id,
|
||
|
'credit_move_id': line_2.id,
|
||
|
},
|
||
|
])
|
||
|
self.assertRecordValues(partials.exchange_move_id, [{'date': fields.Date.from_string('2017-01-31')}])
|
||
|
self.assertRecordValues(partials.exchange_move_id.line_ids, [
|
||
|
{
|
||
|
'debit': 20.0,
|
||
|
'credit': 0.0,
|
||
|
'amount_currency': 0.0,
|
||
|
'currency_id': currency.id,
|
||
|
'account_id': line_2.account_id.id,
|
||
|
},
|
||
|
{
|
||
|
'debit': 0.0,
|
||
|
'credit': 20.0,
|
||
|
'amount_currency': 0.0,
|
||
|
'currency_id': currency.id,
|
||
|
'account_id': self.exch_income_account.id,
|
||
|
},
|
||
|
])
|
||
|
self.assertRecordValues(amls, [
|
||
|
{'amount_residual': 0.0, 'amount_residual_currency': 0.0, 'reconciled': True},
|
||
|
{'amount_residual': 0.0, 'amount_residual_currency': 0.0, 'reconciled': True},
|
||
|
])
|
||
|
|
||
|
def test_reconcile_exchange_difference_on_partial_same_foreign_currency_credit_expense_full_payment(self):
|
||
|
currency = self.currency_data['currency']
|
||
|
|
||
|
line_1 = self.create_line_for_reconciliation(-40.0, -120.0, currency, '2016-01-01')
|
||
|
line_2 = self.create_line_for_reconciliation(60.0, 120.0, currency, '2017-01-01')
|
||
|
amls = line_1 + line_2
|
||
|
|
||
|
amls.reconcile()
|
||
|
partials = self._get_partials(amls)
|
||
|
full_reconcile = amls.full_reconcile_id
|
||
|
|
||
|
self.assertTrue(full_reconcile)
|
||
|
self.assertRecordValues(full_reconcile, [{'exchange_move_id': False}])
|
||
|
self.assertRecordValues(partials, [
|
||
|
{
|
||
|
'amount': 40.0,
|
||
|
'debit_amount_currency': 120.0,
|
||
|
'credit_amount_currency': 120.0,
|
||
|
'debit_move_id': line_2.id,
|
||
|
'credit_move_id': line_1.id,
|
||
|
},
|
||
|
{
|
||
|
'amount': 20.0,
|
||
|
'debit_amount_currency': 0.0,
|
||
|
'credit_amount_currency': 0.0,
|
||
|
'debit_move_id': line_2.id,
|
||
|
'credit_move_id': partials.exchange_move_id.line_ids[0].id,
|
||
|
}
|
||
|
])
|
||
|
self.assertRecordValues(partials.exchange_move_id, [{'date': fields.Date.from_string('2017-01-31')}])
|
||
|
self.assertRecordValues(partials.exchange_move_id.line_ids, [
|
||
|
{
|
||
|
'debit': 0.0,
|
||
|
'credit': 20.0,
|
||
|
'amount_currency': 0.0,
|
||
|
'currency_id': currency.id,
|
||
|
'account_id': line_2.account_id.id,
|
||
|
},
|
||
|
{
|
||
|
'debit': 20.0,
|
||
|
'credit': 0.0,
|
||
|
'amount_currency': 0.0,
|
||
|
'currency_id': currency.id,
|
||
|
'account_id': self.exch_expense_account.id,
|
||
|
},
|
||
|
])
|
||
|
self.assertRecordValues(amls, [
|
||
|
{'amount_residual': 0.0, 'amount_residual_currency': 0.0, 'reconciled': True},
|
||
|
{'amount_residual': 0.0, 'amount_residual_currency': 0.0, 'reconciled': True},
|
||
|
])
|
||
|
|
||
|
def test_reconcile_exchange_difference_on_partial_same_foreign_currency_credit_income_full_payment(self):
|
||
|
currency = self.currency_data['currency']
|
||
|
|
||
|
line_1 = self.create_line_for_reconciliation(-60.0, -120.0, currency, '2017-01-01')
|
||
|
line_2 = self.create_line_for_reconciliation(40.0, 120.0, currency, '2016-01-01')
|
||
|
amls = line_1 + line_2
|
||
|
|
||
|
amls.reconcile()
|
||
|
partials = self._get_partials(amls)
|
||
|
full_reconcile = amls.full_reconcile_id
|
||
|
|
||
|
self.assertTrue(full_reconcile)
|
||
|
self.assertRecordValues(full_reconcile, [{'exchange_move_id': False}])
|
||
|
self.assertRecordValues(partials, [
|
||
|
{
|
||
|
'amount': 40.0,
|
||
|
'debit_amount_currency': 120.0,
|
||
|
'credit_amount_currency': 120.0,
|
||
|
'debit_move_id': line_2.id,
|
||
|
'credit_move_id': line_1.id,
|
||
|
},
|
||
|
{
|
||
|
'amount': 20.0,
|
||
|
'debit_amount_currency': 0.0,
|
||
|
'credit_amount_currency': 0.0,
|
||
|
'debit_move_id': partials.exchange_move_id.line_ids[0].id,
|
||
|
'credit_move_id': line_1.id,
|
||
|
}
|
||
|
])
|
||
|
self.assertRecordValues(partials.exchange_move_id, [{'date': fields.Date.from_string('2017-01-31')}])
|
||
|
self.assertRecordValues(partials.exchange_move_id.line_ids, [
|
||
|
{
|
||
|
'debit': 20.0,
|
||
|
'credit': 0.0,
|
||
|
'amount_currency': 0.0,
|
||
|
'currency_id': currency.id,
|
||
|
'account_id': line_1.account_id.id,
|
||
|
},
|
||
|
{
|
||
|
'debit': 0.0,
|
||
|
'credit': 20.0,
|
||
|
'amount_currency': 0.0,
|
||
|
'currency_id': currency.id,
|
||
|
'account_id': self.exch_income_account.id,
|
||
|
},
|
||
|
])
|
||
|
self.assertRecordValues(line_1 + line_2, [
|
||
|
{'amount_residual': 0.0, 'amount_residual_currency': 0.0, 'reconciled': True},
|
||
|
{'amount_residual': 0.0, 'amount_residual_currency': 0.0, 'reconciled': True},
|
||
|
])
|
||
|
|
||
|
def test_reconcile_exchange_difference_on_partial_one_debit_foreign_currency_debit_expense_full_payment(self):
|
||
|
comp_curr = self.company_data['currency']
|
||
|
foreign_curr = self.currency_data['currency']
|
||
|
|
||
|
line_1 = self.create_line_for_reconciliation(60.0, 120.0, foreign_curr, '2017-01-01')
|
||
|
line_2 = self.create_line_for_reconciliation(-40.0, -40.0, comp_curr, '2016-01-01')
|
||
|
amls = line_1 + line_2
|
||
|
|
||
|
amls.reconcile()
|
||
|
partials = self._get_partials(amls)
|
||
|
full_reconcile = amls.full_reconcile_id
|
||
|
|
||
|
self.assertTrue(full_reconcile)
|
||
|
self.assertRecordValues(full_reconcile, [{'exchange_move_id': False}])
|
||
|
self.assertRecordValues(partials, [
|
||
|
{
|
||
|
'amount': 40.0,
|
||
|
'debit_amount_currency': 120.0,
|
||
|
'credit_amount_currency': 40.0,
|
||
|
'debit_move_id': line_1.id,
|
||
|
'credit_move_id': line_2.id,
|
||
|
},
|
||
|
{
|
||
|
'amount': 20.0,
|
||
|
'debit_amount_currency': 0.0,
|
||
|
'credit_amount_currency': 0.0,
|
||
|
'debit_move_id': line_1.id,
|
||
|
'credit_move_id': partials.exchange_move_id.line_ids[0].id,
|
||
|
},
|
||
|
])
|
||
|
self.assertRecordValues(partials.exchange_move_id, [{'date': fields.Date.from_string('2017-01-31')}])
|
||
|
self.assertRecordValues(partials.exchange_move_id.line_ids, [
|
||
|
{
|
||
|
'debit': 0.0,
|
||
|
'credit': 20.0,
|
||
|
'amount_currency': 0.0,
|
||
|
'currency_id': foreign_curr.id,
|
||
|
'account_id': line_1.account_id.id,
|
||
|
},
|
||
|
{
|
||
|
'debit': 20.0,
|
||
|
'credit': 0.0,
|
||
|
'amount_currency': 0.0,
|
||
|
'currency_id': foreign_curr.id,
|
||
|
'account_id': self.exch_expense_account.id,
|
||
|
},
|
||
|
])
|
||
|
self.assertRecordValues(amls, [
|
||
|
{'amount_residual': 0.0, 'amount_residual_currency': 0.0, 'reconciled': True},
|
||
|
{'amount_residual': 0.0, 'amount_residual_currency': 0.0, 'reconciled': True},
|
||
|
])
|
||
|
|
||
|
def test_reconcile_exchange_difference_on_partial_one_credit_foreign_currency_debit_expense_full_payment(self):
|
||
|
comp_curr = self.company_data['currency']
|
||
|
foreign_curr = self.currency_data['currency']
|
||
|
|
||
|
line_1 = self.create_line_for_reconciliation(60.0, 60.0, comp_curr, '2017-01-01')
|
||
|
line_2 = self.create_line_for_reconciliation(-40.0, -120.0, foreign_curr, '2016-01-01')
|
||
|
amls = line_1 + line_2
|
||
|
|
||
|
amls.reconcile()
|
||
|
partials = self._get_partials(amls)
|
||
|
full_reconcile = amls.full_reconcile_id
|
||
|
|
||
|
self.assertTrue(full_reconcile)
|
||
|
self.assertRecordValues(full_reconcile, [{'exchange_move_id': False}])
|
||
|
self.assertRecordValues(partials, [
|
||
|
{
|
||
|
'amount': 40.0,
|
||
|
'debit_amount_currency': 40.0,
|
||
|
'credit_amount_currency': 120.0,
|
||
|
'debit_move_id': line_1.id,
|
||
|
'credit_move_id': line_2.id,
|
||
|
},
|
||
|
{
|
||
|
'amount': 20.0,
|
||
|
'debit_amount_currency': 20.0,
|
||
|
'credit_amount_currency': 20.0,
|
||
|
'debit_move_id': line_1.id,
|
||
|
'credit_move_id': partials.exchange_move_id.line_ids[0].id,
|
||
|
},
|
||
|
])
|
||
|
self.assertRecordValues(partials.exchange_move_id, [{'date': fields.Date.from_string('2017-01-31')}])
|
||
|
self.assertRecordValues(partials.exchange_move_id.line_ids, [
|
||
|
{
|
||
|
'debit': 0.0,
|
||
|
'credit': 20.0,
|
||
|
'amount_currency': -20.0,
|
||
|
'currency_id': comp_curr.id,
|
||
|
'account_id': line_1.account_id.id,
|
||
|
},
|
||
|
{
|
||
|
'debit': 20.0,
|
||
|
'credit': 0.0,
|
||
|
'amount_currency': 20.0,
|
||
|
'currency_id': comp_curr.id,
|
||
|
'account_id': self.exch_expense_account.id,
|
||
|
},
|
||
|
])
|
||
|
self.assertRecordValues(amls, [
|
||
|
{'amount_residual': 0.0, 'amount_residual_currency': 0.0, 'reconciled': True},
|
||
|
{'amount_residual': 0.0, 'amount_residual_currency': 0.0, 'reconciled': True},
|
||
|
])
|
||
|
|
||
|
def test_reconcile_exchange_difference_on_partial_one_debit_foreign_currency_debit_income_full_payment(self):
|
||
|
comp_curr = self.company_data['currency']
|
||
|
foreign_curr = self.currency_data['currency']
|
||
|
|
||
|
line_1 = self.create_line_for_reconciliation(40.0, 120.0, foreign_curr, '2016-01-01')
|
||
|
line_2 = self.create_line_for_reconciliation(-60.0, -60.0, comp_curr, '2017-01-01')
|
||
|
amls = line_1 + line_2
|
||
|
|
||
|
amls.reconcile()
|
||
|
partials = self._get_partials(amls)
|
||
|
full_reconcile = amls.full_reconcile_id
|
||
|
|
||
|
self.assertTrue(full_reconcile)
|
||
|
self.assertRecordValues(full_reconcile, [{'exchange_move_id': False}])
|
||
|
self.assertRecordValues(partials, [
|
||
|
{
|
||
|
'amount': 40.0,
|
||
|
'debit_amount_currency': 120.0,
|
||
|
'credit_amount_currency': 40.0,
|
||
|
'debit_move_id': line_1.id,
|
||
|
'credit_move_id': line_2.id,
|
||
|
},
|
||
|
{
|
||
|
'amount': 20.0,
|
||
|
'debit_amount_currency': 20.0,
|
||
|
'credit_amount_currency': 20.0,
|
||
|
'debit_move_id': partials.exchange_move_id.line_ids[0].id,
|
||
|
'credit_move_id': line_2.id,
|
||
|
},
|
||
|
])
|
||
|
self.assertRecordValues(partials.exchange_move_id, [{'date': fields.Date.from_string('2017-01-31')}])
|
||
|
self.assertRecordValues(partials.exchange_move_id.line_ids, [
|
||
|
{
|
||
|
'debit': 20.0,
|
||
|
'credit': 0.0,
|
||
|
'amount_currency': 20.0,
|
||
|
'currency_id': comp_curr.id,
|
||
|
'account_id': line_2.account_id.id,
|
||
|
},
|
||
|
{
|
||
|
'debit': 0.0,
|
||
|
'credit': 20.0,
|
||
|
'amount_currency': -20.0,
|
||
|
'currency_id': comp_curr.id,
|
||
|
'account_id': self.exch_income_account.id,
|
||
|
},
|
||
|
])
|
||
|
self.assertRecordValues(amls, [
|
||
|
{'amount_residual': 0.0, 'amount_residual_currency': 0.0, 'reconciled': True},
|
||
|
{'amount_residual': 0.0, 'amount_residual_currency': 0.0, 'reconciled': True},
|
||
|
])
|
||
|
|
||
|
def test_reconcile_exchange_difference_on_partial_one_credit_foreign_currency_debit_income_full_payment(self):
|
||
|
comp_curr = self.company_data['currency']
|
||
|
foreign_curr = self.currency_data['currency']
|
||
|
|
||
|
line_1 = self.create_line_for_reconciliation(40.0, 40.0, comp_curr, '2016-01-01')
|
||
|
line_2 = self.create_line_for_reconciliation(-60.0, -120.0, foreign_curr, '2017-01-01')
|
||
|
amls = line_1 + line_2
|
||
|
|
||
|
amls.reconcile()
|
||
|
partials = self._get_partials(amls)
|
||
|
full_reconcile = amls.full_reconcile_id
|
||
|
|
||
|
self.assertTrue(full_reconcile)
|
||
|
self.assertRecordValues(full_reconcile, [{'exchange_move_id': False}])
|
||
|
self.assertRecordValues(partials, [
|
||
|
{
|
||
|
'amount': 40.0,
|
||
|
'debit_amount_currency': 40.0,
|
||
|
'credit_amount_currency': 120.0,
|
||
|
'debit_move_id': line_1.id,
|
||
|
'credit_move_id': line_2.id,
|
||
|
},
|
||
|
{
|
||
|
'amount': 20.0,
|
||
|
'debit_amount_currency': 0.0,
|
||
|
'credit_amount_currency': 0.0,
|
||
|
'debit_move_id': partials.exchange_move_id.line_ids[0].id,
|
||
|
'credit_move_id': line_2.id,
|
||
|
},
|
||
|
])
|
||
|
self.assertRecordValues(partials.exchange_move_id, [{'date': fields.Date.from_string('2017-01-31')}])
|
||
|
self.assertRecordValues(partials.exchange_move_id.line_ids, [
|
||
|
{
|
||
|
'debit': 20.0,
|
||
|
'credit': 0.0,
|
||
|
'amount_currency': 0.0,
|
||
|
'currency_id': foreign_curr.id,
|
||
|
'account_id': line_2.account_id.id,
|
||
|
},
|
||
|
{
|
||
|
'debit': 0.0,
|
||
|
'credit': 20.0,
|
||
|
'amount_currency': 0.0,
|
||
|
'currency_id': foreign_curr.id,
|
||
|
'account_id': self.exch_income_account.id,
|
||
|
},
|
||
|
])
|
||
|
self.assertRecordValues(amls, [
|
||
|
{'amount_residual': 0.0, 'amount_residual_currency': 0.0, 'reconciled': True},
|
||
|
{'amount_residual': 0.0, 'amount_residual_currency': 0.0, 'reconciled': True},
|
||
|
])
|
||
|
|
||
|
def test_reconcile_exchange_difference_on_partial_one_debit_foreign_currency_credit_expense_full_payment(self):
|
||
|
comp_curr = self.company_data['currency']
|
||
|
foreign_curr = self.currency_data['currency']
|
||
|
|
||
|
line_1 = self.create_line_for_reconciliation(-40.0, -40.0, comp_curr, '2016-01-01')
|
||
|
line_2 = self.create_line_for_reconciliation(60.0, 120.0, foreign_curr, '2017-01-01')
|
||
|
amls = line_1 + line_2
|
||
|
|
||
|
amls.reconcile()
|
||
|
partials = self._get_partials(amls)
|
||
|
full_reconcile = amls.full_reconcile_id
|
||
|
|
||
|
self.assertTrue(full_reconcile)
|
||
|
self.assertRecordValues(full_reconcile, [{'exchange_move_id': False}])
|
||
|
self.assertRecordValues(partials, [
|
||
|
{
|
||
|
'amount': 40.0,
|
||
|
'debit_amount_currency': 120.0,
|
||
|
'credit_amount_currency': 40.0,
|
||
|
'debit_move_id': line_2.id,
|
||
|
'credit_move_id': line_1.id,
|
||
|
},
|
||
|
{
|
||
|
'amount': 20.0,
|
||
|
'debit_amount_currency': 0.0,
|
||
|
'credit_amount_currency': 0.0,
|
||
|
'debit_move_id': line_2.id,
|
||
|
'credit_move_id': partials.exchange_move_id.line_ids[0].id,
|
||
|
},
|
||
|
])
|
||
|
self.assertRecordValues(partials.exchange_move_id, [{'date': fields.Date.from_string('2017-01-31')}])
|
||
|
self.assertRecordValues(partials.exchange_move_id.line_ids, [
|
||
|
{
|
||
|
'debit': 0.0,
|
||
|
'credit': 20.0,
|
||
|
'amount_currency': 0.0,
|
||
|
'currency_id': foreign_curr.id,
|
||
|
'account_id': line_2.account_id.id,
|
||
|
},
|
||
|
{
|
||
|
'debit': 20.0,
|
||
|
'credit': 0.0,
|
||
|
'amount_currency': 0.0,
|
||
|
'currency_id': foreign_curr.id,
|
||
|
'account_id': self.exch_expense_account.id,
|
||
|
},
|
||
|
])
|
||
|
self.assertRecordValues(amls, [
|
||
|
{'amount_residual': 0.0, 'amount_residual_currency': 0.0, 'reconciled': True},
|
||
|
{'amount_residual': 0.0, 'amount_residual_currency': 0.0, 'reconciled': True},
|
||
|
])
|
||
|
|
||
|
def test_reconcile_exchange_difference_on_partial_one_credit_foreign_currency_credit_expense_full_payment(self):
|
||
|
comp_curr = self.company_data['currency']
|
||
|
foreign_curr = self.currency_data['currency']
|
||
|
|
||
|
line_1 = self.create_line_for_reconciliation(-40.0, -120.0, foreign_curr, '2016-01-01')
|
||
|
line_2 = self.create_line_for_reconciliation(60.0, 60.0, comp_curr, '2017-01-01')
|
||
|
amls = line_1 + line_2
|
||
|
|
||
|
amls.reconcile()
|
||
|
partials = self._get_partials(amls)
|
||
|
full_reconcile = amls.full_reconcile_id
|
||
|
|
||
|
self.assertTrue(full_reconcile)
|
||
|
self.assertRecordValues(full_reconcile, [{'exchange_move_id': False}])
|
||
|
self.assertRecordValues(partials, [
|
||
|
{
|
||
|
'amount': 40.0,
|
||
|
'debit_amount_currency': 40.0,
|
||
|
'credit_amount_currency': 120.0,
|
||
|
'debit_move_id': line_2.id,
|
||
|
'credit_move_id': line_1.id,
|
||
|
},
|
||
|
{
|
||
|
'amount': 20.0,
|
||
|
'debit_amount_currency': 20.0,
|
||
|
'credit_amount_currency': 20.0,
|
||
|
'debit_move_id': line_2.id,
|
||
|
'credit_move_id': partials.exchange_move_id.line_ids[0].id,
|
||
|
},
|
||
|
])
|
||
|
self.assertRecordValues(partials.exchange_move_id, [{'date': fields.Date.from_string('2017-01-31')}])
|
||
|
self.assertRecordValues(partials.exchange_move_id.line_ids, [
|
||
|
{
|
||
|
'debit': 0.0,
|
||
|
'credit': 20.0,
|
||
|
'amount_currency': -20.0,
|
||
|
'currency_id': comp_curr.id,
|
||
|
'account_id': line_2.account_id.id,
|
||
|
},
|
||
|
{
|
||
|
'debit': 20.0,
|
||
|
'credit': 0.0,
|
||
|
'amount_currency': 20.0,
|
||
|
'currency_id': comp_curr.id,
|
||
|
'account_id': self.exch_expense_account.id,
|
||
|
},
|
||
|
])
|
||
|
self.assertRecordValues(amls, [
|
||
|
{'amount_residual': 0.0, 'amount_residual_currency': 0.0, 'reconciled': True},
|
||
|
{'amount_residual': 0.0, 'amount_residual_currency': 0.0, 'reconciled': True},
|
||
|
])
|
||
|
|
||
|
def test_reconcile_exchange_difference_on_partial_one_debit_foreign_currency_credit_income_full_payment(self):
|
||
|
comp_curr = self.company_data['currency']
|
||
|
foreign_curr = self.currency_data['currency']
|
||
|
|
||
|
line_1 = self.create_line_for_reconciliation(-60.0, -60.0, comp_curr, '2017-01-01')
|
||
|
line_2 = self.create_line_for_reconciliation(40.0, 120.0, foreign_curr, '2016-01-01')
|
||
|
amls = line_1 + line_2
|
||
|
|
||
|
amls.reconcile()
|
||
|
partials = self._get_partials(amls)
|
||
|
full_reconcile = amls.full_reconcile_id
|
||
|
|
||
|
self.assertTrue(full_reconcile)
|
||
|
self.assertRecordValues(full_reconcile, [{'exchange_move_id': False}])
|
||
|
self.assertRecordValues(partials, [
|
||
|
{
|
||
|
'amount': 40.0,
|
||
|
'debit_amount_currency': 120.0,
|
||
|
'credit_amount_currency': 40.0,
|
||
|
'debit_move_id': line_2.id,
|
||
|
'credit_move_id': line_1.id,
|
||
|
},
|
||
|
{
|
||
|
'amount': 20.0,
|
||
|
'debit_amount_currency': 20.0,
|
||
|
'credit_amount_currency': 20.0,
|
||
|
'debit_move_id': partials.exchange_move_id.line_ids[0].id,
|
||
|
'credit_move_id': line_1.id,
|
||
|
},
|
||
|
])
|
||
|
self.assertRecordValues(partials.exchange_move_id, [{'date': fields.Date.from_string('2017-01-31')}])
|
||
|
self.assertRecordValues(partials.exchange_move_id.line_ids, [
|
||
|
{
|
||
|
'debit': 20.0,
|
||
|
'credit': 0.0,
|
||
|
'amount_currency': 20.0,
|
||
|
'currency_id': comp_curr.id,
|
||
|
'account_id': line_1.account_id.id,
|
||
|
},
|
||
|
{
|
||
|
'debit': 0.0,
|
||
|
'credit': 20.0,
|
||
|
'amount_currency': -20.0,
|
||
|
'currency_id': comp_curr.id,
|
||
|
'account_id': self.exch_income_account.id,
|
||
|
},
|
||
|
])
|
||
|
self.assertRecordValues(amls, [
|
||
|
{'amount_residual': 0.0, 'amount_residual_currency': 0.0, 'reconciled': True},
|
||
|
{'amount_residual': 0.0, 'amount_residual_currency': 0.0, 'reconciled': True},
|
||
|
])
|
||
|
|
||
|
def test_reconcile_exchange_difference_on_partial_one_credit_foreign_currency_credit_income_full_payment(self):
|
||
|
comp_curr = self.company_data['currency']
|
||
|
foreign_curr = self.currency_data['currency']
|
||
|
|
||
|
line_1 = self.create_line_for_reconciliation(-60.0, -120.0, foreign_curr, '2017-01-01')
|
||
|
line_2 = self.create_line_for_reconciliation(40.0, 40.0, comp_curr, '2016-01-01')
|
||
|
amls = line_1 + line_2
|
||
|
|
||
|
amls.reconcile()
|
||
|
partials = self._get_partials(amls)
|
||
|
full_reconcile = amls.full_reconcile_id
|
||
|
|
||
|
self.assertTrue(full_reconcile)
|
||
|
self.assertRecordValues(full_reconcile, [{'exchange_move_id': False}])
|
||
|
self.assertRecordValues(partials, [
|
||
|
{
|
||
|
'amount': 40.0,
|
||
|
'debit_amount_currency': 40.0,
|
||
|
'credit_amount_currency': 120.0,
|
||
|
'debit_move_id': line_2.id,
|
||
|
'credit_move_id': line_1.id,
|
||
|
},
|
||
|
{
|
||
|
'amount': 20.0,
|
||
|
'debit_amount_currency': 0.0,
|
||
|
'credit_amount_currency': 0.0,
|
||
|
'debit_move_id': partials.exchange_move_id.line_ids[0].id,
|
||
|
'credit_move_id': line_1.id,
|
||
|
},
|
||
|
])
|
||
|
self.assertRecordValues(partials.exchange_move_id, [{'date': fields.Date.from_string('2017-01-31')}])
|
||
|
self.assertRecordValues(partials.exchange_move_id.line_ids, [
|
||
|
{
|
||
|
'debit': 20.0,
|
||
|
'credit': 0.0,
|
||
|
'amount_currency': 0.0,
|
||
|
'currency_id': foreign_curr.id,
|
||
|
'account_id': line_1.account_id.id,
|
||
|
},
|
||
|
{
|
||
|
'debit': 0.0,
|
||
|
'credit': 20.0,
|
||
|
'amount_currency': 0.0,
|
||
|
'currency_id': foreign_curr.id,
|
||
|
'account_id': self.exch_income_account.id,
|
||
|
},
|
||
|
])
|
||
|
self.assertRecordValues(amls, [
|
||
|
{'amount_residual': 0.0, 'amount_residual_currency': 0.0, 'reconciled': True},
|
||
|
{'amount_residual': 0.0, 'amount_residual_currency': 0.0, 'reconciled': True},
|
||
|
])
|
||
|
|
||
|
def test_reconcile_invoice_company_curr_payment_foreign_curr(self):
|
||
|
""" Test we always use the payment rate in priority when performing a reconciliation. """
|
||
|
comp_curr = self.company_data['currency']
|
||
|
foreign_curr = self.currency_data['currency']
|
||
|
|
||
|
invoice = self.env['account.move'].create({
|
||
|
'move_type': 'out_invoice',
|
||
|
'invoice_date': '2017-01-01',
|
||
|
'date': '2017-01-01',
|
||
|
'partner_id': self.partner_a.id,
|
||
|
'currency_id': comp_curr.id,
|
||
|
'invoice_line_ids': [Command.create({
|
||
|
'product_id': self.product_a.id,
|
||
|
'price_unit': 60.0,
|
||
|
'tax_ids': [],
|
||
|
})],
|
||
|
})
|
||
|
invoice.action_post()
|
||
|
|
||
|
payment = self.env['account.payment.register']\
|
||
|
.with_context(active_model=invoice._name, active_ids=invoice.ids)\
|
||
|
.create({
|
||
|
'payment_date': '2016-01-01',
|
||
|
'amount': 90.0,
|
||
|
'currency_id': foreign_curr.id,
|
||
|
})\
|
||
|
._create_payments()
|
||
|
|
||
|
lines = (invoice + payment.move_id).line_ids\
|
||
|
.filtered(lambda x: x.account_id.account_type == 'asset_receivable')
|
||
|
self.assertRecordValues(lines, [
|
||
|
# pylint: disable=bad-whitespace
|
||
|
{'amount_residual': 30.0, 'amount_residual_currency': 30.0, 'reconciled': False},
|
||
|
{'amount_residual': 0.0, 'amount_residual_currency': 0.0, 'reconciled': True},
|
||
|
])
|
||
|
|
||
|
def test_reverse_with_multiple_lines(self):
|
||
|
"""
|
||
|
Test if all lines from a reversed entry are fully reconciled
|
||
|
"""
|
||
|
move = self.env['account.move'].create({
|
||
|
'move_type': 'entry',
|
||
|
'line_ids': [
|
||
|
(0, 0, {
|
||
|
'debit': 1200.0,
|
||
|
'credit': 0.0,
|
||
|
'amount_currency': 3600.0,
|
||
|
'currency_id': self.currency_data['currency'].id,
|
||
|
'account_id': self.company_data['default_account_receivable'].id,
|
||
|
}),
|
||
|
(0, 0, {
|
||
|
'debit': 0.0,
|
||
|
'credit': 200.0,
|
||
|
'account_id': self.company_data['default_account_payable'].id,
|
||
|
}),
|
||
|
(0, 0, {
|
||
|
'debit': 0.0,
|
||
|
'credit': 400.0,
|
||
|
'account_id': self.company_data['default_account_payable'].id,
|
||
|
}),
|
||
|
(0, 0, {
|
||
|
'debit': 0.0,
|
||
|
'credit': 600.0,
|
||
|
'account_id': self.company_data['default_account_payable'].id,
|
||
|
}),
|
||
|
],
|
||
|
})
|
||
|
|
||
|
move.action_post()
|
||
|
|
||
|
lines_to_reconcile = move.line_ids.filtered(lambda x: (x.account_id.reconcile or x.account_id.account_type in ('asset_cash', 'liability_credit_card')) and not x.reconciled)
|
||
|
|
||
|
self.assertRecordValues(lines_to_reconcile, [
|
||
|
{'debit': 1200.0, 'credit': 0.0, 'reconciled': False},
|
||
|
{'debit': 0.0, 'credit': 200.0, 'reconciled': False},
|
||
|
{'debit': 0.0, 'credit': 400.0, 'reconciled': False},
|
||
|
{'debit': 0.0, 'credit': 600.0, 'reconciled': False},
|
||
|
])
|
||
|
|
||
|
reversed_move = move._reverse_moves(cancel=True)
|
||
|
|
||
|
reversed_lines = reversed_move.line_ids.filtered(lambda x: (
|
||
|
x.account_id.reconcile or x.account_id.account_type in ('asset_cash', 'liability_credit_card')
|
||
|
))
|
||
|
|
||
|
self.assertRecordValues(reversed_lines, [
|
||
|
{'debit': 0.0, 'credit': 1200.0, 'reconciled': True},
|
||
|
{'debit': 200.0, 'credit': 0.0, 'reconciled': True},
|
||
|
{'debit': 400.0, 'credit': 0.0, 'reconciled': True},
|
||
|
{'debit': 600.0, 'credit': 0.0, 'reconciled': True},
|
||
|
])
|
||
|
|
||
|
self.assertTrue(all([line.full_reconcile_id for line in reversed_lines]))
|
||
|
|
||
|
def test_reconcile_special_mexican_workflow_1(self):
|
||
|
comp_curr = self.company_data['currency']
|
||
|
foreign_curr = self.env['res.currency'].create({
|
||
|
'name': "Sushi",
|
||
|
'symbol': '🍣',
|
||
|
'rounding': 0.01,
|
||
|
'rate_ids': [
|
||
|
Command.create({'name': '2019-09-24', 'rate': 0.050800000000}),
|
||
|
Command.create({'name': '2019-06-28', 'rate': 0.052235000000}),
|
||
|
Command.create({'name': '2019-06-24', 'rate': 0.052686000000}),
|
||
|
Command.create({'name': '2019-06-20', 'rate': 0.052353000000}),
|
||
|
Command.create({'name': '2019-06-12', 'rate': 0.052072000000}),
|
||
|
],
|
||
|
})
|
||
|
|
||
|
refund1 = self.env['account.move'].create({
|
||
|
'move_type': 'out_refund',
|
||
|
'invoice_date': '2019-06-12',
|
||
|
'date': '2019-06-12',
|
||
|
'partner_id': self.partner_a.id,
|
||
|
'currency_id': self.company_data['currency'].id,
|
||
|
'invoice_line_ids': [Command.create({
|
||
|
'product_id': self.product_a.id,
|
||
|
'price_unit': 1385.92,
|
||
|
'tax_ids': [],
|
||
|
})],
|
||
|
})
|
||
|
refund1.action_post()
|
||
|
refund1_rec_line = refund1.line_ids.filtered(lambda x: x.account_id.account_type == 'asset_receivable')
|
||
|
|
||
|
inv1 = self.env['account.move'].create({
|
||
|
'move_type': 'out_invoice',
|
||
|
'invoice_date': '2019-06-20',
|
||
|
'date': '2019-06-20',
|
||
|
'partner_id': self.partner_a.id,
|
||
|
'currency_id': self.company_data['currency'].id,
|
||
|
'invoice_line_ids': [Command.create({
|
||
|
'product_id': self.product_a.id,
|
||
|
'price_unit': 839.40,
|
||
|
'tax_ids': [],
|
||
|
})],
|
||
|
})
|
||
|
inv1.action_post()
|
||
|
inv1_rec_line = inv1.line_ids.filtered(lambda x: x.account_id.account_type == 'asset_receivable')
|
||
|
|
||
|
inv2 = self.env['account.move'].create({
|
||
|
'move_type': 'out_invoice',
|
||
|
'invoice_date': '2019-06-24',
|
||
|
'date': '2019-06-24',
|
||
|
'partner_id': self.partner_a.id,
|
||
|
'currency_id': foreign_curr.id,
|
||
|
'invoice_line_ids': [Command.create({
|
||
|
'product_id': self.product_a.id,
|
||
|
'price_unit': 1935.72,
|
||
|
'tax_ids': [],
|
||
|
})],
|
||
|
})
|
||
|
inv2.action_post()
|
||
|
inv2_rec_line = inv2.line_ids.filtered(lambda x: x.account_id.account_type == 'asset_receivable')
|
||
|
|
||
|
pay1 = self.env['account.payment'].create({
|
||
|
'partner_type': 'customer',
|
||
|
'payment_type': 'inbound',
|
||
|
'date': '2019-06-28',
|
||
|
'amount': 1907.17,
|
||
|
'partner_id': self.partner_a.id,
|
||
|
'currency_id': foreign_curr.id,
|
||
|
})
|
||
|
pay1_liquidity_line = pay1.line_ids.filtered(lambda x: x.account_id.account_type != 'asset_receivable')
|
||
|
pay1_rec_line = pay1.line_ids.filtered(lambda x: x.account_id.account_type == 'asset_receivable')
|
||
|
pay1.action_post()
|
||
|
pay1.write({'line_ids': [
|
||
|
Command.update(pay1_liquidity_line.id, {'debit': 36511.34}),
|
||
|
Command.update(pay1_rec_line.id, {'credit': 36511.34}),
|
||
|
]})
|
||
|
|
||
|
pay2 = self.env['account.payment'].create({
|
||
|
'partner_type': 'customer',
|
||
|
'payment_type': 'inbound',
|
||
|
'date': '2019-09-24',
|
||
|
'amount': 0.09,
|
||
|
'partner_id': self.partner_a.id,
|
||
|
'currency_id': foreign_curr.id,
|
||
|
})
|
||
|
pay2.action_post()
|
||
|
pay2_rec_line = pay2.line_ids.filtered(lambda x: x.account_id.account_type == 'asset_receivable')
|
||
|
|
||
|
# 1st reconciliation refund1 + inv1
|
||
|
self.assert_invoice_outstanding_to_reconcile_widget(refund1, {
|
||
|
inv1.id: 839.40,
|
||
|
inv2.id: 36740.69,
|
||
|
})
|
||
|
self.assertRecordValues(refund1_rec_line + inv1_rec_line, [
|
||
|
{'amount_residual': -1385.92, 'amount_residual_currency': -1385.92, 'reconciled': False},
|
||
|
{'amount_residual': 839.40, 'amount_residual_currency': 839.40, 'reconciled': False},
|
||
|
])
|
||
|
|
||
|
(refund1_rec_line + inv1_rec_line).reconcile()
|
||
|
partials = self._get_partials(refund1_rec_line + inv1_rec_line)
|
||
|
|
||
|
self.assertRecordValues(partials, [{
|
||
|
'amount': 839.4,
|
||
|
'debit_amount_currency': 839.4,
|
||
|
'credit_amount_currency': 839.4,
|
||
|
'debit_move_id': inv1_rec_line.id,
|
||
|
'credit_move_id': refund1_rec_line.id,
|
||
|
'exchange_move_id': None,
|
||
|
}])
|
||
|
self.assertRecordValues(refund1_rec_line + inv1_rec_line, [
|
||
|
{'amount_residual': -546.52, 'amount_residual_currency': -546.52, 'reconciled': False},
|
||
|
{'amount_residual': 0.0, 'amount_residual_currency': 0.0, 'reconciled': True},
|
||
|
])
|
||
|
self.assert_invoice_outstanding_reconciled_widget(refund1, {
|
||
|
inv1.id: 839.40,
|
||
|
})
|
||
|
|
||
|
# 2th reconciliation refund1 + inv2
|
||
|
self.assert_invoice_outstanding_to_reconcile_widget(refund1, {
|
||
|
inv2.id: 36740.69,
|
||
|
})
|
||
|
self.assertRecordValues(refund1_rec_line + inv2_rec_line, [
|
||
|
{'amount_residual': -546.52, 'amount_residual_currency': -546.52, 'reconciled': False},
|
||
|
{'amount_residual': 36740.69, 'amount_residual_currency': 1935.72, 'reconciled': False},
|
||
|
])
|
||
|
|
||
|
partials = self._get_partials(refund1_rec_line + inv2_rec_line)
|
||
|
(refund1_rec_line + inv2_rec_line).reconcile()
|
||
|
partials = self._get_partials(refund1_rec_line + inv2_rec_line) - partials
|
||
|
|
||
|
self.assertRecordValues(partials, [
|
||
|
{
|
||
|
'amount': 540.18,
|
||
|
'debit_amount_currency': 28.46,
|
||
|
'credit_amount_currency': 540.18,
|
||
|
'debit_move_id': inv2_rec_line.id,
|
||
|
'credit_move_id': refund1_rec_line.id,
|
||
|
},
|
||
|
{
|
||
|
'amount': 6.34,
|
||
|
'debit_amount_currency': 6.34,
|
||
|
'credit_amount_currency': 6.34,
|
||
|
'debit_move_id': partials.exchange_move_id.line_ids[0].id,
|
||
|
'credit_move_id': refund1_rec_line.id,
|
||
|
},
|
||
|
])
|
||
|
self.assertRecordValues(partials.exchange_move_id, [{'date': fields.Date.from_string('2019-06-30')}])
|
||
|
self.assertRecordValues(partials.exchange_move_id.line_ids, [
|
||
|
{
|
||
|
'debit': 6.34,
|
||
|
'credit': 0.0,
|
||
|
'amount_currency': 6.34,
|
||
|
'currency_id': comp_curr.id,
|
||
|
'account_id': refund1_rec_line.account_id.id,
|
||
|
},
|
||
|
{
|
||
|
'debit': 0.0,
|
||
|
'credit': 6.34,
|
||
|
'amount_currency': -6.34,
|
||
|
'currency_id': comp_curr.id,
|
||
|
'account_id': self.exch_income_account.id,
|
||
|
},
|
||
|
])
|
||
|
self.assertRecordValues(refund1_rec_line + inv2_rec_line, [
|
||
|
{'amount_residual': 0.0, 'amount_residual_currency': 0.0, 'reconciled': True},
|
||
|
{'amount_residual': 36200.51, 'amount_residual_currency': 1907.26, 'reconciled': False},
|
||
|
])
|
||
|
self.assert_invoice_outstanding_reconciled_widget(refund1, {
|
||
|
inv1.id: 839.40,
|
||
|
inv2.id: 540.18,
|
||
|
partials.exchange_move_id.id: 6.34,
|
||
|
})
|
||
|
self.assert_invoice_outstanding_to_reconcile_widget(refund1, {})
|
||
|
|
||
|
# 3th reconciliation inv1 + pay1
|
||
|
self.assert_invoice_outstanding_reconciled_widget(inv2, {
|
||
|
refund1.id: 28.46,
|
||
|
partials.exchange_move_id.id: 6.34,
|
||
|
})
|
||
|
self.assert_invoice_outstanding_to_reconcile_widget(inv2, {
|
||
|
pay1.move_id.id: 1907.17,
|
||
|
pay2.move_id.id: 0.09,
|
||
|
})
|
||
|
self.assertRecordValues(inv2_rec_line + pay1_rec_line, [
|
||
|
{'amount_residual': 36200.51, 'amount_residual_currency': 1907.26, 'reconciled': False},
|
||
|
{'amount_residual': -36511.34, 'amount_residual_currency': -1907.17, 'reconciled': False},
|
||
|
])
|
||
|
|
||
|
partials = self._get_partials(inv2_rec_line + pay1_rec_line)
|
||
|
(inv2_rec_line + pay1_rec_line).reconcile()
|
||
|
partials = self._get_partials(inv2_rec_line + pay1_rec_line) - partials
|
||
|
|
||
|
self.assertRecordValues(partials, [
|
||
|
{
|
||
|
'amount': 36198.80,
|
||
|
'debit_amount_currency': 1907.17,
|
||
|
'credit_amount_currency': 1907.17,
|
||
|
'debit_move_id': inv2_rec_line.id,
|
||
|
'credit_move_id': pay1_rec_line.id,
|
||
|
},
|
||
|
{
|
||
|
'amount': 312.54,
|
||
|
'debit_amount_currency': 0.0,
|
||
|
'credit_amount_currency': 0.0,
|
||
|
'debit_move_id': partials.exchange_move_id.line_ids[0].id,
|
||
|
'credit_move_id': pay1_rec_line.id,
|
||
|
},
|
||
|
])
|
||
|
self.assertRecordValues(partials.exchange_move_id, [{'date': fields.Date.from_string('2019-06-30')}])
|
||
|
self.assertRecordValues(partials.exchange_move_id.line_ids, [
|
||
|
{
|
||
|
'debit': 312.54,
|
||
|
'credit': 0.0,
|
||
|
'amount_currency': 0.0,
|
||
|
'currency_id': foreign_curr.id,
|
||
|
'account_id': pay1_rec_line.account_id.id,
|
||
|
},
|
||
|
{
|
||
|
'debit': 0.0,
|
||
|
'credit': 312.54,
|
||
|
'amount_currency': 0.0,
|
||
|
'currency_id': foreign_curr.id,
|
||
|
'account_id': self.exch_income_account.id,
|
||
|
},
|
||
|
])
|
||
|
self.assertRecordValues(inv2_rec_line + pay1_rec_line, [
|
||
|
{'amount_residual': 1.71, 'amount_residual_currency': 0.09, 'reconciled': False},
|
||
|
{'amount_residual': 0.0, 'amount_residual_currency': 0.0, 'reconciled': True},
|
||
|
])
|
||
|
payment_exchange_id = inv2_rec_line.matched_credit_ids.filtered(lambda x: x not in partials)
|
||
|
|
||
|
self.assert_invoice_outstanding_reconciled_widget(inv2, {
|
||
|
refund1.id: 28.46,
|
||
|
pay1.move_id.id: 1907.17,
|
||
|
partials.exchange_move_id.id: 312.54,
|
||
|
payment_exchange_id[0].exchange_move_id.id: 6.34,
|
||
|
})
|
||
|
|
||
|
# 4th reconciliation inv2 + pay2
|
||
|
self.assert_invoice_outstanding_to_reconcile_widget(inv2, {
|
||
|
pay2.move_id.id: 0.09,
|
||
|
})
|
||
|
self.assertRecordValues(inv2_rec_line + pay2_rec_line, [
|
||
|
{'amount_residual': 1.71, 'amount_residual_currency': 0.09, 'reconciled': False},
|
||
|
{'amount_residual': -1.77, 'amount_residual_currency': -0.09, 'reconciled': False},
|
||
|
])
|
||
|
|
||
|
partials = self._get_partials(inv2_rec_line + pay2_rec_line)
|
||
|
(inv2_rec_line + pay2_rec_line).reconcile()
|
||
|
partials = self._get_partials(inv2_rec_line + pay2_rec_line) - partials
|
||
|
|
||
|
self.assertRecordValues(partials, [
|
||
|
{
|
||
|
'amount': 1.71,
|
||
|
'debit_amount_currency': 0.09,
|
||
|
'credit_amount_currency': 0.09,
|
||
|
'debit_move_id': inv2_rec_line.id,
|
||
|
'credit_move_id': pay2_rec_line.id,
|
||
|
},
|
||
|
{
|
||
|
'amount': 0.06,
|
||
|
'debit_amount_currency': 0.0,
|
||
|
'credit_amount_currency': 0.0,
|
||
|
'debit_move_id': partials.exchange_move_id.line_ids[0].id,
|
||
|
'credit_move_id': pay2_rec_line.id,
|
||
|
},
|
||
|
])
|
||
|
self.assertRecordValues(partials.exchange_move_id, [{'date': fields.Date.from_string('2019-09-30')}])
|
||
|
self.assertRecordValues(partials.exchange_move_id.line_ids, [
|
||
|
{
|
||
|
'debit': 0.06,
|
||
|
'credit': 0.0,
|
||
|
'amount_currency': 0.0,
|
||
|
'currency_id': foreign_curr.id,
|
||
|
'account_id': inv2_rec_line.account_id.id,
|
||
|
},
|
||
|
{
|
||
|
'debit': 0.0,
|
||
|
'credit': 0.06,
|
||
|
'amount_currency': 0.0,
|
||
|
'currency_id': foreign_curr.id,
|
||
|
'account_id': self.exch_income_account.id,
|
||
|
},
|
||
|
])
|
||
|
self.assertRecordValues(inv2_rec_line + pay2_rec_line, [
|
||
|
{'amount_residual': 0.0, 'amount_residual_currency': 0.0, 'reconciled': True},
|
||
|
{'amount_residual': 0.0, 'amount_residual_currency': 0.0, 'reconciled': True},
|
||
|
])
|
||
|
payment_exchange_id = inv2_rec_line.matched_credit_ids.filtered(lambda x: x not in partials)
|
||
|
|
||
|
self.assert_invoice_outstanding_reconciled_widget(inv2, {
|
||
|
refund1.id: 28.46,
|
||
|
pay1.move_id.id: 1907.17,
|
||
|
pay2.move_id.id: 0.09,
|
||
|
partials.exchange_move_id.id: 0.06,
|
||
|
payment_exchange_id[0].exchange_move_id.id: 6.34,
|
||
|
payment_exchange_id[1].exchange_move_id.id: 312.54,
|
||
|
})
|
||
|
self.assert_invoice_outstanding_to_reconcile_widget(inv2, {})
|
||
|
|
||
|
self.assertRecordValues(inv2_rec_line.full_reconcile_id, [{'exchange_move_id': None}])
|
||
|
|
||
|
def test_reconcile_special_mexican_workflow_2(self):
|
||
|
comp_curr = self.company_data['currency']
|
||
|
foreign_curr = self.env['res.currency'].create({
|
||
|
'name': "Sushi",
|
||
|
'symbol': '🍣',
|
||
|
'rounding': 0.01,
|
||
|
'rate_ids': [
|
||
|
Command.create({'name': '2019-09-24', 'rate': 0.050800000000}),
|
||
|
Command.create({'name': '2019-06-28', 'rate': 0.052235000000}),
|
||
|
Command.create({'name': '2019-06-24', 'rate': 0.052686000000}),
|
||
|
Command.create({'name': '2019-06-20', 'rate': 0.052353000000}),
|
||
|
Command.create({'name': '2019-06-12', 'rate': 0.052072000000}),
|
||
|
],
|
||
|
})
|
||
|
|
||
|
refund1 = self.env['account.move'].create({
|
||
|
'move_type': 'out_refund',
|
||
|
'invoice_date': '2019-06-12',
|
||
|
'date': '2019-06-12',
|
||
|
'partner_id': self.partner_a.id,
|
||
|
'currency_id': self.company_data['currency'].id,
|
||
|
'invoice_line_ids': [Command.create({
|
||
|
'product_id': self.product_a.id,
|
||
|
'price_unit': 1385.92,
|
||
|
'tax_ids': [],
|
||
|
})],
|
||
|
})
|
||
|
refund1.action_post()
|
||
|
refund1_rec_line = refund1.line_ids.filtered(lambda x: x.account_id.account_type == 'asset_receivable')
|
||
|
|
||
|
inv1 = self.env['account.move'].create({
|
||
|
'move_type': 'out_invoice',
|
||
|
'invoice_date': '2019-06-20',
|
||
|
'date': '2019-06-20',
|
||
|
'partner_id': self.partner_a.id,
|
||
|
'currency_id': self.company_data['currency'].id,
|
||
|
'invoice_line_ids': [Command.create({
|
||
|
'product_id': self.product_a.id,
|
||
|
'price_unit': 839.40,
|
||
|
'tax_ids': [],
|
||
|
})],
|
||
|
})
|
||
|
inv1.action_post()
|
||
|
inv1_rec_line = inv1.line_ids.filtered(lambda x: x.account_id.account_type == 'asset_receivable')
|
||
|
|
||
|
inv2 = self.env['account.move'].create({
|
||
|
'move_type': 'out_invoice',
|
||
|
'invoice_date': '2019-06-24',
|
||
|
'date': '2019-06-24',
|
||
|
'partner_id': self.partner_a.id,
|
||
|
'currency_id': foreign_curr.id,
|
||
|
'invoice_line_ids': [Command.create({
|
||
|
'product_id': self.product_a.id,
|
||
|
'price_unit': 1935.72,
|
||
|
'tax_ids': [],
|
||
|
})],
|
||
|
})
|
||
|
inv2.action_post()
|
||
|
inv2_rec_line = inv2.line_ids.filtered(lambda x: x.account_id.account_type == 'asset_receivable')
|
||
|
|
||
|
pay1 = self.env['account.payment'].create({
|
||
|
'partner_type': 'customer',
|
||
|
'payment_type': 'inbound',
|
||
|
'date': '2019-06-28',
|
||
|
'amount': 1907.17,
|
||
|
'partner_id': self.partner_a.id,
|
||
|
'currency_id': foreign_curr.id,
|
||
|
})
|
||
|
pay1_liquidity_line = pay1.line_ids.filtered(lambda x: x.account_id.account_type != 'asset_receivable')
|
||
|
pay1_rec_line = pay1.line_ids.filtered(lambda x: x.account_id.account_type == 'asset_receivable')
|
||
|
pay1.action_post()
|
||
|
pay1.write({'line_ids': [
|
||
|
Command.update(pay1_liquidity_line.id, {'debit': 36511.34}),
|
||
|
Command.update(pay1_rec_line.id, {'credit': 36511.34}),
|
||
|
]})
|
||
|
|
||
|
pay2 = self.env['account.payment'].create({
|
||
|
'partner_type': 'customer',
|
||
|
'payment_type': 'inbound',
|
||
|
'date': '2019-09-24',
|
||
|
'amount': 0.09,
|
||
|
'partner_id': self.partner_a.id,
|
||
|
'currency_id': foreign_curr.id,
|
||
|
})
|
||
|
pay2.action_post()
|
||
|
pay2_rec_line = pay2.line_ids.filtered(lambda x: x.account_id.account_type == 'asset_receivable')
|
||
|
|
||
|
self.assertRecordValues(refund1_rec_line + inv1_rec_line + inv2_rec_line + pay1_rec_line + pay2_rec_line, [
|
||
|
{'amount_residual': -1385.92, 'amount_residual_currency': -1385.92},
|
||
|
{'amount_residual': 839.40, 'amount_residual_currency': 839.40},
|
||
|
{'amount_residual': 36740.69, 'amount_residual_currency': 1935.72},
|
||
|
{'amount_residual': -36511.34, 'amount_residual_currency': -1907.17},
|
||
|
{'amount_residual': -1.77, 'amount_residual_currency': -0.09},
|
||
|
])
|
||
|
|
||
|
# 1st reconciliation refund1 + inv1
|
||
|
self.assert_invoice_outstanding_to_reconcile_widget(refund1, {
|
||
|
inv1.id: 839.40,
|
||
|
inv2.id: 36740.69,
|
||
|
})
|
||
|
self.assertRecordValues(refund1_rec_line + inv1_rec_line, [
|
||
|
{'amount_residual': -1385.92, 'amount_residual_currency': -1385.92, 'reconciled': False},
|
||
|
{'amount_residual': 839.40, 'amount_residual_currency': 839.40, 'reconciled': False},
|
||
|
])
|
||
|
|
||
|
(refund1_rec_line + inv1_rec_line).reconcile()
|
||
|
partials = self._get_partials(refund1_rec_line + inv1_rec_line)
|
||
|
|
||
|
self.assertRecordValues(partials, [{
|
||
|
'amount': 839.4,
|
||
|
'debit_amount_currency': 839.4,
|
||
|
'credit_amount_currency': 839.4,
|
||
|
'debit_move_id': inv1_rec_line.id,
|
||
|
'credit_move_id': refund1_rec_line.id,
|
||
|
'exchange_move_id': None,
|
||
|
}])
|
||
|
self.assertRecordValues(refund1_rec_line + inv1_rec_line, [
|
||
|
{'amount_residual': -546.52, 'amount_residual_currency': -546.52, 'reconciled': False},
|
||
|
{'amount_residual': 0.0, 'amount_residual_currency': 0.0, 'reconciled': True},
|
||
|
])
|
||
|
self.assert_invoice_outstanding_reconciled_widget(refund1, {
|
||
|
inv1.id: 839.40,
|
||
|
})
|
||
|
|
||
|
# 2th reconciliation refund1 + inv2
|
||
|
self.assert_invoice_outstanding_to_reconcile_widget(inv2, {
|
||
|
refund1.id: 28.46,
|
||
|
pay1.move_id.id: 1907.17,
|
||
|
pay2.move_id.id: 0.09,
|
||
|
})
|
||
|
self.assertRecordValues(refund1_rec_line + inv2_rec_line, [
|
||
|
{'amount_residual': -546.52, 'amount_residual_currency': -546.52, 'reconciled': False},
|
||
|
{'amount_residual': 36740.69, 'amount_residual_currency': 1935.72, 'reconciled': False},
|
||
|
])
|
||
|
|
||
|
(inv2_rec_line + pay1_rec_line).reconcile()
|
||
|
partials = self._get_partials(inv2_rec_line + pay1_rec_line)
|
||
|
|
||
|
self.assertRecordValues(partials, [
|
||
|
{
|
||
|
'amount': 36198.8,
|
||
|
'debit_amount_currency': 1907.17,
|
||
|
'credit_amount_currency': 1907.17,
|
||
|
'debit_move_id': inv2_rec_line.id,
|
||
|
'credit_move_id': pay1_rec_line.id,
|
||
|
},
|
||
|
{
|
||
|
'amount': 312.54,
|
||
|
'debit_amount_currency': 0.0,
|
||
|
'credit_amount_currency': 0.0,
|
||
|
'debit_move_id': partials.exchange_move_id.line_ids[0].id,
|
||
|
'credit_move_id': pay1_rec_line.id,
|
||
|
},
|
||
|
])
|
||
|
self.assertRecordValues(partials.exchange_move_id, [{'date': fields.Date.from_string('2019-06-30')}])
|
||
|
self.assertRecordValues(partials.exchange_move_id.line_ids, [
|
||
|
{
|
||
|
'debit': 312.54,
|
||
|
'credit': 0.0,
|
||
|
'amount_currency': 0.0,
|
||
|
'currency_id': foreign_curr.id,
|
||
|
'account_id': inv2_rec_line.account_id.id,
|
||
|
},
|
||
|
{
|
||
|
'debit': 0.0,
|
||
|
'credit': 312.54,
|
||
|
'amount_currency': 0.0,
|
||
|
'currency_id': foreign_curr.id,
|
||
|
'account_id': self.exch_income_account.id,
|
||
|
},
|
||
|
])
|
||
|
self.assertRecordValues(inv2_rec_line + pay1_rec_line, [
|
||
|
{'amount_residual': 541.89, 'amount_residual_currency': 28.55, 'reconciled': False},
|
||
|
{'amount_residual': 0.0, 'amount_residual_currency': 0.0, 'reconciled': True},
|
||
|
])
|
||
|
self.assert_invoice_outstanding_reconciled_widget(inv2, {
|
||
|
pay1.move_id.id: 1907.17,
|
||
|
partials.exchange_move_id.id: 312.54,
|
||
|
})
|
||
|
self.assert_invoice_outstanding_to_reconcile_widget(inv2, {
|
||
|
refund1.id: 28.46,
|
||
|
pay2.move_id.id: 0.09,
|
||
|
})
|
||
|
|
||
|
# 3th reconciliation refund1 + inv2
|
||
|
self.assert_invoice_outstanding_to_reconcile_widget(refund1, {
|
||
|
inv2.id: 541.89,
|
||
|
})
|
||
|
self.assertRecordValues(refund1_rec_line + inv2_rec_line, [
|
||
|
{'amount_residual': -546.52, 'amount_residual_currency': -546.52, 'reconciled': False},
|
||
|
{'amount_residual': 541.89, 'amount_residual_currency': 28.55, 'reconciled': False},
|
||
|
])
|
||
|
|
||
|
partials = self._get_partials(refund1_rec_line + inv2_rec_line)
|
||
|
(refund1_rec_line + inv2_rec_line).reconcile()
|
||
|
partials = self._get_partials(refund1_rec_line + inv2_rec_line) - partials
|
||
|
|
||
|
self.assertRecordValues(partials, [
|
||
|
{
|
||
|
'amount': 540.18,
|
||
|
'debit_amount_currency': 28.46,
|
||
|
'credit_amount_currency': 540.18,
|
||
|
'debit_move_id': inv2_rec_line.id,
|
||
|
'credit_move_id': refund1_rec_line.id,
|
||
|
},
|
||
|
{
|
||
|
'amount': 6.34,
|
||
|
'debit_amount_currency': 6.34,
|
||
|
'credit_amount_currency': 6.34,
|
||
|
'debit_move_id': partials.exchange_move_id.line_ids[0].id,
|
||
|
'credit_move_id': refund1_rec_line.id,
|
||
|
},
|
||
|
])
|
||
|
self.assertRecordValues(partials.exchange_move_id, [{'date': fields.Date.from_string('2019-06-30')}])
|
||
|
self.assertRecordValues(partials.exchange_move_id.line_ids, [
|
||
|
{
|
||
|
'debit': 6.34,
|
||
|
'credit': 0.0,
|
||
|
'amount_currency': 6.34,
|
||
|
'currency_id': comp_curr.id,
|
||
|
'account_id': refund1_rec_line.account_id.id,
|
||
|
},
|
||
|
{
|
||
|
'debit': 0.0,
|
||
|
'credit': 6.34,
|
||
|
'amount_currency': -6.34,
|
||
|
'currency_id': comp_curr.id,
|
||
|
'account_id': self.exch_income_account.id,
|
||
|
},
|
||
|
])
|
||
|
self.assertRecordValues(refund1_rec_line + inv2_rec_line, [
|
||
|
{'amount_residual': 0.0, 'amount_residual_currency': 0.0, 'reconciled': True},
|
||
|
{'amount_residual': 1.71, 'amount_residual_currency': 0.09, 'reconciled': False},
|
||
|
])
|
||
|
self.assert_invoice_outstanding_reconciled_widget(refund1, {
|
||
|
inv1.id: 839.40,
|
||
|
inv2.id: 540.18,
|
||
|
partials.exchange_move_id.id: 6.34,
|
||
|
})
|
||
|
self.assert_invoice_outstanding_to_reconcile_widget(refund1, {})
|
||
|
|
||
|
self.assert_invoice_outstanding_to_reconcile_widget(inv2, {
|
||
|
pay2.move_id.id: 0.09,
|
||
|
})
|
||
|
|
||
|
partials = self._get_partials(inv2_rec_line + pay2_rec_line)
|
||
|
(inv2_rec_line + pay2_rec_line).reconcile()
|
||
|
partials = self._get_partials(inv2_rec_line + pay2_rec_line) - partials
|
||
|
|
||
|
self.assertRecordValues(partials, [
|
||
|
{
|
||
|
'amount': 1.71,
|
||
|
'debit_amount_currency': 0.09,
|
||
|
'credit_amount_currency': 0.09,
|
||
|
'debit_move_id': inv2_rec_line.id,
|
||
|
'credit_move_id': pay2_rec_line.id,
|
||
|
},
|
||
|
{
|
||
|
'amount': 0.06,
|
||
|
'debit_amount_currency': 0.0,
|
||
|
'credit_amount_currency': 0.0,
|
||
|
'debit_move_id': partials.exchange_move_id.line_ids[0].id,
|
||
|
'credit_move_id': pay2_rec_line.id,
|
||
|
},
|
||
|
])
|
||
|
self.assertRecordValues(partials.exchange_move_id, [{'date': fields.Date.from_string('2019-09-30')}])
|
||
|
self.assertRecordValues(partials.exchange_move_id.line_ids, [
|
||
|
{
|
||
|
'debit': 0.06,
|
||
|
'credit': 0.0,
|
||
|
'amount_currency': 0.0,
|
||
|
'currency_id': foreign_curr.id,
|
||
|
'account_id': inv2_rec_line.account_id.id,
|
||
|
},
|
||
|
{
|
||
|
'debit': 0.0,
|
||
|
'credit': 0.06,
|
||
|
'amount_currency': 0.0,
|
||
|
'currency_id': foreign_curr.id,
|
||
|
'account_id': self.exch_income_account.id,
|
||
|
},
|
||
|
])
|
||
|
self.assertRecordValues(inv2_rec_line + pay2_rec_line, [
|
||
|
{'amount_residual': 0.0, 'amount_residual_currency': 0.0, 'reconciled': True},
|
||
|
{'amount_residual': 0.0, 'amount_residual_currency': 0.0, 'reconciled': True},
|
||
|
])
|
||
|
payment_exchange_id = inv2_rec_line.matched_credit_ids.filtered(lambda x: x not in partials)
|
||
|
|
||
|
self.assert_invoice_outstanding_reconciled_widget(inv2, {
|
||
|
refund1.id: 28.46,
|
||
|
pay1.move_id.id: 1907.17,
|
||
|
pay2.move_id.id: 0.09,
|
||
|
partials.exchange_move_id.id: 0.06,
|
||
|
payment_exchange_id[0].exchange_move_id.id: 312.54,
|
||
|
payment_exchange_id[1].exchange_move_id.id: 6.34,
|
||
|
})
|
||
|
self.assert_invoice_outstanding_to_reconcile_widget(inv2, {})
|
||
|
|
||
|
self.assertRecordValues(inv2_rec_line.full_reconcile_id, [{'exchange_move_id': None}])
|
||
|
|
||
|
def test_migration_to_new_reconciliation_same_foreign_currency(self):
|
||
|
foreign_curr = self.currency_data['currency']
|
||
|
|
||
|
line_1 = self.create_line_for_reconciliation(-60.0, -120.0, foreign_curr, '2017-01-01')
|
||
|
line_2 = self.create_line_for_reconciliation(80.0, 240.0, foreign_curr, '2016-01-01')
|
||
|
|
||
|
# Create the partial as it should be created in previous version.
|
||
|
self.env['account.partial.reconcile'].create({
|
||
|
'amount': 60.0,
|
||
|
'debit_amount_currency': 120.0,
|
||
|
'credit_amount_currency': 120.0,
|
||
|
'debit_move_id': line_2.id,
|
||
|
'credit_move_id': line_1.id,
|
||
|
})
|
||
|
self.assertRecordValues(line_1 + line_2, [
|
||
|
{'amount_residual': 0.0, 'amount_residual_currency': 0.0, 'reconciled': True},
|
||
|
{'amount_residual': 20.0, 'amount_residual_currency': 120.0, 'reconciled': False},
|
||
|
])
|
||
|
|
||
|
# Reconcile using the "new" reconciliation.
|
||
|
line_3 = self.create_line_for_reconciliation(-15.0, -30.0, foreign_curr, '2017-01-01')
|
||
|
(line_2 + line_3).reconcile()
|
||
|
self.assertRecordValues(line_2 + line_3, [
|
||
|
{'amount_residual': 10.0, 'amount_residual_currency': 90.0, 'reconciled': False},
|
||
|
{'amount_residual': 0.0, 'amount_residual_currency': 0.0, 'reconciled': True},
|
||
|
])
|
||
|
|
||
|
line_4 = self.create_line_for_reconciliation(-30.0, -90.0, foreign_curr, '2016-01-01')
|
||
|
(line_2 + line_4).reconcile()
|
||
|
self.assertRecordValues(line_2 + line_4, [
|
||
|
{'amount_residual': 0.0, 'amount_residual_currency': 0.0, 'reconciled': True},
|
||
|
{'amount_residual': 0.0, 'amount_residual_currency': 0.0, 'reconciled': True},
|
||
|
])
|
||
|
|
||
|
def test_migration_to_new_reconciliation_multiple_currencies_fix_residual_with_writeoff(self):
|
||
|
comp_curr = self.company_data['currency']
|
||
|
foreign_curr1 = self.currency_data['currency']
|
||
|
|
||
|
line_1 = self.create_line_for_reconciliation(600.0, 1200.0, foreign_curr1, '2017-01-01')
|
||
|
line_2 = self.create_line_for_reconciliation(-800.0, -2400.0, foreign_curr1, '2016-01-01')
|
||
|
line_3 = self.create_line_for_reconciliation(400.0, 400.0, comp_curr, '2016-01-01')
|
||
|
|
||
|
# Create the partials as it should be created in previous version.
|
||
|
self.env['account.partial.reconcile'].create([
|
||
|
{
|
||
|
'amount': 600.0,
|
||
|
'debit_amount_currency': 1200.0,
|
||
|
'credit_amount_currency': 1200.0,
|
||
|
'debit_move_id': line_1.id,
|
||
|
'credit_move_id': line_2.id,
|
||
|
},
|
||
|
{
|
||
|
'amount': 200.0,
|
||
|
'debit_amount_currency': 200.0,
|
||
|
'credit_amount_currency': 600.0,
|
||
|
'debit_move_id': line_3.id,
|
||
|
'credit_move_id': line_2.id,
|
||
|
},
|
||
|
])
|
||
|
self.assertRecordValues(line_1 + line_2 + line_3, [
|
||
|
{'amount_residual': 0.0, 'amount_residual_currency': 0.0, 'reconciled': True},
|
||
|
{'amount_residual': 0.0, 'amount_residual_currency': -600.0, 'reconciled': False},
|
||
|
{'amount_residual': 200.0, 'amount_residual_currency': 200.0, 'reconciled': False},
|
||
|
])
|
||
|
|
||
|
# Fix 'line_2' & 'line_4' using the "new" reconciliation.
|
||
|
line_4 = self.create_line_for_reconciliation(0.0, 600.0, foreign_curr1, '2016-01-01')
|
||
|
line_5 = self.create_line_for_reconciliation(-200.0, -200.0, comp_curr, '2016-01-01')
|
||
|
(line_2 + line_3 + line_4 + line_5).reconcile()
|
||
|
|
||
|
self.assertRecordValues(line_1 + line_2 + line_3 + line_4 + line_5, [
|
||
|
{'amount_residual': 0.0, 'amount_residual_currency': 0.0, 'reconciled': True},
|
||
|
{'amount_residual': 0.0, 'amount_residual_currency': 0.0, 'reconciled': True},
|
||
|
{'amount_residual': 0.0, 'amount_residual_currency': 0.0, 'reconciled': True},
|
||
|
{'amount_residual': 0.0, 'amount_residual_currency': 0.0, 'reconciled': True},
|
||
|
{'amount_residual': 0.0, 'amount_residual_currency': 0.0, 'reconciled': True},
|
||
|
])
|
||
|
|
||
|
def test_reconcile_rounding_issue(self):
|
||
|
rate = 1/1.5289
|
||
|
currency = self.setup_multi_currency_data(default_values={
|
||
|
'name': 'XXX',
|
||
|
'symbol': 'XXX',
|
||
|
'currency_unit_label': 'XX',
|
||
|
'currency_subunit_label': 'X',
|
||
|
'rounding': 0.01,
|
||
|
}, rate2016=rate, rate2017=rate)['currency']
|
||
|
|
||
|
# Create an invoice 26.45 XXX = 40.43 USD
|
||
|
invoice = self.env['account.move'].create({
|
||
|
'move_type': 'out_invoice',
|
||
|
'partner_id': self.partner_a.id,
|
||
|
'currency_id': currency.id,
|
||
|
'date': '2017-01-01',
|
||
|
'invoice_date': '2017-01-01',
|
||
|
'invoice_line_ids': [(0, 0, {
|
||
|
'product_id': self.product_a.id,
|
||
|
'price_unit': 23.0,
|
||
|
'tax_ids': [(6, 0, self.company_data['default_tax_sale'].ids)],
|
||
|
})],
|
||
|
})
|
||
|
invoice.action_post()
|
||
|
|
||
|
# Pay it with 100.0 USD
|
||
|
self.env['account.payment.register']\
|
||
|
.with_context(active_model='account.move', active_ids=invoice.ids)\
|
||
|
.create({'amount': 100.0, 'currency_id': self.company_data['currency'].id})\
|
||
|
._create_payments()
|
||
|
|
||
|
self.assertTrue(invoice.payment_state in ('in_payment', 'paid'))
|
||
|
|
||
|
def test_reconcile_plan(self):
|
||
|
@contextmanager
|
||
|
def rollback():
|
||
|
savepoint = self.cr.savepoint()
|
||
|
yield
|
||
|
savepoint.rollback()
|
||
|
|
||
|
comp_curr = self.company_data['currency']
|
||
|
|
||
|
line_1 = self.create_line_for_reconciliation(600.0, 600.0, comp_curr, '2017-01-01')
|
||
|
line_2 = self.create_line_for_reconciliation(-100.0, -100.0, comp_curr, '2017-01-02')
|
||
|
line_3 = self.create_line_for_reconciliation(700.0, 700.0, comp_curr, '2017-01-03')
|
||
|
line_5 = self.create_line_for_reconciliation(-700.0, -700.0, comp_curr, '2017-01-04')
|
||
|
line_4 = self.create_line_for_reconciliation(-500.0, -500.0, comp_curr, '2017-01-05')
|
||
|
|
||
|
with rollback():
|
||
|
# 5 batches of 1 aml. This won't reconcile anything.
|
||
|
self.env['account.move.line']._reconcile_plan([line_1, line_2, line_3, line_4, line_5])
|
||
|
self.assertFalse(self._get_partials(line_1 + line_2 + line_3 + line_4 + line_5))
|
||
|
|
||
|
with rollback():
|
||
|
# one batch of 5 amls.
|
||
|
self.env['account.move.line']._reconcile_plan([line_1 + line_2 + line_3 + line_4 + line_5])
|
||
|
self.assertRecordValues(
|
||
|
self._get_partials(line_1 + line_2 + line_3 + line_4 + line_5),
|
||
|
[
|
||
|
{'amount': 100.0, 'debit_move_id': line_1.id, 'credit_move_id': line_2.id},
|
||
|
{'amount': 500.0, 'debit_move_id': line_1.id, 'credit_move_id': line_5.id},
|
||
|
{'amount': 200.0, 'debit_move_id': line_3.id, 'credit_move_id': line_5.id},
|
||
|
{'amount': 500.0, 'debit_move_id': line_3.id, 'credit_move_id': line_4.id},
|
||
|
],
|
||
|
)
|
||
|
|
||
|
with rollback():
|
||
|
# Reconcile line_3 + line_5 and line_1 + line_4. line_2 is alone so will not be reconciled.
|
||
|
self.env['account.move.line']._reconcile_plan([line_3 + line_5, line_1 + line_4, line_2])
|
||
|
self.assertRecordValues(
|
||
|
self._get_partials(line_1 + line_2 + line_3 + line_4 + line_5),
|
||
|
[
|
||
|
{'amount': 700.0, 'debit_move_id': line_3.id, 'credit_move_id': line_5.id},
|
||
|
{'amount': 500.0, 'debit_move_id': line_1.id, 'credit_move_id': line_4.id},
|
||
|
],
|
||
|
)
|
||
|
|
||
|
with rollback():
|
||
|
# Reconcile line_3 + line_5 first, then line_1 + line_4, then the remaining amls with line_2.
|
||
|
self.env['account.move.line']._reconcile_plan([[line_3 + line_5, line_1 + line_4, line_2]])
|
||
|
self.assertRecordValues(
|
||
|
self._get_partials(line_1 + line_2 + line_3 + line_4 + line_5),
|
||
|
[
|
||
|
{'amount': 700.0, 'debit_move_id': line_3.id, 'credit_move_id': line_5.id},
|
||
|
{'amount': 500.0, 'debit_move_id': line_1.id, 'credit_move_id': line_4.id},
|
||
|
{'amount': 100.0, 'debit_move_id': line_1.id, 'credit_move_id': line_2.id},
|
||
|
],
|
||
|
)
|
||
|
|
||
|
with rollback():
|
||
|
# Same as the previous test but with a lot of sub-plan to test the result is the same.
|
||
|
self.env['account.move.line']._reconcile_plan([[[line_3 + line_5], [[line_1 + line_4], line_2]]])
|
||
|
self.assertRecordValues(
|
||
|
self._get_partials(line_1 + line_2 + line_3 + line_4 + line_5),
|
||
|
[
|
||
|
{'amount': 700.0, 'debit_move_id': line_3.id, 'credit_move_id': line_5.id},
|
||
|
{'amount': 500.0, 'debit_move_id': line_1.id, 'credit_move_id': line_4.id},
|
||
|
{'amount': 100.0, 'debit_move_id': line_1.id, 'credit_move_id': line_2.id},
|
||
|
],
|
||
|
)
|
||
|
|
||
|
# -------------------------------------------------------------------------
|
||
|
# Test creation of extra journal entries during the reconciliation to
|
||
|
# deal with taxes that are exigible on payment (cash basis).
|
||
|
# -------------------------------------------------------------------------
|
||
|
|
||
|
def test_reconcile_cash_basis_workflow_single_currency(self):
|
||
|
''' Test the generated journal entries during the reconciliation to manage the cash basis taxes.
|
||
|
Also,
|
||
|
- Test the case when there is multiple receivable/payable accounts.
|
||
|
- Test the reconciliation with tiny amounts.
|
||
|
- Check there is no rounding issue when making the percentage.
|
||
|
- Check there is no lost cents when the journal entry is fully reconciled.
|
||
|
'''
|
||
|
self.env.company.tax_exigibility = True
|
||
|
self.cash_basis_tax_tiny_amount.amount = 0.01
|
||
|
cash_basis_move = self.env['account.move'].with_context(skip_invoice_sync=True).create({
|
||
|
'move_type': 'entry',
|
||
|
'date': '2016-01-01',
|
||
|
'line_ids': [
|
||
|
# Base Tax line
|
||
|
(0, 0, {
|
||
|
'debit': 0.0,
|
||
|
'credit': 100.0,
|
||
|
'account_id': self.company_data['default_account_revenue'].id,
|
||
|
'tax_ids': [(6, 0, (self.cash_basis_tax_a_third_amount + self.cash_basis_tax_tiny_amount).ids)],
|
||
|
}),
|
||
|
|
||
|
# Tax lines
|
||
|
(0, 0, {
|
||
|
'debit': 0.0,
|
||
|
'credit': 33.33,
|
||
|
'account_id': self.cash_basis_transfer_account.id,
|
||
|
'tax_repartition_line_id': self.cash_basis_tax_a_third_amount.invoice_repartition_line_ids.filtered(lambda line: line.repartition_type == 'tax').id,
|
||
|
}),
|
||
|
(0, 0, {
|
||
|
'debit': 0.0,
|
||
|
'credit': 0.01,
|
||
|
'account_id': self.cash_basis_transfer_account.id,
|
||
|
'tax_repartition_line_id': self.cash_basis_tax_tiny_amount.invoice_repartition_line_ids.filtered(lambda line: line.repartition_type == 'tax').id,
|
||
|
}),
|
||
|
|
||
|
# Receivable lines
|
||
|
(0, 0, {
|
||
|
'debit': 44.45,
|
||
|
'credit': 0.0,
|
||
|
'account_id': self.extra_receivable_account_1.id,
|
||
|
}),
|
||
|
(0, 0, {
|
||
|
'debit': 44.45,
|
||
|
'credit': 0.0,
|
||
|
'account_id': self.extra_receivable_account_2.id,
|
||
|
}),
|
||
|
(0, 0, {
|
||
|
'debit': 44.45,
|
||
|
'credit': 0.0,
|
||
|
'account_id': self.extra_receivable_account_2.id,
|
||
|
}),
|
||
|
(0, 0, {
|
||
|
'debit': 0.0,
|
||
|
'credit': 0.01,
|
||
|
'account_id': self.extra_payable_account_1.id,
|
||
|
}),
|
||
|
]
|
||
|
})
|
||
|
cash_basis_move.line_ids.flush_model()
|
||
|
|
||
|
payment_move = self.env['account.move'].create({
|
||
|
'move_type': 'entry',
|
||
|
'date': '2017-01-01',
|
||
|
'line_ids': [
|
||
|
(0, 0, {'debit': 0.0, 'credit': 33.34, 'account_id': self.extra_receivable_account_1.id}),
|
||
|
(0, 0, {'debit': 0.0, 'credit': 11.11, 'account_id': self.extra_receivable_account_1.id}),
|
||
|
(0, 0, {'debit': 0.0, 'credit': 88.89, 'account_id': self.extra_receivable_account_2.id}),
|
||
|
(0, 0, {'debit': 0.0, 'credit': 0.01, 'account_id': self.extra_receivable_account_2.id}),
|
||
|
(0, 0, {'debit': 0.01, 'credit': 0.0, 'account_id': self.extra_payable_account_1.id}),
|
||
|
(0, 0, {'debit': 133.34, 'credit': 0.0, 'account_id': self.company_data['default_account_revenue'].id}),
|
||
|
]
|
||
|
})
|
||
|
|
||
|
(cash_basis_move + payment_move).action_post()
|
||
|
|
||
|
# Initial amounts by accounts:
|
||
|
|
||
|
self.assertAmountsGroupByAccount([
|
||
|
# Account Balance Amount Currency
|
||
|
(self.cash_basis_transfer_account, -33.34, -33.34),
|
||
|
(self.tax_account_1, 0.0, 0.0),
|
||
|
(self.tax_account_2, 0.0, 0.0),
|
||
|
(self.cash_basis_base_account, 0.0, 0.0),
|
||
|
])
|
||
|
|
||
|
# There is 44.45 + 44.45 + 44.45 + 0.01 = 133.36 to reconcile on 'cash_basis_move'.
|
||
|
# Reconciling all the amount in extra_receivable_account_1 should compute 2 percentages:
|
||
|
# 33.34 / 133.36 = 0.25
|
||
|
# 11.11 / 133.36 = 0.083308338
|
||
|
|
||
|
receivable_lines_1 = (cash_basis_move + payment_move).line_ids\
|
||
|
.filtered(lambda line: line.account_id == self.extra_receivable_account_1)
|
||
|
tax_cash_basis_moves = self._get_caba_moves(receivable_lines_1.move_id)
|
||
|
receivable_lines_1.reconcile()
|
||
|
tax_cash_basis_moves = self._get_caba_moves(receivable_lines_1.move_id) - tax_cash_basis_moves
|
||
|
|
||
|
self.assertFullReconcile(receivable_lines_1.full_reconcile_id, receivable_lines_1)
|
||
|
self.assertEqual(len(tax_cash_basis_moves), 2)
|
||
|
self.assertRecordValues(tax_cash_basis_moves[0].line_ids, [
|
||
|
# Base amount of tax_1 & tax_2:
|
||
|
{'debit': 8.33, 'credit': 0.0, 'account_id': self.cash_basis_base_account.id},
|
||
|
{'debit': 0.0, 'credit': 8.33, 'account_id': self.cash_basis_base_account.id},
|
||
|
# tax_1:
|
||
|
{'debit': 2.78, 'credit': 0.0, 'account_id': self.cash_basis_transfer_account.id},
|
||
|
{'debit': 0.0, 'credit': 2.78, 'account_id': self.tax_account_1.id},
|
||
|
# tax_2:
|
||
|
{'debit': 0.0, 'credit': 0.0, 'account_id': self.cash_basis_transfer_account.id},
|
||
|
{'debit': 0.0, 'credit': 0.0, 'account_id': self.tax_account_2.id},
|
||
|
])
|
||
|
self.assertRecordValues(tax_cash_basis_moves[1].line_ids, [
|
||
|
# Base amount of tax_1 & tax_2:
|
||
|
{'debit': 25.0, 'credit': 0.0, 'account_id': self.cash_basis_base_account.id},
|
||
|
{'debit': 0.0, 'credit': 25.0, 'account_id': self.cash_basis_base_account.id},
|
||
|
# tax_1:
|
||
|
{'debit': 8.33, 'credit': 0.0, 'account_id': self.cash_basis_transfer_account.id},
|
||
|
{'debit': 0.0, 'credit': 8.33, 'account_id': self.tax_account_1.id},
|
||
|
# tax_2:
|
||
|
{'debit': 0.0, 'credit': 0.0, 'account_id': self.cash_basis_transfer_account.id},
|
||
|
{'debit': 0.0, 'credit': 0.0, 'account_id': self.tax_account_2.id},
|
||
|
])
|
||
|
|
||
|
self.assertAmountsGroupByAccount([
|
||
|
# Account Balance Amount Currency
|
||
|
(self.cash_basis_transfer_account, -22.23, -22.23),
|
||
|
(self.tax_account_1, -11.11, -11.11),
|
||
|
(self.tax_account_2, 0.0, 0.0),
|
||
|
])
|
||
|
|
||
|
# Reconciling all the amount in extra_receivable_account_2 should compute 3 percentages:
|
||
|
# 44.45 / 133.36 = 0.333308338
|
||
|
# 44.44 / 133.36 = 0.333233353
|
||
|
# 0.01 / 133.36 = 0.000074985
|
||
|
|
||
|
receivable_lines_2 = (cash_basis_move + payment_move).line_ids\
|
||
|
.filtered(lambda line: line.account_id == self.extra_receivable_account_2)
|
||
|
tax_cash_basis_moves = self._get_caba_moves(receivable_lines_2.move_id)
|
||
|
receivable_lines_2.reconcile()
|
||
|
tax_cash_basis_moves = self._get_caba_moves(receivable_lines_2.move_id) - tax_cash_basis_moves
|
||
|
|
||
|
self.assertFullReconcile(receivable_lines_2.full_reconcile_id, receivable_lines_2)
|
||
|
self.assertEqual(len(tax_cash_basis_moves), 3)
|
||
|
self.assertRecordValues(tax_cash_basis_moves[0].line_ids, [
|
||
|
# Base amount of tax_1 & tax_2:
|
||
|
{'debit': 0.01, 'credit': 0.0, 'account_id': self.cash_basis_base_account.id},
|
||
|
{'debit': 0.0, 'credit': 0.01, 'account_id': self.cash_basis_base_account.id},
|
||
|
# tax_1:
|
||
|
{'debit': 0.0, 'credit': 0.0, 'account_id': self.cash_basis_transfer_account.id},
|
||
|
{'debit': 0.0, 'credit': 0.0, 'account_id': self.tax_account_1.id},
|
||
|
# tax_2:
|
||
|
{'debit': 0.0, 'credit': 0.0, 'account_id': self.cash_basis_transfer_account.id},
|
||
|
{'debit': 0.0, 'credit': 0.0, 'account_id': self.tax_account_2.id},
|
||
|
])
|
||
|
self.assertRecordValues(tax_cash_basis_moves[1].line_ids, [
|
||
|
# Base amount of tax_1 & tax_2:
|
||
|
{'debit': 33.32, 'credit': 0.0, 'account_id': self.cash_basis_base_account.id},
|
||
|
{'debit': 0.0, 'credit': 33.32, 'account_id': self.cash_basis_base_account.id},
|
||
|
# tax_1:
|
||
|
{'debit': 11.11, 'credit': 0.0, 'account_id': self.cash_basis_transfer_account.id},
|
||
|
{'debit': 0.0, 'credit': 11.11, 'account_id': self.tax_account_1.id},
|
||
|
# tax_2:
|
||
|
{'debit': 0.0, 'credit': 0.0, 'account_id': self.cash_basis_transfer_account.id},
|
||
|
{'debit': 0.0, 'credit': 0.0, 'account_id': self.tax_account_2.id},
|
||
|
])
|
||
|
self.assertRecordValues(tax_cash_basis_moves[2].line_ids, [
|
||
|
# Base amount of tax_1 & tax_2:
|
||
|
{'debit': 33.33, 'credit': 0.0, 'account_id': self.cash_basis_base_account.id},
|
||
|
{'debit': 0.0, 'credit': 33.33, 'account_id': self.cash_basis_base_account.id},
|
||
|
# tax_1:
|
||
|
{'debit': 11.11, 'credit': 0.0, 'account_id': self.cash_basis_transfer_account.id},
|
||
|
{'debit': 0.0, 'credit': 11.11, 'account_id': self.tax_account_1.id},
|
||
|
# tax_2:
|
||
|
{'debit': 0.0, 'credit': 0.0, 'account_id': self.cash_basis_transfer_account.id},
|
||
|
{'debit': 0.0, 'credit': 0.0, 'account_id': self.tax_account_2.id},
|
||
|
])
|
||
|
|
||
|
self.assertAmountsGroupByAccount([
|
||
|
# Account Balance Amount Currency
|
||
|
(self.cash_basis_transfer_account, -0.01, -0.01),
|
||
|
(self.tax_account_1, -33.33, -33.33),
|
||
|
(self.tax_account_2, 0.0, 0.0),
|
||
|
])
|
||
|
|
||
|
# Reconciling all the amount in extra_payable_account_1 should trigger the matching number and ensure all
|
||
|
# the base amount has been covered without any rounding issue.
|
||
|
|
||
|
payable_lines_1 = (cash_basis_move + payment_move).line_ids\
|
||
|
.filtered(lambda line: line.account_id == self.extra_payable_account_1)
|
||
|
tax_cash_basis_moves = self._get_caba_moves(payable_lines_1.move_id)
|
||
|
payable_lines_1.reconcile()
|
||
|
tax_cash_basis_moves = self._get_caba_moves(payable_lines_1.move_id) - tax_cash_basis_moves
|
||
|
|
||
|
self.assertFullReconcile(payable_lines_1.full_reconcile_id, payable_lines_1)
|
||
|
self.assertEqual(len(tax_cash_basis_moves), 1)
|
||
|
self.assertRecordValues(tax_cash_basis_moves.line_ids, [
|
||
|
# Base amount of tax_1 & tax_2:
|
||
|
{'debit': 0.01, 'credit': 0.0, 'account_id': self.cash_basis_base_account.id},
|
||
|
{'debit': 0.0, 'credit': 0.01, 'account_id': self.cash_basis_base_account.id},
|
||
|
# tax_1:
|
||
|
{'debit': 0.0, 'credit': 0.0, 'account_id': self.cash_basis_transfer_account.id},
|
||
|
{'debit': 0.0, 'credit': 0.0, 'account_id': self.tax_account_1.id},
|
||
|
# tax_2:
|
||
|
{'debit': 0.0, 'credit': 0.0, 'account_id': self.cash_basis_transfer_account.id},
|
||
|
{'debit': 0.0, 'credit': 0.0, 'account_id': self.tax_account_2.id},
|
||
|
])
|
||
|
|
||
|
self.assertRecordValues(payable_lines_1.full_reconcile_id.exchange_move_id.line_ids, [
|
||
|
{'account_id': self.tax_account_2.id, 'debit': 0.0, 'credit': 0.01, 'tax_ids': [], 'tax_line_id': self.cash_basis_tax_tiny_amount.id},
|
||
|
{'account_id': self.cash_basis_transfer_account.id, 'debit': 0.01, 'credit': 0.0, 'tax_ids': [], 'tax_line_id': False},
|
||
|
])
|
||
|
|
||
|
self.assertAmountsGroupByAccount([
|
||
|
# Account Balance Amount Currency
|
||
|
(self.cash_basis_transfer_account, 0.0, 0.0),
|
||
|
(self.tax_account_1, -33.33, -33.33),
|
||
|
(self.tax_account_2, -0.01, -0.01),
|
||
|
])
|
||
|
|
||
|
def test_reconcile_cash_basis_workflow_multi_currency(self):
|
||
|
''' Same as before with a foreign currency. '''
|
||
|
|
||
|
self.env.company.tax_exigibility = True
|
||
|
currency_id = self.currency_data['currency'].id
|
||
|
taxes = self.cash_basis_tax_a_third_amount + self.cash_basis_tax_tiny_amount
|
||
|
|
||
|
cash_basis_move = self.env['account.move'].with_context(skip_invoice_sync=True).create({
|
||
|
'move_type': 'entry',
|
||
|
'date': '2016-01-01',
|
||
|
'line_ids': [
|
||
|
# Base Tax line
|
||
|
(0, 0, {
|
||
|
'debit': 0.0,
|
||
|
'credit': 33.34,
|
||
|
'amount_currency': -100.0,
|
||
|
'currency_id': currency_id,
|
||
|
'account_id': self.company_data['default_account_revenue'].id,
|
||
|
'tax_ids': [(6, 0, taxes.ids)],
|
||
|
}),
|
||
|
|
||
|
# Tax lines
|
||
|
(0, 0, {
|
||
|
'debit': 0.0,
|
||
|
'credit': 11.10,
|
||
|
'amount_currency': -33.33,
|
||
|
'currency_id': currency_id,
|
||
|
'account_id': self.cash_basis_transfer_account.id,
|
||
|
'tax_repartition_line_id': self.cash_basis_tax_a_third_amount.invoice_repartition_line_ids.filtered(lambda line: line.repartition_type == 'tax').id,
|
||
|
}),
|
||
|
(0, 0, {
|
||
|
'debit': 0.0,
|
||
|
'credit': 0.01,
|
||
|
'amount_currency': -0.01,
|
||
|
'currency_id': currency_id,
|
||
|
'account_id': self.cash_basis_transfer_account.id,
|
||
|
'tax_repartition_line_id': self.cash_basis_tax_tiny_amount.invoice_repartition_line_ids.filtered(lambda line: line.repartition_type == 'tax').id,
|
||
|
}),
|
||
|
|
||
|
# Receivable lines
|
||
|
(0, 0, {
|
||
|
'debit': 14.82,
|
||
|
'credit': 0.0,
|
||
|
'amount_currency': 44.45,
|
||
|
'currency_id': currency_id,
|
||
|
'account_id': self.extra_receivable_account_1.id,
|
||
|
}),
|
||
|
(0, 0, {
|
||
|
'debit': 14.82,
|
||
|
'credit': 0.0,
|
||
|
'amount_currency': 44.45,
|
||
|
'currency_id': currency_id,
|
||
|
'account_id': self.extra_receivable_account_2.id,
|
||
|
}),
|
||
|
(0, 0, {
|
||
|
'debit': 14.82,
|
||
|
'credit': 0.0,
|
||
|
'amount_currency': 44.45,
|
||
|
'currency_id': currency_id,
|
||
|
'account_id': self.extra_receivable_account_2.id,
|
||
|
}),
|
||
|
(0, 0, {
|
||
|
'debit': 0.0,
|
||
|
'credit': 0.01,
|
||
|
'amount_currency': -0.01,
|
||
|
'currency_id': currency_id,
|
||
|
'account_id': self.extra_payable_account_1.id,
|
||
|
}),
|
||
|
]
|
||
|
})
|
||
|
|
||
|
payment_move = self.env['account.move'].create({
|
||
|
'move_type': 'entry',
|
||
|
'date': '2017-01-01',
|
||
|
'line_ids': [
|
||
|
(0, 0, {'debit': 0.0, 'credit': 16.67, 'amount_currency': -33.34, 'currency_id': currency_id, 'account_id': self.extra_receivable_account_1.id}),
|
||
|
(0, 0, {'debit': 0.0, 'credit': 5.6, 'amount_currency': -11.11, 'currency_id': currency_id, 'account_id': self.extra_receivable_account_1.id}),
|
||
|
(0, 0, {'debit': 0.0, 'credit': 44.45, 'amount_currency': -88.89, 'currency_id': currency_id, 'account_id': self.extra_receivable_account_2.id}),
|
||
|
(0, 0, {'debit': 0.0, 'credit': 0.01, 'amount_currency': -0.01, 'currency_id': currency_id, 'account_id': self.extra_receivable_account_2.id}),
|
||
|
(0, 0, {'debit': 0.01, 'credit': 0.0, 'amount_currency': 0.01, 'currency_id': currency_id, 'account_id': self.extra_payable_account_1.id}),
|
||
|
(0, 0, {'debit': 66.72, 'credit': 0.0, 'account_id': self.company_data['default_account_revenue'].id}),
|
||
|
]
|
||
|
})
|
||
|
|
||
|
(cash_basis_move + payment_move).action_post()
|
||
|
|
||
|
# Initial amounts by accounts:
|
||
|
|
||
|
self.assertAmountsGroupByAccount([
|
||
|
# Account Balance Amount Currency
|
||
|
(self.cash_basis_transfer_account, -11.11, -33.34),
|
||
|
(self.tax_account_1, 0.0, 0.0),
|
||
|
(self.tax_account_2, 0.0, 0.0),
|
||
|
])
|
||
|
|
||
|
# There is 44.45 + 44.45 + 44.45 + 0.01 = 133.36 to reconcile on 'cash_basis_move'.
|
||
|
# Reconciling all the amount in extra_receivable_account_1 should compute 2 percentages:
|
||
|
# 33.34 / 133.36 = 0.25
|
||
|
# 11.11 / 133.36 = 0.083308338
|
||
|
|
||
|
receivable_lines_1 = (cash_basis_move + payment_move).line_ids\
|
||
|
.filtered(lambda line: line.account_id == self.extra_receivable_account_1)
|
||
|
receivable_lines_1.reconcile()
|
||
|
tax_cash_basis_moves = self._get_caba_moves(receivable_lines_1.move_id)
|
||
|
|
||
|
self.assertFullReconcileAccount(receivable_lines_1.full_reconcile_id, self.extra_receivable_account_1)
|
||
|
self.assertEqual(len(tax_cash_basis_moves), 2)
|
||
|
self.assertRecordValues(tax_cash_basis_moves[0].line_ids, [
|
||
|
# Base amount of tax_1 & tax_2:
|
||
|
{'debit': 4.2, 'credit': 0.0, 'amount_currency': 8.331, 'currency_id': currency_id, 'account_id': self.cash_basis_base_account.id},
|
||
|
{'debit': 0.0, 'credit': 4.2, 'amount_currency': -8.331, 'currency_id': currency_id, 'account_id': self.cash_basis_base_account.id},
|
||
|
# tax_1:
|
||
|
{'debit': 1.4, 'credit': 0.0, 'amount_currency': 2.777, 'currency_id': currency_id, 'account_id': self.cash_basis_transfer_account.id},
|
||
|
{'debit': 0.0, 'credit': 1.4, 'amount_currency': -2.777, 'currency_id': currency_id, 'account_id': self.tax_account_1.id},
|
||
|
# tax_2:
|
||
|
{'debit': 0.0, 'credit': 0.0, 'amount_currency': 0.001, 'currency_id': currency_id, 'account_id': self.cash_basis_transfer_account.id},
|
||
|
{'debit': 0.0, 'credit': 0.0, 'amount_currency': -0.001, 'currency_id': currency_id, 'account_id': self.tax_account_2.id},
|
||
|
])
|
||
|
self.assertRecordValues(tax_cash_basis_moves[1].line_ids, [
|
||
|
# Base amount of tax_1 & tax_2:
|
||
|
{'debit': 12.5, 'credit': 0.0, 'amount_currency': 25.0, 'currency_id': currency_id, 'account_id': self.cash_basis_base_account.id},
|
||
|
{'debit': 0.0, 'credit': 12.5, 'amount_currency': -25.0, 'currency_id': currency_id, 'account_id': self.cash_basis_base_account.id},
|
||
|
# tax_1:
|
||
|
{'debit': 4.17, 'credit': 0.0, 'amount_currency': 8.333, 'currency_id': currency_id, 'account_id': self.cash_basis_transfer_account.id},
|
||
|
{'debit': 0.0, 'credit': 4.17, 'amount_currency': -8.333, 'currency_id': currency_id, 'account_id': self.tax_account_1.id},
|
||
|
# tax_2:
|
||
|
{'debit': 0.0, 'credit': 0.0, 'amount_currency': 0.003, 'currency_id': currency_id, 'account_id': self.cash_basis_transfer_account.id},
|
||
|
{'debit': 0.0, 'credit': 0.0, 'amount_currency': -0.003, 'currency_id': currency_id, 'account_id': self.tax_account_2.id},
|
||
|
])
|
||
|
|
||
|
caba_transition_lines_1 = tax_cash_basis_moves.line_ids.filtered(lambda x: x.account_id == self.cash_basis_transfer_account)
|
||
|
caba_transition_exchange_moves_1 = caba_transition_lines_1.matched_credit_ids.exchange_move_id
|
||
|
self.assertEqual(len(caba_transition_exchange_moves_1), 2)
|
||
|
self.assertRecordValues(caba_transition_exchange_moves_1[0].line_ids, [
|
||
|
{'debit': 0.0, 'credit': 1.39, 'amount_currency': 0.0, 'currency_id': currency_id, 'account_id': self.cash_basis_transfer_account.id},
|
||
|
{'debit': 1.39, 'credit': 0.0, 'amount_currency': 0.0, 'currency_id': currency_id, 'account_id': self.env.company.expense_currency_exchange_account_id.id},
|
||
|
])
|
||
|
self.assertRecordValues(caba_transition_exchange_moves_1[1].line_ids, [
|
||
|
{'debit': 0.0, 'credit': 0.48, 'amount_currency': 0.0, 'currency_id': currency_id, 'account_id': self.cash_basis_transfer_account.id},
|
||
|
{'debit': 0.48, 'credit': 0.0, 'amount_currency': 0.0, 'currency_id': currency_id, 'account_id': self.env.company.expense_currency_exchange_account_id.id},
|
||
|
])
|
||
|
|
||
|
self.assertAmountsGroupByAccount([
|
||
|
# Account Balance Amount Currency
|
||
|
(self.cash_basis_transfer_account, -7.41, -22.226),
|
||
|
(self.tax_account_1, -5.57, -11.11),
|
||
|
(self.tax_account_2, 0.0, -0.004),
|
||
|
])
|
||
|
|
||
|
# Reconciling all the amount in extra_receivable_account_2 should compute 3 percentages:
|
||
|
# 44.45 / 133.36 = 0.333308338
|
||
|
# 44.44 / 133.36 = 0.333233353
|
||
|
# 0.01 / 133.36 = 0.000074985
|
||
|
|
||
|
receivable_lines_2 = (cash_basis_move + payment_move).line_ids\
|
||
|
.filtered(lambda line: line.account_id == self.extra_receivable_account_2)
|
||
|
tax_cash_basis_moves = self._get_caba_moves(receivable_lines_2.move_id)
|
||
|
receivable_lines_2.reconcile()
|
||
|
tax_cash_basis_moves = self._get_caba_moves(receivable_lines_2.move_id) - tax_cash_basis_moves
|
||
|
|
||
|
self.assertFullReconcileAccount(receivable_lines_2.full_reconcile_id, self.extra_receivable_account_2)
|
||
|
self.assertEqual(len(tax_cash_basis_moves), 3)
|
||
|
self.assertRecordValues(tax_cash_basis_moves[0].line_ids, [
|
||
|
# Base amount of tax_1 & tax_2:
|
||
|
{'debit': 0.01, 'credit': 0.0, 'amount_currency': 0.007, 'currency_id': currency_id, 'account_id': self.cash_basis_base_account.id},
|
||
|
{'debit': 0.0, 'credit': 0.01, 'amount_currency': -0.007, 'currency_id': currency_id, 'account_id': self.cash_basis_base_account.id},
|
||
|
# tax_1:
|
||
|
{'debit': 0.0, 'credit': 0.0, 'amount_currency': 0.002, 'currency_id': currency_id, 'account_id': self.cash_basis_transfer_account.id},
|
||
|
{'debit': 0.0, 'credit': 0.0, 'amount_currency': -0.002, 'currency_id': currency_id, 'account_id': self.tax_account_1.id},
|
||
|
# tax_2:
|
||
|
{'debit': 0.0, 'credit': 0.0, 'amount_currency': 0.0, 'currency_id': currency_id, 'account_id': self.cash_basis_transfer_account.id},
|
||
|
{'debit': 0.0, 'credit': 0.0, 'amount_currency': 0.0, 'currency_id': currency_id, 'account_id': self.tax_account_2.id},
|
||
|
])
|
||
|
self.assertRecordValues(tax_cash_basis_moves[1].line_ids, [
|
||
|
# Base amount of tax_1 & tax_2:
|
||
|
{'debit': 16.66, 'credit': 0.0, 'amount_currency': 33.323, 'currency_id': currency_id, 'account_id': self.cash_basis_base_account.id},
|
||
|
{'debit': 0.0, 'credit': 16.66, 'amount_currency': -33.323, 'currency_id': currency_id, 'account_id': self.cash_basis_base_account.id},
|
||
|
# tax_1:
|
||
|
{'debit': 5.55, 'credit': 0.0, 'amount_currency': 11.107, 'currency_id': currency_id, 'account_id': self.cash_basis_transfer_account.id},
|
||
|
{'debit': 0.0, 'credit': 5.55, 'amount_currency': -11.107, 'currency_id': currency_id, 'account_id': self.tax_account_1.id},
|
||
|
# tax_2:
|
||
|
{'debit': 0.0, 'credit': 0.0, 'amount_currency': 0.003, 'currency_id': currency_id, 'account_id': self.cash_basis_transfer_account.id},
|
||
|
{'debit': 0.0, 'credit': 0.0, 'amount_currency': -0.003, 'currency_id': currency_id, 'account_id': self.tax_account_2.id},
|
||
|
])
|
||
|
self.assertRecordValues(tax_cash_basis_moves[2].line_ids, [
|
||
|
# Base amount of tax_1 & tax_2:
|
||
|
{'debit': 16.67, 'credit': 0.0, 'amount_currency': 33.331, 'currency_id': currency_id, 'account_id': self.cash_basis_base_account.id},
|
||
|
{'debit': 0.0, 'credit': 16.67, 'amount_currency': -33.331, 'currency_id': currency_id, 'account_id': self.cash_basis_base_account.id},
|
||
|
# tax_1:
|
||
|
{'debit': 5.56, 'credit': 0.0, 'amount_currency': 11.109, 'currency_id': currency_id, 'account_id': self.cash_basis_transfer_account.id},
|
||
|
{'debit': 0.0, 'credit': 5.56, 'amount_currency': -11.109, 'currency_id': currency_id, 'account_id': self.tax_account_1.id},
|
||
|
# tax_2:
|
||
|
{'debit': 0.0, 'credit': 0.0, 'amount_currency': 0.003, 'currency_id': currency_id, 'account_id': self.cash_basis_transfer_account.id},
|
||
|
{'debit': 0.0, 'credit': 0.0, 'amount_currency': -0.003, 'currency_id': currency_id, 'account_id': self.tax_account_2.id},
|
||
|
])
|
||
|
|
||
|
caba_transition_lines_2 = tax_cash_basis_moves.line_ids.filtered(lambda x: x.account_id == self.cash_basis_transfer_account)
|
||
|
caba_transition_exchange_moves_2 = caba_transition_lines_2.matched_credit_ids.exchange_move_id
|
||
|
self.assertEqual(len(caba_transition_exchange_moves_2), 3)
|
||
|
self.assertRecordValues(caba_transition_exchange_moves_2[0].line_ids, [
|
||
|
{'debit': 0.01, 'credit': 0.0, 'amount_currency': 0.0, 'currency_id': currency_id, 'account_id': self.cash_basis_transfer_account.id},
|
||
|
{'debit': 0.0, 'credit': 0.01, 'amount_currency': 0.0, 'currency_id': currency_id, 'account_id': self.env.company.income_currency_exchange_account_id.id},
|
||
|
])
|
||
|
self.assertRecordValues(caba_transition_exchange_moves_2[1].line_ids, [
|
||
|
{'debit': 0.0, 'credit': 1.86, 'amount_currency': 0.0, 'currency_id': currency_id, 'account_id': self.cash_basis_transfer_account.id},
|
||
|
{'debit': 1.86, 'credit': 0.0, 'amount_currency': 0.0, 'currency_id': currency_id, 'account_id': self.env.company.expense_currency_exchange_account_id.id},
|
||
|
])
|
||
|
self.assertRecordValues(caba_transition_exchange_moves_2[2].line_ids, [
|
||
|
{'debit': 0.0, 'credit': 1.85, 'amount_currency': 0.0, 'currency_id': currency_id, 'account_id': self.cash_basis_transfer_account.id},
|
||
|
{'debit': 1.85, 'credit': 0.0, 'amount_currency': 0.0, 'currency_id': currency_id, 'account_id': self.env.company.expense_currency_exchange_account_id.id},
|
||
|
])
|
||
|
|
||
|
self.assertAmountsGroupByAccount([
|
||
|
# Account Balance Amount Currency
|
||
|
(self.cash_basis_transfer_account, 0.0, -0.002),
|
||
|
(self.tax_account_1, -16.68, -33.328),
|
||
|
(self.tax_account_2, 0.0, -0.01),
|
||
|
])
|
||
|
|
||
|
# Reconciling all the amount in extra_payable_account_1 should trigger the matching number and ensure all
|
||
|
# the base amount has been covered without any rounding issue.
|
||
|
|
||
|
payable_lines_1 = (cash_basis_move + payment_move).line_ids\
|
||
|
.filtered(lambda line: line.account_id == self.extra_payable_account_1)
|
||
|
tax_cash_basis_moves = self._get_caba_moves(payable_lines_1.move_id)
|
||
|
payable_lines_1.reconcile()
|
||
|
tax_cash_basis_moves = self._get_caba_moves(payable_lines_1.move_id) - tax_cash_basis_moves
|
||
|
|
||
|
self.assertFullReconcile(payable_lines_1.full_reconcile_id, payable_lines_1)
|
||
|
self.assertEqual(len(tax_cash_basis_moves), 1)
|
||
|
self.assertRecordValues(tax_cash_basis_moves.line_ids, [
|
||
|
# Base amount of tax_1 & tax_2:
|
||
|
{'debit': 0.01, 'credit': 0.0, 'amount_currency': 0.007, 'currency_id': currency_id, 'account_id': self.cash_basis_base_account.id},
|
||
|
{'debit': 0.0, 'credit': 0.01, 'amount_currency': -0.007, 'currency_id': currency_id, 'account_id': self.cash_basis_base_account.id},
|
||
|
# tax_1:
|
||
|
{'debit': 0.0, 'credit': 0.0, 'amount_currency': 0.002, 'currency_id': currency_id, 'account_id': self.cash_basis_transfer_account.id},
|
||
|
{'debit': 0.0, 'credit': 0.0, 'amount_currency': -0.002, 'currency_id': currency_id, 'account_id': self.tax_account_1.id},
|
||
|
# tax_2:
|
||
|
{'debit': 0.0, 'credit': 0.0, 'amount_currency': 0.0, 'currency_id': currency_id, 'account_id': self.cash_basis_transfer_account.id},
|
||
|
{'debit': 0.0, 'credit': 0.0, 'amount_currency': 0.0, 'currency_id': currency_id, 'account_id': self.tax_account_2.id},
|
||
|
])
|
||
|
|
||
|
self.assertRecordValues(payable_lines_1.full_reconcile_id.exchange_move_id.line_ids, [
|
||
|
{'account_id': self.cash_basis_base_account.id, 'debit': 0.0, 'credit': 0.0, 'amount_currency': -0.001, 'tax_ids': taxes.ids, 'tax_line_id': False},
|
||
|
{'account_id': self.cash_basis_base_account.id, 'debit': 0.0, 'credit': 0.0, 'amount_currency': 0.001, 'tax_ids': [], 'tax_line_id': False},
|
||
|
])
|
||
|
|
||
|
# No exchange move should have been created when reconciling the transition account
|
||
|
caba_transition_lines_3 = tax_cash_basis_moves.line_ids.filtered(lambda x: x.account_id == self.cash_basis_transfer_account)
|
||
|
self.assertFalse(caba_transition_lines_3.matched_credit_ids.exchange_move_id)
|
||
|
|
||
|
self.assertAmountsGroupByAccount([
|
||
|
# Account Balance Amount Currency
|
||
|
(self.cash_basis_transfer_account, 0.0, 0.0),
|
||
|
(self.tax_account_1, -16.68, -33.33),
|
||
|
(self.tax_account_2, 0.0, -0.01),
|
||
|
])
|
||
|
|
||
|
def test_reconcile_cash_basis_exchange_difference_transfer_account_check_entries_1(self):
|
||
|
''' Test the generation of the exchange difference for a tax cash basis journal entry when the transfer
|
||
|
account is not reconcilable.
|
||
|
'''
|
||
|
self.env.company.tax_exigibility = True
|
||
|
currency_id = self.currency_data['currency'].id
|
||
|
|
||
|
# Rate 1/3 in 2016.
|
||
|
cash_basis_move = self.env['account.move'].create({
|
||
|
'move_type': 'entry',
|
||
|
'date': '2016-01-01',
|
||
|
'line_ids': [
|
||
|
# Base Tax line
|
||
|
(0, 0, {
|
||
|
'debit': 0.0,
|
||
|
'credit': 100.0,
|
||
|
'amount_currency': -300.0,
|
||
|
'currency_id': currency_id,
|
||
|
'account_id': self.company_data['default_account_revenue'].id,
|
||
|
'tax_ids': [(6, 0, self.cash_basis_tax_a_third_amount.ids)],
|
||
|
}),
|
||
|
|
||
|
# Tax line
|
||
|
(0, 0, {
|
||
|
'debit': 0.0,
|
||
|
'credit': 33.33,
|
||
|
'amount_currency': -100.0,
|
||
|
'currency_id': currency_id,
|
||
|
'account_id': self.cash_basis_transfer_account.id,
|
||
|
'tax_repartition_line_id': self.cash_basis_tax_a_third_amount.invoice_repartition_line_ids.filtered(lambda line: line.repartition_type == 'tax').id,
|
||
|
}),
|
||
|
|
||
|
# Receivable lines
|
||
|
(0, 0, {
|
||
|
'debit': 133.33,
|
||
|
'credit': 0.0,
|
||
|
'amount_currency': 400.0,
|
||
|
'currency_id': currency_id,
|
||
|
'account_id': self.extra_receivable_account_1.id,
|
||
|
}),
|
||
|
]
|
||
|
})
|
||
|
|
||
|
# Rate 1/2 in 2017.
|
||
|
payment_move = self.env['account.move'].create({
|
||
|
'move_type': 'entry',
|
||
|
'date': '2017-01-01',
|
||
|
'line_ids': [
|
||
|
(0, 0, {
|
||
|
'debit': 0.0,
|
||
|
'credit': 201.0,
|
||
|
'amount_currency': -402.0, # Don't create the full reconcile directly.
|
||
|
'currency_id': currency_id,
|
||
|
'account_id': self.extra_receivable_account_1.id,
|
||
|
}),
|
||
|
(0, 0, {
|
||
|
'debit': 201.0,
|
||
|
'credit': 0.0,
|
||
|
'account_id': self.company_data['default_account_revenue'].id,
|
||
|
}),
|
||
|
]
|
||
|
})
|
||
|
|
||
|
# Move making the payment fully paid.
|
||
|
end_move = self.env['account.move'].create({
|
||
|
'move_type': 'entry',
|
||
|
'date': '2017-01-01',
|
||
|
'line_ids': [
|
||
|
(0, 0, {
|
||
|
'debit': 1.0,
|
||
|
'credit': 0.0,
|
||
|
'amount_currency': 2.0,
|
||
|
'currency_id': currency_id,
|
||
|
'account_id': self.extra_receivable_account_1.id,
|
||
|
}),
|
||
|
(0, 0, {
|
||
|
'debit': 0.0,
|
||
|
'credit': 1.0,
|
||
|
'account_id': self.company_data['default_account_revenue'].id,
|
||
|
}),
|
||
|
]
|
||
|
})
|
||
|
|
||
|
(cash_basis_move + payment_move + end_move).action_post()
|
||
|
|
||
|
self.assertAmountsGroupByAccount([
|
||
|
# Account Balance Amount Currency
|
||
|
(self.cash_basis_transfer_account, -33.33, -100.0),
|
||
|
(self.tax_account_1, 0.0, 0.0),
|
||
|
])
|
||
|
|
||
|
receivable_lines = (cash_basis_move + payment_move).line_ids\
|
||
|
.filtered(lambda line: line.account_id == self.extra_receivable_account_1)
|
||
|
receivable_lines.reconcile()
|
||
|
tax_cash_basis_moves = self._get_caba_moves(receivable_lines.move_id)
|
||
|
|
||
|
self.assertEqual(len(tax_cash_basis_moves), 1)
|
||
|
self.assertRecordValues(tax_cash_basis_moves.line_ids, [
|
||
|
# Base amount:
|
||
|
{'debit': 150.0, 'credit': 0.0, 'amount_currency': 300.0, 'currency_id': currency_id, 'account_id': self.cash_basis_base_account.id},
|
||
|
{'debit': 0.0, 'credit': 150.0, 'amount_currency': -300.0, 'currency_id': currency_id, 'account_id': self.cash_basis_base_account.id},
|
||
|
# tax:
|
||
|
{'debit': 50.0, 'credit': 0.0, 'amount_currency': 100.0, 'currency_id': currency_id, 'account_id': self.cash_basis_transfer_account.id},
|
||
|
{'debit': 0.0, 'credit': 50.0, 'amount_currency': -100.0, 'currency_id': currency_id, 'account_id': self.tax_account_1.id},
|
||
|
])
|
||
|
|
||
|
receivable_lines2 = (payment_move + end_move).line_ids\
|
||
|
.filtered(lambda line: line.account_id == self.extra_receivable_account_1)
|
||
|
receivable_lines2.reconcile()
|
||
|
|
||
|
self.assertTrue(receivable_lines2.full_reconcile_id)
|
||
|
exchange_diff = receivable_lines2.full_reconcile_id.exchange_move_id
|
||
|
caba_rounding_correction = exchange_diff.line_ids\
|
||
|
.filtered(lambda line: line.account_id == self.cash_basis_transfer_account)\
|
||
|
.sorted(lambda line: (line.account_id, line.debit, line.credit))
|
||
|
|
||
|
self.assertFalse(caba_rounding_correction, "No cash basis rounding correction should have been created, as the difference between amounts is only due to exchange difference.")
|
||
|
|
||
|
self.assertAmountsGroupByAccount([
|
||
|
# Account Balance Amount Currency
|
||
|
(self.cash_basis_transfer_account, 0.0, 0.0),
|
||
|
(self.tax_account_1, -50.0, -100.0),
|
||
|
])
|
||
|
|
||
|
def test_reconcile_cash_basis_exchange_difference_transfer_account_check_entries_2(self):
|
||
|
''' Test the generation of the exchange difference for a tax cash basis journal entry when the transfer
|
||
|
account is not a reconcile one.
|
||
|
'''
|
||
|
self.env.company.tax_exigibility = True
|
||
|
currency_id = self.setup_multi_currency_data(default_values={
|
||
|
'name': 'bitcoin',
|
||
|
'symbol': 'bc',
|
||
|
'currency_unit_label': 'Bitcoin',
|
||
|
'currency_subunit_label': 'Tiny bitcoin',
|
||
|
}, rate2016=0.5, rate2017=0.66666666666666)['currency'].id
|
||
|
|
||
|
# Rate 2/1 in 2016.
|
||
|
caba_inv = self.env['account.move'].with_context(skip_invoice_sync=True).create({
|
||
|
'move_type': 'entry',
|
||
|
'date': '2016-01-01',
|
||
|
'line_ids': [
|
||
|
# Base Tax line
|
||
|
(0, 0, {
|
||
|
'debit': 0.0,
|
||
|
'credit': 200.0,
|
||
|
'amount_currency': -100.0,
|
||
|
'currency_id': currency_id,
|
||
|
'account_id': self.company_data['default_account_revenue'].id,
|
||
|
'tax_ids': [(6, 0, self.cash_basis_tax_a_third_amount.ids)],
|
||
|
}),
|
||
|
|
||
|
# Tax line
|
||
|
(0, 0, {
|
||
|
'debit': 0.0,
|
||
|
'credit': 20.0,
|
||
|
'amount_currency': -10.0,
|
||
|
'currency_id': currency_id,
|
||
|
'account_id': self.cash_basis_transfer_account.id,
|
||
|
'tax_repartition_line_id': self.cash_basis_tax_a_third_amount.invoice_repartition_line_ids.filtered(lambda line: line.repartition_type == 'tax').id,
|
||
|
}),
|
||
|
|
||
|
# Receivable lines
|
||
|
(0, 0, {
|
||
|
'debit': 220.0,
|
||
|
'credit': 0.0,
|
||
|
'amount_currency': 110.0,
|
||
|
'currency_id': currency_id,
|
||
|
'account_id': self.extra_receivable_account_1.id,
|
||
|
}),
|
||
|
]
|
||
|
})
|
||
|
caba_inv.action_post()
|
||
|
|
||
|
# Rate 3/2 in 2017. Full payment of 110 in foreign currency
|
||
|
pmt_wizard = self.env['account.payment.register'].with_context(active_model='account.move', active_ids=caba_inv.ids).create({
|
||
|
'payment_date': '2017-01-01',
|
||
|
'journal_id': self.company_data['default_journal_bank'].id,
|
||
|
'payment_method_line_id': self.inbound_payment_method_line.id,
|
||
|
})
|
||
|
pmt_wizard._create_payments()
|
||
|
partial_rec = caba_inv.mapped('line_ids.matched_credit_ids')
|
||
|
caba_move = self.env['account.move'].search([('tax_cash_basis_rec_id', 'in', partial_rec.ids)])
|
||
|
|
||
|
self.assertRecordValues(caba_move.line_ids, [
|
||
|
{'account_id': self.cash_basis_base_account.id, 'debit': 150.0, 'credit': 0.0, 'amount_currency': 100.0, 'tax_ids': [], 'tax_line_id': False},
|
||
|
{'account_id': self.cash_basis_base_account.id, 'debit': 0.0, 'credit': 150.0, 'amount_currency': -100.0, 'tax_ids': self.cash_basis_tax_a_third_amount.ids, 'tax_line_id': False},
|
||
|
{'account_id': self.cash_basis_transfer_account.id, 'debit': 15.0, 'credit': 0.0, 'amount_currency': 10.0, 'tax_ids': [], 'tax_line_id': False},
|
||
|
{'account_id': self.tax_account_1.id, 'debit': 0.0, 'credit': 15.0, 'amount_currency': -10.0, 'tax_ids': [], 'tax_line_id': self.cash_basis_tax_a_third_amount.id},
|
||
|
])
|
||
|
|
||
|
receivable_line = caba_inv.line_ids.filtered(lambda x: x.account_id.account_type == 'asset_receivable')
|
||
|
self.assertTrue(receivable_line.full_reconcile_id, "Invoice should be fully paid")
|
||
|
|
||
|
self.assertRecordValues(partial_rec.exchange_move_id.line_ids, [
|
||
|
{'account_id': receivable_line.account_id.id, 'debit': 0.0, 'credit': 55.0, 'amount_currency': 0.0, 'tax_ids': [], 'tax_line_id': False},
|
||
|
{'account_id': caba_move.company_id.expense_currency_exchange_account_id.id, 'debit': 55.0, 'credit': 0.0, 'amount_currency': 0.0, 'tax_ids': [], 'tax_line_id': False},
|
||
|
])
|
||
|
|
||
|
exchange_move = receivable_line.full_reconcile_id.exchange_move_id
|
||
|
self.assertFalse(exchange_move, "No exchange move difference should be created for the full reconcile object ,as there is no cash basis rounding.")
|
||
|
|
||
|
self.assertAmountsGroupByAccount([
|
||
|
# Account Balance Amount Currency
|
||
|
(self.cash_basis_transfer_account, 0.0, 0.0),
|
||
|
(self.tax_account_1, -15.0, -10.0),
|
||
|
])
|
||
|
|
||
|
def test_reconcile_cash_basis_exchange_difference_transfer_account_check_entries_3(self):
|
||
|
''' Test the generation of the exchange difference for a tax cash basis journal entry when the transfer
|
||
|
account is not a reconcile one.
|
||
|
'''
|
||
|
self.env.company.tax_exigibility = True
|
||
|
currency_id = self.setup_multi_currency_data(default_values={
|
||
|
'name': 'bitcoin',
|
||
|
'symbol': 'bc',
|
||
|
'currency_unit_label': 'Bitcoin',
|
||
|
'currency_subunit_label': 'Tiny bitcoin',
|
||
|
'rounding': 0.01,
|
||
|
}, rate2016=0.5, rate2017=0.66666666666666)['currency'].id
|
||
|
|
||
|
# Rate 2/1 in 2016.
|
||
|
caba_inv = self.env['account.move'].with_context(skip_invoice_sync=True).create({
|
||
|
'move_type': 'entry',
|
||
|
'date': '2016-01-01',
|
||
|
'line_ids': [
|
||
|
# Base Tax line
|
||
|
(0, 0, {
|
||
|
'debit': 0.0,
|
||
|
'credit': 200.0,
|
||
|
'amount_currency': -100.0,
|
||
|
'currency_id': currency_id,
|
||
|
'account_id': self.company_data['default_account_revenue'].id,
|
||
|
'tax_ids': [(6, 0, self.cash_basis_tax_a_third_amount.ids)],
|
||
|
}),
|
||
|
|
||
|
# Tax line
|
||
|
(0, 0, {
|
||
|
'debit': 0.0,
|
||
|
'credit': 20.0,
|
||
|
'amount_currency': -10.0,
|
||
|
'currency_id': currency_id,
|
||
|
'account_id': self.cash_basis_transfer_account.id,
|
||
|
'tax_repartition_line_id': self.cash_basis_tax_a_third_amount.invoice_repartition_line_ids.filtered(lambda line: line.repartition_type == 'tax').id,
|
||
|
}),
|
||
|
|
||
|
# Receivable lines
|
||
|
(0, 0, {
|
||
|
'debit': 220.0,
|
||
|
'credit': 0.0,
|
||
|
'amount_currency': 110.0,
|
||
|
'currency_id': currency_id,
|
||
|
'account_id': self.extra_receivable_account_1.id,
|
||
|
}),
|
||
|
]
|
||
|
})
|
||
|
caba_inv.action_post()
|
||
|
|
||
|
self.env['account.payment.register']\
|
||
|
.with_context(active_model='account.move', active_ids=caba_inv.ids)\
|
||
|
.create({
|
||
|
'payment_date': '2017-01-01',
|
||
|
'currency_id': currency_id,
|
||
|
'amount': 110.0,
|
||
|
})\
|
||
|
._create_payments()
|
||
|
|
||
|
receivable_line = caba_inv.line_ids.filtered(lambda x: x.account_id.account_type == 'asset_receivable')
|
||
|
partial_rec = caba_inv.line_ids.matched_credit_ids
|
||
|
self.assertTrue(receivable_line.full_reconcile_id, "Invoice should be fully paid")
|
||
|
|
||
|
caba_move = self.env['account.move'].search([('tax_cash_basis_rec_id', 'in', caba_inv.line_ids.matched_credit_ids.ids)])
|
||
|
self.assertRecordValues(caba_move.line_ids, [
|
||
|
{'account_id': self.cash_basis_base_account.id, 'debit': 150.0, 'credit': 0.0, 'amount_currency': 100.0, 'tax_ids': [], 'tax_line_id': False},
|
||
|
{'account_id': self.cash_basis_base_account.id, 'debit': 0.0, 'credit': 150.0, 'amount_currency': -100.0, 'tax_ids': self.cash_basis_tax_a_third_amount.ids, 'tax_line_id': False},
|
||
|
{'account_id': self.cash_basis_transfer_account.id, 'debit': 15.0, 'credit': 0.0, 'amount_currency': 10.0, 'tax_ids': [], 'tax_line_id': False},
|
||
|
{'account_id': self.tax_account_1.id, 'debit': 0.0, 'credit': 15.0, 'amount_currency': -10.0, 'tax_ids': [], 'tax_line_id': self.cash_basis_tax_a_third_amount.id},
|
||
|
])
|
||
|
|
||
|
self.assertRecordValues(partial_rec.exchange_move_id.line_ids, [
|
||
|
{'account_id': self.extra_receivable_account_1.id, 'debit': 0.0, 'credit': 55.0, 'amount_currency': 0.0, 'tax_ids': [], 'tax_line_id': False},
|
||
|
{'account_id': caba_move.company_id.expense_currency_exchange_account_id.id, 'debit': 55.0, 'credit': 0.0, 'amount_currency': 0.0, 'tax_ids': [], 'tax_line_id': False},
|
||
|
])
|
||
|
|
||
|
exchange_move = receivable_line.full_reconcile_id.exchange_move_id
|
||
|
self.assertFalse(exchange_move, "No exchange move difference should be created for the full reconcile object ,as there is no cash basis rounding.")
|
||
|
|
||
|
self.assertAmountsGroupByAccount([
|
||
|
# Account Balance Amount Currency
|
||
|
(self.cash_basis_transfer_account, 0.0, 0.0),
|
||
|
(self.tax_account_1, -15.0, -10.0),
|
||
|
])
|
||
|
|
||
|
def test_reconcile_cash_basis_exchange_difference_transfer_account_check_entries_4(self):
|
||
|
''' Test the generation of the exchange difference for a tax cash basis journal entry when the tax
|
||
|
account is a reconcile one.
|
||
|
'''
|
||
|
self.env.company.tax_exigibility = True
|
||
|
currency_id = self.currency_data['currency'].id
|
||
|
cash_basis_transition_account = self.env['account.account'].create({
|
||
|
'code': '209.01.01',
|
||
|
'name': 'Cash Basis Transition Account',
|
||
|
'account_type': 'liability_current',
|
||
|
'company_id': self.company_data['company'].id,
|
||
|
'reconcile': True,
|
||
|
})
|
||
|
self.cash_basis_tax_a_third_amount.write({
|
||
|
'cash_basis_transition_account_id': cash_basis_transition_account.id,
|
||
|
})
|
||
|
|
||
|
# Rate 1/3 in 2016.
|
||
|
cash_basis_move = self.env['account.move'].create({
|
||
|
'move_type': 'entry',
|
||
|
'date': '2016-01-01',
|
||
|
'line_ids': [
|
||
|
# Base Tax line
|
||
|
(0, 0, {
|
||
|
'debit': 0.0,
|
||
|
'credit': 100.0,
|
||
|
'amount_currency': -300.0,
|
||
|
'currency_id': currency_id,
|
||
|
'account_id': self.company_data['default_account_revenue'].id,
|
||
|
'tax_ids': [(6, 0, self.cash_basis_tax_a_third_amount.ids)],
|
||
|
}),
|
||
|
|
||
|
# Tax line
|
||
|
(0, 0, {
|
||
|
'debit': 0.0,
|
||
|
'credit': 33.33,
|
||
|
'amount_currency': -100.0,
|
||
|
'currency_id': currency_id,
|
||
|
'account_id': cash_basis_transition_account.id,
|
||
|
'tax_repartition_line_id': self.cash_basis_tax_a_third_amount.invoice_repartition_line_ids.filtered(lambda line: line.repartition_type == 'tax').id,
|
||
|
}),
|
||
|
|
||
|
# Receivable lines
|
||
|
(0, 0, {
|
||
|
'debit': 133.33,
|
||
|
'credit': 0.0,
|
||
|
'amount_currency': 400.0,
|
||
|
'currency_id': currency_id,
|
||
|
'account_id': self.extra_receivable_account_1.id,
|
||
|
}),
|
||
|
]
|
||
|
})
|
||
|
|
||
|
# Rate 1/2 in 2017.
|
||
|
payment_move = self.env['account.move'].create({
|
||
|
'move_type': 'entry',
|
||
|
'date': '2017-01-01',
|
||
|
'line_ids': [
|
||
|
(0, 0, {
|
||
|
'debit': 0.0,
|
||
|
'credit': 200.0,
|
||
|
'amount_currency': -400.0,
|
||
|
'currency_id': currency_id,
|
||
|
'account_id': self.extra_receivable_account_1.id,
|
||
|
}),
|
||
|
(0, 0, {
|
||
|
'debit': 200.0,
|
||
|
'credit': 0.0,
|
||
|
'amount_currency': 400.0,
|
||
|
'currency_id': currency_id,
|
||
|
'account_id': self.company_data['default_account_revenue'].id,
|
||
|
}),
|
||
|
]
|
||
|
})
|
||
|
|
||
|
(cash_basis_move + payment_move).action_post()
|
||
|
|
||
|
self.assertAmountsGroupByAccount([
|
||
|
# Account Balance Amount Currency
|
||
|
(cash_basis_transition_account, -33.33, -100.0),
|
||
|
(self.tax_account_1, 0.0, 0.0),
|
||
|
])
|
||
|
|
||
|
receivable_lines = (cash_basis_move + payment_move).line_ids\
|
||
|
.filtered(lambda line: line.account_id == self.extra_receivable_account_1)
|
||
|
receivable_lines.reconcile()
|
||
|
tax_cash_basis_moves = self._get_caba_moves(receivable_lines.move_id)
|
||
|
|
||
|
self.assertEqual(len(tax_cash_basis_moves), 1)
|
||
|
|
||
|
# Tax values based on payment
|
||
|
# Invoice amount 300 (amount currency) with payment rate 2 (400 payment amount divided by 200 invoice balance)
|
||
|
# - Base amount: 150 company currency
|
||
|
# - Tax amount: 50 company currency
|
||
|
self.assertRecordValues(tax_cash_basis_moves.line_ids, [
|
||
|
# Base amount:
|
||
|
{'debit': 150.0, 'credit': 0.0, 'amount_currency': 300.0, 'currency_id': currency_id, 'account_id': self.cash_basis_base_account.id},
|
||
|
{'debit': 0.0, 'credit': 150.0, 'amount_currency': -300.0, 'currency_id': currency_id, 'account_id': self.cash_basis_base_account.id},
|
||
|
# tax:
|
||
|
{'debit': 50.0, 'credit': 0.0, 'amount_currency': 100.0, 'currency_id': currency_id, 'account_id': cash_basis_transition_account.id},
|
||
|
{'debit': 0.0, 'credit': 50.0, 'amount_currency': -100.0, 'currency_id': currency_id, 'account_id': self.tax_account_1.id},
|
||
|
])
|
||
|
|
||
|
partial_rec = cash_basis_move.line_ids.matched_credit_ids
|
||
|
self.assertRecordValues(partial_rec.exchange_move_id.line_ids, [
|
||
|
{'debit': 66.67, 'credit': 0.0, 'currency_id': currency_id, 'account_id': self.extra_receivable_account_1.id},
|
||
|
{'debit': 0.0, 'credit': 66.67, 'currency_id': currency_id, 'account_id': self.company_data['company'].income_currency_exchange_account_id.id},
|
||
|
])
|
||
|
|
||
|
# Exchange difference
|
||
|
self.assertFalse(receivable_lines.full_reconcile_id.exchange_move_id, "No exchange move difference should be created for the full reconcile object ,as there is no cash basis rounding.")
|
||
|
|
||
|
def test_reconcile_cash_basis_refund_multicurrency(self):
|
||
|
self.env.company.tax_exigibility = True
|
||
|
rates_data = self.setup_multi_currency_data(default_values={
|
||
|
'name': 'Playmock',
|
||
|
'symbol': '🦌',
|
||
|
'rounding': 0.01,
|
||
|
'currency_unit_label': 'Playmock',
|
||
|
'currency_subunit_label': 'Cent',
|
||
|
}, rate2016=0.5, rate2017=0.33333333333333333)
|
||
|
|
||
|
invoice = self.env['account.move'].create({
|
||
|
'move_type': 'out_invoice',
|
||
|
'partner_id': self.partner_a.id,
|
||
|
'currency_id': rates_data['currency'].id,
|
||
|
'invoice_date': '2016-01-01',
|
||
|
'invoice_line_ids': [(0, 0, {
|
||
|
'name': 'dudu',
|
||
|
'account_id': self.company_data['default_account_revenue'].id,
|
||
|
'price_unit': 100.0,
|
||
|
'tax_ids': [(6, 0, self.cash_basis_tax_a_third_amount.ids)],
|
||
|
})],
|
||
|
})
|
||
|
|
||
|
refund = self.env['account.move'].create({
|
||
|
'move_type': 'out_refund',
|
||
|
'partner_id': self.partner_a.id,
|
||
|
'currency_id': rates_data['currency'].id,
|
||
|
'invoice_date': '2017-01-01',
|
||
|
'invoice_line_ids': [(0, 0, {
|
||
|
'name': 'dudu',
|
||
|
'account_id': self.company_data['default_account_revenue'].id,
|
||
|
'price_unit': 100.0,
|
||
|
'tax_ids': [(6, 0, self.cash_basis_tax_a_third_amount.ids)],
|
||
|
})],
|
||
|
})
|
||
|
|
||
|
invoice.action_post()
|
||
|
refund.action_post()
|
||
|
|
||
|
(refund + invoice).line_ids\
|
||
|
.filtered(lambda x: x.account_id.account_type == 'asset_receivable')\
|
||
|
.reconcile()
|
||
|
|
||
|
# Check the cash basis moves
|
||
|
self.assertRecordValues(
|
||
|
self.env['account.move'].search([('tax_cash_basis_origin_move_id', '=', invoice.id)]).line_ids,
|
||
|
[
|
||
|
{
|
||
|
'debit': 200,
|
||
|
'credit': 0,
|
||
|
'amount_currency': 100,
|
||
|
'currency_id': rates_data['currency'].id,
|
||
|
'tax_ids': [],
|
||
|
'tax_repartition_line_id': None,
|
||
|
'tax_tag_ids': [],
|
||
|
},
|
||
|
{
|
||
|
'debit': 0,
|
||
|
'credit': 200,
|
||
|
'amount_currency': -100,
|
||
|
'currency_id': rates_data['currency'].id,
|
||
|
'tax_ids': self.cash_basis_tax_a_third_amount.ids,
|
||
|
'tax_repartition_line_id': None,
|
||
|
'tax_tag_ids': self.tax_tags[0].ids,
|
||
|
},
|
||
|
{
|
||
|
'debit': 66.66,
|
||
|
'credit': 0,
|
||
|
'amount_currency': 33.33,
|
||
|
'currency_id': rates_data['currency'].id,
|
||
|
'tax_ids': [],
|
||
|
'tax_repartition_line_id': None,
|
||
|
'tax_tag_ids': [],
|
||
|
},
|
||
|
{
|
||
|
'debit': 0,
|
||
|
'credit': 66.66,
|
||
|
'amount_currency': -33.33,
|
||
|
'currency_id': rates_data['currency'].id,
|
||
|
'tax_ids': [],
|
||
|
'tax_repartition_line_id': self.cash_basis_tax_a_third_amount.invoice_repartition_line_ids.filtered(lambda x: x.repartition_type == 'tax').id,
|
||
|
'tax_tag_ids': self.tax_tags[1].ids,
|
||
|
},
|
||
|
]
|
||
|
)
|
||
|
|
||
|
self.assertRecordValues(
|
||
|
self.env['account.move'].search([('tax_cash_basis_origin_move_id', '=', refund.id)]).line_ids,
|
||
|
[
|
||
|
{
|
||
|
'debit': 0,
|
||
|
'credit': 300,
|
||
|
'amount_currency': -100,
|
||
|
'currency_id': rates_data['currency'].id,
|
||
|
'tax_ids': [],
|
||
|
'tax_repartition_line_id': None,
|
||
|
'tax_tag_ids': [],
|
||
|
},
|
||
|
{
|
||
|
'debit': 300,
|
||
|
'credit': 0,
|
||
|
'amount_currency': 100,
|
||
|
'currency_id': rates_data['currency'].id,
|
||
|
'tax_ids': self.cash_basis_tax_a_third_amount.ids,
|
||
|
'tax_repartition_line_id': None,
|
||
|
'tax_tag_ids': self.tax_tags[2].ids,
|
||
|
},
|
||
|
{
|
||
|
'debit': 0,
|
||
|
'credit': 99.99,
|
||
|
'amount_currency': -33.33,
|
||
|
'currency_id': rates_data['currency'].id,
|
||
|
'tax_ids': [],
|
||
|
'tax_repartition_line_id': None,
|
||
|
'tax_tag_ids': [],
|
||
|
},
|
||
|
{
|
||
|
'debit': 99.99,
|
||
|
'credit': 0,
|
||
|
'amount_currency': 33.33,
|
||
|
'currency_id': rates_data['currency'].id,
|
||
|
'tax_ids': [],
|
||
|
'tax_repartition_line_id': self.cash_basis_tax_a_third_amount.refund_repartition_line_ids.filtered(lambda x: x.repartition_type == 'tax').id,
|
||
|
'tax_tag_ids': self.tax_tags[3].ids,
|
||
|
},
|
||
|
]
|
||
|
)
|
||
|
|
||
|
# Check the exchange difference move, to be sure no cash basis rounding data was added into it
|
||
|
self.assertRecordValues(
|
||
|
invoice.line_ids.filtered(lambda x: x.account_id.account_type == 'asset_receivable').matched_credit_ids.exchange_move_id.line_ids,
|
||
|
[
|
||
|
{
|
||
|
'debit': 133.33,
|
||
|
'credit': 0,
|
||
|
'amount_currency': 0,
|
||
|
'currency_id': rates_data['currency'].id,
|
||
|
'tax_ids': [],
|
||
|
'tax_repartition_line_id': None,
|
||
|
'tax_tag_ids': [],
|
||
|
},
|
||
|
{
|
||
|
'debit': 0,
|
||
|
'credit': 133.33,
|
||
|
'amount_currency': 0,
|
||
|
'currency_id': rates_data['currency'].id,
|
||
|
'tax_ids': [],
|
||
|
'tax_repartition_line_id': None,
|
||
|
'tax_tag_ids': [],
|
||
|
},
|
||
|
]
|
||
|
)
|
||
|
|
||
|
self.assertFalse(invoice.line_ids.full_reconcile_id.exchange_move_id)
|
||
|
|
||
|
def test_reconcile_cash_basis_revert(self):
|
||
|
''' Ensure the cash basis journal entry can be reverted. '''
|
||
|
self.env.company.tax_exigibility = True
|
||
|
self.cash_basis_transfer_account.reconcile = True
|
||
|
self.cash_basis_tax_a_third_amount.cash_basis_transition_account_id = self.tax_account_1
|
||
|
|
||
|
invoice_move = self.env['account.move'].with_context(skip_invoice_sync=True).create({
|
||
|
'move_type': 'entry',
|
||
|
'date': '2016-01-01',
|
||
|
'line_ids': [
|
||
|
# Base Tax line
|
||
|
(0, 0, {
|
||
|
'debit': 0.0,
|
||
|
'credit': 100.0,
|
||
|
'account_id': self.company_data['default_account_revenue'].id,
|
||
|
'tax_ids': [(6, 0, self.cash_basis_tax_a_third_amount.ids)],
|
||
|
}),
|
||
|
|
||
|
# Tax line
|
||
|
(0, 0, {
|
||
|
'debit': 0.0,
|
||
|
'credit': 33.33,
|
||
|
'account_id': self.cash_basis_transfer_account.id,
|
||
|
'tax_repartition_line_id': self.cash_basis_tax_a_third_amount.invoice_repartition_line_ids.filtered(lambda line: line.repartition_type == 'tax').id,
|
||
|
}),
|
||
|
|
||
|
# Receivable line
|
||
|
(0, 0, {
|
||
|
'debit': 133.33,
|
||
|
'credit': 0.0,
|
||
|
'account_id': self.extra_receivable_account_1.id,
|
||
|
}),
|
||
|
]
|
||
|
})
|
||
|
|
||
|
payment_move = self.env['account.move'].with_context(skip_invoice_sync=True).create({
|
||
|
'move_type': 'entry',
|
||
|
'date': '2016-01-01',
|
||
|
'line_ids': [
|
||
|
(0, 0, {'debit': 0.0, 'credit': 133.33, 'account_id': self.extra_receivable_account_1.id}),
|
||
|
(0, 0, {'debit': 133.33, 'credit': 0.0, 'account_id': self.company_data['default_account_revenue'].id}),
|
||
|
]
|
||
|
})
|
||
|
|
||
|
(invoice_move + payment_move).action_post()
|
||
|
|
||
|
receivable_lines = (invoice_move + payment_move).line_ids\
|
||
|
.filtered(lambda line: line.account_id == self.extra_receivable_account_1)
|
||
|
receivable_lines.reconcile()
|
||
|
tax_cash_basis_moves = self._get_caba_moves(receivable_lines.move_id)
|
||
|
|
||
|
# == Check reconciliation of invoice with payment ==
|
||
|
|
||
|
self.assertFullReconcile(receivable_lines.full_reconcile_id, receivable_lines)
|
||
|
self.assertEqual(len(tax_cash_basis_moves), 1)
|
||
|
|
||
|
# == Check the reconciliation of invoice with tax cash basis journal entry.
|
||
|
# /!\ We make the assumption the tax cash basis journal entry is well created.
|
||
|
|
||
|
tax_cash_basis_move = tax_cash_basis_moves
|
||
|
|
||
|
taxes_lines = (invoice_move.line_ids + tax_cash_basis_move.line_ids.filtered('debit'))\
|
||
|
.filtered(lambda line: line.account_id == self.cash_basis_transfer_account)
|
||
|
taxes_full_reconcile = taxes_lines.matched_debit_ids.full_reconcile_id
|
||
|
|
||
|
self.assertTrue(taxes_full_reconcile)
|
||
|
self.assertFullReconcile(taxes_full_reconcile, taxes_lines)
|
||
|
|
||
|
# == Check the reconciliation after the reverse ==
|
||
|
|
||
|
tax_cash_basis_move_reverse = tax_cash_basis_move._reverse_moves(cancel=True)
|
||
|
|
||
|
self.assertFullReconcile(receivable_lines.full_reconcile_id, receivable_lines)
|
||
|
|
||
|
# == Check the reconciliation of the tax cash basis journal entry with its reverse ==
|
||
|
|
||
|
reversed_taxes_lines = (tax_cash_basis_move + tax_cash_basis_move_reverse).line_ids\
|
||
|
.filtered(lambda line: line.account_id == self.cash_basis_transfer_account)
|
||
|
|
||
|
reversed_taxes_full_reconcile = reversed_taxes_lines.matched_debit_ids.full_reconcile_id
|
||
|
|
||
|
self.assertTrue(reversed_taxes_full_reconcile)
|
||
|
self.assertFullReconcile(reversed_taxes_full_reconcile, reversed_taxes_lines)
|
||
|
|
||
|
def test_reconcile_cash_basis_tax_grid_refund(self):
|
||
|
self.env.company.tax_exigibility = True
|
||
|
invoice_move = self.env['account.move'].create({
|
||
|
'move_type': 'entry',
|
||
|
'date': '2016-01-01',
|
||
|
'line_ids': [
|
||
|
# Base Tax line
|
||
|
(0, 0, {
|
||
|
'debit': 0.0,
|
||
|
'credit': 100.0,
|
||
|
'account_id': self.company_data['default_account_revenue'].id,
|
||
|
'tax_ids': [(6, 0, self.cash_basis_tax_a_third_amount.ids)],
|
||
|
}),
|
||
|
|
||
|
# Tax line
|
||
|
(0, 0, {
|
||
|
'debit': 0.0,
|
||
|
'credit': 33.33,
|
||
|
'account_id': self.cash_basis_transfer_account.id,
|
||
|
'tax_repartition_line_id': self.cash_basis_tax_a_third_amount.invoice_repartition_line_ids.filtered(lambda line: line.repartition_type == 'tax').id,
|
||
|
}),
|
||
|
|
||
|
# Receivable line
|
||
|
(0, 0, {
|
||
|
'debit': 133.33,
|
||
|
'credit': 0.0,
|
||
|
'account_id': self.extra_receivable_account_1.id,
|
||
|
}),
|
||
|
]
|
||
|
})
|
||
|
|
||
|
refund_move = self.env['account.move'].create({
|
||
|
'move_type': 'out_refund',
|
||
|
'partner_id': self.partner_a.id,
|
||
|
'invoice_date': '2016-01-01',
|
||
|
'date': '2016-01-01',
|
||
|
'line_ids': [
|
||
|
Command.create({
|
||
|
'price_unit': 100.0,
|
||
|
'account_id': self.company_data['default_account_revenue'].id,
|
||
|
'tax_ids': [(6, 0, self.cash_basis_tax_a_third_amount.ids)],
|
||
|
}),
|
||
|
]
|
||
|
})
|
||
|
refund_move.line_ids.filtered(lambda l: l.display_type == 'payment_term').account_id = self.extra_receivable_account_1
|
||
|
|
||
|
(invoice_move + refund_move).action_post()
|
||
|
|
||
|
receivable_lines = (invoice_move + refund_move).line_ids\
|
||
|
.filtered(lambda line: line.account_id == self.extra_receivable_account_1)
|
||
|
receivable_lines.reconcile()
|
||
|
tax_cash_basis_moves = self._get_caba_moves(receivable_lines.move_id)
|
||
|
|
||
|
self.assertFullReconcile(receivable_lines.full_reconcile_id, receivable_lines)
|
||
|
self.assertEqual(len(tax_cash_basis_moves), 2)
|
||
|
|
||
|
tax_cash_basis_moves = tax_cash_basis_moves.sorted(lambda move: move.tax_cash_basis_origin_move_id.id)
|
||
|
|
||
|
# Invoice:
|
||
|
cb_lines = tax_cash_basis_moves[0].line_ids.sorted(lambda line: (-abs(line.balance), -line.debit, line.account_id))
|
||
|
self.assertRecordValues(cb_lines, [
|
||
|
# Base amount:
|
||
|
{'debit': 100.0, 'credit': 0.0, 'tax_tag_ids': [], 'account_id': self.cash_basis_base_account.id},
|
||
|
{'debit': 0.0, 'credit': 100.0, 'tax_tag_ids': self.tax_tags[0].ids, 'account_id': self.cash_basis_base_account.id},
|
||
|
# tax:
|
||
|
{'debit': 33.33, 'credit': 0.0, 'tax_tag_ids': [], 'account_id': self.cash_basis_transfer_account.id},
|
||
|
{'debit': 0.0, 'credit': 33.33, 'tax_tag_ids': self.tax_tags[1].ids, 'account_id': self.tax_account_1.id},
|
||
|
])
|
||
|
|
||
|
# Refund:
|
||
|
cb_lines = tax_cash_basis_moves[1].line_ids.sorted(lambda line: (-abs(line.balance), -line.debit, line.account_id))
|
||
|
self.assertRecordValues(cb_lines, [
|
||
|
# Base amount:
|
||
|
{'debit': 100.0, 'credit': 0.0, 'tax_tag_ids': self.tax_tags[2].ids, 'account_id': self.cash_basis_base_account.id},
|
||
|
{'debit': 0.0, 'credit': 100.0, 'tax_tag_ids': [], 'account_id': self.cash_basis_base_account.id},
|
||
|
# tax:
|
||
|
{'debit': 33.33, 'credit': 0.0, 'tax_tag_ids': self.tax_tags[3].ids, 'account_id': self.tax_account_1.id},
|
||
|
{'debit': 0.0, 'credit': 33.33, 'tax_tag_ids': [], 'account_id': self.cash_basis_transfer_account.id},
|
||
|
])
|
||
|
|
||
|
def test_reconcile_cash_basis_tax_grid_reversal(self):
|
||
|
invoice = self.env['account.move'].create({
|
||
|
'move_type': 'out_invoice',
|
||
|
'partner_id': self.partner_a.id,
|
||
|
'date': '2016-01-01',
|
||
|
'invoice_line_ids': [(0, 0, {
|
||
|
'product_id': self.product_a.id,
|
||
|
'price_unit': 1000.0,
|
||
|
'tax_ids': [(6, 0, self.cash_basis_tax_a_third_amount.ids)],
|
||
|
})],
|
||
|
})
|
||
|
invoice.action_post()
|
||
|
|
||
|
self.assertRecordValues(invoice.line_ids.sorted('balance'), [
|
||
|
{'debit': 0.0, 'credit': 1000.0, 'tax_tag_ids': [], 'account_id': self.company_data['default_account_revenue'].id},
|
||
|
{'debit': 0.0, 'credit': 333.33, 'tax_tag_ids': [], 'account_id': self.cash_basis_transfer_account.id},
|
||
|
{'debit': 1333.33, 'credit': 0.0, 'tax_tag_ids': [], 'account_id': self.company_data['default_account_receivable'].id},
|
||
|
])
|
||
|
|
||
|
reversal_wizard = self.env['account.move.reversal']\
|
||
|
.with_context(active_model='account.move', active_ids=invoice.ids)\
|
||
|
.create({
|
||
|
'reason': "test_reconcile_cash_basis_tax_grid_reversal",
|
||
|
'journal_id': invoice.journal_id.id,
|
||
|
})
|
||
|
refund = self.env['account.move'].browse(reversal_wizard.refund_moves()['res_id'])
|
||
|
refund.action_post()
|
||
|
|
||
|
self.assertRecordValues(refund.line_ids.sorted('balance'), [
|
||
|
{'debit': 0.0, 'credit': 1333.33, 'tax_tag_ids': [], 'account_id': self.company_data['default_account_receivable'].id},
|
||
|
{'debit': 333.33, 'credit': 0.0, 'tax_tag_ids': [], 'account_id': self.cash_basis_transfer_account.id},
|
||
|
{'debit': 1000.0, 'credit': 0.0, 'tax_tag_ids': [], 'account_id': self.company_data['default_account_revenue'].id},
|
||
|
])
|
||
|
|
||
|
reversal_wizard = self.env['account.move.reversal']\
|
||
|
.with_context(active_model='account.move', active_ids=refund.ids)\
|
||
|
.create({
|
||
|
'reason': "test_reconcile_cash_basis_tax_grid_reversal",
|
||
|
'journal_id': refund.journal_id.id,
|
||
|
})
|
||
|
reversed_refund = self.env['account.move'].browse(reversal_wizard.refund_moves()['res_id'])
|
||
|
|
||
|
self.assertRecordValues(reversed_refund.line_ids.sorted('balance'), [
|
||
|
{'debit': 0.0, 'credit': 1000.0, 'tax_tag_ids': [], 'account_id': self.company_data['default_account_revenue'].id},
|
||
|
{'debit': 0.0, 'credit': 333.33, 'tax_tag_ids': [], 'account_id': self.cash_basis_transfer_account.id},
|
||
|
{'debit': 1333.33, 'credit': 0.0, 'tax_tag_ids': [], 'account_id': self.company_data['default_account_receivable'].id},
|
||
|
])
|
||
|
|
||
|
def test_reconcile_cash_basis_tax_grid_multi_taxes(self):
|
||
|
''' Test the tax grid when reconciling an invoice with multiple taxes/tax repartition. '''
|
||
|
self.env.company.tax_exigibility = True
|
||
|
base_taxes = self.cash_basis_tax_a_third_amount + self.cash_basis_tax_tiny_amount
|
||
|
base_tags = self.tax_tags[0] + self.tax_tags[4]
|
||
|
|
||
|
# An invoice with 2 taxes:
|
||
|
invoice_move = self.env['account.move'].with_context(skip_invoice_sync=True).create({
|
||
|
'move_type': 'entry',
|
||
|
'date': '2016-01-01',
|
||
|
'line_ids': [
|
||
|
# Base Tax line
|
||
|
(0, 0, {
|
||
|
'debit': 0.0,
|
||
|
'credit': 100.0,
|
||
|
'account_id': self.company_data['default_account_revenue'].id,
|
||
|
'tax_ids': [(6, 0, base_taxes.ids)],
|
||
|
}),
|
||
|
|
||
|
# Tax lines
|
||
|
(0, 0, {
|
||
|
'debit': 0.0,
|
||
|
'credit': 33.33,
|
||
|
'account_id': self.cash_basis_transfer_account.id,
|
||
|
'tax_repartition_line_id': self.cash_basis_tax_a_third_amount.invoice_repartition_line_ids.filtered(lambda line: line.repartition_type == 'tax').id,
|
||
|
}),
|
||
|
(0, 0, {
|
||
|
'debit': 0.0,
|
||
|
'credit': 0.01,
|
||
|
'account_id': self.cash_basis_transfer_account.id,
|
||
|
'tax_repartition_line_id': self.cash_basis_tax_tiny_amount.invoice_repartition_line_ids.filtered(lambda line: line.repartition_type == 'tax').id,
|
||
|
}),
|
||
|
|
||
|
# Receivable lines
|
||
|
(0, 0, {
|
||
|
'debit': 133.34,
|
||
|
'credit': 0.0,
|
||
|
'account_id': self.extra_receivable_account_1.id,
|
||
|
}),
|
||
|
]
|
||
|
})
|
||
|
|
||
|
# A payment paying the full invoice amount.
|
||
|
payment_move = self.env['account.move'].create({
|
||
|
'move_type': 'entry',
|
||
|
'date': '2017-01-01',
|
||
|
'line_ids': [
|
||
|
(0, 0, {'debit': 0.0, 'credit': 133.34, 'account_id': self.extra_receivable_account_1.id}),
|
||
|
(0, 0, {'debit': 133.34, 'credit': 0.0, 'account_id': self.company_data['default_account_revenue'].id}),
|
||
|
]
|
||
|
})
|
||
|
|
||
|
(invoice_move + payment_move).action_post()
|
||
|
|
||
|
receivable_lines = (invoice_move + payment_move).line_ids\
|
||
|
.filtered(lambda line: line.account_id == self.extra_receivable_account_1)
|
||
|
receivable_lines.reconcile()
|
||
|
tax_cash_basis_moves = self._get_caba_moves(receivable_lines.move_id)
|
||
|
|
||
|
self.assertFullReconcile(receivable_lines.full_reconcile_id, receivable_lines)
|
||
|
self.assertEqual(len(tax_cash_basis_moves), 1)
|
||
|
|
||
|
self.assertRecordValues(tax_cash_basis_moves.line_ids, [
|
||
|
# Base amount x 2 because there is two taxes:
|
||
|
{'debit': 100.0, 'credit': 0.0, 'tax_ids': [], 'tax_tag_ids': [], 'account_id': self.cash_basis_base_account.id},
|
||
|
{'debit': 0.0, 'credit': 100.0, 'tax_ids': base_taxes.ids, 'tax_tag_ids': base_tags.ids, 'account_id': self.cash_basis_base_account.id},
|
||
|
# tax_1:
|
||
|
{'debit': 33.33, 'credit': 0.0, 'tax_ids': [], 'tax_tag_ids': [], 'account_id': self.cash_basis_transfer_account.id},
|
||
|
{'debit': 0.0, 'credit': 33.33, 'tax_ids': [], 'tax_tag_ids': self.tax_tags[1].ids, 'account_id': self.tax_account_1.id},
|
||
|
# tax_2:
|
||
|
{'debit': 0.01, 'credit': 0.0, 'tax_ids': [], 'tax_tag_ids': [], 'account_id': self.cash_basis_transfer_account.id},
|
||
|
{'debit': 0.0, 'credit': 0.01, 'tax_ids': [], 'tax_tag_ids': self.tax_tags[5].ids, 'account_id': self.tax_account_2.id},
|
||
|
])
|
||
|
|
||
|
def test_matching_number_full_reconcile(self):
|
||
|
currency = self.env.company.currency_id
|
||
|
line_a = self.create_line_for_reconciliation(1000, 1000, currency, '2016-01-01')
|
||
|
line_b = self.create_line_for_reconciliation(-1000, -1000, currency, '2016-01-01')
|
||
|
(line_a + line_b).reconcile()
|
||
|
self.assertFullReconcile(line_a.full_reconcile_id, (line_a + line_b))
|
||
|
self.assertEqual(line_a.matching_number, str(line_a.full_reconcile_id.id))
|
||
|
self.assertEqual(line_a.matching_number, line_b.matching_number)
|
||
|
|
||
|
def test_matching_number_partial_single_reconcile(self):
|
||
|
currency = self.env.company.currency_id
|
||
|
line_a = self.create_line_for_reconciliation(1000, 1000, currency, '2016-01-01')
|
||
|
line_b = self.create_line_for_reconciliation(-500, -500, currency, '2016-01-01')
|
||
|
(line_a + line_b).reconcile()
|
||
|
self.assertEqual(line_a.matching_number, f'P{line_a.matched_credit_ids.id}')
|
||
|
self.assertEqual(line_a.matching_number, line_b.matching_number)
|
||
|
|
||
|
def test_matching_number_partial_multi_reconcile(self):
|
||
|
currency = self.env.company.currency_id
|
||
|
line_a = self.create_line_for_reconciliation(1000, 1000, currency, '2016-01-01')
|
||
|
line_b = self.create_line_for_reconciliation(-500, -500, currency, '2016-01-01')
|
||
|
line_c = self.create_line_for_reconciliation(-1000, -1000, currency, '2016-01-01')
|
||
|
line_d = self.create_line_for_reconciliation(1000, 1000, currency, '2016-01-01')
|
||
|
(line_a + line_b).reconcile()
|
||
|
(line_a + line_c).reconcile()
|
||
|
(line_c + line_d).reconcile()
|
||
|
self.assertEqual(line_a.matching_number, f'P{line_a.matched_credit_ids.ids[0]}')
|
||
|
self.assertEqual(line_b.matching_number, line_a.matching_number)
|
||
|
self.assertEqual(line_c.matching_number, line_a.matching_number)
|
||
|
self.assertEqual(line_d.matching_number, line_a.matching_number)
|
||
|
|
||
|
line_b.remove_move_reconcile()
|
||
|
self.assertEqual(line_a.matching_number, f'P{line_a.matched_credit_ids.ids[0]}')
|
||
|
self.assertEqual(line_b.matching_number, False)
|
||
|
self.assertEqual(line_c.matching_number, f'P{line_c.matched_debit_ids.ids[0]}')
|
||
|
self.assertEqual(line_d.matching_number, line_c.matching_number)
|
||
|
|
||
|
(line_a + line_b).reconcile() # everything should be matched again
|
||
|
self.assertEqual(line_a.matching_number, line_c.matching_number)
|
||
|
self.assertEqual(line_b.matching_number, line_c.matching_number)
|
||
|
self.assertEqual(line_c.matching_number, f'P{line_c.matched_debit_ids.ids[0]}')
|
||
|
self.assertEqual(line_d.matching_number, line_c.matching_number)
|
||
|
|
||
|
def test_matching_number_partial_multi_separate_reconcile(self):
|
||
|
currency = self.env.company.currency_id
|
||
|
line_a = self.create_line_for_reconciliation(1000, 1000, currency, '2016-01-01')
|
||
|
line_b = self.create_line_for_reconciliation(-500, -500, currency, '2016-01-01')
|
||
|
(line_a + line_b).reconcile()
|
||
|
self.assertEqual(line_a.matching_number, f'P{line_a.matched_credit_ids.id}')
|
||
|
self.assertEqual(line_a.matching_number, line_b.matching_number)
|
||
|
|
||
|
line_c = self.create_line_for_reconciliation(-300, -300, currency, '2016-01-01')
|
||
|
(line_a + line_c).reconcile()
|
||
|
self.assertEqual(line_a.matching_number, f'P{line_a.matched_credit_ids.ids[0]}')
|
||
|
self.assertEqual(line_a.matching_number, line_b.matching_number)
|
||
|
self.assertEqual(line_a.matching_number, line_c.matching_number)
|
||
|
|
||
|
def test_matching_number_unreconcile_single(self):
|
||
|
currency = self.env.company.currency_id
|
||
|
full_line_a = self.create_line_for_reconciliation(200, 200, currency, '2016-01-01')
|
||
|
full_line_b = self.create_line_for_reconciliation(-200, -200, currency, '2016-01-01')
|
||
|
partial_line_a = self.create_line_for_reconciliation(1000, 1000, currency, '2016-01-01')
|
||
|
partial_line_b = self.create_line_for_reconciliation(-500, -500, currency, '2016-01-01')
|
||
|
(full_line_a + full_line_b).reconcile()
|
||
|
(partial_line_a + partial_line_b).reconcile()
|
||
|
(full_line_a + full_line_b + partial_line_a + partial_line_b).remove_move_reconcile()
|
||
|
self.assertFalse(full_line_a.matching_number)
|
||
|
self.assertFalse(full_line_b.matching_number)
|
||
|
self.assertFalse(partial_line_a.matching_number)
|
||
|
self.assertFalse(partial_line_b.matching_number)
|
||
|
|
||
|
def test_matching_number_unreconcile_multi(self):
|
||
|
currency = self.env.company.currency_id
|
||
|
line_a = self.create_line_for_reconciliation(-500, -500, currency, '2016-01-01')
|
||
|
line_b = self.create_line_for_reconciliation(1000, 1000, currency, '2016-01-01')
|
||
|
line_c = self.create_line_for_reconciliation(-1000, -1000, currency, '2016-01-01')
|
||
|
line_d = self.create_line_for_reconciliation(300, 300, currency, '2016-01-01')
|
||
|
(line_a + line_b).reconcile()
|
||
|
(line_b + line_c).reconcile()
|
||
|
(line_c + line_d).reconcile()
|
||
|
|
||
|
previous_matching_number = line_a.matching_number
|
||
|
line_a.remove_move_reconcile()
|
||
|
self.assertFalse(line_a.matching_number)
|
||
|
self.assertNotEqual(previous_matching_number, line_b.matching_number)
|
||
|
self.assertEqual(line_b.matching_number, line_c.matching_number)
|
||
|
self.assertEqual(line_b.matching_number, line_d.matching_number)
|
||
|
|
||
|
previous_matching_number = line_b.matching_number
|
||
|
line_b.remove_move_reconcile()
|
||
|
self.assertFalse(line_b.matching_number)
|
||
|
self.assertNotEqual(previous_matching_number, line_c.matching_number)
|
||
|
self.assertEqual(line_c.matching_number, line_d.matching_number)
|
||
|
|
||
|
line_c.remove_move_reconcile()
|
||
|
self.assertFalse(line_c.matching_number)
|
||
|
self.assertFalse(line_d.matching_number)
|
||
|
|
||
|
def test_matching_loop(self):
|
||
|
currency = self.env.company.currency_id
|
||
|
wrong_credit = self.create_line_for_reconciliation(-500, -500, currency, '2016-01-01')
|
||
|
debit_a = self.create_line_for_reconciliation(1000, 1000, currency, '2016-01-01')
|
||
|
credit_a = self.create_line_for_reconciliation(-1000, -1000, currency, '2016-01-01')
|
||
|
debit_b = self.create_line_for_reconciliation(1000, 1000, currency, '2016-01-01')
|
||
|
credit_b = self.create_line_for_reconciliation(-1000, -1000, currency, '2016-01-01')
|
||
|
(wrong_credit + debit_a).reconcile()
|
||
|
(debit_a + credit_a).reconcile()
|
||
|
wrong_credit.remove_move_reconcile() # now there is an open amount on both the payment and the invoice
|
||
|
(credit_a + debit_b).reconcile()
|
||
|
(debit_b + credit_b).reconcile()
|
||
|
# Everything is reconciled but some amounts are still open
|
||
|
self.assertEqual(len(set((debit_a + debit_b + credit_a + credit_b).mapped('matching_number'))), 1)
|
||
|
self.assertFalse(all(aml.amount_residual == 0 for aml in (debit_a, debit_b, credit_a, credit_b)))
|
||
|
|
||
|
# Now this should create a loop, it should still work, and the residual amounts should now reach 0
|
||
|
(credit_b + debit_a).reconcile()
|
||
|
self.assertTrue(all(aml.amount_residual == 0 for aml in (debit_a, debit_b, credit_a, credit_b)))
|
||
|
|
||
|
def test_caba_mix_reconciliation(self):
|
||
|
""" Test the reconciliation of tax lines (when using a reconcilable tax account)
|
||
|
for cases mixing taxes exigible on payment and on invoices.
|
||
|
"""
|
||
|
|
||
|
# Make the tax account reconcilable
|
||
|
self.tax_account_1.reconcile = True
|
||
|
self.env.company.tax_exigibility = True
|
||
|
|
||
|
# Create a tax using the same accounts as the CABA one
|
||
|
non_caba_tax = self.env['account.tax'].create({
|
||
|
'name': 'tax 20%',
|
||
|
'type_tax_use': 'purchase',
|
||
|
'company_id': self.company_data['company'].id,
|
||
|
'amount': 20,
|
||
|
'tax_exigibility': 'on_invoice',
|
||
|
'invoice_repartition_line_ids': [
|
||
|
(0,0, {'repartition_type': 'base'}),
|
||
|
|
||
|
(0,0, {
|
||
|
'repartition_type': 'tax',
|
||
|
'account_id': self.tax_account_1.id,
|
||
|
}),
|
||
|
],
|
||
|
'refund_repartition_line_ids': [
|
||
|
(0,0, {'repartition_type': 'base'}),
|
||
|
|
||
|
(0,0, {
|
||
|
'repartition_type': 'tax',
|
||
|
'account_id': self.tax_account_1.id,
|
||
|
}),
|
||
|
],
|
||
|
})
|
||
|
|
||
|
# Create an invoice with a non-CABA tax
|
||
|
non_caba_inv = self.init_invoice('in_invoice', amounts=[1000], post=True, taxes=non_caba_tax)
|
||
|
|
||
|
# Create an invoice with a CABA tax using the same tax account and pay it
|
||
|
caba_inv = self.init_invoice('in_invoice', amounts=[300], post=True, taxes=self.cash_basis_tax_a_third_amount)
|
||
|
|
||
|
pmt_wizard = self.env['account.payment.register'].with_context(active_model='account.move', active_ids=caba_inv.ids).create({
|
||
|
'payment_date': caba_inv.date,
|
||
|
'journal_id': self.company_data['default_journal_bank'].id,
|
||
|
'payment_method_line_id': self.inbound_payment_method_line.id,
|
||
|
})
|
||
|
pmt_wizard._create_payments()
|
||
|
|
||
|
partial_rec = caba_inv.mapped('line_ids.matched_debit_ids')
|
||
|
caba_move = self.env['account.move'].search([('tax_cash_basis_rec_id', 'in', partial_rec.ids)])
|
||
|
|
||
|
# Create a misc operation with a line on the tax account, for full reconcile of those tax lines
|
||
|
misc_move = self.env['account.move'].create({
|
||
|
'name': "Misc move",
|
||
|
'journal_id': self.company_data['default_journal_misc'].id,
|
||
|
'line_ids': [
|
||
|
(0, 0, {
|
||
|
'name': 'line 1',
|
||
|
'account_id': self.tax_account_1.id,
|
||
|
'credit': 300,
|
||
|
}),
|
||
|
(0, 0, {
|
||
|
'name': 'line 2',
|
||
|
'account_id': self.company_data['default_account_expense'].id, # Whatever the account here
|
||
|
'debit': 300,
|
||
|
})
|
||
|
],
|
||
|
})
|
||
|
|
||
|
misc_move.action_post()
|
||
|
|
||
|
lines_to_reconcile = (misc_move + caba_move + non_caba_inv).mapped('line_ids').filtered(lambda x: x.account_id == self.tax_account_1)
|
||
|
lines_to_reconcile.reconcile()
|
||
|
|
||
|
# Check full reconciliation
|
||
|
self.assertTrue(all(line.full_reconcile_id for line in lines_to_reconcile), "All tax lines should be fully reconciled")
|
||
|
|
||
|
def test_caba_double_tax(self):
|
||
|
""" Test the CABA entries generated from an invoice with almost
|
||
|
equal lines, different only on analytic accounting
|
||
|
"""
|
||
|
# Required for `analytic_account_id` to be visible in the view
|
||
|
self.env.user.groups_id += self.env.ref('analytic.group_analytic_accounting')
|
||
|
# Make the tax account reconcilable
|
||
|
self.tax_account_1.reconcile = True
|
||
|
self.env.company.tax_exigibility = True
|
||
|
|
||
|
# Create an invoice with a CABA tax using 'Include in analytic cost'
|
||
|
move_form = Form(self.env['account.move'].with_context(default_move_type='in_invoice'))
|
||
|
move_form.invoice_date = fields.Date.from_string('2019-01-01')
|
||
|
move_form.partner_id = self.partner_a
|
||
|
self.cash_basis_tax_a_third_amount.analytic = True
|
||
|
analytic_plan = self.env['account.analytic.plan'].create({'name': 'Plan Test'})
|
||
|
test_analytic_account = self.env['account.analytic.account'].create({'name': 'test_analytic_account', 'plan_id': analytic_plan.id})
|
||
|
|
||
|
tax = self.cash_basis_tax_a_third_amount
|
||
|
|
||
|
# line with analytic account, will generate 2 lines in CABA move
|
||
|
with move_form.invoice_line_ids.new() as line_form:
|
||
|
line_form.name = "test line with analytic account"
|
||
|
line_form.product_id = self.product_a
|
||
|
line_form.tax_ids.clear()
|
||
|
line_form.tax_ids.add(tax)
|
||
|
line_form.analytic_distribution = {test_analytic_account.id: 100}
|
||
|
line_form.price_unit = 100
|
||
|
|
||
|
# line with analytic account, will generate other 2 lines in CABA move
|
||
|
# even if the tax is the same
|
||
|
with move_form.invoice_line_ids.new() as line_form:
|
||
|
line_form.name = "test line"
|
||
|
line_form.product_id = self.product_a
|
||
|
line_form.tax_ids.clear()
|
||
|
line_form.tax_ids.add(tax)
|
||
|
line_form.price_unit = 100
|
||
|
|
||
|
rslt = move_form.save()
|
||
|
rslt.action_post()
|
||
|
|
||
|
pmt_wizard = self.env['account.payment.register'].with_context(active_model='account.move', active_ids=rslt.ids).create({
|
||
|
'amount': rslt.amount_total,
|
||
|
'payment_date': rslt.date,
|
||
|
'journal_id': self.company_data['default_journal_bank'].id,
|
||
|
'payment_method_line_id': self.inbound_payment_method_line.id,
|
||
|
})
|
||
|
pmt_wizard._create_payments()
|
||
|
|
||
|
partial_rec = rslt.mapped('line_ids.matched_debit_ids')
|
||
|
caba_move = self.env['account.move'].search([('tax_cash_basis_rec_id', 'in', partial_rec.ids)])
|
||
|
self.assertEqual(len(caba_move.line_ids), 4, "All lines should be there")
|
||
|
self.assertEqual(caba_move.line_ids.filtered(lambda x: x.tax_line_id).balance, 66.66, "Tax amount should take into account both lines")
|
||
|
|
||
|
def test_caba_double_tax_negative_line(self):
|
||
|
""" Tests making a cash basis invoice with 2 lines using the same tax: a positive and a negative one.
|
||
|
"""
|
||
|
self.env.company.tax_exigibility = True
|
||
|
invoice = self.init_invoice('in_invoice', amounts=[300, -60], post=True, taxes=self.cash_basis_tax_a_third_amount)
|
||
|
|
||
|
pmt_wizard = self.env['account.payment.register'].with_context(active_model='account.move', active_ids=invoice.ids).create({
|
||
|
'amount': 320,
|
||
|
'payment_date': invoice.date,
|
||
|
'journal_id': self.company_data['default_journal_bank'].id,
|
||
|
'payment_method_line_id': self.inbound_payment_method_line.id,
|
||
|
})
|
||
|
|
||
|
pmt_wizard._create_payments()
|
||
|
|
||
|
partial_rec = invoice.mapped('line_ids.matched_debit_ids')
|
||
|
caba_move = self.env['account.move'].search([('tax_cash_basis_rec_id', 'in', partial_rec.ids)])
|
||
|
|
||
|
self.assertRecordValues(caba_move.line_ids.sorted(lambda line: (-abs(line.balance), -line.debit, line.account_id)), [
|
||
|
# Base amount:
|
||
|
{'debit': 240.0, 'credit': 0.0, 'tax_tag_ids': self.tax_tags[0].ids, 'account_id': self.cash_basis_base_account.id},
|
||
|
{'debit': 0.0, 'credit': 240.0, 'tax_tag_ids': [], 'account_id': self.cash_basis_base_account.id},
|
||
|
# tax:
|
||
|
{'debit': 80.0, 'credit': 0.0, 'tax_tag_ids': self.tax_tags[1].ids, 'account_id': self.tax_account_1.id},
|
||
|
{'debit': 0.0, 'credit': 80.0, 'tax_tag_ids': [], 'account_id': self.cash_basis_transfer_account.id},
|
||
|
])
|
||
|
|
||
|
def test_caba_dest_acc_reconciliation_partial_pmt(self):
|
||
|
""" Test the reconciliation of tax lines (when using a reconcilable tax account)
|
||
|
for partially paid invoices with cash basis taxes.
|
||
|
This test is especially useful to check the implementation of the use case tested by
|
||
|
test_reconciliation_cash_basis_foreign_currency_low_values does not have unwanted side effects.
|
||
|
"""
|
||
|
|
||
|
# Make the tax account reconcilable
|
||
|
self.tax_account_1.reconcile = True
|
||
|
self.env.company.tax_exigibility = True
|
||
|
|
||
|
# Create an invoice with a CABA tax using the same tax account and pay half of it
|
||
|
caba_inv = self.init_invoice('in_invoice', amounts=[900], post=True, taxes=self.cash_basis_tax_a_third_amount)
|
||
|
|
||
|
pmt_wizard = self.env['account.payment.register'].with_context(active_model='account.move', active_ids=caba_inv.ids).create({
|
||
|
'amount': 600,
|
||
|
'payment_date': caba_inv.date,
|
||
|
'journal_id': self.company_data['default_journal_bank'].id,
|
||
|
'payment_method_line_id': self.inbound_payment_method_line.id,
|
||
|
})
|
||
|
pmt_wizard._create_payments()
|
||
|
|
||
|
partial_rec = caba_inv.mapped('line_ids.matched_debit_ids')
|
||
|
caba_move = self.env['account.move'].search([('tax_cash_basis_rec_id', 'in', partial_rec.ids)])
|
||
|
|
||
|
# Create a misc operation with a line on the tax account, for full reconcile with the tax line
|
||
|
misc_move = self.env['account.move'].create({
|
||
|
'name': "Misc move",
|
||
|
'journal_id': self.company_data['default_journal_misc'].id,
|
||
|
'line_ids': [
|
||
|
(0, 0, {
|
||
|
'name': 'line 1',
|
||
|
'account_id': self.tax_account_1.id,
|
||
|
'credit': 150,
|
||
|
}),
|
||
|
(0, 0, {
|
||
|
'name': 'line 2',
|
||
|
'account_id': self.company_data['default_account_expense'].id, # Whatever the account here
|
||
|
'debit': 150,
|
||
|
})
|
||
|
],
|
||
|
})
|
||
|
|
||
|
misc_move.action_post()
|
||
|
|
||
|
lines_to_reconcile = (misc_move + caba_move).mapped('line_ids').filtered(lambda x: x.account_id == self.tax_account_1)
|
||
|
lines_to_reconcile.reconcile()
|
||
|
|
||
|
# Check full reconciliation
|
||
|
self.assertTrue(all(line.full_reconcile_id for line in lines_to_reconcile), "All tax lines should be fully reconciled")
|
||
|
|
||
|
def test_caba_undo_reconciliation(self):
|
||
|
''' Make sure there is no traceback like "Record has already been deleted" during the deletion of partials. '''
|
||
|
self.cash_basis_transfer_account.reconcile = True
|
||
|
|
||
|
bill = self.env['account.move'].create({
|
||
|
'move_type': 'in_invoice',
|
||
|
'partner_id': self.partner_a.id,
|
||
|
'invoice_date': '2019-01-01',
|
||
|
'date': '2019-01-01',
|
||
|
'invoice_line_ids': [(0, 0, {
|
||
|
'name': 'line',
|
||
|
'account_id': self.company_data['default_account_expense'].id,
|
||
|
'price_unit': 1000.0,
|
||
|
'tax_ids': [(6, 0, self.cash_basis_tax_a_third_amount.ids)],
|
||
|
})],
|
||
|
})
|
||
|
bill.action_post()
|
||
|
|
||
|
# Register a payment creating the CABA journal entry on the fly and reconcile it with the tax line.
|
||
|
self.env['account.payment.register']\
|
||
|
.with_context(active_ids=bill.ids, active_model='account.move')\
|
||
|
.create({})\
|
||
|
._create_payments()
|
||
|
|
||
|
bill.button_draft()
|
||
|
|
||
|
def test_caba_foreign_vat(self):
|
||
|
self.env.company.tax_exigibility = True
|
||
|
|
||
|
test_country = self.env['res.country'].create({
|
||
|
'name': "Bretonnia",
|
||
|
'code': 'wh',
|
||
|
})
|
||
|
|
||
|
foreign_vat_fpos = self.env['account.fiscal.position'].create({
|
||
|
'name': "Fiscal Position to the Holy Grail",
|
||
|
'country_id': test_country.id,
|
||
|
'foreign_vat': 'WH1234',
|
||
|
})
|
||
|
|
||
|
self.env['account.tax.group'].create({
|
||
|
'name': 'tax_group',
|
||
|
'country_id': test_country.id,
|
||
|
})
|
||
|
|
||
|
foreign_caba_tax = self.env['account.tax'].create({
|
||
|
'name': 'foreign tax_1',
|
||
|
'amount': 33.3333,
|
||
|
'company_id': self.company_data['company'].id,
|
||
|
'cash_basis_transition_account_id': self.cash_basis_transfer_account.id,
|
||
|
'tax_exigibility': 'on_payment',
|
||
|
'country_id': test_country.id,
|
||
|
'invoice_repartition_line_ids': [
|
||
|
(0, 0, {'repartition_type': 'base'}),
|
||
|
|
||
|
(0, 0, {'repartition_type': 'tax'}),
|
||
|
],
|
||
|
'refund_repartition_line_ids': [
|
||
|
(0, 0, {'repartition_type': 'base'}),
|
||
|
|
||
|
(0, 0, {'repartition_type': 'tax'}),
|
||
|
],
|
||
|
})
|
||
|
|
||
|
invoice = self.env['account.move'].create({
|
||
|
'move_type': 'out_invoice',
|
||
|
'partner_id': self.partner_a.id,
|
||
|
'invoice_date': '2021-07-01',
|
||
|
'fiscal_position_id': foreign_vat_fpos.id,
|
||
|
'invoice_line_ids': [
|
||
|
Command.create({
|
||
|
'name': "test",
|
||
|
'price_unit': 100,
|
||
|
'tax_ids': [Command.set(foreign_caba_tax.ids)],
|
||
|
}),
|
||
|
]
|
||
|
})
|
||
|
invoice.action_post()
|
||
|
|
||
|
self.env['account.payment.register'].with_context(active_ids=invoice.ids, active_model='account.move').create({
|
||
|
'payment_date': invoice.date,
|
||
|
})._create_payments()
|
||
|
|
||
|
caba_move = self.env['account.move'].search([('tax_cash_basis_origin_move_id', '=', invoice.id)])
|
||
|
|
||
|
self.assertEqual(caba_move.fiscal_position_id, foreign_vat_fpos, "The foreign VAT fiscal position should be kept in the cash basis move.")
|
||
|
|
||
|
def test_caba_tax_group(self):
|
||
|
""" Test the CABA entries generated from an invoice with
|
||
|
a tax group
|
||
|
"""
|
||
|
self.env.company.tax_exigibility = True
|
||
|
|
||
|
# Make the tax account reconcilable
|
||
|
self.tax_account_1.reconcile = True
|
||
|
|
||
|
# Create an invoice with a CABA tax using 'Include in analytic cost'
|
||
|
move_form = Form(self.env['account.move'].with_context(default_move_type='in_invoice'))
|
||
|
move_form.invoice_date = fields.Date.from_string('2019-01-01')
|
||
|
move_form.partner_id = self.partner_a
|
||
|
|
||
|
tax_a = self.cash_basis_tax_a_third_amount
|
||
|
tax_b = self.cash_basis_tax_tiny_amount
|
||
|
|
||
|
tax_group = self.env['account.tax'].create({
|
||
|
'name': 'tax group',
|
||
|
'amount_type': 'group',
|
||
|
'company_id': self.company_data['company'].id,
|
||
|
'children_tax_ids': [Command.set([tax_a.id, tax_b.id])],
|
||
|
})
|
||
|
|
||
|
# line with analytic account, will generate 2 lines in CABA move
|
||
|
invoice = self.env['account.move'].with_context(skip_invoice_sync=True).create({
|
||
|
'partner_id': self.partner_a.id,
|
||
|
'invoice_date': fields.Date.from_string('2019-01-01'),
|
||
|
'move_type': 'entry',
|
||
|
'line_ids': [
|
||
|
# Base Tax line
|
||
|
Command.create({
|
||
|
'debit': 0.0,
|
||
|
'credit': 3000.0,
|
||
|
'account_id': self.company_data['default_account_revenue'].id,
|
||
|
'tax_ids': [Command.set(tax_group.ids)],
|
||
|
}),
|
||
|
|
||
|
# Tax line A
|
||
|
Command.create({
|
||
|
'debit': 0.0,
|
||
|
'credit': 1000.0,
|
||
|
'account_id': self.cash_basis_transfer_account.id,
|
||
|
'tax_repartition_line_id': tax_a.invoice_repartition_line_ids.filtered(lambda line: line.repartition_type == 'tax').id,
|
||
|
}),
|
||
|
|
||
|
# Tax line B
|
||
|
Command.create({
|
||
|
'debit': 0.0,
|
||
|
'credit': 1.0,
|
||
|
'account_id': self.cash_basis_transfer_account.id,
|
||
|
'tax_repartition_line_id': tax_b.invoice_repartition_line_ids.filtered(lambda line: line.repartition_type == 'tax').id,
|
||
|
}),
|
||
|
|
||
|
# Receivable lines
|
||
|
Command.create({
|
||
|
'debit': 4001.0,
|
||
|
'credit': 0.0,
|
||
|
'account_id': self.extra_receivable_account_1.id,
|
||
|
}),
|
||
|
]
|
||
|
})
|
||
|
|
||
|
invoice.action_post()
|
||
|
|
||
|
pmt_wizard = self.env['account.payment.register'].with_context(active_model='account.move', active_ids=invoice.ids).create({})
|
||
|
pmt_wizard._create_payments()
|
||
|
|
||
|
caba_move = self.env['account.move'].search([('tax_cash_basis_origin_move_id', '=', invoice.id)])
|
||
|
self.assertEqual(len(caba_move.line_ids), 6, "All lines should be there")
|
||
|
tax_group_base_tags = (tax_a | tax_b).invoice_repartition_line_ids.filtered(lambda l: l.repartition_type == 'base').tag_ids.ids
|
||
|
tax_a_tax_tag = tax_a.invoice_repartition_line_ids.filtered(lambda l: l.repartition_type == 'tax').tag_ids.ids
|
||
|
tax_b_tax_tag = tax_b.invoice_repartition_line_ids.filtered(lambda l: l.repartition_type == 'tax').tag_ids.ids
|
||
|
self.assertRecordValues(caba_move.line_ids, [
|
||
|
{'balance': 3000.0, 'tax_line_id': False, 'tax_tag_ids': [], 'tax_ids': []},
|
||
|
{'balance': -3000.0, 'tax_line_id': False, 'tax_tag_ids': tax_group_base_tags, 'tax_ids': (tax_a | tax_b).ids},
|
||
|
{'balance': 1000.0, 'tax_line_id': False, 'tax_tag_ids': [], 'tax_ids': []},
|
||
|
{'balance': -1000.0, 'tax_line_id': tax_a.id, 'tax_tag_ids': tax_a_tax_tag, 'tax_ids': []},
|
||
|
{'balance': 1.0, 'tax_line_id': False, 'tax_tag_ids': [], 'tax_ids': []},
|
||
|
{'balance': -1.0, 'tax_line_id': tax_b.id, 'tax_tag_ids': tax_b_tax_tag, 'tax_ids': []},
|
||
|
])
|
||
|
# No exchange journal entry created for CABA.
|
||
|
exchange_difference_move = invoice.line_ids.filtered(lambda line: line.account_id.account_type == 'receivable').full_reconcile_id.exchange_move_id
|
||
|
self.assertFalse(exchange_difference_move)
|
||
|
|
||
|
def test_caba_rounding_adjustment_monocurrency(self):
|
||
|
self.env.company.tax_exigibility = True
|
||
|
|
||
|
invoice = self.env['account.move'].create({
|
||
|
'move_type': 'out_invoice',
|
||
|
'partner_id': self.partner_a.id,
|
||
|
'invoice_date': fields.Date.from_string('2016-01-01'),
|
||
|
'invoice_line_ids': [Command.create({
|
||
|
'name': 'caba test',
|
||
|
'quantity': 1,
|
||
|
'price_unit': 99.99,
|
||
|
'tax_ids': [Command.set(self.cash_basis_tax_a_third_amount.ids)],
|
||
|
})],
|
||
|
})
|
||
|
invoice.action_post()
|
||
|
|
||
|
payment_date_1 = fields.Date.from_string('2017-01-01')
|
||
|
payment_date_2 = fields.Date.from_string('2018-01-01')
|
||
|
|
||
|
pmt_wizard = self.env['account.payment.register'].with_context(active_model='account.move', active_ids=invoice.ids).create({
|
||
|
'amount': 66.66,
|
||
|
'payment_date': payment_date_1,
|
||
|
})
|
||
|
pmt_wizard._create_payments()
|
||
|
|
||
|
pmt_wizard = self.env['account.payment.register'].with_context(active_model='account.move', active_ids=invoice.ids).create({
|
||
|
'amount': 66.66,
|
||
|
'payment_date': payment_date_2,
|
||
|
})
|
||
|
pmt_wizard._create_payments()
|
||
|
|
||
|
self.assertRecordValues(invoice.tax_cash_basis_created_move_ids.filtered(lambda x: x.date == payment_date_1).line_ids, [
|
||
|
# pylint: disable=bad-whitespace
|
||
|
{'account_id': self.cash_basis_base_account.id, 'debit': 50.0, 'credit': 0.0},
|
||
|
{'account_id': self.cash_basis_base_account.id, 'debit': 0.0, 'credit': 50.0},
|
||
|
{'account_id': self.cash_basis_transfer_account.id, 'debit': 16.67, 'credit': 0.0},
|
||
|
{'account_id': self.tax_account_1.id, 'debit': 0.0, 'credit': 16.67},
|
||
|
])
|
||
|
|
||
|
self.assertRecordValues(invoice.tax_cash_basis_created_move_ids.filtered(lambda x: x.date == payment_date_2).line_ids, [
|
||
|
# pylint: disable=bad-whitespace
|
||
|
{'account_id': self.cash_basis_base_account.id, 'debit': 50.0, 'credit': 0.0},
|
||
|
{'account_id': self.cash_basis_base_account.id, 'debit': 0.0, 'credit': 50.0},
|
||
|
{'account_id': self.cash_basis_transfer_account.id, 'debit': 16.67, 'credit': 0.0},
|
||
|
{'account_id': self.tax_account_1.id, 'debit': 0.0, 'credit': 16.67},
|
||
|
])
|
||
|
|
||
|
# Check the CABA adjustment made in the receivable account's full reconcile's exchange move
|
||
|
self.assertRecordValues(
|
||
|
# pylint: disable=bad-whitespace
|
||
|
invoice.line_ids.filtered(lambda x: x.account_id.account_type == 'asset_receivable').full_reconcile_id.exchange_move_id.line_ids,
|
||
|
[
|
||
|
{'account_id': self.cash_basis_base_account.id, 'debit': 0.01, 'credit': 0.0},
|
||
|
{'account_id': self.cash_basis_base_account.id, 'debit': 0.0, 'credit': 0.01},
|
||
|
{'account_id': self.tax_account_1.id, 'debit': 0.01, 'credit': 0.0},
|
||
|
{'account_id': self.cash_basis_transfer_account.id, 'debit': 0.0, 'credit': 0.01},
|
||
|
]
|
||
|
)
|
||
|
|
||
|
self.assertTrue(
|
||
|
invoice.line_ids.filtered(lambda x: x.account_id == self.cash_basis_transfer_account).full_reconcile_id,
|
||
|
"The cash basis transition account line of the invoice should be fully reconciled with the CABA moves and the adjustment."
|
||
|
)
|
||
|
|
||
|
self.assertAmountsGroupByAccount([
|
||
|
# pylint: disable=bad-whitespace
|
||
|
# Account Balance Amount Currency
|
||
|
(self.cash_basis_transfer_account, 0.0, 0.0),
|
||
|
(self.tax_account_1, -33.33, -33.33),
|
||
|
(self.cash_basis_base_account, 0.0, 0.0)
|
||
|
])
|
||
|
|
||
|
def test_caba_rounding_adjustment_multicurrency(self):
|
||
|
self.env.company.tax_exigibility = True
|
||
|
|
||
|
# Rates are 1/3 for 2016, 1/2 for 2017 and 5/1 in 2018
|
||
|
currency_id = self.setup_multi_currency_data({'name': 'Minovsky Dollar', 'rounding': 0.01})['currency'].id
|
||
|
|
||
|
self.env['res.currency.rate'].create({
|
||
|
'name': '2018-01-01',
|
||
|
'rate': 0.2,
|
||
|
'currency_id': currency_id,
|
||
|
'company_id': self.env.company.id,
|
||
|
})
|
||
|
|
||
|
invoice = self.env['account.move'].create({
|
||
|
'move_type': 'out_invoice',
|
||
|
'partner_id': self.partner_a.id,
|
||
|
'invoice_date': fields.Date.from_string('2016-01-01'),
|
||
|
'currency_id': currency_id,
|
||
|
'invoice_line_ids': [Command.create({
|
||
|
'name': 'caba test',
|
||
|
'quantity': 1,
|
||
|
'price_unit': 99.99,
|
||
|
'tax_ids': [Command.set(self.cash_basis_tax_a_third_amount.ids)],
|
||
|
})],
|
||
|
})
|
||
|
invoice.action_post()
|
||
|
|
||
|
payment_date_1 = fields.Date.from_string('2017-01-01')
|
||
|
payment_date_2 = fields.Date.from_string('2018-01-01')
|
||
|
|
||
|
pmt_wizard = self.env['account.payment.register'].with_context(active_model='account.move', active_ids=invoice.ids).create({
|
||
|
'amount': 66.66,
|
||
|
'currency_id': currency_id,
|
||
|
'payment_date': payment_date_1,
|
||
|
})
|
||
|
pmt_wizard._create_payments()
|
||
|
|
||
|
pmt_wizard = self.env['account.payment.register'].with_context(active_model='account.move', active_ids=invoice.ids).create({
|
||
|
'amount': 66.66,
|
||
|
'currency_id': currency_id,
|
||
|
'payment_date': payment_date_2,
|
||
|
})
|
||
|
pmt_wizard._create_payments()
|
||
|
|
||
|
self.assertRecordValues(invoice.tax_cash_basis_created_move_ids.filtered(lambda x: x.date == payment_date_1).line_ids, [
|
||
|
# pylint: disable=bad-whitespace
|
||
|
{'account_id': self.cash_basis_base_account.id, 'debit': 25.0, 'credit': 0.0, 'amount_currency': 50.0, 'currency_id': currency_id},
|
||
|
{'account_id': self.cash_basis_base_account.id, 'debit': 0.0, 'credit': 25.0, 'amount_currency': -50.0, 'currency_id': currency_id},
|
||
|
{'account_id': self.cash_basis_transfer_account.id, 'debit': 8.34, 'credit': 0.0, 'amount_currency': 16.67, 'currency_id': currency_id},
|
||
|
{'account_id': self.tax_account_1.id, 'debit': 0.0, 'credit': 8.34, 'amount_currency': -16.67, 'currency_id': currency_id},
|
||
|
])
|
||
|
|
||
|
self.assertRecordValues(invoice.tax_cash_basis_created_move_ids.filtered(lambda x: x.date == payment_date_2).line_ids, [
|
||
|
# pylint: disable=bad-whitespace
|
||
|
{'account_id': self.cash_basis_base_account.id, 'debit': 250.0, 'credit': 0.0, 'amount_currency': 50.0, 'currency_id': currency_id},
|
||
|
{'account_id': self.cash_basis_base_account.id, 'debit': 0.0, 'credit': 250.0, 'amount_currency': -50.0, 'currency_id': currency_id},
|
||
|
{'account_id': self.cash_basis_transfer_account.id, 'debit': 83.35, 'credit': 0.0, 'amount_currency': 16.67, 'currency_id': currency_id},
|
||
|
{'account_id': self.tax_account_1.id, 'debit': 0.0, 'credit': 83.35, 'amount_currency': -16.67, 'currency_id': currency_id},
|
||
|
])
|
||
|
|
||
|
# Check the CABA adjustment made in the receivable account's full reconcile's exchange move
|
||
|
self.assertRecordValues(
|
||
|
# pylint: disable=bad-whitespace
|
||
|
invoice.line_ids.filtered(lambda x: x.account_id.account_type == 'asset_receivable').full_reconcile_id.exchange_move_id.line_ids,
|
||
|
[
|
||
|
{'account_id': self.cash_basis_base_account.id, 'debit': 0.05, 'credit': 0.0, 'amount_currency': 0.01, 'currency_id': currency_id},
|
||
|
{'account_id': self.cash_basis_base_account.id, 'debit': 0.0, 'credit': 0.05, 'amount_currency': -0.01, 'currency_id': currency_id},
|
||
|
{'account_id': self.tax_account_1.id, 'debit': 0.05, 'credit': 0.0, 'amount_currency': 0.01, 'currency_id': currency_id},
|
||
|
{'account_id': self.cash_basis_transfer_account.id, 'debit': 0.0, 'credit': 0.05, 'amount_currency': -0.01, 'currency_id': currency_id},
|
||
|
]
|
||
|
)
|
||
|
|
||
|
self.assertTrue(
|
||
|
invoice.line_ids.filtered(lambda x: x.account_id == self.cash_basis_transfer_account).full_reconcile_id,
|
||
|
"The cash basis transition account line of the invoice should be fully reconciled with the CABA moves and the adjustment."
|
||
|
)
|
||
|
|
||
|
self.assertAmountsGroupByAccount([
|
||
|
# pylint: disable=bad-whitespace
|
||
|
# Account Balance Amount Currency
|
||
|
(self.cash_basis_transfer_account, 0.0, 0.0),
|
||
|
(self.tax_account_1, -91.64, -33.33),
|
||
|
(self.cash_basis_base_account, 0.0, 0.0),
|
||
|
])
|
||
|
|
||
|
def test_cash_basis_taxline_without_account(self):
|
||
|
"""
|
||
|
Make sure that cash basis taxlines that don't have an account are handled properly.
|
||
|
"""
|
||
|
self.env.company.tax_exigibility = True
|
||
|
|
||
|
tax = self.env['account.tax'].create({
|
||
|
'name': 'cash basis 20%',
|
||
|
'type_tax_use': 'purchase',
|
||
|
'amount': 20,
|
||
|
'tax_exigibility': 'on_payment',
|
||
|
'cash_basis_transition_account_id': self.cash_basis_transfer_account.id,
|
||
|
'invoice_repartition_line_ids': [
|
||
|
(0, 0, {
|
||
|
'factor_percent': 100,
|
||
|
'repartition_type': 'base',
|
||
|
}),
|
||
|
(0, 0, {
|
||
|
'factor_percent': 40,
|
||
|
'account_id': self.tax_account_1.id,
|
||
|
'repartition_type': 'tax',
|
||
|
}),
|
||
|
|
||
|
(0, 0, {
|
||
|
'factor_percent': 60,
|
||
|
'repartition_type': 'tax',
|
||
|
}),
|
||
|
],
|
||
|
'refund_repartition_line_ids': [
|
||
|
(0, 0, {
|
||
|
'factor_percent': 100,
|
||
|
'repartition_type': 'base',
|
||
|
}),
|
||
|
(0, 0, {
|
||
|
'factor_percent': 40,
|
||
|
'account_id': self.tax_account_1.id,
|
||
|
'repartition_type': 'tax',
|
||
|
}),
|
||
|
|
||
|
(0, 0, {
|
||
|
'factor_percent': 60,
|
||
|
'repartition_type': 'tax',
|
||
|
}),
|
||
|
],
|
||
|
})
|
||
|
|
||
|
# create invoice
|
||
|
move_form = Form(self.env['account.move'].with_context(
|
||
|
default_move_type='in_invoice'))
|
||
|
move_form.partner_id = self.partner_a
|
||
|
move_form.invoice_date = fields.Date.from_string('2017-01-01')
|
||
|
with move_form.invoice_line_ids.new() as line_form:
|
||
|
line_form.product_id = self.product_a
|
||
|
line_form.tax_ids.clear()
|
||
|
line_form.tax_ids.add(tax)
|
||
|
invoice = move_form.save()
|
||
|
invoice.action_post()
|
||
|
|
||
|
# make payment
|
||
|
self.env['account.payment.register'].with_context(active_model='account.move', active_ids=invoice.ids).create({
|
||
|
'payment_date': invoice.date,
|
||
|
})._create_payments()
|
||
|
|
||
|
# check caba move
|
||
|
partial_rec = invoice.mapped('line_ids.matched_debit_ids')
|
||
|
caba_move = self.env['account.move'].search(
|
||
|
[('tax_cash_basis_rec_id', '=', partial_rec.id)])
|
||
|
expected_values = [
|
||
|
{
|
||
|
'account_id': self.cash_basis_base_account.id,
|
||
|
'debit': 0.0,
|
||
|
'credit': 800.0
|
||
|
},
|
||
|
{
|
||
|
'account_id': self.cash_basis_base_account.id,
|
||
|
'debit': 800.0,
|
||
|
'credit': 0.0
|
||
|
},
|
||
|
{
|
||
|
'account_id': self.cash_basis_transfer_account.id,
|
||
|
'debit': 0.0,
|
||
|
'credit': 64.0
|
||
|
},
|
||
|
{
|
||
|
'account_id': self.tax_account_1.id,
|
||
|
'debit': 64.0,
|
||
|
'credit': 0.0},
|
||
|
{
|
||
|
'account_id': self.cash_basis_transfer_account.id,
|
||
|
'debit': 0.0,
|
||
|
'credit': 96.0
|
||
|
},
|
||
|
{
|
||
|
'account_id': self.cash_basis_base_account.id,
|
||
|
'debit': 96.0,
|
||
|
'credit': 0.0
|
||
|
}
|
||
|
]
|
||
|
self.assertRecordValues(caba_move.line_ids, expected_values)
|
||
|
|
||
|
def test_cash_basis_full_refund(self):
|
||
|
""" Ensure the caba entry and the exchange difference journal entry for caba are not created in case of full
|
||
|
refund.
|
||
|
"""
|
||
|
self.env.company.tax_exigibility = True
|
||
|
|
||
|
tax = self.env['account.tax'].create({
|
||
|
'name': 'cash basis 20%',
|
||
|
'type_tax_use': 'purchase',
|
||
|
'amount': 20,
|
||
|
'tax_exigibility': 'on_payment',
|
||
|
'cash_basis_transition_account_id': self.cash_basis_transfer_account.id,
|
||
|
})
|
||
|
|
||
|
invoice = self.init_invoice('out_invoice', post=True, amounts=[1000.0], taxes=tax)
|
||
|
|
||
|
# Reverse completely the invoice.
|
||
|
credit_note_wizard = self.env['account.move.reversal']\
|
||
|
.with_context({'active_ids': invoice.ids, 'active_model': 'account.move'})\
|
||
|
.create({
|
||
|
'reason': 'test_cash_basis_full_refund',
|
||
|
'journal_id': invoice.journal_id.id,
|
||
|
})
|
||
|
action_values = credit_note_wizard.modify_moves()
|
||
|
self.assertRecordValues(invoice, [{'payment_state': 'reversed'}])
|
||
|
|
||
|
# Check no CABA move has been created.
|
||
|
cash_basis_moves = self.env['account.move']\
|
||
|
.search([('tax_cash_basis_origin_move_id', 'in', (invoice.id, action_values['res_id']))])
|
||
|
self.assertFalse(cash_basis_moves)
|
||
|
|
||
|
# No exchange journal entry created for CABA.
|
||
|
caba_transfer_amls = self.env['account.move.line'].search([
|
||
|
('account_id', '=', self.cash_basis_transfer_account.id),
|
||
|
('move_id.move_type', '=', 'entry'),
|
||
|
])
|
||
|
self.assertFalse(caba_transfer_amls.move_id)
|
||
|
|
||
|
def test_reconcile_import(self):
|
||
|
"""Test that the import of matchings does a real matching upon posting"""
|
||
|
comp_curr = self.company_data['currency']
|
||
|
|
||
|
line_1 = self.create_line_for_reconciliation(1000.0, 1000.0, comp_curr, '2016-01-01')
|
||
|
line_1.move_id.button_draft()
|
||
|
line_2 = self.create_line_for_reconciliation(-300.0, -300.0, comp_curr, '2016-01-01')
|
||
|
line_3 = self.create_line_for_reconciliation(-400.0, -400.0, comp_curr, '2016-01-01')
|
||
|
line_4 = self.create_line_for_reconciliation(-500.0, -500.0, comp_curr, '2016-01-01')
|
||
|
line_4.move_id.button_draft()
|
||
|
line_5 = self.create_line_for_reconciliation(200.0, 200.0, comp_curr, '2016-01-01')
|
||
|
(line_1 + line_2 + line_3).matching_number = '11111' # Will be converted to a temporary number
|
||
|
(line_4 + line_5).matching_number = '22222' # Will be converted to a temporary number
|
||
|
# posting triggers the matching of the imported values
|
||
|
(line_1 + line_4).move_id.action_post()
|
||
|
self.assertRegex(line_1.matching_number, r'^P\d+')
|
||
|
self.assertRegex(line_4.matching_number, r'^P\d+')
|
||
|
(line_1 + line_4).reconcile()
|
||
|
self.assertRegex(line_1.matching_number, r'^\d+')
|
||
|
self.assertTrue(line_1.full_reconcile_id)
|
||
|
|
||
|
def test_reconcile_payment_custom_rate(self):
|
||
|
"""When reconciling a payment we want to take the accounting rate and not the odoo rate.
|
||
|
Most likely the payment information are derived from information of the bank, therefore have
|
||
|
the relevant rate.
|
||
|
"""
|
||
|
company_currency = self.company_data['currency']
|
||
|
foreign_currency = self.currency_data['currency']
|
||
|
|
||
|
invoice = self.env['account.move'].create({
|
||
|
'move_type': 'out_invoice',
|
||
|
'invoice_date': '2017-01-01',
|
||
|
'date': '2017-01-01',
|
||
|
'partner_id': self.partner_a.id,
|
||
|
'currency_id': company_currency.id,
|
||
|
'invoice_line_ids': [Command.create({
|
||
|
'product_id': self.product_a.id,
|
||
|
'price_unit': 400.0,
|
||
|
'tax_ids': [],
|
||
|
})],
|
||
|
})
|
||
|
invoice.action_post()
|
||
|
|
||
|
payment = self.env['account.payment'].create({
|
||
|
'date': invoice.date,
|
||
|
'amount': 800.0,
|
||
|
'currency_id': foreign_currency.id,
|
||
|
'partner_id': self.partner_a.id,
|
||
|
})
|
||
|
payment.action_post()
|
||
|
# unlink the rate to simulate a custom rate on the payment
|
||
|
self.env['res.currency.rate'].search([('currency_id', '=', foreign_currency.id)]).unlink()
|
||
|
|
||
|
lines_to_reconcile = (invoice + payment.move_id).line_ids.filtered(lambda x: x.account_id.account_type == 'asset_receivable')
|
||
|
lines_to_reconcile.reconcile()
|
||
|
|
||
|
self.assertTrue(all(lines_to_reconcile.mapped('reconciled')), "All lines should be fully reconciled")
|