odoo-addon-l10n-br-fiscal 16.0.2.17.0__py3-none-any.whl → 16.0.19.4.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (162) hide show
  1. odoo/addons/l10n_br_fiscal/README.rst +11 -4
  2. odoo/addons/l10n_br_fiscal/__manifest__.py +20 -12
  3. odoo/addons/l10n_br_fiscal/constants/fiscal.py +64 -18
  4. odoo/addons/l10n_br_fiscal/data/l10n_br_fiscal.cest.csv +1043 -983
  5. odoo/addons/l10n_br_fiscal/data/l10n_br_fiscal.cfop.csv +620 -620
  6. odoo/addons/l10n_br_fiscal/data/l10n_br_fiscal.cst.csv +58 -0
  7. odoo/addons/l10n_br_fiscal/data/l10n_br_fiscal.document.type.csv +1 -0
  8. odoo/addons/l10n_br_fiscal/data/l10n_br_fiscal.legal.nature.csv +82 -0
  9. odoo/addons/l10n_br_fiscal/data/l10n_br_fiscal.nbs.csv +791 -764
  10. odoo/addons/l10n_br_fiscal/data/l10n_br_fiscal.operation.indicator.csv +27 -0
  11. odoo/addons/l10n_br_fiscal/data/l10n_br_fiscal.partner.profile.csv +11 -0
  12. odoo/addons/l10n_br_fiscal/data/l10n_br_fiscal.tax.classification.csv +163 -0
  13. odoo/addons/l10n_br_fiscal/data/l10n_br_fiscal.tax.csv +32 -0
  14. odoo/addons/l10n_br_fiscal/data/l10n_br_fiscal.tax.group.csv +3 -0
  15. odoo/addons/l10n_br_fiscal/data/l10n_br_fiscal_icms_tax_definition_data.xml +340 -352
  16. odoo/addons/l10n_br_fiscal/data/operation_data.xml +1 -1
  17. odoo/addons/l10n_br_fiscal/data/simplified_tax_data.xml +5 -5
  18. odoo/addons/l10n_br_fiscal/data/uom.alias.csv +25 -0
  19. odoo/addons/l10n_br_fiscal/data/uom_data.xml +104 -33
  20. odoo/addons/l10n_br_fiscal/demo/__init__.py +21 -15
  21. odoo/addons/l10n_br_fiscal/demo/company_demo.xml +6 -0
  22. odoo/addons/l10n_br_fiscal/demo/fiscal_document_demo.xml +3 -377
  23. odoo/addons/l10n_br_fiscal/demo/fiscal_document_nfse_demo.xml +0 -12
  24. odoo/addons/l10n_br_fiscal/demo/fiscal_operation_demo.xml +2 -2
  25. odoo/addons/l10n_br_fiscal/demo/icms_tax_definition_demo.xml +5 -2
  26. odoo/addons/l10n_br_fiscal/demo/res_users_demo.xml +2 -2
  27. odoo/addons/l10n_br_fiscal/i18n/l10n_br_fiscal.pot +1161 -804
  28. odoo/addons/l10n_br_fiscal/i18n/pt_BR.po +22 -22
  29. odoo/addons/l10n_br_fiscal/migrations/16.0.13.0.0/pre-migration.py +25 -0
  30. odoo/addons/l10n_br_fiscal/migrations/16.0.14.0.0/pre-migration.py +30 -0
  31. odoo/addons/l10n_br_fiscal/migrations/16.0.14.0.5/pre-migration.py +15 -0
  32. odoo/addons/l10n_br_fiscal/migrations/16.0.4.0.0/pre-migration.py +220 -0
  33. odoo/addons/l10n_br_fiscal/migrations/16.0.5.0.0/pre-migration.py +33 -0
  34. odoo/addons/l10n_br_fiscal/migrations/16.0.5.2.0/pre-migration.py +21 -0
  35. odoo/addons/l10n_br_fiscal/models/__init__.py +3 -8
  36. odoo/addons/l10n_br_fiscal/models/cest.py +0 -8
  37. odoo/addons/l10n_br_fiscal/models/cfop.py +91 -0
  38. odoo/addons/l10n_br_fiscal/models/city_taxation_code.py +1 -3
  39. odoo/addons/l10n_br_fiscal/models/comment.py +2 -2
  40. odoo/addons/l10n_br_fiscal/models/cst.py +0 -1
  41. odoo/addons/l10n_br_fiscal/models/data_abstract.py +26 -0
  42. odoo/addons/l10n_br_fiscal/models/data_ncm_nbs_abstract.py +1 -1
  43. odoo/addons/l10n_br_fiscal/models/document.py +131 -222
  44. odoo/addons/l10n_br_fiscal/models/document_line.py +82 -5
  45. odoo/addons/l10n_br_fiscal/models/document_line_mixin.py +1952 -138
  46. odoo/addons/l10n_br_fiscal/models/document_mixin.py +741 -6
  47. odoo/addons/l10n_br_fiscal/models/document_related.py +12 -9
  48. odoo/addons/l10n_br_fiscal/models/document_serie.py +33 -0
  49. odoo/addons/l10n_br_fiscal/models/document_type.py +0 -6
  50. odoo/addons/l10n_br_fiscal/models/ibpt.py +1 -1
  51. odoo/addons/l10n_br_fiscal/models/icms_regulation.py +2 -2
  52. odoo/addons/l10n_br_fiscal/models/invalidate_number.py +4 -5
  53. odoo/addons/l10n_br_fiscal/models/legal_nature.py +20 -0
  54. odoo/addons/l10n_br_fiscal/models/nbm.py +0 -8
  55. odoo/addons/l10n_br_fiscal/models/ncm.py +0 -12
  56. odoo/addons/l10n_br_fiscal/models/operation.py +49 -15
  57. odoo/addons/l10n_br_fiscal/models/operation_dashboard.py +3 -2
  58. odoo/addons/l10n_br_fiscal/models/operation_indicator.py +58 -0
  59. odoo/addons/l10n_br_fiscal/models/operation_line.py +75 -6
  60. odoo/addons/l10n_br_fiscal/models/partner_profile.py +6 -0
  61. odoo/addons/l10n_br_fiscal/models/product_mixin.py +24 -21
  62. odoo/addons/l10n_br_fiscal/models/product_template.py +23 -13
  63. odoo/addons/l10n_br_fiscal/models/res_company.py +31 -9
  64. odoo/addons/l10n_br_fiscal/models/res_partner.py +38 -6
  65. odoo/addons/l10n_br_fiscal/models/simplified_tax.py +0 -3
  66. odoo/addons/l10n_br_fiscal/models/simplified_tax_range.py +8 -0
  67. odoo/addons/l10n_br_fiscal/models/tax.py +144 -55
  68. odoo/addons/l10n_br_fiscal/models/tax_classification.py +81 -0
  69. odoo/addons/l10n_br_fiscal/models/tax_definition.py +72 -23
  70. odoo/addons/l10n_br_fiscal/models/tax_pis_cofins.py +0 -3
  71. odoo/addons/l10n_br_fiscal/models/tax_pis_cofins_base.py +1 -1
  72. odoo/addons/l10n_br_fiscal/models/tax_pis_cofins_credit.py +1 -1
  73. odoo/addons/l10n_br_fiscal/models/uom_uom.py +15 -30
  74. odoo/addons/l10n_br_fiscal/security/fiscal_security.xml +11 -27
  75. odoo/addons/l10n_br_fiscal/security/ir.model.access.csv +11 -10
  76. odoo/addons/l10n_br_fiscal/static/description/index.html +27 -21
  77. odoo/addons/l10n_br_fiscal/static/src/js/list_renderer_with_button.esm.js +38 -0
  78. odoo/addons/l10n_br_fiscal/tests/__init__.py +3 -2
  79. odoo/addons/l10n_br_fiscal/tests/test_document_edition.py +308 -0
  80. odoo/addons/l10n_br_fiscal/tests/test_fiscal_document_generic.py +23 -129
  81. odoo/addons/l10n_br_fiscal/tests/test_fiscal_document_nfse.py +5 -15
  82. odoo/addons/l10n_br_fiscal/tests/test_fiscal_document_serie.py +60 -0
  83. odoo/addons/l10n_br_fiscal/tests/test_ibpt.py +4 -3
  84. odoo/addons/l10n_br_fiscal/tests/test_icms_regulation.py +2 -2
  85. odoo/addons/l10n_br_fiscal/tests/test_ncm.py +4 -1
  86. odoo/addons/l10n_br_fiscal/tests/test_tax_benefit.py +17 -22
  87. odoo/addons/l10n_br_fiscal/tests/test_tax_classification.py +110 -0
  88. odoo/addons/l10n_br_fiscal/tools.py +1 -1
  89. odoo/addons/l10n_br_fiscal/views/cest_view.xml +2 -4
  90. odoo/addons/l10n_br_fiscal/views/cfop_view.xml +25 -5
  91. odoo/addons/l10n_br_fiscal/views/city_taxation_code.xml +1 -4
  92. odoo/addons/l10n_br_fiscal/views/cnae_view.xml +2 -4
  93. odoo/addons/l10n_br_fiscal/views/comment_view.xml +2 -4
  94. odoo/addons/l10n_br_fiscal/views/cst_view.xml +6 -8
  95. odoo/addons/l10n_br_fiscal/views/{document_fiscal_line_mixin_view.xml → document_line_mixin_view.xml} +525 -385
  96. odoo/addons/l10n_br_fiscal/views/document_line_view.xml +101 -82
  97. odoo/addons/l10n_br_fiscal/views/document_related_view.xml +44 -46
  98. odoo/addons/l10n_br_fiscal/views/document_serie_view.xml +2 -6
  99. odoo/addons/l10n_br_fiscal/views/document_type_view.xml +0 -8
  100. odoo/addons/l10n_br_fiscal/views/document_view.xml +303 -370
  101. odoo/addons/l10n_br_fiscal/views/icms_regulation_view.xml +14 -16
  102. odoo/addons/l10n_br_fiscal/views/icms_relief_view.xml +8 -10
  103. odoo/addons/l10n_br_fiscal/views/invalidate_number_view.xml +46 -48
  104. odoo/addons/l10n_br_fiscal/views/l10n_br_fiscal_action.xml +166 -280
  105. odoo/addons/l10n_br_fiscal/views/l10n_br_fiscal_menu.xml +25 -99
  106. odoo/addons/l10n_br_fiscal/views/legal_nature_view.xml +40 -0
  107. odoo/addons/l10n_br_fiscal/views/nbm_view.xml +5 -6
  108. odoo/addons/l10n_br_fiscal/views/nbs_view.xml +5 -6
  109. odoo/addons/l10n_br_fiscal/views/ncm_view.xml +12 -15
  110. odoo/addons/l10n_br_fiscal/views/operation_dashboard_view.xml +13 -12
  111. odoo/addons/l10n_br_fiscal/views/operation_indicator_view.xml +75 -0
  112. odoo/addons/l10n_br_fiscal/views/operation_line_view.xml +22 -21
  113. odoo/addons/l10n_br_fiscal/views/operation_view.xml +4 -19
  114. odoo/addons/l10n_br_fiscal/views/partner_profile_view.xml +3 -6
  115. odoo/addons/l10n_br_fiscal/views/product_genre_view.xml +7 -9
  116. odoo/addons/l10n_br_fiscal/views/product_product_view.xml +37 -14
  117. odoo/addons/l10n_br_fiscal/views/product_template_view.xml +34 -14
  118. odoo/addons/l10n_br_fiscal/views/res_company_view.xml +55 -52
  119. odoo/addons/l10n_br_fiscal/views/res_config_settings_view.xml +23 -28
  120. odoo/addons/l10n_br_fiscal/views/res_partner_view.xml +22 -2
  121. odoo/addons/l10n_br_fiscal/views/service_type_view.xml +7 -8
  122. odoo/addons/l10n_br_fiscal/views/simplified_tax_range_view.xml +0 -2
  123. odoo/addons/l10n_br_fiscal/views/simplified_tax_view.xml +0 -2
  124. odoo/addons/l10n_br_fiscal/views/tax_classification.xml +110 -0
  125. odoo/addons/l10n_br_fiscal/views/tax_definition_view.xml +157 -129
  126. odoo/addons/l10n_br_fiscal/views/tax_estimate_view.xml +0 -2
  127. odoo/addons/l10n_br_fiscal/views/tax_group_view.xml +3 -6
  128. odoo/addons/l10n_br_fiscal/views/tax_ipi_control_seal_view.xml +0 -2
  129. odoo/addons/l10n_br_fiscal/views/tax_ipi_guideline_class_view.xml +0 -2
  130. odoo/addons/l10n_br_fiscal/views/tax_ipi_guideline_view.xml +2 -4
  131. odoo/addons/l10n_br_fiscal/views/tax_pis_cofins_base_view.xml +2 -4
  132. odoo/addons/l10n_br_fiscal/views/tax_pis_cofins_credit_view.xml +2 -4
  133. odoo/addons/l10n_br_fiscal/views/tax_pis_cofins_view.xml +5 -7
  134. odoo/addons/l10n_br_fiscal/views/tax_view.xml +5 -7
  135. odoo/addons/l10n_br_fiscal/views/uom_uom.xml +24 -17
  136. odoo/addons/l10n_br_fiscal/wizards/__init__.py +1 -0
  137. odoo/addons/l10n_br_fiscal/wizards/base_wizard_mixin.py +1 -1
  138. odoo/addons/l10n_br_fiscal/wizards/document_import_wizard_mixin.py +129 -0
  139. odoo/addons/l10n_br_fiscal/wizards/document_import_wizard_mixin.xml +41 -0
  140. {odoo_addon_l10n_br_fiscal-16.0.2.17.0.dist-info → odoo_addon_l10n_br_fiscal-16.0.19.4.0.dist-info}/METADATA +15 -6
  141. odoo_addon_l10n_br_fiscal-16.0.19.4.0.dist-info/RECORD +210 -0
  142. {odoo_addon_l10n_br_fiscal-16.0.2.17.0.dist-info → odoo_addon_l10n_br_fiscal-16.0.19.4.0.dist-info}/WHEEL +1 -1
  143. odoo/addons/l10n_br_fiscal/data/l10n_br_fiscal_email_template.xml +0 -68
  144. odoo/addons/l10n_br_fiscal/data/partner_profile_data.xml +0 -96
  145. odoo/addons/l10n_br_fiscal/data/uom_alternative_data.xml +0 -58
  146. odoo/addons/l10n_br_fiscal/demo/l10n_br_fiscal_document_email.xml +0 -54
  147. odoo/addons/l10n_br_fiscal/demo/subsequent_operation_demo.xml +0 -10
  148. odoo/addons/l10n_br_fiscal/models/document_email.py +0 -74
  149. odoo/addons/l10n_br_fiscal/models/document_line_mixin_methods.py +0 -913
  150. odoo/addons/l10n_br_fiscal/models/document_mixin_fields.py +0 -473
  151. odoo/addons/l10n_br_fiscal/models/document_mixin_methods.py +0 -269
  152. odoo/addons/l10n_br_fiscal/models/document_move_mixin.py +0 -261
  153. odoo/addons/l10n_br_fiscal/models/subsequent_document.py +0 -203
  154. odoo/addons/l10n_br_fiscal/models/subsequent_operation.py +0 -54
  155. odoo/addons/l10n_br_fiscal/models/uom_uom_alternative.py +0 -22
  156. odoo/addons/l10n_br_fiscal/tests/test_subsequent_operation.py +0 -71
  157. odoo/addons/l10n_br_fiscal/tests/test_uom_uom.py +0 -22
  158. odoo/addons/l10n_br_fiscal/views/document_email_view.xml +0 -48
  159. odoo/addons/l10n_br_fiscal/views/subsequent_document_view.xml +0 -43
  160. odoo/addons/l10n_br_fiscal/views/subsequent_operation_view.xml +0 -21
  161. odoo_addon_l10n_br_fiscal-16.0.2.17.0.dist-info/RECORD +0 -205
  162. {odoo_addon_l10n_br_fiscal-16.0.2.17.0.dist-info → odoo_addon_l10n_br_fiscal-16.0.19.4.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,308 @@
1
+ # Copyright 2025-TODAY Akretion - Raphaël Valyi
2
+ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
3
+
4
+ from unittest import mock
5
+
6
+ from odoo.tests import TransactionCase
7
+ from odoo.tests.common import Form, tagged
8
+
9
+
10
+ @tagged("post_install", "-at_install")
11
+ class TestDocumentEdition(TransactionCase):
12
+ @classmethod
13
+ def setUpClass(cls):
14
+ super().setUpClass()
15
+ cls.env = cls.env(context=dict(cls.env.context, tracking_disable=True))
16
+ cls.user = cls.env.user
17
+ cls.company = cls.env.ref("l10n_br_base.empresa_lucro_presumido")
18
+ cls.user.company_ids |= cls.company
19
+ cls.user.company_id = cls.company.id
20
+
21
+ def test_basic_doc_edition(self):
22
+ doc_form = Form(
23
+ self.env["l10n_br_fiscal.document"].with_context(
24
+ default_fiscal_operation_type="out",
25
+ )
26
+ )
27
+ doc_form.company_id = self.env.ref("l10n_br_base.empresa_lucro_presumido")
28
+ doc_form.partner_id = self.env.ref("l10n_br_base.res_partner_cliente1_sp")
29
+ doc_form.fiscal_operation_id = self.env.ref("l10n_br_fiscal.fo_venda")
30
+ doc_form.ind_final = "1"
31
+ product_id = self.env.ref("product.product_product_6")
32
+ product_id.list_price = 150 # we will later check we can set price_unit to 100
33
+ with doc_form.fiscal_line_ids.new() as line_form:
34
+ original_method = type(
35
+ self.env["l10n_br_fiscal.operation.line"]
36
+ ).map_fiscal_taxes
37
+
38
+ def wrapped_method(self, *args, **kwargs):
39
+ return original_method(self, *args, **kwargs)
40
+
41
+ with mock.patch.object(
42
+ type(self.env["l10n_br_fiscal.operation.line"]),
43
+ "map_fiscal_taxes",
44
+ side_effect=wrapped_method,
45
+ autospec=True,
46
+ ) as mocked:
47
+ line_form.product_id = product_id
48
+
49
+ # ensure the tax engine is called with the proper
50
+ # parameters, especially ind_final
51
+ # as it is related=document_id.ind_final
52
+ # which is converted to move_id.ind_final to work live
53
+ mocked.assert_called_with(
54
+ self.env.ref("l10n_br_fiscal.fo_venda_revenda"),
55
+ company=doc_form.company_id,
56
+ partner=doc_form.partner_id,
57
+ product=product_id,
58
+ ncm=product_id.ncm_id,
59
+ nbm=self.env["l10n_br_fiscal.nbm"],
60
+ nbs=self.env["l10n_br_fiscal.nbs"],
61
+ cest=self.env["l10n_br_fiscal.cest"],
62
+ city_taxation_code=self.env["l10n_br_fiscal.city.taxation.code"],
63
+ service_type=self.env["l10n_br_fiscal.service.type"],
64
+ ind_final="1",
65
+ )
66
+
67
+ line_form.price_unit = 50
68
+ line_form.quantity = 2
69
+ self.assertEqual(len(line_form.fiscal_tax_ids), 4)
70
+ self.assertEqual(
71
+ line_form.icms_tax_id, self.env.ref("l10n_br_fiscal.tax_icms_12")
72
+ )
73
+ self.assertEqual(line_form.icms_value, 12.0)
74
+ line_form.price_unit = 100
75
+ self.assertEqual(
76
+ line_form.icms_tax_id, self.env.ref("l10n_br_fiscal.tax_icms_12")
77
+ )
78
+ self.assertEqual(line_form.icms_value, 24.0)
79
+ self.assertEqual(
80
+ line_form.fiscal_operation_line_id,
81
+ self.env.ref("l10n_br_fiscal.fo_venda_revenda"),
82
+ )
83
+ self.assertEqual(
84
+ line_form.ipi_tax_id, self.env.ref("l10n_br_fiscal.tax_ipi_nt")
85
+ )
86
+
87
+ line_form.fiscal_operation_line_id = self.env.ref(
88
+ "l10n_br_fiscal.fo_venda_venda"
89
+ )
90
+ self.assertEqual(
91
+ line_form.ipi_tax_id, self.env.ref("l10n_br_fiscal.tax_ipi_3_25")
92
+ )
93
+
94
+ # ensure manually setting a xx_tax_id is properly saved (not recomputed):
95
+ line_form.icms_tax_id = self.env.ref("l10n_br_fiscal.tax_icms_18")
96
+ self.assertEqual(line_form.icms_value, 37.17)
97
+ self.assertEqual(
98
+ line_form.ipi_tax_id, self.env.ref("l10n_br_fiscal.tax_ipi_3_25")
99
+ )
100
+ line_form.icmsfcp_base = line_form.price_unit
101
+ line_form.icmsfcp_value = 3 # ensure manually setting FCP value works
102
+
103
+ doc = doc_form.save()
104
+ line = doc.fiscal_line_ids[0]
105
+ self.assertEqual(line.price_unit, 100)
106
+ self.assertEqual(line.fiscal_price, 100)
107
+ self.assertEqual(line.quantity, 2)
108
+ self.assertEqual(line.fiscal_quantity, 2)
109
+ self.assertEqual(len(line.fiscal_tax_ids), 4)
110
+
111
+ self.assertEqual(
112
+ line.fiscal_operation_line_id,
113
+ self.env.ref("l10n_br_fiscal.fo_venda_venda"),
114
+ )
115
+ self.assertEqual(
116
+ line.icms_tax_id.id,
117
+ self.ref("l10n_br_fiscal.tax_icms_18"),
118
+ )
119
+ self.assertEqual(line.ipi_tax_id, self.env.ref("l10n_br_fiscal.tax_ipi_3_25"))
120
+ self.assertEqual(line.icms_value, 37.17)
121
+ self.assertEqual(line.icmsfcp_base, line.price_unit)
122
+ self.assertEqual(line.icmsfcp_value, 3)
123
+
124
+ def test_product_fiscal_factor(self):
125
+ doc_form = Form(
126
+ self.env["l10n_br_fiscal.document"].with_context(
127
+ default_fiscal_operation_type="out",
128
+ )
129
+ )
130
+ doc_form.company_id = self.env.ref("l10n_br_base.empresa_lucro_presumido")
131
+ doc_form.partner_id = self.env.ref("l10n_br_base.res_partner_cliente1_sp")
132
+ doc_form.fiscal_operation_id = self.env.ref("l10n_br_fiscal.fo_venda")
133
+ doc_form.ind_final = "1"
134
+ product_id = self.env.ref("product.product_product_6")
135
+ product_id.uot_factor = 2
136
+ with doc_form.fiscal_line_ids.new() as line_form:
137
+ line_form.product_id = product_id
138
+ line_form.price_unit = 100
139
+ line_form.quantity = 10
140
+
141
+ doc = doc_form.save()
142
+ self.assertEqual(doc.fiscal_line_ids[0].price_unit, 100)
143
+ self.assertEqual(doc.fiscal_line_ids[0].fiscal_price, 50)
144
+ self.assertEqual(doc.fiscal_line_ids[0].quantity, 10)
145
+ self.assertEqual(doc.fiscal_line_ids[0].fiscal_quantity, 20)
146
+
147
+ def test_product_fiscal_price_and_qty_edition(self):
148
+ doc_form = Form(
149
+ self.env["l10n_br_fiscal.document"].with_context(
150
+ default_fiscal_operation_type="out",
151
+ )
152
+ )
153
+ doc_form.company_id = self.env.ref("l10n_br_base.empresa_lucro_presumido")
154
+ doc_form.partner_id = self.env.ref("l10n_br_base.res_partner_cliente1_sp")
155
+ doc_form.fiscal_operation_id = self.env.ref("l10n_br_fiscal.fo_venda")
156
+ doc_form.ind_final = "1"
157
+ product_id = self.env.ref("product.product_product_6")
158
+ product_id.list_price = 100
159
+ with doc_form.fiscal_line_ids.new() as line_form:
160
+ line_form.product_id = product_id
161
+ line_form.price_unit = 110
162
+ line_form.quantity = 10
163
+ line_form.fiscal_price = 112
164
+ line_form.fiscal_quantity = 5
165
+ self.assertEqual(line_form.price_unit, 110)
166
+ self.assertEqual(line_form.fiscal_price, 112)
167
+ self.assertEqual(line_form.quantity, 10)
168
+ self.assertEqual(line_form.fiscal_quantity, 5)
169
+
170
+ doc = doc_form.save()
171
+ self.assertEqual(doc.fiscal_line_ids[0].price_unit, 110)
172
+ self.assertEqual(doc.fiscal_line_ids[0].fiscal_price, 112)
173
+ self.assertEqual(doc.fiscal_line_ids[0].quantity, 10)
174
+ self.assertEqual(doc.fiscal_line_ids[0].fiscal_quantity, 5)
175
+
176
+ def test_landed_costs_by_line_and_by_total(self):
177
+ """
178
+ Tests both landed cost scenarios: 'by line' and 'by total'.
179
+ 1. By Line: Enters costs on lines and verifies the header totals.
180
+ 2. By Total: Enters costs on the header and verifies lines distribution.
181
+ """
182
+ self.env.user.groups_id |= self.env.ref("l10n_br_fiscal.group_user")
183
+ product1 = self.env.ref("product.product_product_6")
184
+ product2 = self.env.ref("product.product_product_7")
185
+
186
+ # Part 1: Test with delivery_costs = 'line'
187
+ # ----------------------------------------------------
188
+ self.company.delivery_costs = "line"
189
+ doc_form = Form(self.env["l10n_br_fiscal.document"])
190
+ doc_form.company_id = self.company
191
+ doc_form.partner_id = self.env.ref("l10n_br_base.res_partner_cliente1_sp")
192
+ doc_form.fiscal_operation_id = self.env.ref("l10n_br_fiscal.fo_venda")
193
+
194
+ with doc_form.fiscal_line_ids.new() as line1:
195
+ line1.product_id = product1
196
+ line1.fiscal_operation_line_id = self.env.ref(
197
+ "l10n_br_fiscal.fo_venda_venda"
198
+ )
199
+ line1.price_unit = 1000.0
200
+ line1.quantity = 2.0 # Gross: 2000
201
+ line1.freight_value = 10.0
202
+ line1.insurance_value = 20.0
203
+ line1.other_value = 5.0
204
+
205
+ with doc_form.fiscal_line_ids.new() as line2:
206
+ line2.product_id = product2
207
+ line2.fiscal_operation_line_id = self.env.ref(
208
+ "l10n_br_fiscal.fo_venda_venda"
209
+ )
210
+ line2.price_unit = 500.0
211
+ line2.quantity = 1.0 # Gross: 500
212
+ line2.freight_value = 4.0
213
+ line2.insurance_value = 6.0
214
+ line2.other_value = 2.0
215
+
216
+ doc = doc_form.save()
217
+
218
+ self.assertEqual(doc.company_id.delivery_costs, "line")
219
+ # Assert header totals are the SUM of line values
220
+ self.assertAlmostEqual(doc.amount_freight_value, 14.0) # 10.0 + 4.0
221
+ self.assertAlmostEqual(doc.amount_insurance_value, 26.0) # 20.0 + 6.0
222
+ self.assertAlmostEqual(doc.amount_other_value, 7.0) # 5.0 + 2.0
223
+
224
+ # Assert final fiscal totals (bottom-up calculation)
225
+ # price_gross = (1000*2) + (500*1) = 2500
226
+ # landed_costs = 14 + 26 + 7 = 47
227
+ # fiscal_amount_untaxed (IPI Base) = 2500 + 47 = 2547
228
+ self.assertAlmostEqual(doc.fiscal_amount_untaxed, 2547.00)
229
+ # fiscal_amount_tax (IPI) = (2035 * 3.25%) + (512 * 5%) = 66.14 + 25.60 = 91.74
230
+ self.assertAlmostEqual(doc.fiscal_amount_tax, 91.74, places=2)
231
+ # fiscal_amount_total = 2547.00 + 91.74 = 2638.74
232
+ self.assertAlmostEqual(doc.fiscal_amount_total, 2638.74, places=2)
233
+
234
+ # Part 2: Test with delivery_costs = 'total'
235
+ # ----------------------------------------------------
236
+ self.company.delivery_costs = "total"
237
+ doc_form_edit = Form(doc)
238
+ # Set new header totals, which should trigger inverse methods to distribute
239
+ doc_form_edit.amount_freight_value = 30.0
240
+ doc_form_edit.amount_insurance_value = 60.0
241
+ doc_form_edit.amount_other_value = 90.0
242
+ doc_after_total_update = doc_form_edit.save()
243
+
244
+ line1 = doc_after_total_update.fiscal_line_ids[0]
245
+ line2 = doc_after_total_update.fiscal_line_ids[1]
246
+
247
+ # Assert values were distributed proportionally to price_gross
248
+ # (2000 vs 500 -> 80% vs 20%)
249
+ # Freight: 30.0 * 0.8 = 24.0 | 30.0 * 0.2 = 6.0
250
+ self.assertAlmostEqual(line1.freight_value, 24.0)
251
+ self.assertAlmostEqual(line2.freight_value, 6.0)
252
+ # Insurance: 60.0 * 0.8 = 48.0 | 60.0 * 0.2 = 12.0
253
+ self.assertAlmostEqual(line1.insurance_value, 48.0)
254
+ self.assertAlmostEqual(line2.insurance_value, 12.0)
255
+ # Other: 90.0 * 0.8 = 72.0 | 90.0 * 0.2 = 18.0
256
+ self.assertAlmostEqual(line1.other_value, 72.0)
257
+ self.assertAlmostEqual(line2.other_value, 18.0)
258
+
259
+ # Assert final fiscal totals are recomputed correctly (top-down calculation)
260
+ # price_gross = 2500
261
+ # landed_costs = 30 + 60 + 90 = 180
262
+ # fiscal_amount_untaxed (IPI Base) = 2500 + 180 = 2680
263
+ self.assertAlmostEqual(doc_after_total_update.fiscal_amount_untaxed, 2680.00)
264
+ # Line 1 IPI Base = 2000 (product) + 24 (freight) + 48 (insurance)
265
+ # + 72 (other) = 2144
266
+ # Line 1 IPI Value = 2144 * 3.25% = 69.68
267
+ self.assertAlmostEqual(line1.ipi_base, 2144.00)
268
+ self.assertAlmostEqual(line1.ipi_value, 69.68, places=2)
269
+
270
+ # Line 2 IPI Base = 500 (product) + 6 (freight) + 12 (insurance)
271
+ # + 18 (other) = 536
272
+ # Line 2 IPI Value = 536 * 5% = 26.80
273
+ self.assertAlmostEqual(line2.ipi_base, 536.00)
274
+ self.assertAlmostEqual(line2.ipi_value, 26.80, places=2)
275
+
276
+ # fiscal_amount_tax (IPI) = 69.68 + 26.80 = 96.48
277
+ self.assertAlmostEqual(
278
+ doc_after_total_update.fiscal_amount_tax, 96.48, places=2
279
+ )
280
+ # fiscal_amount_total = 2680.00 + 96.48 = 2776.48
281
+ self.assertAlmostEqual(
282
+ doc_after_total_update.fiscal_amount_total, 2776.48, places=2
283
+ )
284
+
285
+ def test_difal_calculation(self):
286
+ partner = self.env.ref("l10n_br_base.res_partner_cliente5_pe")
287
+ partner.ind_ie_dest = "9"
288
+ doc_form = Form(
289
+ self.env["l10n_br_fiscal.document"].with_context(
290
+ default_fiscal_operation_type="out",
291
+ )
292
+ )
293
+ doc_form.company_id = self.company
294
+ doc_form.partner_id = partner
295
+ doc_form.fiscal_operation_id = self.env.ref("l10n_br_fiscal.fo_venda")
296
+
297
+ product = self.env.ref("product.product_product_6")
298
+ with doc_form.fiscal_line_ids.new() as line_form:
299
+ line_form.product_id = product
300
+ line_form.price_unit = 100.0
301
+ line_form.quantity = 1.0
302
+
303
+ doc = doc_form.save()
304
+ line = doc.fiscal_line_ids[0]
305
+ self.assertEqual(line.icms_destination_base, 100.0)
306
+ self.assertEqual(line.icms_origin_percent, 7.0)
307
+ self.assertEqual(line.icms_destination_percent, 20.5)
308
+ self.assertEqual(line.icms_destination_value, 13.5)
@@ -2,7 +2,6 @@
2
2
  # Magno Costa <magno.costa@akretion.com.br>
3
3
  # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
4
4
 
5
-
6
5
  from odoo.tests import TransactionCase
7
6
 
8
7
  from ..constants.icms import ICMS_ORIGIN_TAX_IMPORTED
@@ -12,6 +11,8 @@ class TestFiscalDocumentGeneric(TransactionCase):
12
11
  @classmethod
13
12
  def setUpClass(cls):
14
13
  super().setUpClass()
14
+ cls.env = cls.env(context=dict(cls.env.context, tracking_disable=True))
15
+
15
16
  # Contribuinte
16
17
  cls.nfe_same_state = cls.env.ref("l10n_br_fiscal.demo_nfe_same_state")
17
18
  cls.nfe_other_state = cls.env.ref("l10n_br_fiscal.demo_nfe_other_state")
@@ -38,26 +39,10 @@ class TestFiscalDocumentGeneric(TransactionCase):
38
39
 
39
40
  def test_nfe_same_state(self):
40
41
  """Test NFe same state."""
41
-
42
- self.nfe_same_state._onchange_document_serie_id()
43
- self.nfe_same_state._onchange_fiscal_operation_id()
44
-
45
42
  for line in self.nfe_same_state.fiscal_line_ids:
46
- # Save the original price_unit value of the line as defined in
47
- # the NFe demo data.
48
- original_price_unit = line.price_unit
49
-
50
- line._onchange_product_id_fiscal()
51
-
52
43
  # Restore the original price_unit value,
53
44
  # as the product change might have altered it.
54
- line.price_unit = original_price_unit
55
-
56
- line._onchange_commercial_quantity()
57
- line._onchange_ncm_id()
58
- line._onchange_fiscal_operation_id()
59
- line._onchange_fiscal_operation_line_id()
60
- line._onchange_fiscal_taxes()
45
+ line.price_unit = 100
61
46
 
62
47
  if "Revenda" in line.fiscal_operation_line_id.name:
63
48
  self.assertEqual(
@@ -87,9 +72,10 @@ class TestFiscalDocumentGeneric(TransactionCase):
87
72
  # ICMS
88
73
  self.assertTrue(
89
74
  is_icms_internal,
90
- "Error to mapping ICMS Inernal for {}"
75
+ "Error to mapping ICMS Inernal for "
76
+ f"{self.nfe_same_state.partner_id.state_id.name}"
91
77
  " for Venda de Contribuinte Dentro do "
92
- "Estado.".format(self.nfe_same_state.partner_id.state_id.name),
78
+ "Estado.",
93
79
  )
94
80
  self.assertEqual(
95
81
  line.icms_cst_id.code,
@@ -171,18 +157,7 @@ class TestFiscalDocumentGeneric(TransactionCase):
171
157
 
172
158
  def test_nfe_other_state(self):
173
159
  """Test NFe other state."""
174
-
175
- self.nfe_other_state._onchange_document_serie_id()
176
- self.nfe_other_state._onchange_fiscal_operation_id()
177
-
178
160
  for line in self.nfe_other_state.fiscal_line_ids:
179
- line._onchange_product_id_fiscal()
180
- line._onchange_commercial_quantity()
181
- line._onchange_ncm_id()
182
- line._onchange_fiscal_operation_id()
183
- line._onchange_fiscal_operation_line_id()
184
- line._onchange_fiscal_taxes()
185
-
186
161
  if "Revenda" in line.fiscal_operation_line_id.name:
187
162
  self.assertEqual(
188
163
  line.cfop_id.code,
@@ -293,18 +268,7 @@ class TestFiscalDocumentGeneric(TransactionCase):
293
268
 
294
269
  def test_nfe_not_taxpayer(self):
295
270
  """Test NFe not taxpayer."""
296
-
297
- self.nfe_not_taxpayer._onchange_document_serie_id()
298
- self.nfe_not_taxpayer._onchange_fiscal_operation_id()
299
-
300
271
  for line in self.nfe_not_taxpayer.fiscal_line_ids:
301
- line._onchange_product_id_fiscal()
302
- line._onchange_commercial_quantity()
303
- line._onchange_ncm_id()
304
- line._onchange_fiscal_operation_id()
305
- line._onchange_fiscal_operation_line_id()
306
- line._onchange_fiscal_taxes()
307
-
308
272
  if "Revenda" in line.fiscal_operation_line_id.name:
309
273
  self.assertEqual(
310
274
  line.cfop_id.code,
@@ -402,18 +366,7 @@ class TestFiscalDocumentGeneric(TransactionCase):
402
366
 
403
367
  def test_nfe_not_taxpayer_not_company(self):
404
368
  """Test NFe not taxpayer not Company."""
405
-
406
- self.nfe_not_taxpayer_pf._onchange_document_serie_id()
407
- self.nfe_not_taxpayer_pf._onchange_fiscal_operation_id()
408
-
409
369
  for line in self.nfe_not_taxpayer_pf.fiscal_line_ids:
410
- line._onchange_product_id_fiscal()
411
- line._onchange_commercial_quantity()
412
- line._onchange_ncm_id()
413
- line._onchange_fiscal_operation_id()
414
- line._onchange_fiscal_operation_line_id()
415
- line._onchange_fiscal_taxes()
416
-
417
370
  if "Revenda" in line.fiscal_operation_line_id.name:
418
371
  self.assertEqual(
419
372
  line.cfop_id.code,
@@ -511,18 +464,7 @@ class TestFiscalDocumentGeneric(TransactionCase):
511
464
 
512
465
  def test_nfe_export(self):
513
466
  """Test NFe export."""
514
-
515
- self.nfe_export._onchange_document_serie_id()
516
- self.nfe_export._onchange_fiscal_operation_id()
517
-
518
467
  for line in self.nfe_export.fiscal_line_ids:
519
- line._onchange_product_id_fiscal()
520
- line._onchange_commercial_quantity()
521
- line._onchange_ncm_id()
522
- line._onchange_fiscal_operation_id()
523
- line._onchange_fiscal_operation_line_id()
524
- line._onchange_fiscal_taxes()
525
-
526
468
  if "Revenda" in line.fiscal_operation_line_id.name:
527
469
  self.assertEqual(
528
470
  line.cfop_id.code,
@@ -586,8 +528,7 @@ class TestFiscalDocumentGeneric(TransactionCase):
586
528
  self.assertEqual(
587
529
  line.pis_tax_id.name,
588
530
  "PIS 0,65%",
589
- "Error to mapping PIS 0,65%"
590
- " for Venda de Contribuinte p/ o Exterior.",
531
+ "Error to mapping PIS 0,65% for Venda de Contribuinte p/ o Exterior.",
591
532
  )
592
533
  self.assertEqual(
593
534
  line.pis_cst_id.code,
@@ -601,8 +542,7 @@ class TestFiscalDocumentGeneric(TransactionCase):
601
542
  self.assertEqual(
602
543
  line.cofins_tax_id.name,
603
544
  "COFINS 3%",
604
- "Error to mapping COFINS 3%"
605
- " for Venda de Contribuinte p/ o Exterior.",
545
+ "Error to mapping COFINS 3% for Venda de Contribuinte p/ o Exterior.",
606
546
  )
607
547
  self.assertEqual(
608
548
  line.cofins_cst_id.code,
@@ -614,14 +554,7 @@ class TestFiscalDocumentGeneric(TransactionCase):
614
554
 
615
555
  def test_nfe_sn_same_state(self):
616
556
  """Test NFe Simples Nacional same state."""
617
-
618
- self.nfe_sn_same_state._onchange_document_serie_id()
619
- self.nfe_sn_same_state._onchange_fiscal_operation_id()
620
-
621
557
  for line in self.nfe_sn_same_state.fiscal_line_ids:
622
- line._onchange_product_id_fiscal()
623
- line._onchange_commercial_quantity()
624
-
625
558
  # set fake estimate tax
626
559
  line.ncm_id.tax_estimate_ids.create(
627
560
  {
@@ -632,11 +565,9 @@ class TestFiscalDocumentGeneric(TransactionCase):
632
565
  "federal_taxes_national": 33.00,
633
566
  }
634
567
  )
635
-
636
- line._onchange_ncm_id()
637
- line._onchange_fiscal_operation_id()
638
- line._onchange_fiscal_operation_line_id()
639
- line._onchange_fiscal_taxes()
568
+ # força o compute, pois não é chamado automaticamente
569
+ # quando uma informação externa muda.
570
+ line._compute_tax_fields()
640
571
 
641
572
  if "Revenda" in line.fiscal_operation_line_id.name:
642
573
  self.assertEqual(
@@ -734,18 +665,7 @@ class TestFiscalDocumentGeneric(TransactionCase):
734
665
 
735
666
  def test_nfe_sn_other_state(self):
736
667
  """Test NFe SN other state."""
737
-
738
- self.nfe_sn_other_state._onchange_document_serie_id()
739
- self.nfe_sn_other_state._onchange_fiscal_operation_id()
740
-
741
668
  for line in self.nfe_sn_other_state.fiscal_line_ids:
742
- line._onchange_product_id_fiscal()
743
- line._onchange_commercial_quantity()
744
- line._onchange_ncm_id()
745
- line._onchange_fiscal_operation_id()
746
- line._onchange_fiscal_operation_line_id()
747
- line._onchange_fiscal_taxes()
748
-
749
669
  if "Revenda" in line.fiscal_operation_line_id.name:
750
670
  self.assertEqual(
751
671
  line.cfop_id.code,
@@ -839,18 +759,7 @@ class TestFiscalDocumentGeneric(TransactionCase):
839
759
 
840
760
  def test_nfe_sn_not_taxpayer(self):
841
761
  """Test NFe SN not taxpayer."""
842
-
843
- self.nfe_sn_not_taxpayer._onchange_document_serie_id()
844
- self.nfe_sn_not_taxpayer._onchange_fiscal_operation_id()
845
-
846
762
  for line in self.nfe_sn_not_taxpayer.fiscal_line_ids:
847
- line._onchange_product_id_fiscal()
848
- line._onchange_commercial_quantity()
849
- line._onchange_ncm_id()
850
- line._onchange_fiscal_operation_id()
851
- line._onchange_fiscal_operation_line_id()
852
- line._onchange_fiscal_taxes()
853
-
854
763
  if "Revenda" in line.fiscal_operation_line_id.name:
855
764
  self.assertEqual(
856
765
  line.cfop_id.code,
@@ -890,8 +799,7 @@ class TestFiscalDocumentGeneric(TransactionCase):
890
799
  self.assertEqual(
891
800
  line.ipi_tax_id.name,
892
801
  "IPI 5%",
893
- "Erro ao mapear IPI 5%"
894
- " para Venda de Simples Nacional Fora do Estado.",
802
+ "Erro ao mapear IPI 5% para Venda de Simples Nacional Fora do Estado.",
895
803
  )
896
804
  self.assertEqual(
897
805
  line.ipi_cst_id.code,
@@ -932,18 +840,7 @@ class TestFiscalDocumentGeneric(TransactionCase):
932
840
 
933
841
  def test_nfe_sn_export(self):
934
842
  """Test NFe SN export."""
935
-
936
- self.nfe_sn_export._onchange_document_serie_id()
937
- self.nfe_sn_export._onchange_fiscal_operation_id()
938
-
939
843
  for line in self.nfe_sn_export.fiscal_line_ids:
940
- line._onchange_product_id_fiscal()
941
- line._onchange_commercial_quantity()
942
- line._onchange_ncm_id()
943
- line._onchange_fiscal_operation_id()
944
- line._onchange_fiscal_operation_line_id()
945
- line._onchange_fiscal_taxes()
946
-
947
844
  if "Revenda" in line.fiscal_operation_line_id.name:
948
845
  self.assertEqual(
949
846
  line.cfop_id.code,
@@ -1053,7 +950,7 @@ class TestFiscalDocumentGeneric(TransactionCase):
1053
950
  additional_data = self.nfe_not_taxpayer.fiscal_line_ids[0].additional_data
1054
951
  self.assertEqual(
1055
952
  additional_data,
1056
- "manual comment test",
953
+ "manual comment test - Valor Aprox. dos Tributos: R$\xa00,00",
1057
954
  )
1058
955
 
1059
956
  def test_fields_freight_insurance_other_costs(self):
@@ -1063,6 +960,7 @@ class TestFiscalDocumentGeneric(TransactionCase):
1063
960
 
1064
961
  # Teste definindo os valores Por Linha
1065
962
  for line in self.nfe_same_state.fiscal_line_ids:
963
+ line.price_unit = 100
1066
964
  line.freight_value = 10.0
1067
965
  line.insurance_value = 10.0
1068
966
  line.other_value = 10.0
@@ -1070,19 +968,17 @@ class TestFiscalDocumentGeneric(TransactionCase):
1070
968
  self.assertEqual(
1071
969
  self.nfe_same_state.amount_freight_value,
1072
970
  20.0,
1073
- "Unexpected value for the field" " Amount Freight in Fiscal Document line",
971
+ "Unexpected value for the field Amount Freight in Fiscal Document line",
1074
972
  )
1075
973
  self.assertEqual(
1076
974
  self.nfe_same_state.amount_insurance_value,
1077
975
  20.0,
1078
- "Unexpected value for the field"
1079
- " Amount Insurance in Fiscal Document line",
976
+ "Unexpected value for the field Amount Insurance in Fiscal Document line",
1080
977
  )
1081
978
  self.assertEqual(
1082
979
  self.nfe_same_state.amount_other_value,
1083
980
  20.0,
1084
- "Unexpected value for the field"
1085
- " Amount Other Value in Fiscal Document line",
981
+ "Unexpected value for the field Amount Other Value in Fiscal Document line",
1086
982
  )
1087
983
 
1088
984
  # Teste definindo os valores Por Total
@@ -1098,18 +994,17 @@ class TestFiscalDocumentGeneric(TransactionCase):
1098
994
  self.assertEqual(
1099
995
  line.freight_value,
1100
996
  5.0,
1101
- "Unexpected value for the field" " Freight in Fiscal Document line",
997
+ "Unexpected value for the field Freight in Fiscal Document line",
1102
998
  )
1103
999
  self.assertEqual(
1104
1000
  line.insurance_value,
1105
1001
  5.0,
1106
- "Unexpected value for the field" " Insurance in Fiscal Document line",
1002
+ "Unexpected value for the field Insurance in Fiscal Document line",
1107
1003
  )
1108
1004
  self.assertEqual(
1109
1005
  line.other_value,
1110
1006
  5.0,
1111
- "Unexpected value for the field"
1112
- " Other Values in Fiscal Document line",
1007
+ "Unexpected value for the field Other Values in Fiscal Document line",
1113
1008
  )
1114
1009
 
1115
1010
  # Caso que os Campos na Linha não tem valor
@@ -1126,16 +1021,15 @@ class TestFiscalDocumentGeneric(TransactionCase):
1126
1021
  self.assertEqual(
1127
1022
  line.freight_value,
1128
1023
  10.0,
1129
- "Unexpected value for the field" " Freight in Fiscal Document line",
1024
+ "Unexpected value for the field Freight in Fiscal Document line",
1130
1025
  )
1131
1026
  self.assertEqual(
1132
1027
  line.insurance_value,
1133
1028
  10.0,
1134
- "Unexpected value for the field" " Insurance in Fiscal Document line",
1029
+ "Unexpected value for the field Insurance in Fiscal Document line",
1135
1030
  )
1136
1031
  self.assertEqual(
1137
1032
  line.other_value,
1138
1033
  10.0,
1139
- "Unexpected value for the field"
1140
- " Other Values in Fiscal Document line",
1034
+ "Unexpected value for the field Other Values in Fiscal Document line",
1141
1035
  )
@@ -5,25 +5,15 @@ from odoo.tests.common import TransactionCase
5
5
 
6
6
 
7
7
  class TestFiscalDocumentNFSe(TransactionCase):
8
- def setUp(self):
9
- super().setUp()
10
-
11
- self.nfse_same_state = self.env.ref("l10n_br_fiscal.demo_nfse_same_state")
8
+ @classmethod
9
+ def setUpClass(cls):
10
+ super().setUpClass()
11
+ cls.env = cls.env(context=dict(cls.env.context, tracking_disable=True))
12
+ cls.nfse_same_state = cls.env.ref("l10n_br_fiscal.demo_nfse_same_state")
12
13
 
13
14
  def test_nfse_same_state(self):
14
15
  """Test NFSe same state."""
15
-
16
- self.nfse_same_state._onchange_document_serie_id()
17
- self.nfse_same_state._onchange_fiscal_operation_id()
18
-
19
16
  for line in self.nfse_same_state.fiscal_line_ids:
20
- line._onchange_product_id_fiscal()
21
- line._onchange_commercial_quantity()
22
- line._onchange_ncm_id()
23
- line._onchange_fiscal_operation_id()
24
- line._onchange_fiscal_operation_line_id()
25
- line._onchange_fiscal_taxes()
26
-
27
17
  self.assertEqual(
28
18
  line.fiscal_operation_line_id.name,
29
19
  "Prestação de Serviço",