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
@@ -51,6 +51,9 @@ class ProductTemplate(models.Model):
51
51
  index=True,
52
52
  default=_get_default_ncm_id,
53
53
  string="NCM",
54
+ compute="_compute_ncm_id",
55
+ store=True,
56
+ readonly=False,
54
57
  )
55
58
 
56
59
  nbm_id = fields.Many2one(
@@ -61,10 +64,17 @@ class ProductTemplate(models.Model):
61
64
  selection=TAX_ICMS_OR_ISSQN,
62
65
  string="ICMS or ISSQN Tax",
63
66
  default=TAX_DOMAIN_ICMS,
67
+ compute="_compute_tax_icms_or_issqn",
68
+ store=True,
69
+ readonly=False,
64
70
  )
65
71
 
66
72
  fiscal_genre_id = fields.Many2one(
67
- comodel_name="l10n_br_fiscal.product.genre", string="Fiscal Product Genre"
73
+ comodel_name="l10n_br_fiscal.product.genre",
74
+ string="Fiscal Product Genre",
75
+ compute="_compute_fiscal_genre_id",
76
+ store=True,
77
+ readonly=False,
68
78
  )
69
79
 
70
80
  service_type_id = fields.Many2one(
@@ -73,12 +83,14 @@ class ProductTemplate(models.Model):
73
83
  domain="[('internal_type', '=', 'normal')]",
74
84
  )
75
85
 
76
- city_taxation_code_id = fields.Many2many(
86
+ city_taxation_code_ids = fields.Many2many(
77
87
  comodel_name="l10n_br_fiscal.city.taxation.code", string="City Taxation Code"
78
88
  )
79
89
 
80
90
  fiscal_genre_code = fields.Char(
81
- related="fiscal_genre_id.code", store=True, string="Fiscal Product Genre Code"
91
+ related="fiscal_genre_id.code",
92
+ store=True,
93
+ string="Fiscal Product Genre Code",
82
94
  )
83
95
 
84
96
  ipi_guideline_class_id = fields.Many2one(
@@ -94,6 +106,10 @@ class ProductTemplate(models.Model):
94
106
  comodel_name="l10n_br_fiscal.nbs", index=True, string="NBS"
95
107
  )
96
108
 
109
+ operation_indicator_id = fields.Many2one(
110
+ comodel_name="l10n_br_fiscal.operation.indicator",
111
+ )
112
+
97
113
  cest_id = fields.Many2one(
98
114
  comodel_name="l10n_br_fiscal.cest",
99
115
  index=True,
@@ -102,7 +118,10 @@ class ProductTemplate(models.Model):
102
118
  )
103
119
 
104
120
  uoe_id = fields.Many2one(
105
- comodel_name="uom.uom", related="ncm_id.uoe_id", store=True, string="Export UoM"
121
+ comodel_name="uom.uom",
122
+ related="ncm_id.uoe_id",
123
+ store=True,
124
+ string="Export UoM",
106
125
  )
107
126
 
108
127
  uoe_factor = fields.Float(string="Export UoM Factor", default=1.00)
@@ -110,12 +129,3 @@ class ProductTemplate(models.Model):
110
129
  uot_id = fields.Many2one(comodel_name="uom.uom", string="Tax UoM")
111
130
 
112
131
  uot_factor = fields.Float(string="Tax UoM Factor")
113
-
114
- tax_definition_ids = fields.Many2many(
115
- comodel_name="l10n_br_fiscal.tax.definition",
116
- relation="tax_definition_product_rel",
117
- column1="product_id",
118
- column2="tax_definition_id",
119
- readonly=True,
120
- string="Tax Definition",
121
- )
@@ -14,10 +14,12 @@ from ..constants.fiscal import (
14
14
  PROCESSADOR_NENHUM,
15
15
  PROFIT_CALCULATION,
16
16
  PROFIT_CALCULATION_PRESUMED,
17
+ TAX_DOMAIN_CBS,
17
18
  TAX_DOMAIN_COFINS,
18
19
  TAX_DOMAIN_COFINS_WH,
19
20
  TAX_DOMAIN_CSLL,
20
21
  TAX_DOMAIN_CSLL_WH,
22
+ TAX_DOMAIN_IBS,
21
23
  TAX_DOMAIN_ICMS,
22
24
  TAX_DOMAIN_ICMS_SN,
23
25
  TAX_DOMAIN_INSS,
@@ -45,9 +47,15 @@ class ResCompany(models.Model):
45
47
  partner_fields = super()._get_company_address_field_names()
46
48
  return partner_fields + [
47
49
  "tax_framework",
50
+ "legal_nature_id",
48
51
  "cnae_main_id",
49
52
  ]
50
53
 
54
+ def _inverse_legal_nature_id(self):
55
+ """Write the l10n_br specific functional fields."""
56
+ for c in self:
57
+ c.partner_id.legal_nature_id = c.legal_nature_id
58
+
51
59
  def _inverse_cnae_main_id(self):
52
60
  """Write the l10n_br specific functional fields."""
53
61
  for c in self:
@@ -105,6 +113,13 @@ class ResCompany(models.Model):
105
113
  record.currency_id.decimal_places,
106
114
  )
107
115
 
116
+ legal_nature_id = fields.Many2one(
117
+ comodel_name="l10n_br_fiscal.legal.nature",
118
+ string="Legal Nature",
119
+ compute="_compute_address",
120
+ inverse="_inverse_legal_nature_id",
121
+ )
122
+
108
123
  cnae_main_id = fields.Many2one(
109
124
  comodel_name="l10n_br_fiscal.cnae",
110
125
  compute="_compute_address",
@@ -116,9 +131,6 @@ class ResCompany(models.Model):
116
131
 
117
132
  cnae_secondary_ids = fields.Many2many(
118
133
  comodel_name="l10n_br_fiscal.cnae",
119
- relation="res_company_fiscal_cnae_rel",
120
- column1="company_id",
121
- column2="cnae_id",
122
134
  domain="[('internal_type', '=', 'normal'), " "('id', '!=', cnae_main_id)]",
123
135
  string="Secondary CNAE",
124
136
  )
@@ -287,6 +299,12 @@ class ResCompany(models.Model):
287
299
  domain=[("tax_domain", "=", TAX_DOMAIN_INSS_WH)],
288
300
  )
289
301
 
302
+ tax_classification_id = fields.Many2one(
303
+ comodel_name="l10n_br_fiscal.tax.classification",
304
+ string="Default Tax Classification",
305
+ domain=[("tax_ibs_id", "!=", False), ("tax_cbs_id", "!=", False)],
306
+ )
307
+
290
308
  tax_definition_ids = fields.One2many(
291
309
  comodel_name="l10n_br_fiscal.tax.definition",
292
310
  inverse_name="company_id",
@@ -303,12 +321,6 @@ class ResCompany(models.Model):
303
321
  comodel_name="l10n_br_fiscal.document.type", string="Default Document Type"
304
322
  )
305
323
 
306
- document_email_ids = fields.One2many(
307
- comodel_name="l10n_br_fiscal.document.email",
308
- inverse_name="company_id",
309
- string="Email Template Definition",
310
- )
311
-
312
324
  document_save_disk = fields.Boolean(
313
325
  string="Save Documents to disk",
314
326
  default=True,
@@ -373,6 +385,7 @@ class ResCompany(models.Model):
373
385
  self.tax_icms_id = False
374
386
 
375
387
  self._onchange_piscofins_id()
388
+ self._onchange_tax_classification_id()
376
389
  self._onchange_ripi()
377
390
  self._onchange_tax_ipi_id()
378
391
  self._onchange_tax_icms_id()
@@ -498,3 +511,12 @@ class ResCompany(models.Model):
498
511
  self._set_tax_definition(self.tax_inss_wh_id)
499
512
  else:
500
513
  self._del_tax_definition(TAX_DOMAIN_INSS_WH)
514
+
515
+ @api.onchange("tax_classification_id")
516
+ def _onchange_tax_classification_id(self):
517
+ if self.tax_classification_id:
518
+ self._set_tax_definition(self.tax_classification_id.tax_cbs_id)
519
+ self._set_tax_definition(self.tax_classification_id.tax_ibs_id)
520
+ else:
521
+ self._del_tax_definition(TAX_DOMAIN_CBS)
522
+ self._del_tax_definition(TAX_DOMAIN_IBS)
@@ -10,6 +10,7 @@ from ..constants.fiscal import (
10
10
  NFE_IND_IE_DEST,
11
11
  NFE_IND_IE_DEST_9,
12
12
  NFE_IND_IE_DEST_DEFAULT,
13
+ PUBLIC_ENTIRY_TYPE,
13
14
  TAX_FRAMEWORK,
14
15
  TAX_FRAMEWORK_NORMAL,
15
16
  )
@@ -33,12 +34,23 @@ class ResPartner(models.Model):
33
34
  tracking=True,
34
35
  )
35
36
 
37
+ legal_nature_id = fields.Many2one(
38
+ comodel_name="l10n_br_fiscal.legal.nature",
39
+ string="Legal Nature",
40
+ )
41
+
36
42
  cnae_main_id = fields.Many2one(
37
43
  comodel_name="l10n_br_fiscal.cnae",
38
44
  domain=[("internal_type", "=", "normal")],
39
45
  string="Main CNAE",
40
46
  )
41
47
 
48
+ cnae_secondary_ids = fields.Many2many(
49
+ comodel_name="l10n_br_fiscal.cnae",
50
+ domain="[('internal_type', '=', 'normal'), ('id', '!=', cnae_main_id)]",
51
+ string="Secondary CNAEs",
52
+ )
53
+
42
54
  ind_ie_dest = fields.Selection(
43
55
  selection=NFE_IND_IE_DEST,
44
56
  string="Contribuinte do ICMS",
@@ -65,6 +77,11 @@ class ResPartner(models.Model):
65
77
  "other government-controlled organizations.",
66
78
  )
67
79
 
80
+ public_entity_type = fields.Selection(
81
+ selection=PUBLIC_ENTIRY_TYPE,
82
+ string="Tipo de Entidade Governamental",
83
+ )
84
+
68
85
  ind_final = fields.Selection(
69
86
  selection=FINAL_CUSTOMER,
70
87
  string="Final Consumption Operation",
@@ -72,15 +89,15 @@ class ResPartner(models.Model):
72
89
  tracking=True,
73
90
  )
74
91
 
75
- cnpj_cpf = fields.Char(
92
+ vat = fields.Char(
76
93
  tracking=True,
77
94
  )
78
95
 
79
- inscr_est = fields.Char(
96
+ l10n_br_ie_code = fields.Char(
80
97
  tracking=True,
81
98
  )
82
99
 
83
- inscr_mun = fields.Char(
100
+ l10n_br_im_code = fields.Char(
84
101
  tracking=True,
85
102
  )
86
103
 
@@ -96,6 +113,20 @@ class ResPartner(models.Model):
96
113
  tracking=True,
97
114
  )
98
115
 
116
+ rntrc_code = fields.Char(
117
+ string="RNTRC Code", size=12, unaccent=False, tracking=True
118
+ )
119
+
120
+ nif_motive_absence = fields.Selection(
121
+ selection=[
122
+ ("0", "Not informed in the origin note"),
123
+ ("1", "Exemption from NIF"),
124
+ ("2", "NIF not required"),
125
+ ],
126
+ default=False,
127
+ string="NIF motive absence",
128
+ )
129
+
99
130
  def _inverse_fiscal_profile(self):
100
131
  for p in self:
101
132
  p._onchange_fiscal_profile_id()
@@ -112,12 +143,13 @@ class ResPartner(models.Model):
112
143
  p.tax_framework = p.fiscal_profile_id.tax_framework
113
144
  p.ind_ie_dest = p.fiscal_profile_id.ind_ie_dest
114
145
  p.is_public_entity = p.fiscal_profile_id.is_public_entity
146
+ p.public_entity_type = p.fiscal_profile_id.public_entity_type
115
147
 
116
148
  @api.onchange("ind_ie_dest")
117
149
  def _onchange_ind_ie_dest(self):
118
150
  for p in self:
119
151
  if p.ind_ie_dest == NFE_IND_IE_DEST_9:
120
- p.inscr_est = False
152
+ p.l10n_br_ie_code = False
121
153
  p.state_tax_number_ids = False
122
154
 
123
155
  @api.model
@@ -128,6 +160,6 @@ class ResPartner(models.Model):
128
160
  "ind_ie_dest",
129
161
  "fiscal_profile_id",
130
162
  "ind_final",
131
- "inscr_est",
132
- "inscr_mun",
163
+ "l10n_br_ie_code",
164
+ "l10n_br_im_code",
133
165
  ]
@@ -13,9 +13,6 @@ class SimplifiedTax(models.Model):
13
13
 
14
14
  cnae_ids = fields.Many2many(
15
15
  comodel_name="l10n_br_fiscal.cnae",
16
- relation="fiscal_simplified_tax_cnae_rel",
17
- column1="simplified_tax_id",
18
- column2="cnae_id",
19
16
  domain="[('internal_type', '=', 'normal')]",
20
17
  string="CNAEs",
21
18
  )
@@ -66,3 +66,11 @@ class SimplifiedTaxRange(models.Model):
66
66
  tax_pis_percent = fields.Float(
67
67
  string="Tax PIS Percent", digits="Fiscal Tax Percent"
68
68
  )
69
+
70
+ tax_ibs_percent = fields.Float(
71
+ string="Tax IBS Percent", digits="Fiscal Tax Percent"
72
+ )
73
+
74
+ tax_cbs_percent = fields.Float(
75
+ string="Tax CBS Percent", digits="Fiscal Tax Percent"
76
+ )
@@ -57,8 +57,64 @@ TAX_DICT_VALUES = {
57
57
  "icms_dest_value": 0.00,
58
58
  }
59
59
 
60
+ ICMS_ST_BASE_TYPE_REL = {
61
+ "0": TAX_BASE_TYPE_VALUE,
62
+ "1": TAX_BASE_TYPE_VALUE,
63
+ "2": TAX_BASE_TYPE_VALUE,
64
+ "3": TAX_BASE_TYPE_VALUE,
65
+ "4": TAX_BASE_TYPE_PERCENT,
66
+ "5": TAX_BASE_TYPE_VALUE,
67
+ }
68
+
60
69
 
61
70
  class Tax(models.Model):
71
+ """
72
+ Represents a specific Brazilian fiscal tax (e.g., ICMS, IPI, PIS, COFINS)
73
+ and acts as the core engine for calculating its value in a given context.
74
+
75
+ This model is distinct from Odoo's generic `account.tax`. Each record
76
+ defines a particular tax, its domain (e.g., 'icms', 'ipi'), how its
77
+ base is calculated (percentage, fixed value, per quantity), applicable
78
+ rates, percentage reductions, and links to its Tax Group and default
79
+ CST codes (Código de Situação Tributária).
80
+
81
+ Key Responsibilities:
82
+ 1. **Tax Definition**: Stores the parameters for a single fiscal tax,
83
+ including its calculation method, rates (percent_amount,
84
+ value_amount), base reduction (percent_reduction), and specific
85
+ attributes for complex taxes like ICMS (e.g., icms_base_type,
86
+ icmsst_base_type, icmsst_mva_percent).
87
+
88
+ 2. **Tax Calculation Engine (`compute_taxes` method)**:
89
+ The primary entry point for tax computation. When called on a
90
+ recordset of `l10n_br_fiscal.tax` objects (representing all taxes
91
+ potentially applicable to a transaction line), it iterates through
92
+ them in a defined sequence. For each tax, it:
93
+ a. Initializes a standard dictionary (`TAX_DICT_VALUES`) to hold
94
+ results.
95
+ b. Invokes a specialized internal method (e.g., `_compute_icms`,
96
+ `_compute_ipi`, or the generic `_compute_tax`) to perform
97
+ the actual calculation logic for that tax domain. These
98
+ internal methods determine the tax base, apply reductions,
99
+ and calculate the tax value.
100
+ c. Handles inter-tax dependencies (e.g., IPI value affecting
101
+ ICMS base).
102
+ d. Aggregates results, including total tax included in price,
103
+ tax not included, and withholding amounts.
104
+
105
+ 3. **Contextual Adaptation**: The calculation methods
106
+ (`_compute_<tax_domain>`) take numerous keyword arguments
107
+ (`**kwargs`) representing the full fiscal context (company, partner,
108
+ product, operation details, other calculated taxes, etc.) to ensure
109
+ taxes are computed according to specific scenarios (e.g., interstate
110
+ operations, final consumer, import/export).
111
+
112
+ This model, in conjunction with `l10n_br_fiscal.tax.definition` (which
113
+ determines *which* of these `l10n_br_fiscal.tax` records apply),
114
+ forms the heart of the Brazilian tax calculation system in this
115
+ localization.
116
+ """
117
+
62
118
  _name = "l10n_br_fiscal.tax"
63
119
  _order = "sequence, tax_domain, name"
64
120
  _description = "Fiscal Tax"
@@ -87,6 +143,8 @@ class Tax(models.Model):
87
143
  selection=TAX_BASE_TYPE,
88
144
  default=TAX_BASE_TYPE_PERCENT,
89
145
  required=True,
146
+ compute="_compute_tax_base_type",
147
+ store=True,
90
148
  )
91
149
 
92
150
  percent_amount = fields.Float(
@@ -392,9 +450,13 @@ class Tax(models.Model):
392
450
  and cfop.destination == CFOP_DESTINATION_EXTERNAL
393
451
  and partner.ind_ie_dest == NFE_IND_IE_DEST_9
394
452
  and tax_dict.get("tax_value")
395
- and operation_line.fiscal_operation_type == FISCAL_OUT
396
- or operation_line.fiscal_operation_id.fiscal_type == "return_in"
397
- and operation_line.fiscal_operation_type == FISCAL_IN
453
+ and (
454
+ operation_line.fiscal_operation_type == FISCAL_OUT
455
+ or (
456
+ operation_line.fiscal_operation_type == FISCAL_IN
457
+ and operation_line.fiscal_operation_id.fiscal_type != "return_in"
458
+ )
459
+ )
398
460
  ):
399
461
  icms_tax_difal, _ = company.icms_regulation_id.map_tax_def_icms_difal(
400
462
  company, partner, product, ncm, nbm, cest, operation_line, ind_final
@@ -616,14 +678,20 @@ class Tax(models.Model):
616
678
 
617
679
  @api.model
618
680
  def _compute_tax_sequence(self, taxes_dict, **kwargs):
619
- """Método para calcular a ordem que os impostos serão calculados.
620
- Por padrão é utilizado o campo compute_sequence do objeto para
621
- ordenar a sequencia que os impostos serão calculados.
622
- Por padrão é obdecida a seguinte sequencia:
681
+ """
682
+ Method to determine the order in which taxes will be calculated.
623
683
 
624
- compute_sequence = {
625
- tax_domain: compute_sequence,
684
+ By default, the `compute_sequence` field of the tax object is used
685
+ to sort the sequence for tax calculation. The default processing
686
+ order is based on these `compute_sequence` values, conceptually
687
+ like:
688
+
689
+ {
690
+ 'tax_domain_A': its_compute_sequence_value,
691
+ 'tax_domain_B': its_compute_sequence_value,
692
+ # ... and so on for other tax domains
626
693
  }
694
+ # Lower compute_sequence values are typically processed earlier.
627
695
  """
628
696
  # Pega por padrão os valores do campo compute_sequence
629
697
  compute_sequence = {t.tax_domain: t.compute_sequence for t in self}
@@ -643,39 +711,66 @@ class Tax(models.Model):
643
711
 
644
712
  def compute_taxes(self, **kwargs):
645
713
  """
646
- arguments:
647
- company,
648
- partner,
649
- product,
650
- price_unit,
651
- quantity,
652
- uom_id,
653
- fiscal_price,
654
- fiscal_quantity,
655
- uot_id,
656
- discount_value,
657
- insurance_value,
658
- other_value,
659
- freight_value,
660
- ii_customhouse_charges,
661
- ii_iof_value,
662
- ncm,
663
- nbs,
664
- nbm,
665
- cest,
666
- operation_line,
667
- cfop,
668
- icmssn_range,
669
- icms_origin,
670
- ind_final,
671
- return
672
- {
673
- 'amount_included': float
674
- 'amount_not_included': float
675
- 'amount_withholding': float
676
- 'taxes': dict
677
- }
714
+ Compute all applicable Brazilian taxes based on a set of input parameters.
715
+
716
+ This method orchestrates the calculation of various taxes (ICMS, IPI, PIS,
717
+ COFINS, ISSQN, etc.) by calling specialized internal _compute_<tax_domain>
718
+ methods. It respects a defined computation sequence for taxes and handles
719
+ interdependencies, such as IPI influencing the ICMS base under certain
720
+ conditions.
721
+
722
+ The result includes the calculated tax values for each domain, amounts
723
+ included in the price, amounts not included, and withholding amounts.
724
+ It also calculates an estimated total tax amount as per "Lei da Transparência".
725
+
726
+ :param company: res.company record of the emitting company.
727
+ :param partner: res.partner record of the recipient/customer.
728
+ :param product: product.product record being taxed.
729
+ :param price_unit: float, the unit price of the product/service before
730
+ discounts.
731
+ :param quantity: float, the quantity of the product/service.
732
+ :param uom_id: uom.uom record, unit of measure for the quantity.
733
+ :param fiscal_price: float, the fiscal price unit (e.g., for tax
734
+ calculation if different from commercial price).
735
+ :param fiscal_quantity: float, the fiscal quantity (e.g., for tax
736
+ calculation if different from commercial quantity).
737
+ :param uot_id: uom.uom record, unit of taxation if different from uom_id.
738
+ :param discount_value: float, total discount amount for the line.
739
+ :param insurance_value: float, total insurance amount for the line.
740
+ :param other_value: float, total other costs/fees for the line.
741
+ :param freight_value: float, total freight amount for the line.
742
+ :param ii_customhouse_charges: float, customs house charges for Import Tax
743
+ (II).
744
+ :param ii_iof_value: float, IOF value related to Import Tax (II).
745
+ :param ncm: l10n_br_fiscal.ncm record, NCM code for the product.
746
+ :param nbs: l10n_br_fiscal.nbs record, NBS code for the service.
747
+ :param nbm: l10n_br_fiscal.nbm record, NBM code for the product.
748
+ :param cest: l10n_br_fiscal.cest record, CEST code for the product.
749
+ :param operation_line: l10n_br_fiscal.operation.line record defining
750
+ the fiscal context.
751
+ :param cfop: l10n_br_fiscal.cfop record, the determined CFOP for the
752
+ operation.
753
+ :param icmssn_range: l10n_br_fiscal.simplified.tax.range record for
754
+ Simples Nacional ICMS calculation.
755
+ :param icms_origin: str, ICMS origin code for the product.
756
+ :param icms_cst_id: l10n_br_fiscal.cst record, the ICMS CST code.
757
+ :param icms_relief_id: l10n_br_fiscal.icms.relief record, if ICMS relief
758
+ applies.
759
+ :param ind_final: str, indicates if the operation is for a final
760
+ consumer ('0' or '1').
761
+
762
+ :return: dict containing:
763
+ - 'amount_included': float, sum of tax values included in the price.
764
+ - 'amount_not_included': float, sum of tax values not included in
765
+ the price (added on top).
766
+ - 'amount_withholding': float, sum of withholding tax values.
767
+ - 'estimate_tax': float, estimated total tax amount for transparency.
768
+ - 'taxes': dict, where keys are tax domains (e.g., 'icms', 'ipi')
769
+ and values are dictionaries with detailed calculation results for
770
+ that tax (base, percent, value, cst, etc., as defined in
771
+ TAX_DICT_VALUES).
678
772
  """
773
+
679
774
  result_amounts = {
680
775
  "amount_included": 0.00,
681
776
  "amount_not_included": 0.00,
@@ -693,7 +788,7 @@ class Tax(models.Model):
693
788
  fiscal_operation_type = operation_line.fiscal_operation_type or FISCAL_OUT
694
789
  kwargs.update({"cst": tax.cst_from_tax(fiscal_operation_type)})
695
790
  try:
696
- compute_method = getattr(self, "_compute_%s" % tax.tax_domain)
791
+ compute_method = getattr(self, f"_compute_{tax.tax_domain}")
697
792
  taxes[tax.tax_domain].update(compute_method(tax, taxes, **kwargs))
698
793
 
699
794
  except AttributeError:
@@ -714,16 +809,10 @@ class Tax(models.Model):
714
809
  result_amounts["taxes"] = taxes
715
810
  return result_amounts
716
811
 
717
- @api.onchange("icmsst_base_type")
718
- def _onchange_icmsst_base_type(self):
719
- if self.icmsst_base_type:
720
- ICMS_ST_BASE_TYPE_REL = {
721
- "0": TAX_BASE_TYPE_VALUE,
722
- "1": TAX_BASE_TYPE_VALUE,
723
- "2": TAX_BASE_TYPE_VALUE,
724
- "3": TAX_BASE_TYPE_VALUE,
725
- "4": TAX_BASE_TYPE_PERCENT,
726
- "5": TAX_BASE_TYPE_VALUE,
727
- }
728
-
729
- self.tax_base_type = ICMS_ST_BASE_TYPE_REL.get(self.icmsst_base_type)
812
+ @api.depends("icmsst_base_type")
813
+ def _compute_tax_base_type(self):
814
+ for tax in self:
815
+ if tax.icmsst_base_type:
816
+ tax.tax_base_type = ICMS_ST_BASE_TYPE_REL.get(tax.icmsst_base_type)
817
+ elif tax.tax_base_type is None:
818
+ tax.tax_base_type = False
@@ -0,0 +1,81 @@
1
+ # Copyright 2025 Marcel Savegnago <https://escodoo.com.br>
2
+ # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
3
+
4
+ from odoo import api, fields, models
5
+
6
+ from ..constants.fiscal import (
7
+ TAX_DOMAIN_CBS,
8
+ TAX_DOMAIN_IBS,
9
+ TAX_RATE_TYPE,
10
+ TAX_RATE_TYPE_DEFAULT,
11
+ )
12
+
13
+
14
+ class TaxClassification(models.Model):
15
+ _name = "l10n_br_fiscal.tax.classification"
16
+ _inherit = "l10n_br_fiscal.data.abstract"
17
+ _order = "code"
18
+ _description = "Tax Classification"
19
+
20
+ code = fields.Char(size=8)
21
+
22
+ description = fields.Text()
23
+
24
+ cst_code_prefix_like = fields.Char(
25
+ compute="_compute_cst_code_prefix_like",
26
+ help="Helper field to filter taxes by CST code prefix (3 chars) using LIKE.",
27
+ )
28
+
29
+ @api.depends("code")
30
+ def _compute_cst_code_prefix_like(self):
31
+ for rec in self:
32
+ prefix = (rec.code or "")[:3]
33
+ # Avoid matching all records when the prefix is not available yet.
34
+ rec.cst_code_prefix_like = (
35
+ f"{prefix}%" if len(prefix) == 3 else "__no_match__%"
36
+ )
37
+
38
+ tax_ibs_id = fields.Many2one(
39
+ comodel_name="l10n_br_fiscal.tax",
40
+ string="Tax IBS",
41
+ domain=(
42
+ f"[('tax_domain', '=', '{TAX_DOMAIN_IBS}'), '|', "
43
+ "('cst_in_id.code', 'like', cst_code_prefix_like), "
44
+ "('cst_out_id.code', 'like', cst_code_prefix_like)]"
45
+ ),
46
+ )
47
+
48
+ tax_cbs_id = fields.Many2one(
49
+ comodel_name="l10n_br_fiscal.tax",
50
+ string="Tax CBS",
51
+ domain=(
52
+ f"[('tax_domain', '=', '{TAX_DOMAIN_CBS}'), '|', "
53
+ "('cst_in_id.code', 'like', cst_code_prefix_like), "
54
+ "('cst_out_id.code', 'like', cst_code_prefix_like)]"
55
+ ),
56
+ )
57
+
58
+ regular_taxation = fields.Boolean(
59
+ default=False,
60
+ )
61
+
62
+ presumed_credit = fields.Boolean(
63
+ default=False,
64
+ )
65
+
66
+ credit_reversal = fields.Boolean(
67
+ default=False,
68
+ )
69
+
70
+ rate_type = fields.Selection(
71
+ selection=TAX_RATE_TYPE,
72
+ default=TAX_RATE_TYPE_DEFAULT,
73
+ required=True,
74
+ )
75
+
76
+ document_type_ids = fields.Many2many(
77
+ comodel_name="l10n_br_fiscal.document.type",
78
+ relation="tax_classification_document_type_rel",
79
+ string="Related DFes",
80
+ help="Related Digital Fiscal Documents",
81
+ )