summaryrefslogtreecommitdiff
path: root/addons/account/tests/test_tax_report.py
blob: 2301408459fb77e8bffd9a4e251c7f3d2db89c9f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
# -*- coding: utf-8 -*-
from odoo.addons.account.tests.common import AccountTestInvoicingCommon
from odoo.tests import tagged


@tagged('post_install', '-at_install')
class TaxReportTest(AccountTestInvoicingCommon):

    @classmethod
    def setUpClass(cls, chart_template_ref=None):
        super().setUpClass(chart_template_ref=chart_template_ref)
        cls.test_country_1 = cls.env['res.country'].create({
            'name': "The Old World",
            'code': 'YY',
        })

        cls.test_country_2 = cls.env['res.country'].create({
            'name': "The Principality of Zeon",
            'code': 'ZZ',
        })
        cls.test_country_3 = cls.env['res.country'].create({
            'name': "Alagaësia",
            'code': 'QQ',
        })

        cls.tax_report_1 = cls.env['account.tax.report'].create({
            'name': "Tax report 1",
            'country_id': cls.test_country_1.id,
        })

        cls.tax_report_line_1_1 = cls.env['account.tax.report.line'].create({
            'name': "[01] Line 01",
            'tag_name': '01',
            'report_id': cls.tax_report_1.id,
            'sequence': 2,
        })

        cls.tax_report_line_1_2 = cls.env['account.tax.report.line'].create({
            'name': "[01] Line 02",
            'tag_name': '02',
            'report_id': cls.tax_report_1.id,
            'sequence': 3,
        })

        cls.tax_report_line_1_3 = cls.env['account.tax.report.line'].create({
            'name': "[03] Line 03",
            'tag_name': '03',
            'report_id': cls.tax_report_1.id,
            'sequence': 4,
        })

        cls.tax_report_line_1_4 = cls.env['account.tax.report.line'].create({
            'name': "[04] Line 04",
            'report_id': cls.tax_report_1.id,
            'sequence': 5,
        })

        cls.tax_report_line_1_5 = cls.env['account.tax.report.line'].create({
            'name': "[05] Line 05",
            'report_id': cls.tax_report_1.id,
            'sequence': 6,
        })

        cls.tax_report_line_1_55 = cls.env['account.tax.report.line'].create({
            'name': "[55] Line 55",
            'tag_name': '55',
            'report_id': cls.tax_report_1.id,
            'sequence': 7,
        })

        cls.tax_report_line_1_6 = cls.env['account.tax.report.line'].create({
            'name': "[100] Line 100",
            'tag_name': '100',
            'report_id': cls.tax_report_1.id,
            'sequence': 8,
        })

        cls.tax_report_2 = cls.env['account.tax.report'].create({
            'name': "Tax report 2",
            'country_id': cls.test_country_1.id,
        })

        cls.tax_report_line_2_1 = cls.env['account.tax.report.line'].create({
            'name': "[01] Line 01, but in report 2",
            'tag_name': '01',
            'report_id': cls.tax_report_2.id,
            'sequence': 1,
        })

        cls.tax_report_line_2_2 = cls.env['account.tax.report.line'].create({
            'name': "[02] Line 02, but in report 2",
            'report_id': cls.tax_report_2.id,
            'sequence': 2,
        })

        cls.tax_report_line_2_42 = cls.env['account.tax.report.line'].create({
            'name': "[42] Line 42",
            'tag_name': '42',
            'report_id': cls.tax_report_2.id,
            'sequence': 3,
        })

        cls.tax_report_line_2_6 = cls.env['account.tax.report.line'].create({
            'name': "[100] Line 100",
            'tag_name': '100',
            'report_id': cls.tax_report_2.id,
            'sequence': 4,
        })

    def _get_tax_tags(self, tag_name=None):
        domain = [('country_id', '=', self.test_country_1.id), ('applicability', '=', 'taxes')]
        if tag_name:
            domain.append(('name', 'like', '_' + tag_name ))
        return self.env['account.account.tag'].search(domain)

    def test_write_add_tagname(self):
        """ Adding a tag_name to a line without any should create new tags.
        """
        tags_before = self._get_tax_tags()
        self.tax_report_line_2_2.tag_name = 'tournicoti'
        tags_after = self._get_tax_tags()

        self.assertEqual(len(tags_after), len(tags_before) + 2, "Two tags should have been created, +tournicoti and -tournicoti.")

    def test_write_single_line_tagname(self):
        """ Writing on the tag_name of a line with a non-null tag_name used in
        no other line should overwrite the name of the existing tags.
        """
        start_tags = self._get_tax_tags()
        original_tag_name = self.tax_report_line_1_55.tag_name
        original_tags = self.tax_report_line_1_55.tag_ids
        self.tax_report_line_1_55.tag_name = 'Mille sabords !'

        self.assertEqual(len(self._get_tax_tags(original_tag_name)), 0, "The original tag name of the line should not correspond to any tag anymore.")
        self.assertEqual(original_tags, self.tax_report_line_1_55.tag_ids, "The tax report line should still be linked to the same tags.")
        self.assertEqual(len(self._get_tax_tags()), len(start_tags), "No new tag should have been created.")

    def test_write_single_line_remove_tagname(self):
        """ Setting None as the tag_name of a line with a non-null tag_name used
        in a unique line should delete the tags, also removing all the references to it
        from tax repartition lines and account move lines
        """

        test_tax = self.env['account.tax'].create({
            'name': "Test tax",
            'amount_type': 'percent',
            'amount': 25,
            'type_tax_use': 'sale',
            'invoice_repartition_line_ids': [
                (0,0, {
                    'factor_percent': 100,
                    'repartition_type': 'base',
                }),

                (0,0, {
                    'factor_percent': 100,
                    'repartition_type': 'tax',
                    'tag_ids': [(6, 0, self.tax_report_line_1_55.tag_ids[0].ids)],
                }),
            ],
            'refund_repartition_line_ids': [
                (0,0, {
                    'factor_percent': 100,
                    'repartition_type': 'base',
                }),

                (0,0, {
                    'factor_percent': 100,
                    'repartition_type': 'tax',
                }),
            ],
        })

        test_invoice = self.env['account.move'].create({
            'move_type': 'out_invoice',
            'partner_id': self.partner_a.id,
            'date': '1992-12-22',
            'invoice_line_ids': [
                (0, 0, {'quantity': 1, 'price_unit': 42, 'tax_ids': [(6, 0, test_tax.ids)]}),
            ],
        })
        test_invoice.action_post()

        self.assertTrue(any(line.tax_tag_ids == self.tax_report_line_1_55.tag_ids[0] for line in test_invoice.line_ids), "The test invoice should contain a tax line with tag 55")
        tag_name_before = self.tax_report_line_1_55.tag_name
        tag_nber_before = len(self._get_tax_tags())
        self.tax_report_line_1_55.tag_name = None
        self.assertFalse(self.tax_report_line_1_55.tag_name, "The tag name for line 55 should now be None")
        self.assertEqual(len(self._get_tax_tags(tag_name_before)), 0, "None of the original tags for this line should be left after setting tag_name to None if no other line was using this tag_name.")
        self.assertEqual(len(self._get_tax_tags()), tag_nber_before - 2, "No new tag should have been created, and the two that were assigned to the report line should have been removed.")
        self.assertFalse(test_tax.mapped('invoice_repartition_line_ids.tag_ids'), "There should be no tag left on test tax's repartition lines after the removal of tag 55.")
        self.assertFalse(test_invoice.mapped('line_ids.tax_tag_ids'), "The link between test invoice and tag 55 should have been broken. There should be no tag left on the invoice's lines.")

    def test_write_multi_no_change(self):
        """ Writing the same tag_name as they already use on a set of tax report
        lines with the same tag_name should not do anything.
        """
        tags_before = self._get_tax_tags().ids
        (self.tax_report_line_1_1 + self.tax_report_line_2_1).write({'tag_name': '01'})
        tags_after = self._get_tax_tags().ids
        self.assertEqual(tags_before, tags_after, "Re-assigning the same tag_name should keep the same tags.")

    def test_edit_line_shared_tags(self):
        """ Setting the tag_name of a tax report line sharing its tags with another line
        should edit the tags' name and the tag_name of this other report line, to
        keep consistency.
        """
        original_tag_name = self.tax_report_line_1_1.tag_name
        self.tax_report_line_1_1.tag_name = 'Groucha'
        self.assertEqual(self.tax_report_line_2_1.tag_name, self.tax_report_line_1_1.tag_name, "Modifying the tag name of a tax report line sharing it with another one should also modify the other's.")

    def test_edit_multi_line_tagname_all_different_new(self):
        """ Writing a tag_name on multiple lines with distinct tag_names should
        delete all the former tags and replace them by new ones (also on lines
        sharing tags with them).
        """
        lines = self.tax_report_line_1_1 + self.tax_report_line_2_2 + self.tax_report_line_2_42
        previous_tag_ids = lines.mapped('tag_ids.id')
        lines.write({'tag_name': 'crabe'})
        new_tags = lines.mapped('tag_ids')

        self.assertNotEqual(new_tags.ids, previous_tag_ids, "All the tags should have changed")
        self.assertEqual(len(new_tags), 2, "Only two distinct tags should be assigned to all the lines after writing tag_name on them all")
        surviving_tags = self.env['account.account.tag'].search([('id', 'in', previous_tag_ids)])
        self.assertEqual(len(surviving_tags), 0, "All former tags should have been deleted")
        self.assertEqual(self.tax_report_line_1_1.tag_ids, self.tax_report_line_2_1.tag_ids, "The report lines initially sharing their tag_name with the written-on lines should also have been impacted")

    def test_remove_line_dependency(self):
        """ Setting to None the tag_name of a report line sharing its tags with
        other lines should only impact this line ; the other ones should keep their
        link to the initial tags (their tag_name will hence differ in the end).
        """
        tags_before = self.tax_report_line_1_1.tag_ids
        self.tax_report_line_1_1.tag_name = None
        self.assertEqual(len(self.tax_report_line_1_1.tag_ids), 0, "Setting the tag_name to None should have removed the tags.")
        self.assertEqual(self.tax_report_line_2_1.tag_ids, tags_before, "Setting tag_name to None on a line linked to another one via tag_name should break this link.")

    def test_tax_report_change_country(self):
        """ Tests that duplicating and modifying the country of a tax report works
        as intended (countries wanting to use the tax report of another
        country need that).
        """
        # Copy our first report
        tags_before = self._get_tax_tags().ids
        copied_report_1 = self.tax_report_1.copy()
        copied_report_2 = self.tax_report_1.copy()
        tags_after = self._get_tax_tags().ids
        self.assertEqual(tags_before, tags_after, "Report duplication should not create or remove any tag")

        for original, copy in zip(self.tax_report_1.get_lines_in_hierarchy(), copied_report_1.get_lines_in_hierarchy()):
            self.assertEqual(original.tag_ids, copy.tag_ids, "Copying the lines of a tax report should keep the same tags on lines")

        # Assign another country to one of the copies
        copied_report_1.country_id = self.test_country_2
        for original, copy in zip(self.tax_report_1.get_lines_in_hierarchy(), copied_report_1.get_lines_in_hierarchy()):
            if original.tag_ids or copy.tag_ids:
                self.assertNotEqual(original.tag_ids, copy.tag_ids, "Changing the country of a copied report should create brand new tags for all of its lines")

        for original, copy in zip(self.tax_report_1.get_lines_in_hierarchy(), copied_report_2.get_lines_in_hierarchy()):
            self.assertEqual(original.tag_ids, copy.tag_ids, "Changing the country of a copied report should not impact the other copies or the original report")


        # Direclty change the country of a report without copying it first (some of its tags are shared, but not all)
        original_report_2_tags = {line.id: line.tag_ids.ids for line in self.tax_report_2.get_lines_in_hierarchy()}
        self.tax_report_2.country_id = self.test_country_2
        for line in self.tax_report_2.get_lines_in_hierarchy():
            if line == self.tax_report_line_2_42:
                # This line is the only one of the report not sharing its tags
                self.assertEqual(line.tag_ids.ids, original_report_2_tags[line.id], "The tax report lines not sharing their tags with any other report should keep the same tags when the country of their report is changed")
            elif line.tag_ids or original_report_2_tags[line.id]:
                self.assertNotEqual(line.tag_ids.ids, original_report_2_tags[line.id], "The tax report lines sharing their tags with other report should receive new tags when the country of their report is changed")

    def test_unlink_report_line_tags(self):
        """ Under certain circumstances, unlinking a tax report line should also unlink
        the tags that are linked to it. We test those cases here.
        """
        def check_tags_unlink(tag_name, report_lines, unlinked, error_message):
            report_lines.unlink()
            surviving_tags = self._get_tax_tags(tag_name)
            required_len = 0 if unlinked else 2 # 2 for + and - tag
            self.assertEqual(len(surviving_tags), required_len, error_message)

        check_tags_unlink('42', self.tax_report_line_2_42, True, "Unlinking one line not sharing its tags should also unlink them")
        check_tags_unlink('01', self.tax_report_line_1_1, False, "Unlinking one line sharing its tags with others should keep the tags")
        check_tags_unlink('100', self.tax_report_line_1_6 + self.tax_report_line_2_6, True, "Unlinkink all the lines sharing the same tags should also unlink them")