summaryrefslogtreecommitdiff
path: root/addons/account/tests/test_tax.py
diff options
context:
space:
mode:
Diffstat (limited to 'addons/account/tests/test_tax.py')
-rw-r--r--addons/account/tests/test_tax.py1075
1 files changed, 1075 insertions, 0 deletions
diff --git a/addons/account/tests/test_tax.py b/addons/account/tests/test_tax.py
new file mode 100644
index 00000000..068031ce
--- /dev/null
+++ b/addons/account/tests/test_tax.py
@@ -0,0 +1,1075 @@
+# -*- coding: utf-8 -*-
+from odoo.addons.account.tests.common import AccountTestInvoicingCommon
+from odoo.tests import tagged
+
+
+@tagged('post_install', '-at_install')
+class TestTaxCommon(AccountTestInvoicingCommon):
+
+ @classmethod
+ def setUpClass(cls, chart_template_ref=None):
+ super().setUpClass(chart_template_ref=chart_template_ref)
+
+ # Setup another company having a rounding of 1.0.
+ cls.currency_data['currency'].rounding = 1.0
+ cls.currency_no_decimal = cls.currency_data['currency']
+ cls.company_data_2 = cls.setup_company_data('company_2', currency_id=cls.currency_no_decimal.id)
+ cls.env.user.company_id = cls.company_data['company']
+
+ cls.fixed_tax = cls.env['account.tax'].create({
+ 'name': "Fixed tax",
+ 'amount_type': 'fixed',
+ 'amount': 10,
+ 'sequence': 1,
+ })
+ cls.fixed_tax_bis = cls.env['account.tax'].create({
+ 'name': "Fixed tax bis",
+ 'amount_type': 'fixed',
+ 'amount': 15,
+ 'sequence': 2,
+ })
+ cls.percent_tax = cls.env['account.tax'].create({
+ 'name': "Percent tax",
+ 'amount_type': 'percent',
+ 'amount': 10,
+ 'sequence': 3,
+ })
+ cls.percent_tax_bis = cls.env['account.tax'].create({
+ 'name': "Percent tax bis",
+ 'amount_type': 'percent',
+ 'amount': 10,
+ 'sequence': 4,
+ })
+ cls.division_tax = cls.env['account.tax'].create({
+ 'name': "Division tax",
+ 'amount_type': 'division',
+ 'amount': 10,
+ 'sequence': 4,
+ })
+ cls.group_tax = cls.env['account.tax'].create({
+ 'name': "Group tax",
+ 'amount_type': 'group',
+ 'amount': 0,
+ 'sequence': 5,
+ 'children_tax_ids': [
+ (4, cls.fixed_tax.id, 0),
+ (4, cls.percent_tax.id, 0)
+ ]
+ })
+ cls.group_tax_bis = cls.env['account.tax'].create({
+ 'name': "Group tax bis",
+ 'amount_type': 'group',
+ 'amount': 0,
+ 'sequence': 6,
+ 'children_tax_ids': [
+ (4, cls.fixed_tax.id, 0),
+ (4, cls.percent_tax.id, 0)
+ ]
+ })
+ cls.group_tax_percent = cls.env['account.tax'].create({
+ 'name': "Group tax percent",
+ 'amount_type': 'group',
+ 'amount': 0,
+ 'sequence': 6,
+ 'children_tax_ids': [
+ (4, cls.percent_tax.id, 0),
+ (4, cls.percent_tax_bis.id, 0)
+ ]
+ })
+ cls.group_of_group_tax = cls.env['account.tax'].create({
+ 'name': "Group of group tax",
+ 'amount_type': 'group',
+ 'amount': 0,
+ 'sequence': 7,
+ 'children_tax_ids': [
+ (4, cls.group_tax.id, 0),
+ (4, cls.group_tax_bis.id, 0)
+ ]
+ })
+ cls.tax_with_no_account = cls.env['account.tax'].create({
+ 'name': "Tax with no account",
+ 'amount_type': 'fixed',
+ 'amount': 0,
+ 'sequence': 8,
+ })
+ some_account = cls.env['account.account'].search([], limit=1)
+ cls.tax_with_account = cls.env['account.tax'].create({
+ 'name': "Tax with account",
+ 'amount_type': 'fixed',
+ 'amount': 0,
+ 'sequence': 8,
+ 'invoice_repartition_line_ids': [
+ (0,0, {
+ 'factor_percent': 100,
+ 'repartition_type': 'base',
+ }),
+
+ (0,0, {
+ 'factor_percent': 100,
+ 'repartition_type': 'tax',
+ 'account_id': some_account.id,
+ }),
+ ],
+ 'refund_repartition_line_ids': [
+ (0,0, {
+ 'factor_percent': 100,
+ 'repartition_type': 'base',
+ }),
+
+ (0,0, {
+ 'factor_percent': 100,
+ 'repartition_type': 'tax',
+ 'account_id': some_account.id,
+ }),
+ ],
+ })
+
+ cls.tax_0_percent = cls.env['account.tax'].with_company(cls.company_data['company']).create({
+ 'name': "test_0_percent",
+ 'amount_type': 'percent',
+ 'amount': 0,
+ })
+
+ cls.tax_5_percent = cls.env['account.tax'].with_company(cls.company_data['company']).create({
+ 'name': "test_5_percent",
+ 'amount_type': 'percent',
+ 'amount': 5,
+ })
+
+ cls.tax_8_percent = cls.env['account.tax'].with_company(cls.company_data['company']).create({
+ 'name': "test_8_percent",
+ 'amount_type': 'percent',
+ 'amount': 8,
+ })
+ cls.tax_12_percent = cls.env['account.tax'].with_company(cls.company_data['company']).create({
+ 'name': "test_12_percent",
+ 'amount_type': 'percent',
+ 'amount': 12,
+ })
+
+ cls.tax_19_percent = cls.env['account.tax'].with_company(cls.company_data_2['company']).create({
+ 'name': "test_19_percent",
+ 'amount_type': 'percent',
+ 'amount': 19,
+ })
+
+ cls.tax_21_percent = cls.env['account.tax'].with_company(cls.company_data['company']).create({
+ 'name': "test_21_percent",
+ 'amount_type': 'percent',
+ 'amount': 19,
+ })
+
+ cls.tax_21_percent = cls.env['account.tax'].with_company(cls.company_data['company']).create({
+ 'name': "test_rounding_methods_2",
+ 'amount_type': 'percent',
+ 'amount': 21,
+ })
+
+ cls.bank_journal = cls.company_data['default_journal_bank']
+ cls.bank_account = cls.bank_journal.default_account_id
+ cls.expense_account = cls.company_data['default_account_expense']
+
+ def _check_compute_all_results(self, total_included, total_excluded, taxes, res):
+ self.assertAlmostEqual(res['total_included'], total_included)
+ self.assertAlmostEqual(res['total_excluded'], total_excluded)
+ for i in range(0, len(taxes)):
+ self.assertAlmostEqual(res['taxes'][i]['base'], taxes[i][0])
+ self.assertAlmostEqual(res['taxes'][i]['amount'], taxes[i][1])
+
+
+@tagged('post_install', '-at_install')
+class TestTax(TestTaxCommon):
+
+ @classmethod
+ def setUpClass(cls):
+ super(TestTax, cls).setUpClass()
+
+ def test_tax_group_of_group_tax(self):
+ self.fixed_tax.include_base_amount = True
+ res = self.group_of_group_tax.compute_all(200.0)
+ self._check_compute_all_results(
+ 263, # 'total_included'
+ 200, # 'total_excluded'
+ [
+ # base , amount | seq | amount | incl | incl_base
+ # ---------------------------------------------------
+ (200.0, 10.0), # | 1 | 10 | | t
+ (210.0, 21.0), # | 3 | 10% | |
+ (210.0, 10.0), # | 1 | 10 | | t
+ (220.0, 22.0), # | 3 | 10% | |
+ # ---------------------------------------------------
+ ],
+ res
+ )
+
+ def test_tax_group(self):
+ res = self.group_tax.compute_all(200.0)
+ self._check_compute_all_results(
+ 230, # 'total_included'
+ 200, # 'total_excluded'
+ [
+ # base , amount | seq | amount | incl | incl_base
+ # ---------------------------------------------------
+ (200.0, 10.0), # | 1 | 10 | |
+ (200.0, 20.0), # | 3 | 10% | |
+ # ---------------------------------------------------
+ ],
+ res
+ )
+
+ def test_tax_group_percent(self):
+ res = self.group_tax_percent.with_context({'force_price_include':True}).compute_all(100.0)
+ self._check_compute_all_results(
+ 100, # 'total_included'
+ 83.33, # 'total_excluded'
+ [
+ # base , amount | seq | amount | incl | incl_base
+ # ---------------------------------------------------
+ (83.33, 8.33), # | 1 | 10% | |
+ (83.33, 8.34), # | 2 | 10% | |
+ # ---------------------------------------------------
+ ],
+ res
+ )
+
+ def test_tax_percent_division(self):
+ self.division_tax.price_include = True
+ self.division_tax.include_base_amount = True
+ res_division = self.division_tax.compute_all(200.0)
+ self._check_compute_all_results(
+ 200, # 'total_included'
+ 180, # 'total_excluded'
+ [
+ # base , amount | seq | amount | incl | incl_base
+ # ---------------------------------------------------
+ (180.0, 20.0), # | 4 | 10/ | t | t
+ # ---------------------------------------------------
+ ],
+ res_division
+ )
+ self.percent_tax.price_include = False
+ self.percent_tax.include_base_amount = False
+ res_percent = self.percent_tax.compute_all(100.0)
+ self._check_compute_all_results(
+ 110, # 'total_included'
+ 100, # 'total_excluded'
+ [
+ # base , amount | seq | amount | incl | incl_base
+ # ---------------------------------------------------
+ (100.0, 10.0), # | 3 | 10% | |
+ # ---------------------------------------------------
+ ],
+ res_percent
+ )
+ self.division_tax.price_include = False
+ self.division_tax.include_base_amount = False
+ res_division = self.division_tax.compute_all(180.0)
+ self._check_compute_all_results(
+ 200, # 'total_included'
+ 180, # 'total_excluded'
+ [
+ # base, amount | seq | amount | incl | incl_base
+ # ---------------------------------------------------
+ (180.0, 20.0), # | 4 | 10/ | |
+ # ---------------------------------------------------
+ ],
+ res_division
+ )
+ self.percent_tax.price_include = True
+ self.percent_tax.include_base_amount = True
+ res_percent = self.percent_tax.compute_all(110.0)
+ self._check_compute_all_results(
+ 110, # 'total_included'
+ 100, # 'total_excluded'
+ [
+ # base, amount | seq | amount | incl | incl_base
+ # ---------------------------------------------------
+ (100.0, 10.0), # | 3 | 10% | t | t
+ # ---------------------------------------------------
+ ],
+ res_percent
+ )
+ self.percent_tax_bis.price_include = True
+ self.percent_tax_bis.include_base_amount = True
+ self.percent_tax_bis.amount = 21
+ res_percent = self.percent_tax_bis.compute_all(7.0)
+ self._check_compute_all_results(
+ 7.0, # 'total_included'
+ 5.79, # 'total_excluded'
+ [
+ # base , amount | seq | amount | incl | incl_base
+ # ---------------------------------------------------
+ (5.79, 1.21), # | 3 | 21% | t | t
+ # ---------------------------------------------------
+ ],
+ res_percent
+ )
+
+ def test_tax_sequence_normalized_set(self):
+ self.division_tax.sequence = 1
+ self.fixed_tax.sequence = 2
+ self.percent_tax.sequence = 3
+ taxes_set = (self.group_tax | self.division_tax)
+ res = taxes_set.compute_all(200.0)
+ self._check_compute_all_results(
+ 252.22, # 'total_included'
+ 200, # 'total_excluded'
+ [
+ # base , amount | seq | amount | incl | incl_base
+ # ---------------------------------------------------
+ (200.0, 22.22), # | 1 | 10/ | |
+ (200.0, 10.0), # | 2 | 10 | |
+ (200.0, 20.0), # | 3 | 10% | |
+ # ---------------------------------------------------
+ ],
+ res
+ )
+
+ def test_fixed_tax_include_base_amount(self):
+ self.fixed_tax.include_base_amount = True
+ res = self.group_tax.compute_all(200.0)
+ self._check_compute_all_results(
+ 231, # 'total_included'
+ 200, # 'total_excluded'
+ [
+ # base , amount | seq | amount | incl | incl_base
+ # ---------------------------------------------------
+ (200.0, 10.0), # | 1 | 10 | | t
+ (210.0, 21.0), # | 3 | 10% | |
+ # ---------------------------------------------------
+ ],
+ res
+ )
+
+ self.fixed_tax.price_include = True
+ self.fixed_tax.include_base_amount = False
+ res = self.fixed_tax.compute_all(100.0, quantity=2.0)
+ self._check_compute_all_results(
+ 200, # 'total_included'
+ 180, # 'total_excluded'
+ [
+ # base , amount | seq | amount | incl | incl_base
+ # ---------------------------------------------------
+ (180.0, 20.0), # | 1 | 20 | | t
+ # ---------------------------------------------------
+ ],
+ res
+ )
+
+ def test_percent_tax_include_base_amount(self):
+ self.percent_tax.price_include = True
+ self.percent_tax.amount = 21.0
+ res = self.percent_tax.compute_all(7.0)
+ self._check_compute_all_results(
+ 7.0, # 'total_included'
+ 5.79, # 'total_excluded'
+ [
+ # base , amount | seq | amount | incl | incl_base
+ # ---------------------------------------------------
+ (5.79, 1.21), # | 3 | 21% | t |
+ # ---------------------------------------------------
+ ],
+ res
+ )
+
+ self.percent_tax.price_include = True
+ self.percent_tax.amount = 20.0
+ res = self.percent_tax.compute_all(399.99)
+ self._check_compute_all_results(
+ 399.99, # 'total_included'
+ 333.33, # 'total_excluded'
+ [
+ # base , amount | seq | amount | incl | incl_base
+ # ---------------------------------------------------
+ (333.33, 66.66), # | 3 | 20% | t |
+ # ---------------------------------------------------
+ ],
+ res
+ )
+
+ def test_tax_decimals(self):
+ """Test the rounding of taxes up to 6 decimals (maximum decimals places allowed for currencies)"""
+ self.env.user.company_id.currency_id.rounding = 0.000001
+
+ self.percent_tax.price_include = True
+ self.percent_tax.amount = 21.0
+ res = self.percent_tax.compute_all(7.0)
+ self._check_compute_all_results(
+ 7.0, # 'total_included'
+ 5.785124, # 'total_excluded'
+ [
+ # base , amount | seq | amount | incl | incl_base
+ # --------------------------------------------------------
+ (5.785124, 1.214876), # | 3 | 21% | t |
+ # --------------------------------------------------------
+ ],
+ res
+ )
+
+ self.percent_tax.price_include = True
+ self.percent_tax.amount = 20.0
+ res = self.percent_tax.compute_all(399.999999)
+ self._check_compute_all_results(
+ 399.999999, # 'total_included'
+ 333.333333, # 'total_excluded'
+ [
+ # base , amount | seq | amount | incl | incl_base
+ # -----------------------------------------------------------
+ (333.333333, 66.666666), # | 3 | 20% | t |
+ # -----------------------------------------------------------
+ ],
+ res
+ )
+
+ def test_advanced_taxes_computation_0(self):
+ '''Test more advanced taxes computation (see issue 34471).'''
+ tax_1 = self.env['account.tax'].create({
+ 'name': 'test_advanced_taxes_computation_0_1',
+ 'amount_type': 'percent',
+ 'amount': 10,
+ 'price_include': True,
+ 'include_base_amount': True,
+ 'sequence': 1,
+ 'invoice_repartition_line_ids': [
+ (0, 0, {'repartition_type': 'base', 'factor_percent': 100.0}),
+ (0, 0, {'repartition_type': 'tax', 'factor_percent': 50.0}),
+ (0, 0, {'repartition_type': 'tax', 'factor_percent': 50.0}),
+ ],
+ 'refund_repartition_line_ids': [
+ (0, 0, {'repartition_type': 'base', 'factor_percent': 100.0}),
+ (0, 0, {'repartition_type': 'tax', 'factor_percent': 50.0}),
+ (0, 0, {'repartition_type': 'tax', 'factor_percent': 50.0}),
+ ],
+ })
+ tax_2 = self.env['account.tax'].create({
+ 'name': 'test_advanced_taxes_computation_0_2',
+ 'amount_type': 'percent',
+ 'amount': 10,
+ 'sequence': 2,
+ 'invoice_repartition_line_ids': [
+ (0, 0, {'repartition_type': 'base', 'factor_percent': 100.0}),
+ (0, 0, {'repartition_type': 'tax', 'factor_percent': 50.0}),
+ (0, 0, {'repartition_type': 'tax', 'factor_percent': 50.0}),
+ ],
+ 'refund_repartition_line_ids': [
+ (0, 0, {'repartition_type': 'base', 'factor_percent': 100.0}),
+ (0, 0, {'repartition_type': 'tax', 'factor_percent': 50.0}),
+ (0, 0, {'repartition_type': 'tax', 'factor_percent': 50.0}),
+ ],
+ })
+ tax_3 = self.env['account.tax'].create({
+ 'name': 'test_advanced_taxes_computation_0_3',
+ 'amount_type': 'percent',
+ 'amount': 10,
+ 'price_include': True,
+ 'sequence': 3,
+ 'invoice_repartition_line_ids': [
+ (0, 0, {'repartition_type': 'base', 'factor_percent': 100.0}),
+ (0, 0, {'repartition_type': 'tax', 'factor_percent': 50.0}),
+ (0, 0, {'repartition_type': 'tax', 'factor_percent': 50.0}),
+ ],
+ 'refund_repartition_line_ids': [
+ (0, 0, {'repartition_type': 'base', 'factor_percent': 100.0}),
+ (0, 0, {'repartition_type': 'tax', 'factor_percent': 50.0}),
+ (0, 0, {'repartition_type': 'tax', 'factor_percent': 50.0}),
+ ],
+ })
+ tax_4 = self.env['account.tax'].create({
+ 'name': 'test_advanced_taxes_computation_0_4',
+ 'amount_type': 'percent',
+ 'amount': 10,
+ 'sequence': 4,
+ 'invoice_repartition_line_ids': [
+ (0, 0, {'repartition_type': 'base', 'factor_percent': 100.0}),
+ (0, 0, {'repartition_type': 'tax', 'factor_percent': 50.0}),
+ (0, 0, {'repartition_type': 'tax', 'factor_percent': 50.0}),
+ ],
+ 'refund_repartition_line_ids': [
+ (0, 0, {'repartition_type': 'base', 'factor_percent': 100.0}),
+ (0, 0, {'repartition_type': 'tax', 'factor_percent': 50.0}),
+ (0, 0, {'repartition_type': 'tax', 'factor_percent': 50.0}),
+ ],
+ })
+ tax_5 = self.env['account.tax'].create({
+ 'name': 'test_advanced_taxes_computation_0_5',
+ 'amount_type': 'percent',
+ 'amount': 10,
+ 'price_include': True,
+ 'sequence': 5,
+ 'invoice_repartition_line_ids': [
+ (0, 0, {'repartition_type': 'base', 'factor_percent': 100.0}),
+ (0, 0, {'repartition_type': 'tax', 'factor_percent': 50.0}),
+ (0, 0, {'repartition_type': 'tax', 'factor_percent': 50.0}),
+ ],
+ 'refund_repartition_line_ids': [
+ (0, 0, {'repartition_type': 'base', 'factor_percent': 100.0}),
+ (0, 0, {'repartition_type': 'tax', 'factor_percent': 50.0}),
+ (0, 0, {'repartition_type': 'tax', 'factor_percent': 50.0}),
+ ],
+ })
+ taxes = tax_1 + tax_2 + tax_3 + tax_4 + tax_5
+
+ # Test with positive amount.
+ self._check_compute_all_results(
+ 154, # 'total_included'
+ 100, # 'total_excluded'
+ [
+ # base , amount | seq | amount | incl | incl_base
+ # ---------------------------------------------------
+ (100.0, 5.0), # | 1 | 10% | t | t
+ (100.0, 5.0), # | 1 | 10% | t | t
+ (110.0, 5.5), # | 2 | 10% | |
+ (110.0, 5.5), # | 2 | 10% | |
+ (110.0, 5.5), # | 3 | 10% | t |
+ (110.0, 5.5), # | 3 | 10% | t |
+ (110.0, 5.5), # | 4 | 10% | |
+ (110.0, 5.5), # | 4 | 10% | |
+ (110.0, 5.5), # | 5 | 10% | t |
+ (110.0, 5.5), # | 5 | 10% | t |
+ # ---------------------------------------------------
+ ],
+ taxes.compute_all(132.0)
+ )
+
+ # Test with negative amount.
+ self._check_compute_all_results(
+ -154, # 'total_included'
+ -100, # 'total_excluded'
+ [
+ # base , amount | seq | amount | incl | incl_base
+ # ---------------------------------------------------
+ (-100.0, -5.0), # | 1 | 10% | t | t
+ (-100.0, -5.0), # | 1 | 10% | t | t
+ (-110.0, -5.5), # | 2 | 10% | |
+ (-110.0, -5.5), # | 2 | 10% | |
+ (-110.0, -5.5), # | 3 | 10% | t |
+ (-110.0, -5.5), # | 3 | 10% | t |
+ (-110.0, -5.5), # | 4 | 10% | |
+ (-110.0, -5.5), # | 4 | 10% | |
+ (-110.0, -5.5), # | 5 | 10% | t |
+ (-110.0, -5.5), # | 5 | 10% | t |
+ # ---------------------------------------------------
+ ],
+ taxes.compute_all(-132.0)
+ )
+
+ def test_intracomm_taxes_computation_0(self):
+ ''' Test usage of intracomm taxes having e.g.+100%, -100% as repartition lines. '''
+ intracomm_tax = self.env['account.tax'].create({
+ 'name': 'test_intracomm_taxes_computation_0_1',
+ 'amount_type': 'percent',
+ 'amount': 21,
+ 'invoice_repartition_line_ids': [
+ (0, 0, {'repartition_type': 'base', 'factor_percent': 100.0}),
+ (0, 0, {'repartition_type': 'tax', 'factor_percent': 100.0}),
+ (0, 0, {'repartition_type': 'tax', 'factor_percent': -100.0}),
+ ],
+ 'refund_repartition_line_ids': [
+ (0, 0, {'repartition_type': 'base', 'factor_percent': 100.0}),
+ (0, 0, {'repartition_type': 'tax', 'factor_percent': 100.0}),
+ (0, 0, {'repartition_type': 'tax', 'factor_percent': -100.0}),
+ ],
+ })
+
+ # Test with positive amount.
+ self._check_compute_all_results(
+ 100, # 'total_included'
+ 100, # 'total_excluded'
+ [
+ # base , amount
+ # ---------------
+ (100.0, 21.0),
+ (100.0, -21.0),
+ # ---------------
+ ],
+ intracomm_tax.compute_all(100.0)
+ )
+
+ # Test with negative amount.
+ self._check_compute_all_results(
+ -100, # 'total_included'
+ -100, # 'total_excluded'
+ [
+ # base , amount
+ # ---------------
+ (-100.0, -21.0),
+ (-100.0, 21.0),
+ # ---------------
+ ],
+ intracomm_tax.compute_all(-100.0)
+ )
+
+ def test_rounding_issues_0(self):
+ ''' Test taxes having a complex setup of repartition lines. '''
+ tax = self.env['account.tax'].create({
+ 'name': 'test_rounding_issues_0',
+ 'amount_type': 'percent',
+ 'amount': 3,
+ 'invoice_repartition_line_ids': [
+ (0, 0, {'repartition_type': 'base', 'factor_percent': 100.0}),
+ (0, 0, {'repartition_type': 'tax', 'factor_percent': 50.0}),
+ (0, 0, {'repartition_type': 'tax', 'factor_percent': 50.0}),
+ (0, 0, {'repartition_type': 'tax', 'factor_percent': 50.0}),
+ (0, 0, {'repartition_type': 'tax', 'factor_percent': 50.0}),
+ (0, 0, {'repartition_type': 'tax', 'factor_percent': 50.0}),
+ (0, 0, {'repartition_type': 'tax', 'factor_percent': 50.0}),
+ ],
+ 'refund_repartition_line_ids': [
+ (0, 0, {'repartition_type': 'base', 'factor_percent': 100.0}),
+ (0, 0, {'repartition_type': 'tax', 'factor_percent': 50.0}),
+ (0, 0, {'repartition_type': 'tax', 'factor_percent': 50.0}),
+ (0, 0, {'repartition_type': 'tax', 'factor_percent': 50.0}),
+ (0, 0, {'repartition_type': 'tax', 'factor_percent': 50.0}),
+ (0, 0, {'repartition_type': 'tax', 'factor_percent': 50.0}),
+ (0, 0, {'repartition_type': 'tax', 'factor_percent': 50.0}),
+ ],
+ })
+
+ # Test with positive amount.
+ self._check_compute_all_results(
+ 1.09, # 'total_included'
+ 1, # 'total_excluded'
+ [
+ # base , amount
+ # ---------------
+ (1.0, 0.01),
+ (1.0, 0.01),
+ (1.0, 0.01),
+ (1.0, 0.02),
+ (1.0, 0.02),
+ (1.0, 0.02),
+ # ---------------
+ ],
+ tax.compute_all(1.0)
+ )
+
+ # Test with negative amount.
+ self._check_compute_all_results(
+ -1.09, # 'total_included'
+ -1, # 'total_excluded'
+ [
+ # base , amount
+ # ---------------
+ (-1.0, -0.01),
+ (-1.0, -0.01),
+ (-1.0, -0.01),
+ (-1.0, -0.02),
+ (-1.0, -0.02),
+ (-1.0, -0.02),
+ # ---------------
+ ],
+ tax.compute_all(-1.0)
+ )
+
+ def test_rounding_issues_1(self):
+ ''' Test taxes having a complex setup of repartition lines. '''
+ tax = self.env['account.tax'].create({
+ 'name': 'test_advanced_taxes_repartition_lines_computation_1',
+ 'amount_type': 'percent',
+ 'amount': 3,
+ 'invoice_repartition_line_ids': [
+ (0, 0, {'repartition_type': 'base', 'factor_percent': 100.0}),
+ (0, 0, {'repartition_type': 'tax', 'factor_percent': 50.0}),
+ (0, 0, {'repartition_type': 'tax', 'factor_percent': -50.0}),
+ (0, 0, {'repartition_type': 'tax', 'factor_percent': 25.0}),
+ (0, 0, {'repartition_type': 'tax', 'factor_percent': 25.0}),
+ (0, 0, {'repartition_type': 'tax', 'factor_percent': -25.0}),
+ (0, 0, {'repartition_type': 'tax', 'factor_percent': -25.0}),
+ ],
+ 'refund_repartition_line_ids': [
+ (0, 0, {'repartition_type': 'base', 'factor_percent': 100.0}),
+ (0, 0, {'repartition_type': 'tax', 'factor_percent': 50.0}),
+ (0, 0, {'repartition_type': 'tax', 'factor_percent': -50.0}),
+ (0, 0, {'repartition_type': 'tax', 'factor_percent': 25.0}),
+ (0, 0, {'repartition_type': 'tax', 'factor_percent': 25.0}),
+ (0, 0, {'repartition_type': 'tax', 'factor_percent': -25.0}),
+ (0, 0, {'repartition_type': 'tax', 'factor_percent': -25.0}),
+ ],
+ })
+
+ # Test with positive amount.
+ self._check_compute_all_results(
+ 1, # 'total_included'
+ 1, # 'total_excluded'
+ [
+ # base , amount
+ # ---------------
+ (1.0, 0.02),
+ (1.0, -0.02),
+ (1.0, 0.01),
+ (1.0, 0.01),
+ (1.0, -0.01),
+ (1.0, -0.01),
+ # ---------------
+ ],
+ tax.compute_all(1.0)
+ )
+
+ # Test with negative amount.
+ self._check_compute_all_results(
+ -1, # 'total_included'
+ -1, # 'total_excluded'
+ [
+ # base , amount
+ # ---------------
+ (-1.0, -0.02),
+ (-1.0, 0.02),
+ (-1.0, -0.01),
+ (-1.0, -0.01),
+ (-1.0, 0.01),
+ (-1.0, 0.01),
+ # ---------------
+ ],
+ tax.compute_all(-1.0)
+ )
+
+ def test_rounding_tax_excluded_round_per_line_01(self):
+ ''' Test the rounding of a 19% price excluded tax in an invoice having 22689 and 9176 as lines.
+ The decimal precision is set to zero.
+ The computation must be similar to round(22689 * 0.19) + round(9176 * 0.19).
+ '''
+ self.tax_19_percent.company_id.currency_id.rounding = 1.0
+ self.tax_19_percent.company_id.tax_calculation_rounding_method = 'round_per_line'
+
+ res1 = self.tax_19_percent.compute_all(22689)
+ self._check_compute_all_results(
+ 27000, # 'total_included'
+ 22689, # 'total_excluded'
+ [
+ # base, amount
+ # ---------------
+ (22689, 4311),
+ # ---------------
+ ],
+ res1
+ )
+
+ res2 = self.tax_19_percent.compute_all(9176)
+ self._check_compute_all_results(
+ 10919, # 'total_included'
+ 9176, # 'total_excluded'
+ [
+ # base , amount
+ # ---------------
+ (9176, 1743),
+ # ---------------
+ ],
+ res2
+ )
+
+ def test_rounding_tax_excluded_round_globally(self):
+ ''' Test the rounding of a 19% price excluded tax in an invoice having 22689 and 9176 as lines.
+ The decimal precision is set to zero.
+ The computation must be similar to round((22689 + 9176) * 0.19).
+ '''
+ self.tax_19_percent.company_id.tax_calculation_rounding_method = 'round_globally'
+
+ res1 = self.tax_19_percent.compute_all(22689)
+ self._check_compute_all_results(
+ 27000, # 'total_included'
+ 22689, # 'total_excluded'
+ [
+ # base, amount
+ # ---------------
+ (22689, 4310.91),
+ # ---------------
+ ],
+ res1
+ )
+
+ res2 = self.tax_19_percent.compute_all(9176)
+ self._check_compute_all_results(
+ 10919, # 'total_included'
+ 9176, # 'total_excluded'
+ [
+ # base , amount
+ # ---------------
+ (9176, 1743.44),
+ # ---------------
+ ],
+ res2
+ )
+
+ def test_rounding_tax_included_round_per_line_01(self):
+ ''' Test the rounding of a 19% price included tax in an invoice having 27000 and 10920 as lines.
+ The decimal precision is set to zero.
+ The computation must be similar to round(27000 / 1.19) + round(10920 / 1.19).
+ '''
+ self.tax_19_percent.price_include = True
+ self.tax_19_percent.company_id.currency_id.rounding = 1.0
+ self.tax_19_percent.company_id.tax_calculation_rounding_method = 'round_per_line'
+
+ res1 = self.tax_19_percent.compute_all(27000)
+ self._check_compute_all_results(
+ 27000, # 'total_included'
+ 22689, # 'total_excluded'
+ [
+ # base , amount
+ # ---------------
+ (22689, 4311),
+ # ---------------
+ ],
+ res1
+ )
+
+ res2 = self.tax_19_percent.compute_all(10920)
+ self._check_compute_all_results(
+ 10920, # 'total_included'
+ 9176, # 'total_excluded'
+ [
+ # base , amount
+ # ---------------
+ (9176, 1744),
+ # ---------------
+ ],
+ res2
+ )
+
+ def test_rounding_tax_included_round_per_line_02(self):
+ ''' Test the rounding of a 12% price included tax in an invoice having 52.50 as line.
+ The decimal precision is set to 2.
+ '''
+ self.tax_12_percent.price_include = True
+ self.tax_12_percent.company_id.currency_id.rounding = 0.01
+
+ res1 = self.tax_12_percent.compute_all(52.50)
+ self._check_compute_all_results(
+ 52.50, # 'total_included'
+ 46.88, # 'total_excluded'
+ [
+ # base , amount
+ # -------------
+ (46.88, 5.62),
+ # -------------
+ ],
+ res1
+ )
+
+ def test_rounding_tax_included_round_per_line_03(self):
+ ''' Test the rounding of a 8% and 0% price included tax in an invoice having 8 * 15.55 as line.
+ The decimal precision is set to 2.
+ '''
+ self.tax_0_percent.company_id.currency_id.rounding = 0.01
+ self.tax_0_percent.price_include = True
+ self.tax_8_percent.price_include = True
+
+ self.group_tax.children_tax_ids = [(6, 0, self.tax_0_percent.ids)]
+ self.group_tax_bis.children_tax_ids = [(6, 0, self.tax_8_percent.ids)]
+
+ res1 = (self.tax_8_percent | self.tax_0_percent).compute_all(15.55, quantity=8.0)
+ self._check_compute_all_results(
+ 124.40, # 'total_included'
+ 115.19, # 'total_excluded'
+ [
+ # base , amount
+ # -------------
+ (115.19, 9.21),
+ (115.19, 0.00),
+ # -------------
+ ],
+ res1
+ )
+
+ res2 = (self.tax_0_percent | self.tax_8_percent).compute_all(15.55, quantity=8.0)
+ self._check_compute_all_results(
+ 124.40, # 'total_included'
+ 115.19, # 'total_excluded'
+ [
+ # base , amount
+ # -------------
+ (115.19, 0.00),
+ (115.19, 9.21),
+ # -------------
+ ],
+ res2
+ )
+
+ def test_rounding_tax_included_round_per_line_04(self):
+ ''' Test the rounding of a 5% price included tax.
+ The decimal precision is set to 0.05.
+ '''
+ self.tax_5_percent.price_include = True
+ self.tax_5_percent.company_id.currency_id.rounding = 0.05
+ self.tax_5_percent.company_id.tax_calculation_rounding_method = 'round_per_line'
+
+ res1 = self.tax_5_percent.compute_all(5)
+ self._check_compute_all_results(
+ 5, # 'total_included'
+ 4.75, # 'total_excluded'
+ [
+ # base , amount
+ # ---------------
+ (4.75, 0.25),
+ # ---------------
+ ],
+ res1
+ )
+
+ res2 = self.tax_5_percent.compute_all(10)
+ self._check_compute_all_results(
+ 10, # 'total_included'
+ 9.5, # 'total_excluded'
+ [
+ # base , amount
+ # ---------------
+ (9.5, 0.5),
+ # ---------------
+ ],
+ res2
+ )
+
+ res3 = self.tax_5_percent.compute_all(50)
+ self._check_compute_all_results(
+ 50, # 'total_included'
+ 47.6, # 'total_excluded'
+ [
+ # base , amount
+ # ---------------
+ (47.6, 2.4),
+ # ---------------
+ ],
+ res3
+ )
+
+ def test_rounding_tax_included_round_globally_01(self):
+ ''' Test the rounding of a 19% price included tax in an invoice having 27000 and 10920 as lines.
+ The decimal precision is set to zero.
+ The computation must be similar to round((27000 + 10920) / 1.19).
+ '''
+ self.tax_19_percent.price_include = True
+ self.tax_19_percent.company_id.tax_calculation_rounding_method = 'round_globally'
+
+ res1 = self.tax_19_percent.compute_all(27000)
+ self._check_compute_all_results(
+ 27000, # 'total_included'
+ 22689, # 'total_excluded'
+ [
+ # base , amount
+ # ---------------
+ (22689, 4311),
+ # ---------------
+ ],
+ res1
+ )
+
+ res2 = self.tax_19_percent.compute_all(10920)
+ self._check_compute_all_results(
+ 10920, # 'total_included'
+ 9176, # 'total_excluded'
+ [
+ # base , amount
+ # ---------------
+ (9176, 1744),
+ # ---------------
+ ],
+ res2
+ )
+
+ def test_rounding_tax_included_round_globally_02(self):
+ ''' Test the rounding of a 21% price included tax in an invoice having 11.90 and 2.80 as lines.
+ The decimal precision is set to 2.
+ '''
+ self.tax_21_percent.price_include = True
+ self.tax_21_percent.company_id.currency_id.rounding = 0.01
+ self.tax_21_percent.company_id.tax_calculation_rounding_method = 'round_globally'
+
+ res1 = self.tax_21_percent.compute_all(11.90)
+ self._check_compute_all_results(
+ 11.90, # 'total_included'
+ 9.83, # 'total_excluded'
+ [
+ # base , amount
+ # ---------------
+ (9.83, 2.07),
+ # ---------------
+ ],
+ res1
+ )
+
+ res2 = self.tax_21_percent.compute_all(2.80)
+ self._check_compute_all_results(
+ 2.80, # 'total_included'
+ 2.31, # 'total_excluded'
+ [
+ # base , amount
+ # ---------------
+ (2.31, 0.49),
+ # ---------------
+ ],
+ res2
+ )
+
+ def test_rounding_tax_included_round_globally_03(self):
+ ''' Test the rounding of a 5% price included tax.
+ The decimal precision is set to 0.05.
+ '''
+ self.tax_5_percent.price_include = True
+ self.tax_5_percent.company_id.currency_id.rounding = 0.05
+ self.tax_5_percent.company_id.tax_calculation_rounding_method = 'round_globally'
+
+ res1 = self.tax_5_percent.compute_all(5)
+ self._check_compute_all_results(
+ 5, # 'total_included'
+ 4.75, # 'total_excluded'
+ [
+ # base , amount
+ # ---------------
+ (4.75, 0.25),
+ # ---------------
+ ],
+ res1
+ )
+
+ res2 = self.tax_5_percent.compute_all(10)
+ self._check_compute_all_results(
+ 10, # 'total_included'
+ 9.5, # 'total_excluded'
+ [
+ # base , amount
+ # ---------------
+ (9.50, 0.50),
+ # ---------------
+ ],
+ res2
+ )
+
+ res3 = self.tax_5_percent.compute_all(50)
+ self._check_compute_all_results(
+ 50, # 'total_included'
+ 47.6, # 'total_excluded'
+ [
+ # base , amount
+ # ---------------
+ (47.60, 2.40),
+ # ---------------
+ ],
+ res3
+ )
+
+ def test_mixing_price_included_excluded_with_affect_base(self):
+ tax_10_fix = self.env['account.tax'].create({
+ 'name': "tax_10_fix",
+ 'amount_type': 'fixed',
+ 'amount': 10.0,
+ 'include_base_amount': True,
+ })
+ tax_21 = self.env['account.tax'].create({
+ 'name': "tax_21",
+ 'amount_type': 'percent',
+ 'amount': 21.0,
+ 'price_include': True,
+ 'include_base_amount': True,
+ })
+
+ self._check_compute_all_results(
+ 1222.1, # 'total_included'
+ 1000.0, # 'total_excluded'
+ [
+ # base , amount
+ # ---------------
+ (1000.0, 10.0),
+ (1010.0, 212.1),
+ # ---------------
+ ],
+ (tax_10_fix + tax_21).compute_all(1210),
+ )