737 lines
33 KiB
Python
737 lines
33 KiB
Python
# -*- coding: utf-8 -*-
|
|
# pylint: disable=C0326
|
|
from odoo import Command
|
|
from odoo.addons.account.tests.common import AccountTestInvoicingCommon
|
|
from odoo.tests import tagged, Form
|
|
|
|
|
|
@tagged('post_install', '-at_install')
|
|
class TestInvoiceTaxes(AccountTestInvoicingCommon):
|
|
|
|
@classmethod
|
|
def setUpClass(cls, chart_template_ref=None):
|
|
super().setUpClass(chart_template_ref=chart_template_ref)
|
|
|
|
cls.company_data['company'].country_id = cls.env.ref('base.us')
|
|
|
|
cls.percent_tax_1 = cls.env['account.tax'].create({
|
|
'name': '21%',
|
|
'amount_type': 'percent',
|
|
'amount': 21,
|
|
'sequence': 10,
|
|
})
|
|
cls.percent_tax_1_incl = cls.env['account.tax'].create({
|
|
'name': '21% incl',
|
|
'amount_type': 'percent',
|
|
'amount': 21,
|
|
'price_include': True,
|
|
'include_base_amount': True,
|
|
'sequence': 20,
|
|
})
|
|
cls.percent_tax_2 = cls.env['account.tax'].create({
|
|
'name': '12%',
|
|
'amount_type': 'percent',
|
|
'amount': 12,
|
|
'sequence': 30,
|
|
})
|
|
cls.percent_tax_3_incl = cls.env['account.tax'].create({
|
|
'name': '5% incl',
|
|
'amount_type': 'percent',
|
|
'amount': 5,
|
|
'price_include': True,
|
|
'include_base_amount': True,
|
|
'sequence': 40,
|
|
})
|
|
cls.group_tax = cls.env['account.tax'].create({
|
|
'name': 'group 12% + 21%',
|
|
'amount_type': 'group',
|
|
'amount': 21,
|
|
'children_tax_ids': [
|
|
(4, cls.percent_tax_1_incl.id),
|
|
(4, cls.percent_tax_2.id)
|
|
],
|
|
'sequence': 40,
|
|
})
|
|
|
|
tax_report = cls.env['account.report'].create({
|
|
'name': "Tax report",
|
|
'country_id': cls.company_data['company'].country_id.id,
|
|
'column_ids': [
|
|
Command.create({
|
|
'name': "Balance",
|
|
'expression_label': 'balance',
|
|
}),
|
|
],
|
|
})
|
|
|
|
tax_report_line = cls.env['account.report.line'].create({
|
|
'name': 'test_tax_report_line',
|
|
'report_id': tax_report.id,
|
|
'sequence': 10,
|
|
'expression_ids': [
|
|
Command.create({
|
|
'label': 'balance',
|
|
'engine': 'tax_tags',
|
|
'formula': 'test_tax_report_line',
|
|
}),
|
|
],
|
|
})
|
|
tax_tags = tax_report_line.expression_ids._get_matching_tags()
|
|
cls.tax_tag_pos, cls.tax_tag_neg = tax_tags.sorted('tax_negate')
|
|
|
|
base_report_line = cls.env['account.report.line'].create({
|
|
'name': 'base_test_tax_report_line',
|
|
'report_id': tax_report.id,
|
|
'sequence': 10,
|
|
'expression_ids': [
|
|
Command.create({
|
|
'label': 'balance',
|
|
'engine': 'tax_tags',
|
|
'formula': 'base_test_tax_report_line',
|
|
}),
|
|
],
|
|
})
|
|
base_tags = base_report_line.expression_ids._get_matching_tags()
|
|
cls.base_tag_pos, cls.base_tag_neg = base_tags.sorted('tax_negate')
|
|
|
|
def _create_invoice(self, taxes_per_line, inv_type='out_invoice', currency_id=False, invoice_payment_term_id=False):
|
|
''' Create an invoice on the fly.
|
|
|
|
:param taxes_per_line: A list of tuple (price_unit, account.tax recordset)
|
|
'''
|
|
vals = {
|
|
'move_type': inv_type,
|
|
'partner_id': self.partner_a.id,
|
|
'invoice_line_ids': [(0, 0, {
|
|
'name': 'xxxx',
|
|
'quantity': 1,
|
|
'price_unit': amount,
|
|
'tax_ids': [(6, 0, taxes.ids)],
|
|
}) for amount, taxes in taxes_per_line],
|
|
}
|
|
if currency_id:
|
|
vals['currency_id'] = currency_id.id
|
|
if invoice_payment_term_id:
|
|
vals['invoice_payment_term_id'] = invoice_payment_term_id.id
|
|
return self.env['account.move'].create(vals)
|
|
|
|
def test_setting_tax_separately(self):
|
|
''' Test:
|
|
price_unit | Taxes
|
|
------------------
|
|
100 | 21%
|
|
Expected:
|
|
Tax | Taxes | Base | Amount
|
|
--------------------------------------------
|
|
21% | / | 100 | 21
|
|
'''
|
|
invoice = self._create_invoice([(100, self.env['account.tax'])])
|
|
invoice.invoice_line_ids[0].tax_ids = self.percent_tax_1
|
|
self.assertRecordValues(invoice.line_ids.filtered('tax_line_id'), [
|
|
{'name': self.percent_tax_1.name, 'tax_base_amount': 100, 'balance': -21, 'tax_ids': []},
|
|
])
|
|
|
|
def test_one_tax_per_line(self):
|
|
''' Test:
|
|
price_unit | Taxes
|
|
------------------
|
|
100 | 21%
|
|
121 | 21% incl
|
|
100 | 12%
|
|
|
|
Expected:
|
|
Tax | Taxes | Base | Amount
|
|
--------------------------------------------
|
|
21% | / | 100 | 21
|
|
21% incl | / | 100 | 21
|
|
12% | / | 100 | 12
|
|
'''
|
|
invoice = self._create_invoice([
|
|
(100, self.percent_tax_1),
|
|
(121, self.percent_tax_1_incl),
|
|
(100, self.percent_tax_2),
|
|
])
|
|
invoice.action_post()
|
|
self.assertRecordValues(invoice.line_ids.filtered('tax_line_id').sorted(lambda x: x.name), [
|
|
{'name': self.percent_tax_2.name, 'tax_base_amount': 100, 'balance': -12, 'tax_ids': []},
|
|
{'name': self.percent_tax_1.name, 'tax_base_amount': 100, 'balance': -21, 'tax_ids': []},
|
|
{'name': self.percent_tax_1_incl.name, 'tax_base_amount': 100, 'balance': -21, 'tax_ids': []},
|
|
])
|
|
|
|
def test_affecting_base_amount(self):
|
|
''' Test:
|
|
price_unit | Taxes
|
|
------------------
|
|
121 | 21% incl, 12%
|
|
100 | 12%
|
|
|
|
Expected:
|
|
Tax | Taxes | Base | Amount
|
|
--------------------------------------------
|
|
21% incl | 12% | 100 | 21
|
|
12% | / | 121 | 14.52
|
|
12% | / | 100 | 12
|
|
'''
|
|
invoice = self._create_invoice([
|
|
(121, self.percent_tax_1_incl + self.percent_tax_2),
|
|
(100, self.percent_tax_2),
|
|
])
|
|
invoice.action_post()
|
|
self.assertRecordValues(invoice.line_ids.filtered('tax_line_id').sorted(lambda x: -x.balance), [
|
|
{'name': self.percent_tax_1_incl.name, 'tax_base_amount': 100, 'balance': -21, 'tax_ids': [self.percent_tax_2.id]},
|
|
{'name': self.percent_tax_2.name, 'tax_base_amount': 221, 'balance': -26.52, 'tax_ids': []},
|
|
])
|
|
|
|
def test_group_of_taxes(self):
|
|
''' Test:
|
|
price_unit | Taxes
|
|
------------------
|
|
121 | 21% incl + 12%
|
|
100 | 12%
|
|
|
|
Expected:
|
|
Tax | Taxes | Base | Amount
|
|
--------------------------------------------
|
|
21% incl | / | 100 | 21
|
|
12% | 21% incl | 121 | 14.52
|
|
12% | / | 100 | 12
|
|
'''
|
|
invoice = self._create_invoice([
|
|
(121, self.group_tax),
|
|
(100, self.percent_tax_2),
|
|
])
|
|
invoice.action_post()
|
|
self.assertRecordValues(invoice.line_ids.filtered('tax_line_id').sorted('balance'), [
|
|
{'name': self.percent_tax_1_incl.name, 'tax_base_amount': 100.0, 'balance': -21.0, 'tax_ids': [self.percent_tax_2.id]},
|
|
{'name': self.percent_tax_2.name, 'tax_base_amount': 121.0, 'balance': -14.52, 'tax_ids': []},
|
|
{'name': self.percent_tax_2.name, 'tax_base_amount': 100.0, 'balance': -12.0, 'tax_ids': []},
|
|
])
|
|
|
|
def _create_tax_tag(self, tag_name):
|
|
return self.env['account.account.tag'].create({
|
|
'name': tag_name,
|
|
'applicability': 'taxes',
|
|
'country_id': self.env.company.country_id.id,
|
|
})
|
|
|
|
def test_tax_repartition(self):
|
|
inv_base_tag = self._create_tax_tag('invoice_base')
|
|
inv_tax_tag_10 = self._create_tax_tag('invoice_tax_10')
|
|
inv_tax_tag_90 = self._create_tax_tag('invoice_tax_90')
|
|
ref_base_tag = self._create_tax_tag('refund_base')
|
|
ref_tax_tag = self._create_tax_tag('refund_tax')
|
|
|
|
account_1 = self.env['account.account'].create({'name': 'test1', 'code': 'test1', 'account_type': 'asset_current'})
|
|
account_2 = self.env['account.account'].create({'name': 'test2', 'code': 'test2', 'account_type': 'asset_current'})
|
|
|
|
tax = self.env['account.tax'].create({
|
|
'name': "Tax with account",
|
|
'amount_type': 'fixed',
|
|
'type_tax_use': 'sale',
|
|
'amount': 42,
|
|
'invoice_repartition_line_ids': [
|
|
(0,0, {
|
|
'repartition_type': 'base',
|
|
'tag_ids': [(4, inv_base_tag.id, 0)],
|
|
}),
|
|
|
|
(0,0, {
|
|
'factor_percent': 10,
|
|
'repartition_type': 'tax',
|
|
'account_id': account_1.id,
|
|
'tag_ids': [(4, inv_tax_tag_10.id, 0)],
|
|
}),
|
|
|
|
(0,0, {
|
|
'factor_percent': 90,
|
|
'repartition_type': 'tax',
|
|
'account_id': account_2.id,
|
|
'tag_ids': [(4, inv_tax_tag_90.id, 0)],
|
|
}),
|
|
],
|
|
'refund_repartition_line_ids': [
|
|
(0,0, {
|
|
'repartition_type': 'base',
|
|
'tag_ids': [(4, ref_base_tag.id, 0)],
|
|
}),
|
|
|
|
(0,0, {
|
|
'factor_percent': 10,
|
|
'repartition_type': 'tax',
|
|
'tag_ids': [(4, ref_tax_tag.id, 0)],
|
|
}),
|
|
|
|
(0,0, {
|
|
'factor_percent': 90,
|
|
'repartition_type': 'tax',
|
|
'account_id': account_1.id,
|
|
'tag_ids': [(4, ref_tax_tag.id, 0)],
|
|
}),
|
|
],
|
|
})
|
|
|
|
# Test invoice repartition
|
|
invoice = self._create_invoice([(100, tax)], inv_type='out_invoice')
|
|
invoice.action_post()
|
|
|
|
self.assertEqual(len(invoice.line_ids), 4, "There should be 4 account move lines created for the invoice: payable, base and 2 tax lines")
|
|
inv_base_line = invoice.line_ids.filtered(lambda x: not x.tax_repartition_line_id and x.account_id.account_type != 'asset_receivable')
|
|
self.assertEqual(len(inv_base_line), 1, "There should be only one base line generated")
|
|
self.assertEqual(abs(inv_base_line.balance), 100, "Base amount should be 100")
|
|
self.assertEqual(inv_base_line.tax_tag_ids, inv_base_tag, "Base line should have received base tag")
|
|
inv_tax_lines = invoice.line_ids.filtered(lambda x: x.tax_repartition_line_id.repartition_type == 'tax')
|
|
self.assertEqual(len(inv_tax_lines), 2, "There should be two tax lines, one for each repartition line.")
|
|
self.assertEqual(abs(inv_tax_lines.filtered(lambda x: x.account_id == account_1).balance), 4.2, "Tax line on account 1 should amount to 4.2 (10% of 42)")
|
|
self.assertEqual(inv_tax_lines.filtered(lambda x: x.account_id == account_1).tax_tag_ids, inv_tax_tag_10, "Tax line on account 1 should have 10% tag")
|
|
self.assertAlmostEqual(abs(inv_tax_lines.filtered(lambda x: x.account_id == account_2).balance), 37.8, 2, "Tax line on account 2 should amount to 37.8 (90% of 42)")
|
|
self.assertEqual(inv_tax_lines.filtered(lambda x: x.account_id == account_2).tax_tag_ids, inv_tax_tag_90, "Tax line on account 2 should have 90% tag")
|
|
|
|
# Test refund repartition
|
|
refund = self._create_invoice([(100, tax)], inv_type='out_refund')
|
|
refund.action_post()
|
|
|
|
self.assertEqual(len(refund.line_ids), 4, "There should be 4 account move lines created for the refund: payable, base and 2 tax lines")
|
|
ref_base_line = refund.line_ids.filtered(lambda x: not x.tax_repartition_line_id and x.account_id.account_type != 'asset_receivable')
|
|
self.assertEqual(len(ref_base_line), 1, "There should be only one base line generated")
|
|
self.assertEqual(abs(ref_base_line.balance), 100, "Base amount should be 100")
|
|
self.assertEqual(ref_base_line.tax_tag_ids, ref_base_tag, "Base line should have received base tag")
|
|
ref_tax_lines = refund.line_ids.filtered(lambda x: x.tax_repartition_line_id.repartition_type == 'tax')
|
|
self.assertEqual(len(ref_tax_lines), 2, "There should be two refund tax lines")
|
|
self.assertEqual(abs(ref_tax_lines.filtered(lambda x: x.account_id == ref_base_line.account_id).balance), 4.2, "Refund tax line on base account should amount to 4.2 (10% of 42)")
|
|
self.assertAlmostEqual(abs(ref_tax_lines.filtered(lambda x: x.account_id == account_1).balance), 37.8, 2, "Refund tax line on account 1 should amount to 37.8 (90% of 42)")
|
|
self.assertEqual(ref_tax_lines.mapped('tax_tag_ids'), ref_tax_tag, "Refund tax lines should have the right tag")
|
|
|
|
def test_division_tax(self):
|
|
'''
|
|
Test that when using division tax, with percentage amount
|
|
100% any change on price unit is correctly reflected on
|
|
the whole move.
|
|
|
|
Complete scenario:
|
|
- Create a division tax, 100% amount, included in price.
|
|
- Create an invoice, with only the mentioned tax
|
|
- Change price_unit of the aml
|
|
- Total price of the move should change as well
|
|
'''
|
|
|
|
sale_tax = self.env['account.tax'].create({
|
|
'name': 'tax',
|
|
'type_tax_use': 'sale',
|
|
'amount_type': 'division',
|
|
'amount': 100,
|
|
'price_include': True,
|
|
'include_base_amount': True,
|
|
})
|
|
invoice = self._create_invoice([(100, sale_tax)])
|
|
self.assertRecordValues(invoice.line_ids.filtered('tax_line_id'), [{
|
|
'name': sale_tax.name,
|
|
'tax_base_amount': 0.0,
|
|
'balance': -100,
|
|
}])
|
|
# change price unit, everything should change as well
|
|
with Form(invoice) as invoice_form:
|
|
with invoice_form.invoice_line_ids.edit(0) as line_edit:
|
|
line_edit.price_unit = 200
|
|
|
|
self.assertRecordValues(invoice.line_ids.filtered('tax_line_id'), [{
|
|
'name': sale_tax.name,
|
|
'tax_base_amount': 0.0,
|
|
'balance': -200,
|
|
}])
|
|
|
|
def test_misc_journal_entry_tax_tags_sale(self):
|
|
sale_tax = self.env['account.tax'].create({
|
|
'name': 'tax',
|
|
'type_tax_use': 'sale',
|
|
'amount_type': 'percent',
|
|
'amount': 10,
|
|
'invoice_repartition_line_ids': [
|
|
(0, 0, {
|
|
'repartition_type': 'base',
|
|
'tag_ids': [(6, 0, self.base_tag_pos.ids)],
|
|
}),
|
|
(0, 0, {
|
|
'repartition_type': 'tax',
|
|
'tag_ids': [(6, 0, self.tax_tag_pos.ids)],
|
|
}),
|
|
],
|
|
'refund_repartition_line_ids': [
|
|
(0, 0, {
|
|
'repartition_type': 'base',
|
|
'tag_ids': [(6, 0, self.base_tag_neg.ids)],
|
|
}),
|
|
(0, 0, {
|
|
'repartition_type': 'tax',
|
|
'tag_ids': [(6, 0, self.tax_tag_neg.ids)],
|
|
}),
|
|
],
|
|
})
|
|
|
|
inv_tax_rep_ln = sale_tax.invoice_repartition_line_ids.filtered(lambda x: x.repartition_type == 'tax')
|
|
ref_tax_rep_ln = sale_tax.refund_repartition_line_ids.filtered(lambda x: x.repartition_type == 'tax')
|
|
|
|
# === Tax in debit ===
|
|
|
|
move_form = Form(self.env['account.move'], view='account.view_move_form')
|
|
move_form.ref = 'azerty'
|
|
|
|
# Debit base tax line.
|
|
with move_form.line_ids.new() as credit_line:
|
|
credit_line.name = 'debit_line_1'
|
|
credit_line.account_id = self.company_data['default_account_revenue']
|
|
credit_line.debit = 1000.0
|
|
credit_line.tax_ids.clear()
|
|
credit_line.tax_ids.add(sale_tax)
|
|
|
|
|
|
# Balance the journal entry.
|
|
with move_form.line_ids.new() as credit_line:
|
|
credit_line.name = 'balance'
|
|
credit_line.account_id = self.company_data['default_account_revenue']
|
|
credit_line.credit = 1100.0
|
|
|
|
move = move_form.save()
|
|
|
|
self.assertRecordValues(move.line_ids.sorted('balance'), [
|
|
{'balance': -1100.0, 'tax_ids': [], 'tax_tag_ids': [], 'tax_base_amount': 0, 'tax_repartition_line_id': False, 'tax_tag_invert': False},
|
|
{'balance': 100.0, 'tax_ids': [], 'tax_tag_ids': self.tax_tag_neg.ids, 'tax_base_amount': 1000, 'tax_repartition_line_id': ref_tax_rep_ln.id, 'tax_tag_invert': False},
|
|
{'balance': 1000.0, 'tax_ids': sale_tax.ids, 'tax_tag_ids': self.base_tag_neg.ids, 'tax_base_amount': 0, 'tax_repartition_line_id': False, 'tax_tag_invert': False},
|
|
])
|
|
|
|
# === Tax in credit ===
|
|
|
|
move_form = Form(self.env['account.move'], view='account.view_move_form')
|
|
move_form.ref = 'azerty'
|
|
|
|
# Debit base tax line.
|
|
with move_form.line_ids.new() as credit_line:
|
|
credit_line.name = 'debit_line_1'
|
|
credit_line.account_id = self.company_data['default_account_revenue']
|
|
credit_line.credit = 1000.0
|
|
credit_line.tax_ids.clear()
|
|
credit_line.tax_ids.add(sale_tax)
|
|
|
|
# Balance the journal entry.
|
|
with move_form.line_ids.new() as debit_line:
|
|
debit_line.name = 'balance'
|
|
debit_line.account_id = self.company_data['default_account_revenue']
|
|
debit_line.debit = 1100.0
|
|
|
|
move = move_form.save()
|
|
|
|
self.assertRecordValues(move.line_ids.sorted('balance'), [
|
|
{'balance': -1000.0, 'tax_ids': sale_tax.ids, 'tax_tag_ids': self.base_tag_pos.ids, 'tax_base_amount': 0, 'tax_repartition_line_id': False, 'tax_tag_invert': True},
|
|
{'balance': -100.0, 'tax_ids': [], 'tax_tag_ids': self.tax_tag_pos.ids, 'tax_base_amount': 1000, 'tax_repartition_line_id': inv_tax_rep_ln.id, 'tax_tag_invert': True},
|
|
{'balance': 1100.0, 'tax_ids': [], 'tax_tag_ids': [], 'tax_base_amount': 0, 'tax_repartition_line_id': False, 'tax_tag_invert': False},
|
|
])
|
|
|
|
def test_misc_journal_entry_tax_tags_purchase(self):
|
|
purch_tax = self.env['account.tax'].create({
|
|
'name': 'tax',
|
|
'type_tax_use': 'purchase',
|
|
'amount_type': 'percent',
|
|
'amount': 10,
|
|
'invoice_repartition_line_ids': [
|
|
(0, 0, {
|
|
'repartition_type': 'base',
|
|
'tag_ids': [(6, 0, self.base_tag_pos.ids)],
|
|
}),
|
|
(0, 0, {
|
|
'repartition_type': 'tax',
|
|
'tag_ids': [(6, 0, self.tax_tag_pos.ids)],
|
|
}),
|
|
],
|
|
'refund_repartition_line_ids': [
|
|
(0, 0, {
|
|
'repartition_type': 'base',
|
|
'tag_ids': [(6, 0, self.base_tag_neg.ids)],
|
|
}),
|
|
(0, 0, {
|
|
'repartition_type': 'tax',
|
|
'tag_ids': [(6, 0, self.tax_tag_neg.ids)],
|
|
}),
|
|
],
|
|
})
|
|
|
|
inv_tax_rep_ln = purch_tax.invoice_repartition_line_ids.filtered(lambda x: x.repartition_type == 'tax')
|
|
ref_tax_rep_ln = purch_tax.refund_repartition_line_ids.filtered(lambda x: x.repartition_type == 'tax')
|
|
|
|
# === Tax in debit ===
|
|
|
|
move_form = Form(self.env['account.move'])
|
|
move_form.ref = 'azerty'
|
|
|
|
# Debit base tax line.
|
|
with move_form.line_ids.new() as credit_line:
|
|
credit_line.name = 'debit_line_1'
|
|
credit_line.account_id = self.company_data['default_account_revenue']
|
|
credit_line.debit = 1000.0
|
|
credit_line.tax_ids.clear()
|
|
credit_line.tax_ids.add(purch_tax)
|
|
|
|
# Balance the journal entry.
|
|
with move_form.line_ids.new() as credit_line:
|
|
credit_line.name = 'balance'
|
|
credit_line.account_id = self.company_data['default_account_revenue']
|
|
credit_line.credit = 1100.0
|
|
|
|
move = move_form.save()
|
|
|
|
self.assertRecordValues(move.line_ids.sorted('balance'), [
|
|
{'balance': -1100.0, 'tax_ids': [], 'tax_tag_ids': [], 'tax_base_amount': 0, 'tax_repartition_line_id': False, 'tax_tag_invert': False},
|
|
{'balance': 100.0, 'tax_ids': [], 'tax_tag_ids': self.tax_tag_pos.ids, 'tax_base_amount': 1000, 'tax_repartition_line_id': inv_tax_rep_ln.id, 'tax_tag_invert': False},
|
|
{'balance': 1000.0, 'tax_ids': purch_tax.ids, 'tax_tag_ids': self.base_tag_pos.ids, 'tax_base_amount': 0, 'tax_repartition_line_id': False, 'tax_tag_invert': False},
|
|
])
|
|
|
|
# === Tax in credit ===
|
|
|
|
move_form = Form(self.env['account.move'])
|
|
move_form.ref = 'azerty'
|
|
|
|
# Debit base tax line.
|
|
with move_form.line_ids.new() as credit_line:
|
|
credit_line.name = 'debit_line_1'
|
|
credit_line.account_id = self.company_data['default_account_revenue']
|
|
credit_line.credit = 1000.0
|
|
credit_line.tax_ids.clear()
|
|
credit_line.tax_ids.add(purch_tax)
|
|
|
|
# Balance the journal entry.
|
|
with move_form.line_ids.new() as debit_line:
|
|
debit_line.name = 'balance'
|
|
debit_line.account_id = self.company_data['default_account_revenue']
|
|
debit_line.debit = 1100.0
|
|
|
|
move = move_form.save()
|
|
|
|
self.assertRecordValues(move.line_ids.sorted('balance'), [
|
|
{'balance': -1000.0, 'tax_ids': purch_tax.ids, 'tax_tag_ids': self.base_tag_neg.ids, 'tax_base_amount': 0, 'tax_repartition_line_id': False, 'tax_tag_invert': True},
|
|
{'balance': -100.0, 'tax_ids': [], 'tax_tag_ids': self.tax_tag_neg.ids, 'tax_base_amount': 1000, 'tax_repartition_line_id': ref_tax_rep_ln.id, 'tax_tag_invert': True},
|
|
{'balance': 1100.0, 'tax_ids': [], 'tax_tag_ids': [], 'tax_base_amount': 0, 'tax_repartition_line_id': False, 'tax_tag_invert': False},
|
|
])
|
|
|
|
def test_misc_entry_tax_group_signs(self):
|
|
""" Tests sign inversion of the tags on misc operations made with tax
|
|
groups.
|
|
"""
|
|
def _create_group_of_taxes(tax_type):
|
|
# We use asymmetric tags between the child taxes to avoid shadowing errors
|
|
child1_sale_tax = self.env['account.tax'].create({
|
|
'sequence': 1,
|
|
'name': 'child1_%s' % tax_type,
|
|
'type_tax_use': 'none',
|
|
'amount_type': 'percent',
|
|
'amount': 5,
|
|
'invoice_repartition_line_ids': [
|
|
(0, 0, {
|
|
'repartition_type': 'base',
|
|
'tag_ids': [(6, 0, self.base_tag_pos.ids)],
|
|
}),
|
|
(0, 0, {
|
|
'repartition_type': 'tax',
|
|
'tag_ids': [(6, 0, self.tax_tag_pos.ids)],
|
|
}),
|
|
],
|
|
'refund_repartition_line_ids': [
|
|
(0, 0, {'repartition_type': 'base'}),
|
|
(0, 0, {'repartition_type': 'tax'}),
|
|
],
|
|
})
|
|
child2_sale_tax = self.env['account.tax'].create({
|
|
'sequence': 2,
|
|
'name': 'child2_%s' % tax_type,
|
|
'type_tax_use': 'none',
|
|
'amount_type': 'percent',
|
|
'amount': 10,
|
|
'invoice_repartition_line_ids': [
|
|
(0, 0, {'repartition_type': 'base'}),
|
|
(0, 0, {'repartition_type': 'tax'}),
|
|
],
|
|
'refund_repartition_line_ids': [
|
|
(0, 0, {
|
|
'repartition_type': 'base',
|
|
'tag_ids': [(6, 0, self.base_tag_neg.ids)],
|
|
}),
|
|
(0, 0, {
|
|
'repartition_type': 'tax',
|
|
'tag_ids': [(6, 0, self.tax_tag_neg.ids)],
|
|
}),
|
|
],
|
|
})
|
|
return self.env['account.tax'].create({
|
|
'name': 'group_%s' % tax_type,
|
|
'type_tax_use': tax_type,
|
|
'amount_type': 'group',
|
|
'amount': 10,
|
|
'children_tax_ids':[(6,0,[child1_sale_tax.id, child2_sale_tax.id])]
|
|
})
|
|
|
|
def _create_misc_operation(tax, tax_field):
|
|
with Form(self.env['account.move'], view='account.view_move_form') as move_form:
|
|
for line_field in ('debit', 'credit'):
|
|
line_amount = tax_field == line_field and 1000 or 1150
|
|
with move_form.line_ids.new() as line_form:
|
|
line_form.name = '%s_line' % line_field
|
|
line_form.account_id = self.company_data['default_account_revenue']
|
|
line_form.debit = line_field == 'debit' and line_amount or 0
|
|
line_form.credit = line_field == 'credit' and line_amount or 0
|
|
|
|
if tax_field == line_field:
|
|
line_form.tax_ids.clear()
|
|
line_form.tax_ids.add(tax)
|
|
|
|
return move_form.save()
|
|
|
|
sale_group = _create_group_of_taxes('sale')
|
|
purchase_group = _create_group_of_taxes('purchase')
|
|
|
|
# Sale tax on debit: use refund repartition
|
|
debit_sale_move = _create_misc_operation(sale_group, 'debit')
|
|
self.assertRecordValues(debit_sale_move.line_ids.sorted('balance'), [
|
|
{'balance': -1150.0, 'tax_ids': [], 'tax_tag_ids': [], 'tax_base_amount': 0},
|
|
{'balance': 50.0, 'tax_ids': [], 'tax_tag_ids': [], 'tax_base_amount': 1000},
|
|
{'balance': 100.0, 'tax_ids': [], 'tax_tag_ids': self.tax_tag_neg.ids, 'tax_base_amount': 1000},
|
|
{'balance': 1000.0, 'tax_ids': sale_group.ids, 'tax_tag_ids': self.base_tag_neg.ids, 'tax_base_amount': 0},
|
|
])
|
|
|
|
# Sale tax on credit: use invoice repartition
|
|
credit_sale_move = _create_misc_operation(sale_group, 'credit')
|
|
self.assertRecordValues(credit_sale_move.line_ids.sorted('balance'), [
|
|
{'balance': -1000.0, 'tax_ids': sale_group.ids, 'tax_tag_ids': self.base_tag_pos.ids, 'tax_base_amount': 0},
|
|
{'balance': -100.0, 'tax_ids': [], 'tax_tag_ids': [], 'tax_base_amount': 1000},
|
|
{'balance': -50.0, 'tax_ids': [], 'tax_tag_ids': self.tax_tag_pos.ids, 'tax_base_amount': 1000},
|
|
{'balance': 1150.0, 'tax_ids': [], 'tax_tag_ids': [], 'tax_base_amount': 0},
|
|
])
|
|
|
|
# Purchase tax on debit: use invoice repartition
|
|
debit_purchase_move = _create_misc_operation(purchase_group, 'debit')
|
|
self.assertRecordValues(debit_purchase_move.line_ids.sorted('balance'), [
|
|
{'balance': -1150.0, 'tax_ids': [], 'tax_tag_ids': [], 'tax_base_amount': 0},
|
|
{'balance': 50.0, 'tax_ids': [], 'tax_tag_ids': self.tax_tag_pos.ids, 'tax_base_amount': 1000},
|
|
{'balance': 100.0, 'tax_ids': [], 'tax_tag_ids': [], 'tax_base_amount': 1000},
|
|
{'balance': 1000.0, 'tax_ids': purchase_group.ids, 'tax_tag_ids': self.base_tag_pos.ids, 'tax_base_amount': 0},
|
|
])
|
|
|
|
# Purchase tax on credit: use refund repartition
|
|
credit_purchase_move = _create_misc_operation(purchase_group, 'credit')
|
|
self.assertRecordValues(credit_purchase_move.line_ids.sorted('balance'), [
|
|
{'balance': -1000.0, 'tax_ids': purchase_group.ids, 'tax_tag_ids': self.base_tag_neg.ids, 'tax_base_amount': 0},
|
|
{'balance': -100.0, 'tax_ids': [], 'tax_tag_ids': self.tax_tag_neg.ids, 'tax_base_amount': 1000},
|
|
{'balance': -50.0, 'tax_ids': [], 'tax_tag_ids': [], 'tax_base_amount': 1000},
|
|
{'balance': 1150.0, 'tax_ids': [], 'tax_tag_ids': [], 'tax_base_amount': 0},
|
|
])
|
|
|
|
def test_tax_calculation_foreign_currency_large_quantity(self):
|
|
''' Test:
|
|
Foreign currency with rate of 1.1726 and tax of 21%
|
|
price_unit | Quantity | Taxes
|
|
------------------
|
|
2.82 | 20000 | 21% not incl
|
|
'''
|
|
self.env['res.currency.rate'].create({
|
|
'name': '2018-01-01',
|
|
'rate': 1.1726,
|
|
'currency_id': self.currency_data['currency'].id,
|
|
'company_id': self.env.company.id,
|
|
})
|
|
self.currency_data['currency'].rounding = 0.05
|
|
|
|
invoice = self.env['account.move'].create({
|
|
'move_type': 'out_invoice',
|
|
'partner_id': self.partner_a.id,
|
|
'currency_id': self.currency_data['currency'].id,
|
|
'invoice_date': '2018-01-01',
|
|
'date': '2018-01-01',
|
|
'invoice_line_ids': [(0, 0, {
|
|
'name': 'xxxx',
|
|
'quantity': 20000,
|
|
'price_unit': 2.82,
|
|
'tax_ids': [(6, 0, self.percent_tax_1.ids)],
|
|
})]
|
|
})
|
|
|
|
self.assertRecordValues(invoice.line_ids.filtered('tax_line_id'), [{
|
|
'tax_base_amount': 48098.24, # 20000 * 2.82 / 1.1726
|
|
'credit': 10100.63, # tax_base_amount * 0.21
|
|
}])
|
|
|
|
def test_ensure_no_unbalanced_entry(self):
|
|
''' Ensure to not create an unbalanced journal entry when saving. '''
|
|
self.env['res.currency.rate'].create({
|
|
'name': '2018-01-01',
|
|
'rate': 0.654065014,
|
|
'currency_id': self.currency_data['currency'].id,
|
|
'company_id': self.env.company.id,
|
|
})
|
|
self.currency_data['currency'].rounding = 0.05
|
|
|
|
invoice = self._create_invoice([
|
|
(5, self.percent_tax_3_incl),
|
|
(10, self.percent_tax_3_incl),
|
|
(50, self.percent_tax_3_incl),
|
|
], currency_id=self.currency_data['currency'], invoice_payment_term_id=self.pay_terms_a)
|
|
invoice.action_post()
|
|
|
|
def test_tax_calculation_multi_currency(self):
|
|
self.env['res.currency.rate'].create({
|
|
'name': '2018-01-01',
|
|
'rate': 0.273748,
|
|
'currency_id': self.currency_data['currency'].id,
|
|
'company_id': self.env.company.id,
|
|
})
|
|
self.currency_data['currency'].rounding = 0.01
|
|
|
|
invoice = self.env['account.move'].create({
|
|
'move_type': 'out_invoice',
|
|
'partner_id': self.partner_a.id,
|
|
'currency_id': self.currency_data['currency'].id,
|
|
'invoice_date': '2018-01-01',
|
|
'date': '2018-01-01',
|
|
'invoice_line_ids': [(0, 0, {
|
|
'name': 'xxxx',
|
|
'quantity': 1,
|
|
'price_unit': 155.32,
|
|
'tax_ids': [(6, 0, self.percent_tax_1.ids)],
|
|
})]
|
|
})
|
|
|
|
self.assertRecordValues(invoice.line_ids.filtered('tax_line_id'), [{
|
|
'tax_base_amount': 567.38, # 155.32 * 1 / (1 / 0.273748)
|
|
'balance': -119.16, # tax_base_amount * 0.21
|
|
}])
|
|
|
|
self.assertRecordValues(invoice.line_ids.filtered(lambda l: not l.name), [{
|
|
'balance': 686.54,
|
|
}])
|
|
|
|
with Form(invoice) as invoice_form:
|
|
invoice_form.currency_id = self.currency_data['currency']
|
|
|
|
self.assertRecordValues(invoice.line_ids.filtered('tax_line_id'), [{
|
|
'tax_base_amount': 567.38,
|
|
'balance': -119.16,
|
|
}])
|
|
|
|
self.assertRecordValues(invoice.line_ids.filtered(lambda l: l.account_id.account_type == 'asset_receivable'), [{
|
|
'balance': 686.54,
|
|
}])
|
|
|
|
def test_fixed_tax_with_zero_price(self):
|
|
fixed_tax = self.env['account.tax'].create({
|
|
'name': 'Test 5 fixed',
|
|
'amount_type': 'fixed',
|
|
'amount': 5,
|
|
})
|
|
invoice = self._create_invoice([
|
|
(0, fixed_tax),
|
|
])
|
|
self.assertRecordValues(invoice.line_ids.filtered('tax_line_id'), [{
|
|
'credit': 5.0,
|
|
'debit': 0,
|
|
}])
|
|
invoice.invoice_line_ids.quantity = 2
|
|
self.assertRecordValues(invoice.line_ids.filtered('tax_line_id'), [{
|
|
'credit': 10.0,
|
|
'debit': 0,
|
|
}])
|