odoo-addon-l10n-br-fiscal 16.0.8.0.2__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 (115) hide show
  1. odoo/addons/l10n_br_fiscal/README.rst +1 -1
  2. odoo/addons/l10n_br_fiscal/__manifest__.py +10 -3
  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.cst.csv +58 -0
  6. odoo/addons/l10n_br_fiscal/data/l10n_br_fiscal.document.type.csv +1 -0
  7. odoo/addons/l10n_br_fiscal/data/l10n_br_fiscal.operation.indicator.csv +27 -0
  8. odoo/addons/l10n_br_fiscal/data/l10n_br_fiscal.tax.classification.csv +163 -0
  9. odoo/addons/l10n_br_fiscal/data/l10n_br_fiscal.tax.csv +31 -0
  10. odoo/addons/l10n_br_fiscal/data/l10n_br_fiscal.tax.group.csv +3 -0
  11. odoo/addons/l10n_br_fiscal/data/operation_data.xml +1 -1
  12. odoo/addons/l10n_br_fiscal/data/uom_data.xml +186 -33
  13. odoo/addons/l10n_br_fiscal/demo/fiscal_document_demo.xml +3 -377
  14. odoo/addons/l10n_br_fiscal/demo/fiscal_document_nfse_demo.xml +0 -12
  15. odoo/addons/l10n_br_fiscal/demo/fiscal_operation_demo.xml +2 -2
  16. odoo/addons/l10n_br_fiscal/i18n/l10n_br_fiscal.pot +902 -304
  17. odoo/addons/l10n_br_fiscal/i18n/pt_BR.po +22 -22
  18. odoo/addons/l10n_br_fiscal/migrations/16.0.13.0.0/pre-migration.py +25 -0
  19. odoo/addons/l10n_br_fiscal/migrations/16.0.14.0.0/pre-migration.py +30 -0
  20. odoo/addons/l10n_br_fiscal/migrations/16.0.14.0.5/pre-migration.py +15 -0
  21. odoo/addons/l10n_br_fiscal/models/__init__.py +3 -2
  22. odoo/addons/l10n_br_fiscal/models/comment.py +2 -2
  23. odoo/addons/l10n_br_fiscal/models/data_ncm_nbs_abstract.py +1 -1
  24. odoo/addons/l10n_br_fiscal/models/document.py +83 -226
  25. odoo/addons/l10n_br_fiscal/models/document_line.py +67 -5
  26. odoo/addons/l10n_br_fiscal/models/document_line_mixin.py +1932 -136
  27. odoo/addons/l10n_br_fiscal/models/document_mixin.py +248 -17
  28. odoo/addons/l10n_br_fiscal/models/document_related.py +11 -8
  29. odoo/addons/l10n_br_fiscal/models/document_serie.py +33 -0
  30. odoo/addons/l10n_br_fiscal/models/ibpt.py +1 -1
  31. odoo/addons/l10n_br_fiscal/models/icms_regulation.py +1 -1
  32. odoo/addons/l10n_br_fiscal/models/invalidate_number.py +4 -5
  33. odoo/addons/l10n_br_fiscal/models/operation_dashboard.py +3 -2
  34. odoo/addons/l10n_br_fiscal/models/operation_indicator.py +58 -0
  35. odoo/addons/l10n_br_fiscal/models/operation_line.py +28 -0
  36. odoo/addons/l10n_br_fiscal/models/partner_profile.py +6 -0
  37. odoo/addons/l10n_br_fiscal/models/product_template.py +5 -1
  38. odoo/addons/l10n_br_fiscal/models/res_company.py +18 -0
  39. odoo/addons/l10n_br_fiscal/models/res_partner.py +27 -6
  40. odoo/addons/l10n_br_fiscal/models/simplified_tax_range.py +8 -0
  41. odoo/addons/l10n_br_fiscal/models/tax.py +7 -3
  42. odoo/addons/l10n_br_fiscal/models/tax_classification.py +81 -0
  43. odoo/addons/l10n_br_fiscal/models/tax_pis_cofins_base.py +1 -1
  44. odoo/addons/l10n_br_fiscal/models/tax_pis_cofins_credit.py +1 -1
  45. odoo/addons/l10n_br_fiscal/models/uom_uom.py +24 -0
  46. odoo/addons/l10n_br_fiscal/security/fiscal_security.xml +6 -16
  47. odoo/addons/l10n_br_fiscal/security/ir.model.access.csv +8 -2
  48. odoo/addons/l10n_br_fiscal/static/description/index.html +1 -1
  49. odoo/addons/l10n_br_fiscal/tests/__init__.py +3 -0
  50. odoo/addons/l10n_br_fiscal/tests/test_document_edition.py +308 -0
  51. odoo/addons/l10n_br_fiscal/tests/test_fiscal_document_generic.py +23 -111
  52. odoo/addons/l10n_br_fiscal/tests/test_fiscal_document_nfse.py +5 -13
  53. odoo/addons/l10n_br_fiscal/tests/test_fiscal_document_serie.py +60 -0
  54. odoo/addons/l10n_br_fiscal/tests/test_ibpt.py +2 -2
  55. odoo/addons/l10n_br_fiscal/tests/test_icms_regulation.py +2 -2
  56. odoo/addons/l10n_br_fiscal/tests/test_tax_benefit.py +14 -20
  57. odoo/addons/l10n_br_fiscal/tests/test_tax_classification.py +110 -0
  58. odoo/addons/l10n_br_fiscal/tools.py +1 -1
  59. odoo/addons/l10n_br_fiscal/views/cest_view.xml +2 -4
  60. odoo/addons/l10n_br_fiscal/views/cfop_view.xml +3 -5
  61. odoo/addons/l10n_br_fiscal/views/city_taxation_code.xml +1 -4
  62. odoo/addons/l10n_br_fiscal/views/cnae_view.xml +2 -4
  63. odoo/addons/l10n_br_fiscal/views/comment_view.xml +2 -4
  64. odoo/addons/l10n_br_fiscal/views/cst_view.xml +6 -8
  65. odoo/addons/l10n_br_fiscal/views/{document_fiscal_line_mixin_view.xml → document_line_mixin_view.xml} +525 -388
  66. odoo/addons/l10n_br_fiscal/views/document_line_view.xml +101 -82
  67. odoo/addons/l10n_br_fiscal/views/document_related_view.xml +44 -46
  68. odoo/addons/l10n_br_fiscal/views/document_serie_view.xml +2 -6
  69. odoo/addons/l10n_br_fiscal/views/document_type_view.xml +0 -2
  70. odoo/addons/l10n_br_fiscal/views/document_view.xml +304 -346
  71. odoo/addons/l10n_br_fiscal/views/icms_regulation_view.xml +14 -16
  72. odoo/addons/l10n_br_fiscal/views/icms_relief_view.xml +8 -10
  73. odoo/addons/l10n_br_fiscal/views/invalidate_number_view.xml +46 -48
  74. odoo/addons/l10n_br_fiscal/views/l10n_br_fiscal_action.xml +162 -244
  75. odoo/addons/l10n_br_fiscal/views/l10n_br_fiscal_menu.xml +16 -72
  76. odoo/addons/l10n_br_fiscal/views/legal_nature_view.xml +0 -2
  77. odoo/addons/l10n_br_fiscal/views/nbm_view.xml +5 -6
  78. odoo/addons/l10n_br_fiscal/views/nbs_view.xml +5 -6
  79. odoo/addons/l10n_br_fiscal/views/ncm_view.xml +12 -15
  80. odoo/addons/l10n_br_fiscal/views/operation_dashboard_view.xml +13 -12
  81. odoo/addons/l10n_br_fiscal/views/operation_indicator_view.xml +75 -0
  82. odoo/addons/l10n_br_fiscal/views/operation_line_view.xml +22 -21
  83. odoo/addons/l10n_br_fiscal/views/operation_view.xml +3 -6
  84. odoo/addons/l10n_br_fiscal/views/partner_profile_view.xml +3 -6
  85. odoo/addons/l10n_br_fiscal/views/product_genre_view.xml +7 -9
  86. odoo/addons/l10n_br_fiscal/views/product_product_view.xml +37 -14
  87. odoo/addons/l10n_br_fiscal/views/product_template_view.xml +34 -14
  88. odoo/addons/l10n_br_fiscal/views/res_company_view.xml +40 -38
  89. odoo/addons/l10n_br_fiscal/views/res_config_settings_view.xml +23 -28
  90. odoo/addons/l10n_br_fiscal/views/res_partner_view.xml +13 -2
  91. odoo/addons/l10n_br_fiscal/views/service_type_view.xml +7 -8
  92. odoo/addons/l10n_br_fiscal/views/simplified_tax_range_view.xml +0 -2
  93. odoo/addons/l10n_br_fiscal/views/simplified_tax_view.xml +0 -2
  94. odoo/addons/l10n_br_fiscal/views/tax_classification.xml +110 -0
  95. odoo/addons/l10n_br_fiscal/views/tax_definition_view.xml +157 -129
  96. odoo/addons/l10n_br_fiscal/views/tax_estimate_view.xml +0 -2
  97. odoo/addons/l10n_br_fiscal/views/tax_group_view.xml +3 -6
  98. odoo/addons/l10n_br_fiscal/views/tax_ipi_control_seal_view.xml +0 -2
  99. odoo/addons/l10n_br_fiscal/views/tax_ipi_guideline_class_view.xml +0 -2
  100. odoo/addons/l10n_br_fiscal/views/tax_ipi_guideline_view.xml +2 -4
  101. odoo/addons/l10n_br_fiscal/views/tax_pis_cofins_base_view.xml +2 -4
  102. odoo/addons/l10n_br_fiscal/views/tax_pis_cofins_credit_view.xml +2 -4
  103. odoo/addons/l10n_br_fiscal/views/tax_pis_cofins_view.xml +5 -7
  104. odoo/addons/l10n_br_fiscal/views/tax_view.xml +5 -7
  105. odoo/addons/l10n_br_fiscal/views/uom_uom.xml +52 -0
  106. odoo/addons/l10n_br_fiscal/wizards/__init__.py +1 -0
  107. odoo/addons/l10n_br_fiscal/wizards/base_wizard_mixin.py +1 -1
  108. odoo/addons/l10n_br_fiscal/wizards/document_import_wizard_mixin.py +129 -0
  109. odoo/addons/l10n_br_fiscal/wizards/document_import_wizard_mixin.xml +41 -0
  110. {odoo_addon_l10n_br_fiscal-16.0.8.0.2.dist-info → odoo_addon_l10n_br_fiscal-16.0.19.4.0.dist-info}/METADATA +3 -3
  111. {odoo_addon_l10n_br_fiscal-16.0.8.0.2.dist-info → odoo_addon_l10n_br_fiscal-16.0.19.4.0.dist-info}/RECORD +113 -99
  112. {odoo_addon_l10n_br_fiscal-16.0.8.0.2.dist-info → odoo_addon_l10n_br_fiscal-16.0.19.4.0.dist-info}/WHEEL +1 -1
  113. odoo/addons/l10n_br_fiscal/models/document_line_mixin_methods.py +0 -814
  114. odoo/addons/l10n_br_fiscal/models/document_mixin_methods.py +0 -363
  115. {odoo_addon_l10n_br_fiscal-16.0.8.0.2.dist-info → odoo_addon_l10n_br_fiscal-16.0.19.4.0.dist-info}/top_level.txt +0 -0
@@ -1,18 +1,29 @@
1
1
  # Copyright (C) 2019 Renato Lima - Akretion <renato.lima@akretion.com.br>
2
2
  # License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html
3
3
 
4
- from odoo import api, fields, models
4
+ from copy import deepcopy
5
+
6
+ from lxml import etree
7
+ from lxml.builder import E
8
+
9
+ from odoo import Command, api, fields, models
5
10
 
6
11
  from ..constants.fiscal import (
12
+ CFOP_DESTINATION_EXPORT,
13
+ FINAL_CUSTOMER,
7
14
  FISCAL_COMMENT_LINE,
15
+ FISCAL_IN,
16
+ FISCAL_TAX_ID_FIELDS,
8
17
  PRODUCT_FISCAL_TYPE,
9
18
  TAX_BASE_TYPE,
10
19
  TAX_BASE_TYPE_PERCENT,
20
+ TAX_DOMAIN_CBS,
11
21
  TAX_DOMAIN_COFINS,
12
22
  TAX_DOMAIN_COFINS_ST,
13
23
  TAX_DOMAIN_COFINS_WH,
14
24
  TAX_DOMAIN_CSLL,
15
25
  TAX_DOMAIN_CSLL_WH,
26
+ TAX_DOMAIN_IBS,
16
27
  TAX_DOMAIN_ICMS,
17
28
  TAX_DOMAIN_ICMS_FCP,
18
29
  TAX_DOMAIN_ICMS_FCP_ST,
@@ -66,22 +77,11 @@ class FiscalDocumentLineMixin(models.AbstractModel):
66
77
  ISSQN, etc.), covering their respective bases, rates, and
67
78
  calculated values.
68
79
  - Line-level totals and cost components.
69
-
70
- It inherits computational logic, onchange handlers, and other complex
71
- methods from `l10n_br_fiscal.document.line.mixin.methods`. Models
72
- that represent actual document lines (e.g.,
73
- `l10n_br_fiscal.document.line`) should inherit this mixin to
74
- acquire the necessary fiscal field definitions and associated behaviors.
75
80
  """
76
81
 
77
82
  _name = "l10n_br_fiscal.document.line.mixin"
78
- _inherit = "l10n_br_fiscal.document.line.mixin.methods"
79
83
  _description = "Document Fiscal Mixin"
80
84
 
81
- @api.model
82
- def _default_operation(self):
83
- return False
84
-
85
85
  @api.model
86
86
  def _default_icmssn_range_id(self):
87
87
  company = self.env.company
@@ -102,6 +102,810 @@ class FiscalDocumentLineMixin(models.AbstractModel):
102
102
  domain = [("state", "=", "approved")]
103
103
  return domain
104
104
 
105
+ @api.model
106
+ def inject_fiscal_fields(
107
+ self,
108
+ doc,
109
+ view_ref="l10n_br_fiscal.document_fiscal_line_mixin_form",
110
+ xpath_mappings=None,
111
+ ):
112
+ """
113
+ Inject common fiscal fields into view placeholder elements.
114
+ Used for invoice line, sale order line, purchase order line...
115
+ """
116
+
117
+ # the list of computed fields we will add to the view when missing
118
+ missing_line_fields = set(
119
+ [
120
+ fname
121
+ for fname, _field in filter(
122
+ lambda item: item[1].compute
123
+ in (
124
+ "_compute_tax_fields",
125
+ "_compute_fiscal_tax_ids",
126
+ "_compute_product_fiscal_fields",
127
+ ),
128
+ self.env["l10n_br_fiscal.document.line.mixin"]._fields.items(),
129
+ )
130
+ ]
131
+ )
132
+
133
+ fiscal_view = self.env.ref(
134
+ "l10n_br_fiscal.document_fiscal_line_mixin_form"
135
+ ).sudo()
136
+ fsc_doc = etree.fromstring(
137
+ fiscal_view.with_context(inherit_branding=True).get_combined_arch()
138
+ )
139
+
140
+ if xpath_mappings is None:
141
+ xpath_mappings = (
142
+ # (placeholder_xpath, fiscal_xpath)
143
+ (".//group[@name='fiscal_fields']", "//group[@name='fiscal_fields']"),
144
+ (".//page[@name='fiscal_taxes']", "//page[@name='fiscal_taxes']"),
145
+ (
146
+ ".//page[@name='fiscal_line_extra_info']",
147
+ "//page[@name='fiscal_line_extra_info']",
148
+ ),
149
+ # these will only collect (invisible) fields for onchanges:
150
+ (
151
+ ".//control[@name='fiscal_fields']...",
152
+ "//group[@name='fiscal_fields']//field",
153
+ ),
154
+ (
155
+ ".//control[@name='fiscal_taxes_fields']...",
156
+ "//page[@name='fiscal_taxes']//field",
157
+ ),
158
+ (
159
+ ".//control[@name='fiscal_line_extra_info_fields']...",
160
+ "//page[@name='fiscal_line_extra_info']//field",
161
+ ),
162
+ )
163
+ for placeholder_xpath, fiscal_xpath in xpath_mappings:
164
+ placeholder_nodes = doc.findall(placeholder_xpath)
165
+ if not placeholder_nodes:
166
+ continue
167
+ fiscal_nodes = fsc_doc.xpath(fiscal_xpath)
168
+ for target_node in placeholder_nodes:
169
+ if len(fiscal_nodes) == 1:
170
+ # replace unique placeholder
171
+ # (deepcopy is required to inject fiscal nodes in possible
172
+ # next places)
173
+ replace_node = deepcopy(fiscal_nodes[0])
174
+ target_node.getparent().replace(target_node, replace_node)
175
+ else:
176
+ # append multiple fields to placeholder container
177
+ existing_fields = [
178
+ e.attrib["name"] for e in target_node if e.tag == "field"
179
+ ]
180
+ for fiscal_node in fiscal_nodes:
181
+ if fiscal_node.attrib["name"] in missing_line_fields:
182
+ missing_line_fields.remove(fiscal_node.attrib["name"])
183
+ if fiscal_node.attrib["name"] in existing_fields:
184
+ continue
185
+ field = deepcopy(fiscal_node)
186
+ if not field.attrib.get("optional"):
187
+ field.attrib["optional"] = "hide"
188
+ target_node.append(field)
189
+ for fname in missing_line_fields:
190
+ if fname not in existing_fields:
191
+ target_node.append(
192
+ E.field(name=fname, string=fname, optional="hide")
193
+ )
194
+ return doc
195
+
196
+ @api.model
197
+ def _get_view(self, view_id=None, view_type="form", **options):
198
+ arch, view = super()._get_view(view_id, view_type, **options)
199
+ if view_type == "form":
200
+ arch = self.inject_fiscal_fields(arch)
201
+ return arch, view
202
+
203
+ @api.depends(
204
+ "discount_value",
205
+ "amount_tax_not_included",
206
+ "amount_tax_withholding",
207
+ "price_unit",
208
+ "quantity",
209
+ "fiscal_operation_line_id",
210
+ "cfop_id",
211
+ "icms_relief_value",
212
+ "insurance_value",
213
+ "other_value",
214
+ "freight_value",
215
+ "pis_value",
216
+ "cofins_value",
217
+ "icms_value",
218
+ "ii_value",
219
+ "ii_customhouse_charges",
220
+ )
221
+ def _compute_fiscal_amounts(self):
222
+ for record in self:
223
+ round_curr = record.currency_id or self.env.ref("base.BRL")
224
+
225
+ # Total value of products or services
226
+ record.price_gross = round_curr.round(record.price_unit * record.quantity)
227
+ record.amount_fiscal = record.price_gross - record.discount_value
228
+ record.fiscal_amount_tax = record.amount_tax_not_included
229
+
230
+ add_to_amount = sum(record[a] for a in record._add_fields_to_amount())
231
+ rm_to_amount = sum(record[r] for r in record._rm_fields_to_amount())
232
+ record.fiscal_amount_untaxed = (
233
+ record.price_gross
234
+ - record.discount_value
235
+ + add_to_amount
236
+ - rm_to_amount
237
+ )
238
+
239
+ # Valor do documento (NF)
240
+ record.fiscal_amount_total = (
241
+ record.fiscal_amount_untaxed + record.fiscal_amount_tax
242
+ )
243
+
244
+ # Valor Liquido (TOTAL + IMPOSTOS - RETENÇÕES)
245
+ record.amount_taxed = (
246
+ record.fiscal_amount_total - record.amount_tax_withholding
247
+ )
248
+
249
+ # Valor do documento (NF) - RETENÇÕES
250
+ record.fiscal_amount_total = record.amount_taxed
251
+
252
+ # Valor financeiro
253
+ if (
254
+ record.fiscal_operation_line_id
255
+ and record.fiscal_operation_line_id.add_to_amount
256
+ and (not record.cfop_id or record.cfop_id.finance_move)
257
+ ):
258
+ record.financial_total = record.amount_taxed
259
+ record.financial_total_gross = (
260
+ record.financial_total + record.discount_value
261
+ )
262
+ record.financial_discount_value = record.discount_value
263
+ else:
264
+ record.financial_total_gross = record.financial_total = 0.0
265
+ record.financial_discount_value = 0.0
266
+
267
+ @api.depends("tax_icms_or_issqn", "partner_id")
268
+ def _compute_allow_csll_irpj(self):
269
+ """Calculates the possibility of 'CSLL' and 'IRPJ' tax charges."""
270
+ for line in self:
271
+ # Determine if 'CSLL' and 'IRPJ' taxes may apply:
272
+ # 1. When providing services (tax_icms_or_issqn == "issqn")
273
+ # 2. When supplying products to public entities (partner_is_public_entity
274
+ # is True)
275
+ if line.tax_icms_or_issqn == "issqn" or line.partner_is_public_entity:
276
+ line.allow_csll_irpj = True # Tax charges may apply
277
+ else:
278
+ line.allow_csll_irpj = False # No tax charges expected
279
+
280
+ def _prepare_br_fiscal_dict(self, default=False):
281
+ self.ensure_one()
282
+ fields = self.env["l10n_br_fiscal.document.line.mixin"]._fields.keys()
283
+
284
+ # we now read the record fiscal fields except the m2m tax:
285
+ vals = self._convert_to_write(self.read(fields)[0])
286
+
287
+ # remove id field to avoid conflicts
288
+ vals.pop("id", None)
289
+
290
+ if default: # in case you want to use new rather than write later
291
+ return {f"default_{k}": vals[k] for k in vals.keys()}
292
+ return vals
293
+
294
+ @api.depends("fiscal_operation_id", "partner_id", "product_id")
295
+ def _compute_fiscal_operation_line_id(self):
296
+ for line in self:
297
+ if line.fiscal_operation_id:
298
+ line.fiscal_operation_line_id = (
299
+ line.fiscal_operation_id.line_definition(
300
+ company=line.company_id,
301
+ partner=line.partner_id,
302
+ product=line.product_id,
303
+ )
304
+ )
305
+
306
+ @api.depends(
307
+ "partner_id",
308
+ "fiscal_operation_line_id",
309
+ "product_id",
310
+ "ncm_id",
311
+ "nbs_id",
312
+ "nbm_id",
313
+ "cest_id",
314
+ "city_taxation_code_id",
315
+ "service_type_id",
316
+ "ind_final",
317
+ )
318
+ def _compute_fiscal_tax_ids(self):
319
+ for line in self:
320
+ if line.fiscal_operation_line_id:
321
+ mapping_result = line.fiscal_operation_line_id.map_fiscal_taxes(
322
+ company=line.company_id,
323
+ partner=line._get_fiscal_partner(),
324
+ product=line.product_id,
325
+ ncm=line.ncm_id,
326
+ nbm=line.nbm_id,
327
+ nbs=line.nbs_id,
328
+ cest=line.cest_id,
329
+ city_taxation_code=line.city_taxation_code_id,
330
+ service_type=line.service_type_id,
331
+ ind_final=line.ind_final,
332
+ )
333
+ line.cfop_id = mapping_result["cfop"]
334
+ line.ipi_guideline_id = mapping_result["ipi_guideline"]
335
+ line.tax_classification_id = mapping_result["tax_classification"]
336
+ line.icms_tax_benefit_id = mapping_result["icms_tax_benefit_id"]
337
+
338
+ if line._is_imported():
339
+ continue
340
+
341
+ taxes = line.env["l10n_br_fiscal.tax"]
342
+ for tax in mapping_result["taxes"].values():
343
+ taxes |= tax
344
+ line.fiscal_tax_ids = taxes
345
+
346
+ @api.depends("fiscal_operation_line_id")
347
+ def _compute_comment_ids(self):
348
+ for line in self:
349
+ line.comment_ids = [
350
+ Command.set(line.fiscal_operation_line_id.comment_ids.ids)
351
+ ]
352
+
353
+ @api.model
354
+ def _build_null_mask_dict(self) -> dict:
355
+ """
356
+ Build a null values mask dict to reset all fiscal fields.
357
+ """
358
+ mask_dict = {
359
+ f[0]: False
360
+ for f in filter(
361
+ lambda f: f[1].compute == "_compute_tax_fields",
362
+ self.env["l10n_br_fiscal.document.line.mixin"]._fields.items(),
363
+ )
364
+ }
365
+ for fiscal_tax_field in FISCAL_TAX_ID_FIELDS:
366
+ mask_dict[fiscal_tax_field] = False
367
+ return mask_dict
368
+
369
+ def write(self, vals):
370
+ res = super().write(vals)
371
+
372
+ # Verifica se algum campo de imposto relevante foi alterado no 'write'
373
+ tax_fields_in_vals = [fld for fld in vals if fld in FISCAL_TAX_ID_FIELDS]
374
+
375
+ if tax_fields_in_vals:
376
+ # Por segurança, sempre recalcula se um campo relevante mudou.
377
+ self._update_fiscal_tax_ids()
378
+
379
+ return res
380
+
381
+ def _update_fiscal_tax_ids(self):
382
+ taxes = self.env["l10n_br_fiscal.tax"]
383
+ for fiscal_tax_field in FISCAL_TAX_ID_FIELDS:
384
+ taxes |= self[fiscal_tax_field]
385
+
386
+ for line in self:
387
+ taxes_groups = line.fiscal_tax_ids.mapped("tax_domain")
388
+ fiscal_taxes = line.fiscal_tax_ids.filtered(
389
+ lambda ft, taxes_groups=taxes_groups: ft.tax_domain not in taxes_groups
390
+ )
391
+ line.fiscal_tax_ids = fiscal_taxes + taxes
392
+
393
+ @api.onchange(*FISCAL_TAX_ID_FIELDS)
394
+ def _onchange_fiscal_taxes(self):
395
+ self._update_fiscal_tax_ids()
396
+
397
+ @api.depends(
398
+ "partner_id",
399
+ "fiscal_tax_ids",
400
+ "product_id",
401
+ "price_unit",
402
+ "quantity",
403
+ "uom_id",
404
+ "fiscal_price",
405
+ "fiscal_quantity",
406
+ "uot_id",
407
+ "discount_value",
408
+ "insurance_value",
409
+ "ii_customhouse_charges",
410
+ "ii_iof_value",
411
+ "other_value",
412
+ "freight_value",
413
+ "ncm_id",
414
+ "nbs_id",
415
+ "nbm_id",
416
+ "cest_id",
417
+ "fiscal_operation_line_id",
418
+ "cfop_id",
419
+ "icmssn_range_id",
420
+ "icms_origin",
421
+ "icms_cst_id",
422
+ "ind_final",
423
+ "icms_relief_id",
424
+ )
425
+ def _compute_tax_fields(self):
426
+ """
427
+ Compute base, percent, value... tax fields for ICMS, IPI, PIS, COFINS... taxes.
428
+ """
429
+ null_mask = None
430
+ for line in self.filtered(lambda line: not line._is_imported()):
431
+ if null_mask is None:
432
+ null_mask = self._build_null_mask_dict()
433
+ to_update = null_mask.copy()
434
+ # prepare with default values
435
+ to_update.update(
436
+ {
437
+ "icms_base_type": ICMS_BASE_TYPE_DEFAULT,
438
+ "icmsst_base_type": ICMS_ST_BASE_TYPE_DEFAULT,
439
+ "ipi_base_type": TAX_BASE_TYPE_PERCENT,
440
+ "cofins_base_type": TAX_BASE_TYPE_PERCENT,
441
+ "cofinsst_base_type": TAX_BASE_TYPE_PERCENT,
442
+ "cofins_wh_base_type": TAX_BASE_TYPE_PERCENT,
443
+ "pis_base_type": TAX_BASE_TYPE_PERCENT,
444
+ "pisst_base_type": TAX_BASE_TYPE_PERCENT,
445
+ "pis_wh_base_type": TAX_BASE_TYPE_PERCENT,
446
+ "cbs_base_type": TAX_BASE_TYPE_PERCENT,
447
+ "ibs_base_type": TAX_BASE_TYPE_PERCENT,
448
+ }
449
+ )
450
+ if line.fiscal_operation_line_id:
451
+ compute_result = line.fiscal_tax_ids.compute_taxes(
452
+ company=line.company_id,
453
+ partner=line._get_fiscal_partner(),
454
+ product=line.product_id,
455
+ price_unit=line.price_unit,
456
+ quantity=line.quantity,
457
+ uom_id=line.uom_id,
458
+ fiscal_price=line.fiscal_price,
459
+ fiscal_quantity=line.fiscal_quantity,
460
+ uot_id=line.uot_id,
461
+ discount_value=line.discount_value,
462
+ insurance_value=line.insurance_value,
463
+ ii_customhouse_charges=line.ii_customhouse_charges,
464
+ ii_iof_value=line.ii_iof_value,
465
+ other_value=line.other_value,
466
+ freight_value=line.freight_value,
467
+ ncm=line.ncm_id,
468
+ nbs=line.nbs_id,
469
+ nbm=line.nbm_id,
470
+ cest=line.cest_id,
471
+ operation_line=line.fiscal_operation_line_id,
472
+ cfop=line.cfop_id,
473
+ icmssn_range=line.icmssn_range_id,
474
+ icms_origin=line.icms_origin,
475
+ icms_cst_id=line.icms_cst_id,
476
+ ind_final=line.ind_final,
477
+ icms_relief_id=line.icms_relief_id,
478
+ )
479
+ to_update.update(line._prepare_tax_fields(compute_result))
480
+ else:
481
+ compute_result = {}
482
+ to_update.update(
483
+ {
484
+ "amount_tax_included": compute_result.get("amount_included", 0.0),
485
+ "amount_tax_not_included": compute_result.get(
486
+ "amount_not_included", 0.0
487
+ ),
488
+ "amount_tax_withholding": compute_result.get(
489
+ "amount_withholding", 0.0
490
+ ),
491
+ "estimate_tax": compute_result.get("estimate_tax", 0.0),
492
+ }
493
+ )
494
+ in_draft_mode = line != line._origin
495
+ if in_draft_mode:
496
+ line.update(to_update)
497
+ else:
498
+ line.write(to_update)
499
+
500
+ def _prepare_tax_fields(self, compute_result):
501
+ self.ensure_one()
502
+ tax_values = {}
503
+ if self._is_imported():
504
+ return tax_values
505
+ computed_taxes = compute_result.get("taxes", {})
506
+ for tax in self.fiscal_tax_ids:
507
+ computed_tax = computed_taxes.get(tax.tax_domain, {})
508
+ tax_field_name = f"{tax.tax_domain}_tax_id"
509
+ if hasattr(self, tax_field_name):
510
+ tax_values[tax_field_name] = tax.ids[0]
511
+ method = getattr(self, f"_prepare_fields_{tax.tax_domain}", None)
512
+ if method and computed_tax:
513
+ prepared_fields = method(computed_tax)
514
+ if prepared_fields:
515
+ tax_values.update(prepared_fields)
516
+ return tax_values
517
+
518
+ @api.depends(
519
+ "product_id",
520
+ "fiscal_operation_id",
521
+ )
522
+ def _compute_price_unit_fiscal(self): # OK when edited from aml?? c-> check
523
+ for line in self:
524
+ line.price_unit = {
525
+ "sale_price": line.product_id.list_price,
526
+ "cost_price": line.product_id.standard_price,
527
+ }.get(line.fiscal_operation_id.default_price_unit, 0)
528
+
529
+ def _get_document(self):
530
+ self.ensure_one()
531
+ return self.document_id
532
+
533
+ def _get_fiscal_partner(self):
534
+ """
535
+ Meant to be overriden when the l10n_br_fiscal.document partner_id should not
536
+ be the same as the sale.order, purchase.order, account.move (...) partner_id.
537
+
538
+ (In the case of invoicing, the invoicing partner set by the user should
539
+ get priority over any invoicing contact returned by address_get.)
540
+ """
541
+ self.ensure_one()
542
+ return self.partner_id
543
+
544
+ @api.depends("product_id")
545
+ def _compute_product_fiscal_fields(self):
546
+ for line in self:
547
+ if not line.product_id:
548
+ # reset to default values:
549
+ line.fiscal_type = False
550
+ line.ncm_id = False
551
+ line.nbm_id = False
552
+ line.tax_icms_or_issqn = TAX_DOMAIN_ICMS
553
+ line.icms_origin = ICMS_ORIGIN_DEFAULT
554
+ line.cest_id = False
555
+ line.nbs_id = False
556
+ line.fiscal_genre_id = False
557
+ line.service_type_id = False
558
+ line.operation_indicator_id = False
559
+ continue
560
+ p = line.product_id
561
+ line.fiscal_type = p.fiscal_type
562
+ line.ncm_id = p.ncm_id
563
+ line.nbm_id = p.nbm_id
564
+ line.tax_icms_or_issqn = p.tax_icms_or_issqn
565
+ line.icms_origin = p.icms_origin
566
+ line.cest_id = p.cest_id
567
+ line.nbs_id = p.nbs_id
568
+ line.fiscal_genre_id = p.fiscal_genre_id
569
+ line.service_type_id = p.service_type_id
570
+ line.operation_indicator_id = p.operation_indicator_id
571
+
572
+ @api.depends("product_id")
573
+ def _compute_city_taxation_code_id(self):
574
+ for line in self:
575
+ if not line.product_id:
576
+ line.city_taxation_code_id = False
577
+ continue
578
+ company_city = line.company_id.city_id
579
+ city_tax_codes = line.product_id.city_taxation_code_ids
580
+ city_tax_code = city_tax_codes.filtered(
581
+ lambda r, _city_id=company_city: r.city_id == _city_id
582
+ )
583
+ if city_tax_code:
584
+ line.city_taxation_code_id = city_tax_code
585
+ else:
586
+ line.city_taxation_code_id = False
587
+
588
+ def _prepare_fields_issqn(self, tax_dict):
589
+ self.ensure_one()
590
+ return {
591
+ "issqn_base": tax_dict.get("base"),
592
+ "issqn_percent": tax_dict.get("percent_amount"),
593
+ "issqn_reduction": tax_dict.get("percent_reduction"),
594
+ "issqn_value": tax_dict.get("tax_value"),
595
+ }
596
+
597
+ def _prepare_fields_issqn_wh(self, tax_dict):
598
+ self.ensure_one()
599
+ return {
600
+ "issqn_wh_base": tax_dict.get("base"),
601
+ "issqn_wh_percent": tax_dict.get("percent_amount"),
602
+ "issqn_wh_reduction": tax_dict.get("percent_reduction"),
603
+ "issqn_wh_value": tax_dict.get("tax_value"),
604
+ }
605
+
606
+ def _prepare_fields_csll(self, tax_dict):
607
+ self.ensure_one()
608
+ return {
609
+ "csll_base": tax_dict.get("base"),
610
+ "csll_percent": tax_dict.get("percent_amount"),
611
+ "csll_reduction": tax_dict.get("percent_reduction"),
612
+ "csll_value": tax_dict.get("tax_value"),
613
+ }
614
+
615
+ def _prepare_fields_csll_wh(self, tax_dict):
616
+ self.ensure_one()
617
+ return {
618
+ "csll_wh_base": tax_dict.get("base"),
619
+ "csll_wh_percent": tax_dict.get("percent_amount"),
620
+ "csll_wh_reduction": tax_dict.get("percent_reduction"),
621
+ "csll_wh_value": tax_dict.get("tax_value"),
622
+ }
623
+
624
+ def _prepare_fields_irpj(self, tax_dict):
625
+ self.ensure_one()
626
+ return {
627
+ "irpj_base": tax_dict.get("base"),
628
+ "irpj_percent": tax_dict.get("percent_amount"),
629
+ "irpj_reduction": tax_dict.get("percent_reduction"),
630
+ "irpj_value": tax_dict.get("tax_value"),
631
+ }
632
+
633
+ def _prepare_fields_irpj_wh(self, tax_dict):
634
+ self.ensure_one()
635
+ return {
636
+ "irpj_wh_base": tax_dict.get("base"),
637
+ "irpj_wh_percent": tax_dict.get("percent_amount"),
638
+ "irpj_wh_reduction": tax_dict.get("percent_reduction"),
639
+ "irpj_wh_value": tax_dict.get("tax_value"),
640
+ }
641
+
642
+ def _prepare_fields_inss(self, tax_dict):
643
+ self.ensure_one()
644
+ return {
645
+ "inss_base": tax_dict.get("base"),
646
+ "inss_percent": tax_dict.get("percent_amount"),
647
+ "inss_reduction": tax_dict.get("percent_reduction"),
648
+ "inss_value": tax_dict.get("tax_value"),
649
+ }
650
+
651
+ def _prepare_fields_inss_wh(self, tax_dict):
652
+ self.ensure_one()
653
+ return {
654
+ "inss_wh_base": tax_dict.get("base"),
655
+ "inss_wh_percent": tax_dict.get("percent_amount"),
656
+ "inss_wh_reduction": tax_dict.get("percent_reduction"),
657
+ "inss_wh_value": tax_dict.get("tax_value"),
658
+ }
659
+
660
+ def _prepare_fields_icms(self, tax_dict):
661
+ self.ensure_one()
662
+ cst_id = tax_dict.get("cst_id").id if tax_dict.get("cst_id") else False
663
+ return {
664
+ "icms_cst_id": cst_id,
665
+ "icms_base_type": tax_dict.get("icms_base_type", ICMS_BASE_TYPE_DEFAULT),
666
+ "icms_base": tax_dict.get("base", 0.0),
667
+ "icms_percent": tax_dict.get("percent_amount", 0.0),
668
+ "icms_reduction": tax_dict.get("percent_reduction", 0.0),
669
+ "icms_value": tax_dict.get("tax_value", 0.0),
670
+ "icms_origin_percent": tax_dict.get("icms_origin_perc", 0.0),
671
+ "icms_destination_percent": tax_dict.get("icms_dest_perc", 0.0),
672
+ "icms_sharing_percent": tax_dict.get("icms_sharing_percent", 0.0),
673
+ "icms_destination_base": tax_dict.get("icms_dest_base", 0.0),
674
+ "icms_origin_value": tax_dict.get("icms_origin_value", 0.0),
675
+ "icms_destination_value": tax_dict.get("icms_dest_value", 0.0),
676
+ "icms_relief_value": tax_dict.get("icms_relief", 0.0),
677
+ }
678
+
679
+ @api.onchange(
680
+ "icms_base",
681
+ "icms_percent",
682
+ "icms_reduction",
683
+ "icms_value",
684
+ "icms_destination_base",
685
+ "icms_origin_percent",
686
+ "icms_destination_percent",
687
+ "icms_sharing_percent",
688
+ "icms_origin_value",
689
+ "icms_tax_benefit_id",
690
+ )
691
+ def _onchange_icms_fields(self):
692
+ if self.icms_tax_benefit_id:
693
+ self.icms_tax_id = self.icms_tax_benefit_id.tax_id
694
+
695
+ @api.onchange("tax_classification_id")
696
+ def _onchange_tax_classification_id(self):
697
+ if self.tax_classification_id:
698
+ self.ibs_tax_id = self.tax_classification_id.tax_ibs_id
699
+ self.cbs_tax_id = self.tax_classification_id.tax_cbs_id
700
+
701
+ def _prepare_fields_icmssn(self, tax_dict):
702
+ self.ensure_one()
703
+ cst_id = tax_dict.get("cst_id").id if tax_dict.get("cst_id") else False
704
+ icmssn_base = tax_dict.get("base", 0.0)
705
+ icmssn_credit_value = tax_dict.get("tax_value", 0.0)
706
+ simple_value = icmssn_base * self.icmssn_range_id.total_tax_percent
707
+ simple_without_icms_value = simple_value - icmssn_credit_value
708
+ return {
709
+ "icms_cst_id": cst_id,
710
+ "icmssn_base": icmssn_base,
711
+ "icmssn_percent": tax_dict.get("percent_amount"),
712
+ "icmssn_reduction": tax_dict.get("percent_reduction"),
713
+ "icmssn_credit_value": icmssn_credit_value,
714
+ "simple_value": simple_value,
715
+ "simple_without_icms_value": simple_without_icms_value,
716
+ }
717
+
718
+ def _prepare_fields_icmsst(self, tax_dict):
719
+ self.ensure_one()
720
+ return {
721
+ "icmsst_base_type": tax_dict.get(
722
+ "icmsst_base_type", ICMS_ST_BASE_TYPE_DEFAULT
723
+ ),
724
+ "icmsst_mva_percent": tax_dict.get("icmsst_mva_percent"),
725
+ "icmsst_percent": tax_dict.get("percent_amount"),
726
+ "icmsst_reduction": tax_dict.get("percent_reduction"),
727
+ "icmsst_base": tax_dict.get("base"),
728
+ "icmsst_value": tax_dict.get("tax_value"),
729
+ }
730
+
731
+ def _prepare_fields_icmsfcp(self, tax_dict):
732
+ self.ensure_one()
733
+ return {
734
+ "icmsfcp_base": tax_dict.get("base", 0.0),
735
+ "icmsfcp_percent": tax_dict.get("percent_amount", 0.0),
736
+ "icmsfcp_value": tax_dict.get("tax_value", 0.0),
737
+ }
738
+
739
+ def _prepare_fields_icmsfcpst(self, tax_dict):
740
+ self.ensure_one()
741
+ return {
742
+ "icmsfcpst_base": self.icmsst_base,
743
+ "icmsfcpst_percent": tax_dict.get("percent_amount", 0.0),
744
+ "icmsfcpst_value": tax_dict.get("tax_value", 0.0),
745
+ }
746
+
747
+ def _prepare_fields_ipi(self, tax_dict):
748
+ self.ensure_one()
749
+ cst_id = tax_dict.get("cst_id").id if tax_dict.get("cst_id") else False
750
+ return {
751
+ "ipi_cst_id": cst_id,
752
+ "ipi_base_type": tax_dict.get("base_type", False),
753
+ "ipi_base": tax_dict.get("base", 0.00),
754
+ "ipi_percent": tax_dict.get("percent_amount", 0.00),
755
+ "ipi_reduction": tax_dict.get("percent_reduction", 0.00),
756
+ "ipi_value": tax_dict.get("tax_value", 0.00),
757
+ }
758
+
759
+ def _prepare_fields_ii(self, tax_dict):
760
+ self.ensure_one()
761
+ return {
762
+ "ii_base": tax_dict.get("base", 0.00),
763
+ "ii_percent": tax_dict.get("percent_amount", 0.00),
764
+ "ii_value": tax_dict.get("tax_value", 0.00),
765
+ }
766
+
767
+ def _prepare_fields_cbs(self, tax_dict):
768
+ self.ensure_one()
769
+ cst_id = tax_dict.get("cst_id").id if tax_dict.get("cst_id") else False
770
+ return {
771
+ "cbs_cst_id": cst_id,
772
+ "cbs_base_type": tax_dict.get("base_type", False),
773
+ "cbs_base": tax_dict.get("base", 0.00),
774
+ "cbs_percent": tax_dict.get("percent_amount", 0.00),
775
+ "cbs_reduction": tax_dict.get("percent_reduction", 0.00),
776
+ "cbs_value": tax_dict.get("tax_value", 0.00),
777
+ }
778
+
779
+ def _prepare_fields_ibs(self, tax_dict):
780
+ self.ensure_one()
781
+ cst_id = tax_dict.get("cst_id").id if tax_dict.get("cst_id") else False
782
+ return {
783
+ "ibs_cst_id": cst_id,
784
+ "ibs_base_type": tax_dict.get("base_type", False),
785
+ "ibs_base": tax_dict.get("base", 0.00),
786
+ "ibs_percent": tax_dict.get("percent_amount", 0.00),
787
+ "ibs_reduction": tax_dict.get("percent_reduction", 0.00),
788
+ "ibs_value": tax_dict.get("tax_value", 0.00),
789
+ }
790
+
791
+ def _prepare_fields_pis(self, tax_dict):
792
+ self.ensure_one()
793
+ cst_id = tax_dict.get("cst_id").id if tax_dict.get("cst_id") else False
794
+ return {
795
+ "pis_cst_id": cst_id,
796
+ "pis_base_type": tax_dict.get("base_type"),
797
+ "pis_base": tax_dict.get("base", 0.00),
798
+ "pis_percent": tax_dict.get("percent_amount", 0.00),
799
+ "pis_reduction": tax_dict.get("percent_reduction", 0.00),
800
+ "pis_value": tax_dict.get("tax_value", 0.00),
801
+ }
802
+
803
+ def _prepare_fields_pis_wh(self, tax_dict):
804
+ self.ensure_one()
805
+ return {
806
+ "pis_wh_base_type": tax_dict.get("base_type"),
807
+ "pis_wh_base": tax_dict.get("base", 0.00),
808
+ "pis_wh_percent": tax_dict.get("percent_amount", 0.00),
809
+ "pis_wh_reduction": tax_dict.get("percent_reduction", 0.00),
810
+ "pis_wh_value": tax_dict.get("tax_value", 0.00),
811
+ }
812
+
813
+ def _prepare_fields_pisst(self, tax_dict):
814
+ self.ensure_one()
815
+ cst_id = tax_dict.get("cst_id").id if tax_dict.get("cst_id") else False
816
+ return {
817
+ "pisst_cst_id": cst_id,
818
+ "pisst_base_type": tax_dict.get("base_type"),
819
+ "pisst_base": tax_dict.get("base", 0.00),
820
+ "pisst_percent": tax_dict.get("percent_amount", 0.00),
821
+ "pisst_reduction": tax_dict.get("percent_reduction", 0.00),
822
+ "pisst_value": tax_dict.get("tax_value", 0.00),
823
+ }
824
+
825
+ def _prepare_fields_cofins(self, tax_dict):
826
+ self.ensure_one()
827
+ cst_id = tax_dict.get("cst_id").id if tax_dict.get("cst_id") else False
828
+ return {
829
+ "cofins_cst_id": cst_id,
830
+ "cofins_base_type": tax_dict.get("base_type"),
831
+ "cofins_base": tax_dict.get("base", 0.00),
832
+ "cofins_percent": tax_dict.get("percent_amount", 0.00),
833
+ "cofins_reduction": tax_dict.get("percent_reduction", 0.00),
834
+ "cofins_value": tax_dict.get("tax_value", 0.00),
835
+ }
836
+
837
+ def _prepare_fields_cofins_wh(self, tax_dict):
838
+ self.ensure_one()
839
+ return {
840
+ "cofins_wh_base_type": tax_dict.get("base_type"),
841
+ "cofins_wh_base": tax_dict.get("base", 0.00),
842
+ "cofins_wh_percent": tax_dict.get("percent_amount", 0.00),
843
+ "cofins_wh_reduction": tax_dict.get("percent_reduction", 0.00),
844
+ "cofins_wh_value": tax_dict.get("tax_value", 0.00),
845
+ }
846
+
847
+ def _prepare_fields_cofinsst(self, tax_dict):
848
+ self.ensure_one()
849
+ cst_id = tax_dict.get("cst_id").id if tax_dict.get("cst_id") else False
850
+ return {
851
+ "cofinsst_cst_id": cst_id,
852
+ "cofinsst_base_type": tax_dict.get("base_type"),
853
+ "cofinsst_base": tax_dict.get("base", 0.00),
854
+ "cofinsst_percent": tax_dict.get("percent_amount", 0.00),
855
+ "cofinsst_reduction": tax_dict.get("percent_reduction", 0.00),
856
+ "cofinsst_value": tax_dict.get("tax_value", 0.00),
857
+ }
858
+
859
+ @api.depends("product_id", "uom_id")
860
+ def _compute_uot_id(self):
861
+ for line in self:
862
+ p = line.product_id
863
+ line.uot_id = (p.uot_id if p else False) or line.uom_id
864
+
865
+ @api.depends("price_unit")
866
+ def _compute_fiscal_price(self):
867
+ for line in self:
868
+ if line.product_id and line.price_unit:
869
+ line.fiscal_price = line.price_unit / (
870
+ line.product_id.uot_factor or 1.0
871
+ )
872
+ else:
873
+ line.fiscal_price = line.price_unit
874
+
875
+ @api.depends("quantity")
876
+ def _compute_fiscal_quantity(self):
877
+ for line in self:
878
+ if line.product_id and line.quantity:
879
+ line.fiscal_quantity = line.quantity * (
880
+ line.product_id.uot_factor or 1.0
881
+ )
882
+ else:
883
+ line.fiscal_quantity = line.quantity
884
+
885
+ @api.model
886
+ def _add_fields_to_amount(self):
887
+ fields_to_amount = ["insurance_value", "other_value", "freight_value"]
888
+ if (
889
+ self.cfop_id.destination == CFOP_DESTINATION_EXPORT
890
+ and self.fiscal_operation_id.fiscal_operation_type == FISCAL_IN
891
+ ):
892
+ fields_to_amount.append("pis_value")
893
+ fields_to_amount.append("cofins_value")
894
+ fields_to_amount.append("icms_value")
895
+ fields_to_amount.append("ii_value")
896
+ fields_to_amount.append("ii_customhouse_charges")
897
+ return fields_to_amount
898
+
899
+ @api.model
900
+ def _rm_fields_to_amount(self):
901
+ return ["icms_relief_value"]
902
+
903
+ def _is_imported(self):
904
+ # When the mixin is used for instance
905
+ # in a PO line or SO line, there is no document_id
906
+ # and we consider the document is not imported
907
+ return hasattr(self, "document_id") and self.document_id.imported_document
908
+
105
909
  currency_id = fields.Many2one(
106
910
  comodel_name="res.currency",
107
911
  string="Currency",
@@ -117,7 +921,10 @@ class FiscalDocumentLineMixin(models.AbstractModel):
117
921
  tax_icms_or_issqn = fields.Selection(
118
922
  selection=TAX_ICMS_OR_ISSQN,
119
923
  string="ICMS or ISSQN Tax",
120
- default=TAX_DOMAIN_ICMS,
924
+ compute="_compute_product_fiscal_fields",
925
+ store=True,
926
+ readonly=False,
927
+ precompute=True,
121
928
  )
122
929
 
123
930
  partner_is_public_entity = fields.Boolean(related="partner_id.is_public_entity")
@@ -127,22 +934,60 @@ class FiscalDocumentLineMixin(models.AbstractModel):
127
934
  help="Indicates potential 'CSLL' and 'IRPJ' tax charges.",
128
935
  )
129
936
 
130
- price_unit = fields.Float(digits="Product Price")
937
+ price_unit = fields.Float(
938
+ digits="Product Price",
939
+ store=True,
940
+ )
131
941
 
132
942
  partner_id = fields.Many2one(comodel_name="res.partner", string="Partner")
133
943
 
944
+ company_id = fields.Many2one(
945
+ comodel_name="res.company",
946
+ string="Company",
947
+ )
948
+
949
+ ind_final = fields.Selection(
950
+ selection=FINAL_CUSTOMER,
951
+ string="Consumidor final",
952
+ compute="_compute_ind_final",
953
+ store=True,
954
+ precompute=True,
955
+ readonly=False,
956
+ )
957
+
958
+ def _compute_ind_final(self):
959
+ for line in self:
960
+ doc = line._get_document()
961
+ if line.ind_final != doc.ind_final:
962
+ line.ind_final = doc.ind_final
963
+
134
964
  partner_company_type = fields.Selection(related="partner_id.company_type")
135
965
 
136
- uom_id = fields.Many2one(comodel_name="uom.uom", string="UOM")
966
+ uom_id = fields.Many2one(
967
+ comodel_name="uom.uom",
968
+ string="UOM",
969
+ )
137
970
 
138
971
  quantity = fields.Float(
139
972
  digits="Product Unit of Measure",
140
973
  )
141
974
 
142
- fiscal_type = fields.Selection(selection=PRODUCT_FISCAL_TYPE)
975
+ fiscal_type = fields.Selection(
976
+ selection=PRODUCT_FISCAL_TYPE,
977
+ compute="_compute_product_fiscal_fields",
978
+ store=True,
979
+ readonly=False,
980
+ precompute=True,
981
+ )
143
982
 
144
983
  ncm_id = fields.Many2one(
145
- comodel_name="l10n_br_fiscal.ncm", index=True, string="NCM"
984
+ comodel_name="l10n_br_fiscal.ncm",
985
+ index=True,
986
+ string="NCM",
987
+ compute="_compute_product_fiscal_fields",
988
+ store=True,
989
+ readonly=False,
990
+ precompute=True,
146
991
  )
147
992
 
148
993
  nbm_id = fields.Many2one(
@@ -150,6 +995,10 @@ class FiscalDocumentLineMixin(models.AbstractModel):
150
995
  index=True,
151
996
  string="NBM",
152
997
  domain="[('ncm_ids', '=', ncm_id)]",
998
+ compute="_compute_product_fiscal_fields",
999
+ store=True,
1000
+ readonly=False,
1001
+ precompute=True,
153
1002
  )
154
1003
 
155
1004
  cest_id = fields.Many2one(
@@ -157,17 +1006,26 @@ class FiscalDocumentLineMixin(models.AbstractModel):
157
1006
  index=True,
158
1007
  string="CEST",
159
1008
  domain="[('ncm_ids', '=', ncm_id)]",
1009
+ compute="_compute_product_fiscal_fields",
1010
+ store=True,
1011
+ readonly=False,
1012
+ precompute=True,
160
1013
  )
161
1014
 
162
1015
  nbs_id = fields.Many2one(
163
- comodel_name="l10n_br_fiscal.nbs", index=True, string="NBS"
1016
+ comodel_name="l10n_br_fiscal.nbs",
1017
+ index=True,
1018
+ string="NBS",
1019
+ compute="_compute_product_fiscal_fields",
1020
+ store=True,
1021
+ readonly=False,
1022
+ precompute=True,
164
1023
  )
165
1024
 
166
1025
  fiscal_operation_id = fields.Many2one(
167
1026
  comodel_name="l10n_br_fiscal.operation",
168
1027
  string="Operation",
169
1028
  domain=lambda self: self._operation_domain(),
170
- default=_default_operation,
171
1029
  )
172
1030
 
173
1031
  fiscal_operation_type = fields.Selection(
@@ -183,14 +1041,22 @@ class FiscalDocumentLineMixin(models.AbstractModel):
183
1041
  fiscal_operation_line_id = fields.Many2one(
184
1042
  comodel_name="l10n_br_fiscal.operation.line",
185
1043
  string="Operation Line",
1044
+ compute="_compute_fiscal_operation_line_id",
186
1045
  domain="[('fiscal_operation_id', '=', fiscal_operation_id), "
187
1046
  "('state', '=', 'approved')]",
1047
+ store=True,
1048
+ precompute=True,
1049
+ readonly=False,
188
1050
  )
189
1051
 
190
1052
  cfop_id = fields.Many2one(
191
1053
  comodel_name="l10n_br_fiscal.cfop",
192
1054
  string="CFOP",
193
1055
  domain="[('type_in_out', '=', fiscal_operation_type)]",
1056
+ compute="_compute_fiscal_tax_ids",
1057
+ store=True,
1058
+ precompute=True,
1059
+ readonly=False,
194
1060
  )
195
1061
 
196
1062
  cfop_destination = fields.Selection(
@@ -198,11 +1064,30 @@ class FiscalDocumentLineMixin(models.AbstractModel):
198
1064
  string="CFOP Destination",
199
1065
  )
200
1066
 
201
- fiscal_price = fields.Float(digits="Product Price")
1067
+ fiscal_price = fields.Float(
1068
+ digits="Product Price",
1069
+ compute="_compute_fiscal_price",
1070
+ store=True,
1071
+ precompute=True,
1072
+ readonly=False,
1073
+ )
202
1074
 
203
- uot_id = fields.Many2one(comodel_name="uom.uom", string="Tax UoM")
1075
+ uot_id = fields.Many2one(
1076
+ comodel_name="uom.uom",
1077
+ string="Tax UoM",
1078
+ compute="_compute_uot_id",
1079
+ store=True,
1080
+ readonly=False,
1081
+ precompute=True,
1082
+ )
204
1083
 
205
- fiscal_quantity = fields.Float(digits="Product Unit of Measure")
1084
+ fiscal_quantity = fields.Float(
1085
+ digits="Product Unit of Measure",
1086
+ compute="_compute_fiscal_quantity",
1087
+ store=True,
1088
+ precompute=True,
1089
+ readonly=False,
1090
+ )
206
1091
 
207
1092
  discount_value = fields.Monetary()
208
1093
 
@@ -215,6 +1100,10 @@ class FiscalDocumentLineMixin(models.AbstractModel):
215
1100
  fiscal_tax_ids = fields.Many2many(
216
1101
  comodel_name="l10n_br_fiscal.tax",
217
1102
  string="Fiscal Taxes",
1103
+ compute="_compute_fiscal_tax_ids",
1104
+ store=True,
1105
+ precompute=True,
1106
+ readonly=False,
218
1107
  )
219
1108
 
220
1109
  amount_fiscal = fields.Monetary(
@@ -230,11 +1119,11 @@ class FiscalDocumentLineMixin(models.AbstractModel):
230
1119
  compute="_compute_fiscal_amounts",
231
1120
  )
232
1121
 
233
- amount_untaxed = fields.Monetary(
1122
+ fiscal_amount_untaxed = fields.Monetary(
234
1123
  compute="_compute_fiscal_amounts",
235
1124
  )
236
1125
 
237
- amount_tax = fields.Monetary(
1126
+ fiscal_amount_tax = fields.Monetary(
238
1127
  compute="_compute_fiscal_amounts",
239
1128
  )
240
1129
 
@@ -242,7 +1131,7 @@ class FiscalDocumentLineMixin(models.AbstractModel):
242
1131
  compute="_compute_fiscal_amounts",
243
1132
  )
244
1133
 
245
- amount_total = fields.Monetary(
1134
+ fiscal_amount_total = fields.Monetary(
246
1135
  compute="_compute_fiscal_amounts",
247
1136
  )
248
1137
 
@@ -261,14 +1150,35 @@ class FiscalDocumentLineMixin(models.AbstractModel):
261
1150
  compute="_compute_fiscal_amounts",
262
1151
  )
263
1152
 
264
- amount_tax_included = fields.Monetary()
1153
+ amount_tax_included = fields.Monetary(
1154
+ compute="_compute_tax_fields",
1155
+ store=True,
1156
+ precompute=True,
1157
+ readonly=False,
1158
+ )
265
1159
 
266
- amount_tax_not_included = fields.Monetary()
1160
+ amount_tax_not_included = fields.Monetary(
1161
+ compute="_compute_tax_fields",
1162
+ store=True,
1163
+ precompute=True,
1164
+ readonly=False,
1165
+ )
267
1166
 
268
- amount_tax_withholding = fields.Monetary(string="Tax Withholding")
1167
+ amount_tax_withholding = fields.Monetary(
1168
+ string="Tax Withholding",
1169
+ compute="_compute_tax_fields",
1170
+ store=True,
1171
+ precompute=True,
1172
+ readonly=False,
1173
+ )
269
1174
 
270
1175
  fiscal_genre_id = fields.Many2one(
271
- comodel_name="l10n_br_fiscal.product.genre", string="Fiscal Product Genre"
1176
+ comodel_name="l10n_br_fiscal.product.genre",
1177
+ string="Fiscal Product Genre",
1178
+ compute="_compute_product_fiscal_fields",
1179
+ store=True,
1180
+ readonly=False,
1181
+ precompute=True,
272
1182
  )
273
1183
 
274
1184
  fiscal_genre_code = fields.Char(
@@ -279,10 +1189,27 @@ class FiscalDocumentLineMixin(models.AbstractModel):
279
1189
  comodel_name="l10n_br_fiscal.service.type",
280
1190
  string="Service Type LC 166",
281
1191
  domain="[('internal_type', '=', 'normal')]",
1192
+ compute="_compute_product_fiscal_fields",
1193
+ store=True,
1194
+ readonly=False,
1195
+ precompute=True,
282
1196
  )
283
1197
 
284
1198
  city_taxation_code_id = fields.Many2one(
285
- comodel_name="l10n_br_fiscal.city.taxation.code", string="City Taxation Code"
1199
+ comodel_name="l10n_br_fiscal.city.taxation.code",
1200
+ compute="_compute_city_taxation_code_id",
1201
+ store=True,
1202
+ readonly=False,
1203
+ precompute=True,
1204
+ )
1205
+
1206
+ operation_indicator_id = fields.Many2one(
1207
+ comodel_name="l10n_br_fiscal.operation.indicator",
1208
+ string="Operation Indicator",
1209
+ compute="_compute_product_fiscal_fields",
1210
+ store=True,
1211
+ readonly=False,
1212
+ precompute=True,
286
1213
  )
287
1214
 
288
1215
  partner_order = fields.Char(string="Partner Order (xPed)", size=15)
@@ -294,11 +1221,18 @@ class FiscalDocumentLineMixin(models.AbstractModel):
294
1221
  comodel_name="l10n_br_fiscal.tax",
295
1222
  string="Tax ISSQN",
296
1223
  domain=[("tax_domain", "=", TAX_DOMAIN_ISSQN)],
1224
+ compute="_compute_tax_fields",
1225
+ store=True,
1226
+ precompute=True,
1227
+ readonly=False,
297
1228
  )
298
1229
 
299
1230
  issqn_fg_city_id = fields.Many2one(
300
1231
  comodel_name="res.city",
1232
+ related="city_taxation_code_id.city_id",
301
1233
  string="ISSQN City",
1234
+ store=True,
1235
+ precompute=True,
302
1236
  )
303
1237
 
304
1238
  # vDeducao
@@ -327,33 +1261,89 @@ class FiscalDocumentLineMixin(models.AbstractModel):
327
1261
  default=ISSQN_INCENTIVE_DEFAULT,
328
1262
  )
329
1263
 
330
- issqn_base = fields.Monetary(string="ISSQN Base")
1264
+ issqn_base = fields.Monetary(
1265
+ string="ISSQN Base",
1266
+ compute="_compute_tax_fields",
1267
+ store=True,
1268
+ precompute=True,
1269
+ readonly=False,
1270
+ )
331
1271
 
332
- issqn_percent = fields.Float(string="ISSQN %")
1272
+ issqn_percent = fields.Float(
1273
+ string="ISSQN %",
1274
+ compute="_compute_tax_fields",
1275
+ store=True,
1276
+ precompute=True,
1277
+ readonly=False,
1278
+ )
333
1279
 
334
- issqn_reduction = fields.Float(string="ISSQN % Reduction")
1280
+ issqn_reduction = fields.Float(
1281
+ string="ISSQN % Reduction",
1282
+ compute="_compute_tax_fields",
1283
+ store=True,
1284
+ precompute=True,
1285
+ readonly=False,
1286
+ )
335
1287
 
336
- issqn_value = fields.Monetary(string="ISSQN Value")
1288
+ issqn_value = fields.Monetary(
1289
+ string="ISSQN Value",
1290
+ compute="_compute_tax_fields",
1291
+ store=True,
1292
+ precompute=True,
1293
+ readonly=False,
1294
+ )
337
1295
 
338
1296
  issqn_wh_tax_id = fields.Many2one(
339
1297
  comodel_name="l10n_br_fiscal.tax",
340
1298
  string="Tax ISSQN RET",
341
1299
  domain=[("tax_domain", "=", TAX_DOMAIN_ISSQN_WH)],
1300
+ compute="_compute_tax_fields",
1301
+ store=True,
1302
+ precompute=True,
1303
+ readonly=False,
342
1304
  )
343
1305
 
344
- issqn_wh_base = fields.Monetary(string="ISSQN RET Base")
1306
+ issqn_wh_base = fields.Monetary(
1307
+ string="ISSQN RET Base",
1308
+ compute="_compute_tax_fields",
1309
+ store=True,
1310
+ precompute=True,
1311
+ readonly=False,
1312
+ )
345
1313
 
346
- issqn_wh_percent = fields.Float(string="ISSQN RET %")
1314
+ issqn_wh_percent = fields.Float(
1315
+ string="ISSQN RET %",
1316
+ compute="_compute_tax_fields",
1317
+ store=True,
1318
+ precompute=True,
1319
+ readonly=False,
1320
+ )
347
1321
 
348
- issqn_wh_reduction = fields.Float(string="ISSQN RET % Reduction")
1322
+ issqn_wh_reduction = fields.Float(
1323
+ string="ISSQN RET % Reduction",
1324
+ compute="_compute_tax_fields",
1325
+ store=True,
1326
+ precompute=True,
1327
+ readonly=False,
1328
+ )
349
1329
 
350
- issqn_wh_value = fields.Monetary(string="ISSQN RET Value")
1330
+ issqn_wh_value = fields.Monetary(
1331
+ string="ISSQN RET Value",
1332
+ compute="_compute_tax_fields",
1333
+ store=True,
1334
+ precompute=True,
1335
+ readonly=False,
1336
+ )
351
1337
 
352
1338
  # ICMS Fields
353
1339
  icms_tax_id = fields.Many2one(
354
1340
  comodel_name="l10n_br_fiscal.tax",
355
1341
  string="Tax ICMS",
356
1342
  domain=[("tax_domain", "=", TAX_DOMAIN_ICMS)],
1343
+ compute="_compute_tax_fields",
1344
+ store=True,
1345
+ precompute=True,
1346
+ readonly=False,
357
1347
  )
358
1348
 
359
1349
  icms_cst_id = fields.Many2one(
@@ -361,6 +1351,10 @@ class FiscalDocumentLineMixin(models.AbstractModel):
361
1351
  string="CST ICMS",
362
1352
  domain="[('tax_domain', '=', {'1': 'icmssn', '2': 'icmssn', "
363
1353
  "'3': 'icms'}.get(tax_framework))]",
1354
+ compute="_compute_tax_fields",
1355
+ store=True,
1356
+ precompute=True,
1357
+ readonly=False,
364
1358
  )
365
1359
 
366
1360
  icms_cst_code = fields.Char(
@@ -374,6 +1368,10 @@ class FiscalDocumentLineMixin(models.AbstractModel):
374
1368
  ("is_benefit", "=", True),
375
1369
  ("tax_domain", "=", TAX_DOMAIN_ICMS),
376
1370
  ],
1371
+ compute="_compute_fiscal_tax_ids",
1372
+ store=True,
1373
+ precompute=True,
1374
+ readonly=False,
377
1375
  )
378
1376
 
379
1377
  icms_tax_benefit_code = fields.Char(
@@ -383,24 +1381,56 @@ class FiscalDocumentLineMixin(models.AbstractModel):
383
1381
  icms_base_type = fields.Selection(
384
1382
  selection=ICMS_BASE_TYPE,
385
1383
  string="ICMS Base Type",
386
- default=ICMS_BASE_TYPE_DEFAULT,
1384
+ compute="_compute_tax_fields",
1385
+ store=True,
1386
+ precompute=True,
1387
+ readonly=False,
387
1388
  )
388
1389
 
389
1390
  icms_origin = fields.Selection(
390
- selection=ICMS_ORIGIN, string="ICMS Origin", default=ICMS_ORIGIN_DEFAULT
1391
+ selection=ICMS_ORIGIN,
1392
+ string="ICMS Origin",
1393
+ compute="_compute_product_fiscal_fields",
1394
+ store=True,
1395
+ readonly=False,
1396
+ precompute=True,
391
1397
  )
392
1398
 
393
1399
  # vBC - Valor da base de cálculo do ICMS
394
- icms_base = fields.Monetary(string="ICMS Base")
1400
+ icms_base = fields.Monetary(
1401
+ string="ICMS Base",
1402
+ compute="_compute_tax_fields",
1403
+ store=True,
1404
+ precompute=True,
1405
+ readonly=False,
1406
+ )
395
1407
 
396
1408
  # pICMS - Alíquota do IMCS
397
- icms_percent = fields.Float(string="ICMS %")
1409
+ icms_percent = fields.Float(
1410
+ string="ICMS %",
1411
+ compute="_compute_tax_fields",
1412
+ store=True,
1413
+ precompute=True,
1414
+ readonly=False,
1415
+ )
398
1416
 
399
1417
  # pRedBC - Percentual de redução do ICMS
400
- icms_reduction = fields.Float(string="ICMS % Reduction")
1418
+ icms_reduction = fields.Float(
1419
+ string="ICMS % Reduction",
1420
+ compute="_compute_tax_fields",
1421
+ store=True,
1422
+ precompute=True,
1423
+ readonly=False,
1424
+ )
401
1425
 
402
1426
  # vICMS - Valor do ICMS
403
- icms_value = fields.Monetary(string="ICMS Value")
1427
+ icms_value = fields.Monetary(
1428
+ string="ICMS Value",
1429
+ compute="_compute_tax_fields",
1430
+ store=True,
1431
+ precompute=True,
1432
+ readonly=False,
1433
+ )
404
1434
 
405
1435
  # vICMSSubstituto - Valor do ICMS cobrado em operação anterior
406
1436
  icms_substitute = fields.Monetary(
@@ -414,36 +1444,79 @@ class FiscalDocumentLineMixin(models.AbstractModel):
414
1444
  )
415
1445
 
416
1446
  # vICMSDeson - Valor do ICMS desonerado
417
- icms_relief_value = fields.Monetary(string="ICMS Relief Value")
1447
+ icms_relief_value = fields.Monetary(
1448
+ string="ICMS Relief Value",
1449
+ compute="_compute_tax_fields",
1450
+ store=True,
1451
+ precompute=True,
1452
+ readonly=False,
1453
+ )
418
1454
 
419
1455
  # ICMS ST Fields
420
1456
  icmsst_tax_id = fields.Many2one(
421
1457
  comodel_name="l10n_br_fiscal.tax",
422
1458
  string="Tax ICMS ST",
423
1459
  domain=[("tax_domain", "=", TAX_DOMAIN_ICMS_ST)],
1460
+ compute="_compute_tax_fields",
1461
+ store=True,
1462
+ precompute=True,
1463
+ readonly=False,
424
1464
  )
425
1465
 
426
1466
  # modBCST - Modalidade de determinação da BC do ICMS ST
427
1467
  icmsst_base_type = fields.Selection(
428
1468
  selection=ICMS_ST_BASE_TYPE,
429
1469
  string="ICMS ST Base Type",
430
- default=ICMS_ST_BASE_TYPE_DEFAULT,
1470
+ compute="_compute_tax_fields",
1471
+ store=True,
1472
+ precompute=True,
1473
+ readonly=False,
431
1474
  )
432
1475
 
433
1476
  # pMVAST - Percentual da margem de valor Adicionado do ICMS ST
434
- icmsst_mva_percent = fields.Float(string="ICMS ST MVA %")
1477
+ icmsst_mva_percent = fields.Float(
1478
+ string="ICMS ST MVA %",
1479
+ compute="_compute_tax_fields",
1480
+ store=True,
1481
+ precompute=True,
1482
+ readonly=False,
1483
+ )
435
1484
 
436
1485
  # pRedBCST - Percentual da Redução de BC do ICMS ST
437
- icmsst_reduction = fields.Float(string="ICMS ST % Reduction")
1486
+ icmsst_reduction = fields.Float(
1487
+ string="ICMS ST % Reduction",
1488
+ compute="_compute_tax_fields",
1489
+ store=True,
1490
+ precompute=True,
1491
+ readonly=False,
1492
+ )
438
1493
 
439
1494
  # vBCST - Valor da BC do ICMS ST
440
- icmsst_base = fields.Monetary(string="ICMS ST Base")
1495
+ icmsst_base = fields.Monetary(
1496
+ string="ICMS ST Base",
1497
+ compute="_compute_tax_fields",
1498
+ store=True,
1499
+ precompute=True,
1500
+ readonly=False,
1501
+ )
441
1502
 
442
1503
  # pICMSST - Alíquota do imposto do ICMS ST
443
- icmsst_percent = fields.Float(string="ICMS ST %")
1504
+ icmsst_percent = fields.Float(
1505
+ string="ICMS ST %",
1506
+ compute="_compute_tax_fields",
1507
+ store=True,
1508
+ precompute=True,
1509
+ readonly=False,
1510
+ )
444
1511
 
445
1512
  # vICMSST - Valor do ICMS ST
446
- icmsst_value = fields.Monetary(string="ICMS ST Value")
1513
+ icmsst_value = fields.Monetary(
1514
+ string="ICMS ST Value",
1515
+ compute="_compute_tax_fields",
1516
+ store=True,
1517
+ precompute=True,
1518
+ readonly=False,
1519
+ )
447
1520
 
448
1521
  # vBCSTRet - Valor da base de cálculo do ICMS ST retido
449
1522
  icmsst_wh_base = fields.Monetary(string="ICMS ST WH Base")
@@ -459,58 +1532,134 @@ class FiscalDocumentLineMixin(models.AbstractModel):
459
1532
  comodel_name="l10n_br_fiscal.tax",
460
1533
  string="Tax ICMS FCP",
461
1534
  domain=[("tax_domain", "=", TAX_DOMAIN_ICMS_FCP)],
1535
+ compute="_compute_tax_fields",
1536
+ store=True,
1537
+ precompute=True,
1538
+ readonly=False,
462
1539
  )
463
1540
 
464
1541
  # vBCFCPUFDest
465
1542
  icmsfcp_base = fields.Monetary(
466
1543
  string="ICMS FCP Base",
1544
+ compute="_compute_tax_fields",
1545
+ store=True,
1546
+ precompute=True,
1547
+ readonly=False,
467
1548
  )
468
1549
 
469
1550
  # pFCPUFDest - Percentual do ICMS relativo ao Fundo de
470
1551
  # Combate à Pobreza (FCP) na UF de destino
471
- icmsfcp_percent = fields.Float(string="ICMS FCP %")
1552
+ icmsfcp_percent = fields.Float(
1553
+ string="ICMS FCP %",
1554
+ compute="_compute_tax_fields",
1555
+ store=True,
1556
+ precompute=True,
1557
+ readonly=False,
1558
+ )
472
1559
 
473
1560
  # vFCPUFDest - Valor do ICMS relativo ao Fundo
474
1561
  # de Combate à Pobreza (FCP) da UF de destino
475
- icmsfcp_value = fields.Monetary(string="ICMS FCP Value")
1562
+ icmsfcp_value = fields.Monetary(
1563
+ string="ICMS FCP Value",
1564
+ compute="_compute_tax_fields",
1565
+ store=True,
1566
+ precompute=True,
1567
+ readonly=False,
1568
+ )
476
1569
 
477
1570
  # ICMS FCP ST Fields
478
1571
  icmsfcpst_tax_id = fields.Many2one(
479
1572
  comodel_name="l10n_br_fiscal.tax",
480
1573
  string="Tax ICMS FCP ST",
481
1574
  domain=[("tax_domain", "=", TAX_DOMAIN_ICMS_FCP_ST)],
1575
+ compute="_compute_tax_fields",
1576
+ store=True,
1577
+ precompute=True,
1578
+ readonly=False,
482
1579
  )
483
1580
 
484
1581
  # vBCFCPST
485
1582
  icmsfcpst_base = fields.Monetary(
486
1583
  string="ICMS FCP ST Base",
1584
+ compute="_compute_tax_fields",
1585
+ store=True,
1586
+ precompute=True,
1587
+ readonly=False,
487
1588
  )
488
1589
 
489
1590
  # pFCPST - Percentual do FCP ST
490
- icmsfcpst_percent = fields.Float(string="ICMS FCP ST %")
1591
+ icmsfcpst_percent = fields.Float(
1592
+ string="ICMS FCP ST %",
1593
+ compute="_compute_tax_fields",
1594
+ store=True,
1595
+ precompute=True,
1596
+ readonly=False,
1597
+ )
491
1598
 
492
1599
  # vFCPST - Valor do ICMS relativo ao
493
1600
  # Fundo de Combate à Pobreza (FCP) por Substituição Tributária
494
- icmsfcpst_value = fields.Monetary(string="ICMS FCP ST Value")
1601
+ icmsfcpst_value = fields.Monetary(
1602
+ string="ICMS FCP ST Value",
1603
+ compute="_compute_tax_fields",
1604
+ store=True,
1605
+ precompute=True,
1606
+ readonly=False,
1607
+ )
495
1608
 
496
1609
  # ICMS DIFAL Fields
497
1610
  # vBCUFDest - Valor da BC do ICMS na UF de destino
498
- icms_destination_base = fields.Monetary(string="ICMS Destination Base")
1611
+ icms_destination_base = fields.Monetary(
1612
+ string="ICMS Destination Base",
1613
+ compute="_compute_tax_fields",
1614
+ store=True,
1615
+ precompute=True,
1616
+ readonly=False,
1617
+ )
499
1618
 
500
1619
  # pICMSUFDest - Alíquota interna da UF de destino
501
- icms_origin_percent = fields.Float(string="ICMS Internal %")
1620
+ icms_origin_percent = fields.Float(
1621
+ string="ICMS Internal %",
1622
+ compute="_compute_tax_fields",
1623
+ store=True,
1624
+ precompute=True,
1625
+ readonly=False,
1626
+ )
502
1627
 
503
1628
  # pICMSInter - Alíquota interestadual das UF envolvidas
504
- icms_destination_percent = fields.Float(string="ICMS External %")
1629
+ icms_destination_percent = fields.Float(
1630
+ string="ICMS External %",
1631
+ compute="_compute_tax_fields",
1632
+ store=True,
1633
+ precompute=True,
1634
+ readonly=False,
1635
+ )
505
1636
 
506
1637
  # pICMSInterPart - Percentual provisório de partilha do ICMS Interestadual
507
- icms_sharing_percent = fields.Float(string="ICMS Sharing %")
1638
+ icms_sharing_percent = fields.Float(
1639
+ string="ICMS Sharing %",
1640
+ compute="_compute_tax_fields",
1641
+ store=True,
1642
+ precompute=True,
1643
+ readonly=False,
1644
+ )
508
1645
 
509
1646
  # vICMSUFRemet - Valor do ICMS Interestadual para a UF do remetente
510
- icms_origin_value = fields.Monetary(string="ICMS Origin Value")
1647
+ icms_origin_value = fields.Monetary(
1648
+ string="ICMS Origin Value",
1649
+ compute="_compute_tax_fields",
1650
+ store=True,
1651
+ precompute=True,
1652
+ readonly=False,
1653
+ )
511
1654
 
512
1655
  # vICMSUFDest - Valor do ICMS Interestadual para a UF de destino
513
- icms_destination_value = fields.Monetary(string="ICMS Dest. Value")
1656
+ icms_destination_value = fields.Monetary(
1657
+ string="ICMS Dest. Value",
1658
+ compute="_compute_tax_fields",
1659
+ store=True,
1660
+ precompute=True,
1661
+ readonly=False,
1662
+ )
514
1663
 
515
1664
  # ICMS Simples Nacional Fields
516
1665
  icmssn_range_id = fields.Many2one(
@@ -523,17 +1672,45 @@ class FiscalDocumentLineMixin(models.AbstractModel):
523
1672
  comodel_name="l10n_br_fiscal.tax",
524
1673
  string="Tax ICMS SN",
525
1674
  domain=[("tax_domain", "=", TAX_DOMAIN_ICMS_SN)],
1675
+ compute="_compute_tax_fields",
1676
+ store=True,
1677
+ precompute=True,
1678
+ readonly=False,
526
1679
  )
527
1680
 
528
- icmssn_base = fields.Monetary(string="ICMS SN Base")
1681
+ icmssn_base = fields.Monetary(
1682
+ string="ICMS SN Base",
1683
+ compute="_compute_tax_fields",
1684
+ store=True,
1685
+ precompute=True,
1686
+ readonly=False,
1687
+ )
529
1688
 
530
- icmssn_reduction = fields.Monetary(string="ICMS SN Reduction")
1689
+ icmssn_reduction = fields.Monetary(
1690
+ string="ICMS SN Reduction",
1691
+ compute="_compute_tax_fields",
1692
+ store=True,
1693
+ precompute=True,
1694
+ readonly=False,
1695
+ )
531
1696
 
532
1697
  # pCredICMSSN - Alíquota aplicável de cálculo do crédito (Simples Nacional)
533
- icmssn_percent = fields.Float(string="ICMS SN %")
1698
+ icmssn_percent = fields.Float(
1699
+ string="ICMS SN %",
1700
+ compute="_compute_tax_fields",
1701
+ store=True,
1702
+ precompute=True,
1703
+ readonly=False,
1704
+ )
534
1705
 
535
1706
  # vCredICMSSN - Valor do crédito do ICMS que pode ser aproveitado
536
- icmssn_credit_value = fields.Monetary(string="ICMS SN Credit")
1707
+ icmssn_credit_value = fields.Monetary(
1708
+ string="ICMS SN Credit",
1709
+ compute="_compute_tax_fields",
1710
+ store=True,
1711
+ precompute=True,
1712
+ readonly=False,
1713
+ )
537
1714
 
538
1715
  # ICMS COBRADO ANTERIORMENTE POR ST
539
1716
  # vBCFCPSTRet - Valor da base de cálculo do FCP retido anteriormente
@@ -562,13 +1739,20 @@ class FiscalDocumentLineMixin(models.AbstractModel):
562
1739
  comodel_name="l10n_br_fiscal.tax",
563
1740
  string="Tax IPI",
564
1741
  domain=[("tax_domain", "=", TAX_DOMAIN_IPI)],
1742
+ compute="_compute_tax_fields",
1743
+ store=True,
1744
+ precompute=True,
1745
+ readonly=False,
565
1746
  )
566
1747
 
567
1748
  ipi_cst_id = fields.Many2one(
568
1749
  comodel_name="l10n_br_fiscal.cst",
569
1750
  string="CST IPI",
570
- domain="[('cst_type', '=', fiscal_operation_type),"
571
- "('tax_domain', '=', 'ipi')]",
1751
+ domain="[('cst_type', '=', fiscal_operation_type),('tax_domain', '=', 'ipi')]",
1752
+ compute="_compute_tax_fields",
1753
+ store=True,
1754
+ precompute=True,
1755
+ readonly=False,
572
1756
  )
573
1757
 
574
1758
  ipi_cst_code = fields.Char(
@@ -576,22 +1760,54 @@ class FiscalDocumentLineMixin(models.AbstractModel):
576
1760
  )
577
1761
 
578
1762
  ipi_base_type = fields.Selection(
579
- selection=TAX_BASE_TYPE, string="IPI Base Type", default=TAX_BASE_TYPE_PERCENT
1763
+ selection=TAX_BASE_TYPE,
1764
+ string="IPI Base Type",
1765
+ compute="_compute_tax_fields",
1766
+ store=True,
1767
+ precompute=True,
1768
+ readonly=False,
580
1769
  )
581
1770
 
582
- ipi_base = fields.Monetary(string="IPI Base")
1771
+ ipi_base = fields.Monetary(
1772
+ string="IPI Base",
1773
+ compute="_compute_tax_fields",
1774
+ store=True,
1775
+ precompute=True,
1776
+ readonly=False,
1777
+ )
583
1778
 
584
- ipi_percent = fields.Float(string="IPI %")
1779
+ ipi_percent = fields.Float(
1780
+ string="IPI %",
1781
+ compute="_compute_tax_fields",
1782
+ store=True,
1783
+ precompute=True,
1784
+ readonly=False,
1785
+ )
585
1786
 
586
- ipi_reduction = fields.Float(string="IPI % Reduction")
1787
+ ipi_reduction = fields.Float(
1788
+ string="IPI % Reduction",
1789
+ compute="_compute_tax_fields",
1790
+ store=True,
1791
+ precompute=True,
1792
+ readonly=False,
1793
+ )
587
1794
 
588
- ipi_value = fields.Monetary(string="IPI Value")
1795
+ ipi_value = fields.Monetary(
1796
+ string="IPI Value",
1797
+ compute="_compute_tax_fields",
1798
+ store=True,
1799
+ precompute=True,
1800
+ readonly=False,
1801
+ )
589
1802
 
590
1803
  ipi_guideline_id = fields.Many2one(
591
1804
  comodel_name="l10n_br_fiscal.tax.ipi.guideline",
592
1805
  string="IPI Guideline",
593
- domain="['|', ('cst_in_id', '=', ipi_cst_id),"
594
- "('cst_out_id', '=', ipi_cst_id)]",
1806
+ domain="['|', ('cst_in_id', '=', ipi_cst_id),('cst_out_id', '=', ipi_cst_id)]",
1807
+ compute="_compute_fiscal_tax_ids",
1808
+ store=True,
1809
+ precompute=True,
1810
+ readonly=False,
595
1811
  )
596
1812
 
597
1813
  # IPI Devolvido Fields
@@ -599,18 +1815,205 @@ class FiscalDocumentLineMixin(models.AbstractModel):
599
1815
 
600
1816
  ipi_devol_value = fields.Monetary(string="Valor do IPI devolvido")
601
1817
 
1818
+ # CBS Fields
1819
+ cbs_tax_id = fields.Many2one(
1820
+ comodel_name="l10n_br_fiscal.tax",
1821
+ string="Tax CBS",
1822
+ domain=(
1823
+ f"[('tax_domain', '=', '{TAX_DOMAIN_CBS}'), '|', "
1824
+ "('cst_in_id.code', 'like', cst_code_prefix_like), "
1825
+ "('cst_out_id.code', 'like', cst_code_prefix_like)]"
1826
+ ),
1827
+ compute="_compute_tax_fields",
1828
+ store=True,
1829
+ precompute=True,
1830
+ readonly=False,
1831
+ )
1832
+
1833
+ cbs_cst_id = fields.Many2one(
1834
+ comodel_name="l10n_br_fiscal.cst",
1835
+ string="CST CBS",
1836
+ domain="[('cst_type', '=', fiscal_operation_type),('tax_domain', '=', 'cbs')]",
1837
+ compute="_compute_tax_fields",
1838
+ store=True,
1839
+ precompute=True,
1840
+ readonly=False,
1841
+ )
1842
+
1843
+ cbs_cst_code = fields.Char(
1844
+ related="cbs_cst_id.code", string="CBS CST Code", store=True
1845
+ )
1846
+
1847
+ cbs_base_type = fields.Selection(
1848
+ selection=TAX_BASE_TYPE,
1849
+ string="CBS Base Type",
1850
+ compute="_compute_tax_fields",
1851
+ store=True,
1852
+ precompute=True,
1853
+ readonly=False,
1854
+ )
1855
+
1856
+ cbs_base = fields.Monetary(
1857
+ string="CBS Base",
1858
+ compute="_compute_tax_fields",
1859
+ store=True,
1860
+ precompute=True,
1861
+ readonly=False,
1862
+ )
1863
+
1864
+ cbs_percent = fields.Float(
1865
+ string="CBS %",
1866
+ compute="_compute_tax_fields",
1867
+ store=True,
1868
+ precompute=True,
1869
+ readonly=False,
1870
+ )
1871
+
1872
+ cbs_reduction = fields.Float(
1873
+ string="CBS % Reduction",
1874
+ compute="_compute_tax_fields",
1875
+ store=True,
1876
+ precompute=True,
1877
+ readonly=False,
1878
+ )
1879
+
1880
+ cbs_value = fields.Monetary(
1881
+ string="CBS Value",
1882
+ compute="_compute_tax_fields",
1883
+ store=True,
1884
+ precompute=True,
1885
+ readonly=False,
1886
+ )
1887
+
1888
+ # IBS Fields
1889
+ ibs_tax_id = fields.Many2one(
1890
+ comodel_name="l10n_br_fiscal.tax",
1891
+ string="Tax IBS",
1892
+ domain=(
1893
+ f"[('tax_domain', '=', '{TAX_DOMAIN_IBS}'), '|', "
1894
+ "('cst_in_id.code', 'like', cst_code_prefix_like), "
1895
+ "('cst_out_id.code', 'like', cst_code_prefix_like)]"
1896
+ ),
1897
+ compute="_compute_tax_fields",
1898
+ store=True,
1899
+ precompute=True,
1900
+ readonly=False,
1901
+ )
1902
+
1903
+ ibs_cst_id = fields.Many2one(
1904
+ comodel_name="l10n_br_fiscal.cst",
1905
+ string="CST IBS",
1906
+ domain="[('cst_type', '=', fiscal_operation_type),('tax_domain', '=', 'ibs')]",
1907
+ compute="_compute_tax_fields",
1908
+ store=True,
1909
+ precompute=True,
1910
+ readonly=False,
1911
+ )
1912
+
1913
+ ibs_cst_code = fields.Char(
1914
+ related="ibs_cst_id.code", string="IBS CST Code", store=True
1915
+ )
1916
+
1917
+ ibs_base_type = fields.Selection(
1918
+ selection=TAX_BASE_TYPE,
1919
+ string="IBS Base Type",
1920
+ compute="_compute_tax_fields",
1921
+ store=True,
1922
+ precompute=True,
1923
+ readonly=False,
1924
+ )
1925
+
1926
+ ibs_base = fields.Monetary(
1927
+ string="IBS Base",
1928
+ compute="_compute_tax_fields",
1929
+ store=True,
1930
+ precompute=True,
1931
+ readonly=False,
1932
+ )
1933
+
1934
+ ibs_percent = fields.Float(
1935
+ string="IBS %",
1936
+ compute="_compute_tax_fields",
1937
+ store=True,
1938
+ precompute=True,
1939
+ readonly=False,
1940
+ )
1941
+
1942
+ ibs_reduction = fields.Float(
1943
+ string="IBS % Reduction",
1944
+ compute="_compute_tax_fields",
1945
+ store=True,
1946
+ precompute=True,
1947
+ readonly=False,
1948
+ )
1949
+
1950
+ ibs_value = fields.Monetary(
1951
+ string="IBS Value",
1952
+ compute="_compute_tax_fields",
1953
+ store=True,
1954
+ precompute=True,
1955
+ readonly=False,
1956
+ )
1957
+
1958
+ # CBS/IBS Tax Classification
1959
+ tax_classification_id = fields.Many2one(
1960
+ comodel_name="l10n_br_fiscal.tax.classification",
1961
+ string="Tax Classification",
1962
+ compute="_compute_fiscal_tax_ids",
1963
+ store=True,
1964
+ precompute=True,
1965
+ readonly=False,
1966
+ )
1967
+
1968
+ cst_code_prefix_like = fields.Char(
1969
+ compute="_compute_cst_code_prefix_like",
1970
+ help="Helper field to filter taxes by CST code prefix (3 chars) using LIKE.",
1971
+ )
1972
+
1973
+ @api.depends("tax_classification_id")
1974
+ def _compute_cst_code_prefix_like(self):
1975
+ for rec in self:
1976
+ code = rec.tax_classification_id.code if rec.tax_classification_id else ""
1977
+ prefix = (code or "")[:3]
1978
+ # Avoid matching all records when the prefix is not available yet.
1979
+ rec.cst_code_prefix_like = (
1980
+ f"{prefix}%" if len(prefix) == 3 else "__no_match__%"
1981
+ )
1982
+
602
1983
  # II Fields
603
1984
  ii_tax_id = fields.Many2one(
604
1985
  comodel_name="l10n_br_fiscal.tax",
605
1986
  string="Tax II",
606
1987
  domain=[("tax_domain", "=", TAX_DOMAIN_II)],
1988
+ compute="_compute_tax_fields",
1989
+ store=True,
1990
+ precompute=True,
1991
+ readonly=False,
607
1992
  )
608
1993
 
609
- ii_base = fields.Monetary(string="II Base")
1994
+ ii_base = fields.Monetary(
1995
+ string="II Base",
1996
+ compute="_compute_tax_fields",
1997
+ store=True,
1998
+ precompute=True,
1999
+ readonly=False,
2000
+ )
610
2001
 
611
- ii_percent = fields.Float(string="II %")
2002
+ ii_percent = fields.Float(
2003
+ string="II %",
2004
+ compute="_compute_tax_fields",
2005
+ store=True,
2006
+ precompute=True,
2007
+ readonly=False,
2008
+ )
612
2009
 
613
- ii_value = fields.Monetary(string="II Value")
2010
+ ii_value = fields.Monetary(
2011
+ string="II Value",
2012
+ compute="_compute_tax_fields",
2013
+ store=True,
2014
+ precompute=True,
2015
+ readonly=False,
2016
+ )
614
2017
 
615
2018
  ii_iof_value = fields.Monetary(string="IOF Value")
616
2019
 
@@ -622,6 +2025,10 @@ class FiscalDocumentLineMixin(models.AbstractModel):
622
2025
  comodel_name="l10n_br_fiscal.tax",
623
2026
  string="Tax COFINS",
624
2027
  domain=[("tax_domain", "=", TAX_DOMAIN_COFINS)],
2028
+ compute="_compute_tax_fields",
2029
+ store=True,
2030
+ precompute=True,
2031
+ readonly=False,
625
2032
  )
626
2033
 
627
2034
  cofins_cst_id = fields.Many2one(
@@ -630,6 +2037,10 @@ class FiscalDocumentLineMixin(models.AbstractModel):
630
2037
  domain="['|', ('cst_type', '=', fiscal_operation_type),"
631
2038
  "('cst_type', '=', 'all'),"
632
2039
  "('tax_domain', '=', 'cofins')]",
2040
+ compute="_compute_tax_fields",
2041
+ store=True,
2042
+ precompute=True,
2043
+ readonly=False,
633
2044
  )
634
2045
 
635
2046
  cofins_cst_code = fields.Char(
@@ -639,16 +2050,43 @@ class FiscalDocumentLineMixin(models.AbstractModel):
639
2050
  cofins_base_type = fields.Selection(
640
2051
  selection=TAX_BASE_TYPE,
641
2052
  string="COFINS Base Type",
642
- default=TAX_BASE_TYPE_PERCENT,
2053
+ compute="_compute_tax_fields",
2054
+ store=True,
2055
+ precompute=True,
2056
+ readonly=False,
643
2057
  )
644
2058
 
645
- cofins_base = fields.Monetary(string="COFINS Base")
2059
+ cofins_base = fields.Monetary(
2060
+ string="COFINS Base",
2061
+ compute="_compute_tax_fields",
2062
+ store=True,
2063
+ precompute=True,
2064
+ readonly=False,
2065
+ )
646
2066
 
647
- cofins_percent = fields.Float(string="COFINS %")
2067
+ cofins_percent = fields.Float(
2068
+ string="COFINS %",
2069
+ compute="_compute_tax_fields",
2070
+ store=True,
2071
+ precompute=True,
2072
+ readonly=False,
2073
+ )
648
2074
 
649
- cofins_reduction = fields.Float(string="COFINS % Reduction")
2075
+ cofins_reduction = fields.Float(
2076
+ string="COFINS % Reduction",
2077
+ compute="_compute_tax_fields",
2078
+ store=True,
2079
+ precompute=True,
2080
+ readonly=False,
2081
+ )
650
2082
 
651
- cofins_value = fields.Monetary(string="COFINS Value")
2083
+ cofins_value = fields.Monetary(
2084
+ string="COFINS Value",
2085
+ compute="_compute_tax_fields",
2086
+ store=True,
2087
+ precompute=True,
2088
+ readonly=False,
2089
+ )
652
2090
 
653
2091
  cofins_base_id = fields.Many2one(
654
2092
  comodel_name="l10n_br_fiscal.tax.pis.cofins.base", string="COFINS Base Code"
@@ -663,6 +2101,10 @@ class FiscalDocumentLineMixin(models.AbstractModel):
663
2101
  comodel_name="l10n_br_fiscal.tax",
664
2102
  string="Tax COFINS ST",
665
2103
  domain=[("tax_domain", "=", TAX_DOMAIN_COFINS_ST)],
2104
+ compute="_compute_tax_fields",
2105
+ store=True,
2106
+ precompute=True,
2107
+ readonly=False,
666
2108
  )
667
2109
 
668
2110
  cofinsst_cst_id = fields.Many2one(
@@ -671,6 +2113,10 @@ class FiscalDocumentLineMixin(models.AbstractModel):
671
2113
  domain="['|', ('cst_type', '=', fiscal_operation_type),"
672
2114
  "('cst_type', '=', 'all'),"
673
2115
  "('tax_domain', '=', 'cofinsst')]",
2116
+ compute="_compute_tax_fields",
2117
+ store=True,
2118
+ precompute=True,
2119
+ readonly=False,
674
2120
  )
675
2121
 
676
2122
  cofinsst_cst_code = fields.Char(
@@ -680,42 +2126,104 @@ class FiscalDocumentLineMixin(models.AbstractModel):
680
2126
  cofinsst_base_type = fields.Selection(
681
2127
  selection=TAX_BASE_TYPE,
682
2128
  string="COFINS ST Base Type",
683
- default=TAX_BASE_TYPE_PERCENT,
2129
+ compute="_compute_tax_fields",
2130
+ store=True,
2131
+ precompute=True,
2132
+ readonly=False,
684
2133
  )
685
2134
 
686
- cofinsst_base = fields.Monetary(string="COFINS ST Base")
2135
+ cofinsst_base = fields.Monetary(
2136
+ string="COFINS ST Base",
2137
+ compute="_compute_tax_fields",
2138
+ store=True,
2139
+ precompute=True,
2140
+ readonly=False,
2141
+ )
687
2142
 
688
- cofinsst_percent = fields.Float(string="COFINS ST %")
2143
+ cofinsst_percent = fields.Float(
2144
+ string="COFINS ST %",
2145
+ compute="_compute_tax_fields",
2146
+ store=True,
2147
+ precompute=True,
2148
+ readonly=False,
2149
+ )
689
2150
 
690
- cofinsst_reduction = fields.Float(string="COFINS ST % Reduction")
2151
+ cofinsst_reduction = fields.Float(
2152
+ string="COFINS ST % Reduction",
2153
+ compute="_compute_tax_fields",
2154
+ store=True,
2155
+ precompute=True,
2156
+ readonly=False,
2157
+ )
691
2158
 
692
- cofinsst_value = fields.Monetary(string="COFINS ST Value")
2159
+ cofinsst_value = fields.Monetary(
2160
+ string="COFINS ST Value",
2161
+ compute="_compute_tax_fields",
2162
+ store=True,
2163
+ precompute=True,
2164
+ readonly=False,
2165
+ )
693
2166
 
694
2167
  cofins_wh_tax_id = fields.Many2one(
695
2168
  comodel_name="l10n_br_fiscal.tax",
696
2169
  string="Tax COFINS RET",
697
2170
  domain=[("tax_domain", "=", TAX_DOMAIN_COFINS_WH)],
2171
+ compute="_compute_tax_fields",
2172
+ store=True,
2173
+ precompute=True,
2174
+ readonly=False,
698
2175
  )
699
2176
 
700
2177
  cofins_wh_base_type = fields.Selection(
701
2178
  selection=TAX_BASE_TYPE,
702
2179
  string="COFINS WH Base Type",
703
- default=TAX_BASE_TYPE_PERCENT,
2180
+ compute="_compute_tax_fields",
2181
+ store=True,
2182
+ precompute=True,
2183
+ readonly=False,
704
2184
  )
705
2185
 
706
- cofins_wh_base = fields.Monetary(string="COFINS RET Base")
2186
+ cofins_wh_base = fields.Monetary(
2187
+ string="COFINS RET Base",
2188
+ compute="_compute_tax_fields",
2189
+ store=True,
2190
+ precompute=True,
2191
+ readonly=False,
2192
+ )
707
2193
 
708
- cofins_wh_percent = fields.Float(string="COFINS RET %")
2194
+ cofins_wh_percent = fields.Float(
2195
+ string="COFINS RET %",
2196
+ compute="_compute_tax_fields",
2197
+ store=True,
2198
+ precompute=True,
2199
+ readonly=False,
2200
+ )
709
2201
 
710
- cofins_wh_reduction = fields.Float(string="COFINS RET % Reduction")
2202
+ cofins_wh_reduction = fields.Float(
2203
+ string="COFINS RET % Reduction",
2204
+ compute="_compute_tax_fields",
2205
+ store=True,
2206
+ precompute=True,
2207
+ readonly=False,
2208
+ )
711
2209
 
712
- cofins_wh_value = fields.Monetary(string="COFINS RET Value")
2210
+ cofins_wh_value = fields.Monetary(
2211
+ string="COFINS RET Value",
2212
+ compute="_compute_tax_fields",
2213
+ store=True,
2214
+ precompute=True,
2215
+ readonly=False,
2216
+ )
713
2217
 
714
2218
  # PIS
715
2219
  pis_tax_id = fields.Many2one(
716
2220
  comodel_name="l10n_br_fiscal.tax",
717
2221
  string="Tax PIS",
718
2222
  domain=[("tax_domain", "=", TAX_DOMAIN_PIS)],
2223
+ compute="_compute_tax_fields",
2224
+ store=True,
2225
+ precompute=True,
2226
+ readonly=False,
719
2227
  )
720
2228
 
721
2229
  pis_cst_id = fields.Many2one(
@@ -724,6 +2232,10 @@ class FiscalDocumentLineMixin(models.AbstractModel):
724
2232
  domain="['|', ('cst_type', '=', fiscal_operation_type),"
725
2233
  "('cst_type', '=', 'all'),"
726
2234
  "('tax_domain', '=', 'pis')]",
2235
+ compute="_compute_tax_fields",
2236
+ store=True,
2237
+ precompute=True,
2238
+ readonly=False,
727
2239
  )
728
2240
 
729
2241
  pis_cst_code = fields.Char(
@@ -731,16 +2243,45 @@ class FiscalDocumentLineMixin(models.AbstractModel):
731
2243
  )
732
2244
 
733
2245
  pis_base_type = fields.Selection(
734
- selection=TAX_BASE_TYPE, string="PIS Base Type", default=TAX_BASE_TYPE_PERCENT
2246
+ selection=TAX_BASE_TYPE,
2247
+ string="PIS Base Type",
2248
+ compute="_compute_tax_fields",
2249
+ store=True,
2250
+ precompute=True,
2251
+ readonly=False,
735
2252
  )
736
2253
 
737
- pis_base = fields.Monetary(string="PIS Base")
2254
+ pis_base = fields.Monetary(
2255
+ string="PIS Base",
2256
+ compute="_compute_tax_fields",
2257
+ store=True,
2258
+ precompute=True,
2259
+ readonly=False,
2260
+ )
738
2261
 
739
- pis_percent = fields.Float(string="PIS %")
2262
+ pis_percent = fields.Float(
2263
+ string="PIS %",
2264
+ compute="_compute_tax_fields",
2265
+ store=True,
2266
+ precompute=True,
2267
+ readonly=False,
2268
+ )
740
2269
 
741
- pis_reduction = fields.Float(string="PIS % Reduction")
2270
+ pis_reduction = fields.Float(
2271
+ string="PIS % Reduction",
2272
+ compute="_compute_tax_fields",
2273
+ store=True,
2274
+ precompute=True,
2275
+ readonly=False,
2276
+ )
742
2277
 
743
- pis_value = fields.Monetary(string="PIS Value")
2278
+ pis_value = fields.Monetary(
2279
+ string="PIS Value",
2280
+ compute="_compute_tax_fields",
2281
+ store=True,
2282
+ precompute=True,
2283
+ readonly=False,
2284
+ )
744
2285
 
745
2286
  pis_base_id = fields.Many2one(
746
2287
  comodel_name="l10n_br_fiscal.tax.pis.cofins.base", string="PIS Base Code"
@@ -755,6 +2296,10 @@ class FiscalDocumentLineMixin(models.AbstractModel):
755
2296
  comodel_name="l10n_br_fiscal.tax",
756
2297
  string="Tax PIS ST",
757
2298
  domain=[("tax_domain", "=", TAX_DOMAIN_PIS_ST)],
2299
+ compute="_compute_tax_fields",
2300
+ store=True,
2301
+ precompute=True,
2302
+ readonly=False,
758
2303
  )
759
2304
 
760
2305
  pisst_cst_id = fields.Many2one(
@@ -763,6 +2308,10 @@ class FiscalDocumentLineMixin(models.AbstractModel):
763
2308
  domain="['|', ('cst_type', '=', fiscal_operation_type),"
764
2309
  "('cst_type', '=', 'all'),"
765
2310
  "('tax_domain', '=', 'pisst')]",
2311
+ compute="_compute_tax_fields",
2312
+ store=True,
2313
+ precompute=True,
2314
+ readonly=False,
766
2315
  )
767
2316
 
768
2317
  pisst_cst_code = fields.Char(
@@ -772,145 +2321,392 @@ class FiscalDocumentLineMixin(models.AbstractModel):
772
2321
  pisst_base_type = fields.Selection(
773
2322
  selection=TAX_BASE_TYPE,
774
2323
  string="PIS ST Base Type",
775
- default=TAX_BASE_TYPE_PERCENT,
2324
+ compute="_compute_tax_fields",
2325
+ store=True,
2326
+ precompute=True,
2327
+ readonly=False,
776
2328
  )
777
2329
 
778
- pisst_base = fields.Monetary(string="PIS ST Base")
2330
+ pisst_base = fields.Monetary(
2331
+ string="PIS ST Base",
2332
+ compute="_compute_tax_fields",
2333
+ store=True,
2334
+ precompute=True,
2335
+ readonly=False,
2336
+ )
779
2337
 
780
- pisst_percent = fields.Float(string="PIS ST %")
2338
+ pisst_percent = fields.Float(
2339
+ string="PIS ST %",
2340
+ compute="_compute_tax_fields",
2341
+ store=True,
2342
+ precompute=True,
2343
+ readonly=False,
2344
+ )
781
2345
 
782
- pisst_reduction = fields.Float(string="PIS ST % Reduction")
2346
+ pisst_reduction = fields.Float(
2347
+ string="PIS ST % Reduction",
2348
+ compute="_compute_tax_fields",
2349
+ store=True,
2350
+ precompute=True,
2351
+ readonly=False,
2352
+ )
783
2353
 
784
- pisst_value = fields.Monetary(string="PIS ST Value")
2354
+ pisst_value = fields.Monetary(
2355
+ string="PIS ST Value",
2356
+ compute="_compute_tax_fields",
2357
+ store=True,
2358
+ precompute=True,
2359
+ readonly=False,
2360
+ )
785
2361
 
786
2362
  pis_wh_tax_id = fields.Many2one(
787
2363
  comodel_name="l10n_br_fiscal.tax",
788
2364
  string="Tax PIS RET",
789
2365
  domain=[("tax_domain", "=", TAX_DOMAIN_PIS_WH)],
2366
+ compute="_compute_tax_fields",
2367
+ store=True,
2368
+ precompute=True,
2369
+ readonly=False,
790
2370
  )
791
2371
 
792
2372
  pis_wh_base_type = fields.Selection(
793
2373
  selection=TAX_BASE_TYPE,
794
2374
  string="PIS WH Base Type",
795
- default=TAX_BASE_TYPE_PERCENT,
2375
+ compute="_compute_tax_fields",
2376
+ store=True,
2377
+ precompute=True,
2378
+ readonly=False,
796
2379
  )
797
2380
 
798
- pis_wh_base = fields.Monetary(string="PIS RET Base")
2381
+ pis_wh_base = fields.Monetary(
2382
+ string="PIS RET Base",
2383
+ compute="_compute_tax_fields",
2384
+ store=True,
2385
+ precompute=True,
2386
+ readonly=False,
2387
+ )
799
2388
 
800
- pis_wh_percent = fields.Float(string="PIS RET %")
2389
+ pis_wh_percent = fields.Float(
2390
+ string="PIS RET %",
2391
+ compute="_compute_tax_fields",
2392
+ store=True,
2393
+ precompute=True,
2394
+ readonly=False,
2395
+ )
801
2396
 
802
- pis_wh_reduction = fields.Float(string="PIS RET % Reduction")
2397
+ pis_wh_reduction = fields.Float(
2398
+ string="PIS RET % Reduction",
2399
+ compute="_compute_tax_fields",
2400
+ store=True,
2401
+ precompute=True,
2402
+ readonly=False,
2403
+ )
803
2404
 
804
- pis_wh_value = fields.Monetary(string="PIS RET Value")
2405
+ pis_wh_value = fields.Monetary(
2406
+ string="PIS RET Value",
2407
+ compute="_compute_tax_fields",
2408
+ store=True,
2409
+ precompute=True,
2410
+ readonly=False,
2411
+ )
805
2412
 
806
2413
  # CSLL Fields
807
2414
  csll_tax_id = fields.Many2one(
808
2415
  comodel_name="l10n_br_fiscal.tax",
809
2416
  string="Tax CSLL",
810
2417
  domain=[("tax_domain", "=", TAX_DOMAIN_CSLL)],
2418
+ compute="_compute_tax_fields",
2419
+ store=True,
2420
+ precompute=True,
2421
+ readonly=False,
811
2422
  )
812
2423
 
813
- csll_base = fields.Monetary(string="CSLL Base")
2424
+ csll_base = fields.Monetary(
2425
+ string="CSLL Base",
2426
+ compute="_compute_tax_fields",
2427
+ store=True,
2428
+ precompute=True,
2429
+ readonly=False,
2430
+ )
814
2431
 
815
- csll_percent = fields.Float(string="CSLL %")
2432
+ csll_percent = fields.Float(
2433
+ string="CSLL %",
2434
+ compute="_compute_tax_fields",
2435
+ store=True,
2436
+ precompute=True,
2437
+ readonly=False,
2438
+ )
816
2439
 
817
- csll_reduction = fields.Float(string="CSLL % Reduction")
2440
+ csll_reduction = fields.Float(
2441
+ string="CSLL % Reduction",
2442
+ compute="_compute_tax_fields",
2443
+ store=True,
2444
+ precompute=True,
2445
+ readonly=False,
2446
+ )
818
2447
 
819
- csll_value = fields.Monetary(string="CSLL Value")
2448
+ csll_value = fields.Monetary(
2449
+ string="CSLL Value",
2450
+ compute="_compute_tax_fields",
2451
+ store=True,
2452
+ precompute=True,
2453
+ readonly=False,
2454
+ )
820
2455
 
821
2456
  csll_wh_tax_id = fields.Many2one(
822
2457
  comodel_name="l10n_br_fiscal.tax",
823
2458
  string="Tax CSLL RET",
824
2459
  domain=[("tax_domain", "=", TAX_DOMAIN_CSLL_WH)],
2460
+ compute="_compute_tax_fields",
2461
+ store=True,
2462
+ precompute=True,
2463
+ readonly=False,
825
2464
  )
826
2465
 
827
- csll_wh_base = fields.Monetary(string="CSLL RET Base")
2466
+ csll_wh_base = fields.Monetary(
2467
+ string="CSLL RET Base",
2468
+ compute="_compute_tax_fields",
2469
+ store=True,
2470
+ precompute=True,
2471
+ readonly=False,
2472
+ )
828
2473
 
829
- csll_wh_percent = fields.Float(string="CSLL RET %")
2474
+ csll_wh_percent = fields.Float(
2475
+ string="CSLL RET %",
2476
+ compute="_compute_tax_fields",
2477
+ store=True,
2478
+ precompute=True,
2479
+ readonly=False,
2480
+ )
830
2481
 
831
- csll_wh_reduction = fields.Float(string="CSLL RET % Reduction")
2482
+ csll_wh_reduction = fields.Float(
2483
+ string="CSLL RET % Reduction",
2484
+ compute="_compute_tax_fields",
2485
+ store=True,
2486
+ precompute=True,
2487
+ readonly=False,
2488
+ )
832
2489
 
833
- csll_wh_value = fields.Monetary(string="CSLL RET Value")
2490
+ csll_wh_value = fields.Monetary(
2491
+ string="CSLL RET Value",
2492
+ compute="_compute_tax_fields",
2493
+ store=True,
2494
+ precompute=True,
2495
+ readonly=False,
2496
+ )
834
2497
 
835
2498
  irpj_tax_id = fields.Many2one(
836
2499
  comodel_name="l10n_br_fiscal.tax",
837
2500
  string="Tax IRPJ",
838
2501
  domain=[("tax_domain", "=", TAX_DOMAIN_IRPJ)],
2502
+ compute="_compute_tax_fields",
2503
+ store=True,
2504
+ precompute=True,
2505
+ readonly=False,
839
2506
  )
840
2507
 
841
- irpj_base = fields.Monetary(string="IRPJ Base")
2508
+ irpj_base = fields.Monetary(
2509
+ string="IRPJ Base",
2510
+ compute="_compute_tax_fields",
2511
+ store=True,
2512
+ precompute=True,
2513
+ readonly=False,
2514
+ )
842
2515
 
843
- irpj_percent = fields.Float(string="IRPJ %")
2516
+ irpj_percent = fields.Float(
2517
+ string="IRPJ %",
2518
+ compute="_compute_tax_fields",
2519
+ store=True,
2520
+ precompute=True,
2521
+ readonly=False,
2522
+ )
844
2523
 
845
- irpj_reduction = fields.Float(string="IRPJ % Reduction")
2524
+ irpj_reduction = fields.Float(
2525
+ string="IRPJ % Reduction",
2526
+ compute="_compute_tax_fields",
2527
+ store=True,
2528
+ precompute=True,
2529
+ readonly=False,
2530
+ )
846
2531
 
847
- irpj_value = fields.Monetary(string="IRPJ Value")
2532
+ irpj_value = fields.Monetary(
2533
+ string="IRPJ Value",
2534
+ compute="_compute_tax_fields",
2535
+ store=True,
2536
+ precompute=True,
2537
+ readonly=False,
2538
+ )
848
2539
 
849
2540
  irpj_wh_tax_id = fields.Many2one(
850
2541
  comodel_name="l10n_br_fiscal.tax",
851
2542
  string="Tax IRPJ RET",
852
2543
  domain=[("tax_domain", "=", TAX_DOMAIN_IRPJ_WH)],
2544
+ compute="_compute_tax_fields",
2545
+ store=True,
2546
+ precompute=True,
2547
+ readonly=False,
853
2548
  )
854
2549
 
855
- irpj_wh_base = fields.Monetary(string="IRPJ RET Base")
2550
+ irpj_wh_base = fields.Monetary(
2551
+ string="IRPJ RET Base",
2552
+ compute="_compute_tax_fields",
2553
+ store=True,
2554
+ precompute=True,
2555
+ readonly=False,
2556
+ )
856
2557
 
857
- irpj_wh_percent = fields.Float(string="IRPJ RET %")
2558
+ irpj_wh_percent = fields.Float(
2559
+ string="IRPJ RET %",
2560
+ compute="_compute_tax_fields",
2561
+ store=True,
2562
+ precompute=True,
2563
+ readonly=False,
2564
+ )
858
2565
 
859
- irpj_wh_reduction = fields.Float(string="IRPJ RET % Reduction")
2566
+ irpj_wh_reduction = fields.Float(
2567
+ string="IRPJ RET % Reduction",
2568
+ compute="_compute_tax_fields",
2569
+ store=True,
2570
+ precompute=True,
2571
+ readonly=False,
2572
+ )
860
2573
 
861
- irpj_wh_value = fields.Monetary(string="IRPJ RET Value")
2574
+ irpj_wh_value = fields.Monetary(
2575
+ string="IRPJ RET Value",
2576
+ compute="_compute_tax_fields",
2577
+ store=True,
2578
+ precompute=True,
2579
+ readonly=False,
2580
+ )
862
2581
 
863
2582
  inss_tax_id = fields.Many2one(
864
2583
  comodel_name="l10n_br_fiscal.tax",
865
2584
  string="Tax INSS",
866
2585
  domain=[("tax_domain", "=", TAX_DOMAIN_INSS)],
2586
+ compute="_compute_tax_fields",
2587
+ store=True,
2588
+ precompute=True,
2589
+ readonly=False,
867
2590
  )
868
2591
 
869
- inss_base = fields.Monetary(string="INSS Base")
2592
+ inss_base = fields.Monetary(
2593
+ string="INSS Base",
2594
+ compute="_compute_tax_fields",
2595
+ store=True,
2596
+ precompute=True,
2597
+ readonly=False,
2598
+ )
870
2599
 
871
- inss_percent = fields.Float(string="INSS %")
2600
+ inss_percent = fields.Float(
2601
+ string="INSS %",
2602
+ compute="_compute_tax_fields",
2603
+ store=True,
2604
+ precompute=True,
2605
+ readonly=False,
2606
+ )
872
2607
 
873
- inss_reduction = fields.Float(string="INSS % Reduction")
2608
+ inss_reduction = fields.Float(
2609
+ string="INSS % Reduction",
2610
+ compute="_compute_tax_fields",
2611
+ store=True,
2612
+ precompute=True,
2613
+ readonly=False,
2614
+ )
874
2615
 
875
- inss_value = fields.Monetary(string="INSS Value")
2616
+ inss_value = fields.Monetary(
2617
+ string="INSS Value",
2618
+ compute="_compute_tax_fields",
2619
+ store=True,
2620
+ precompute=True,
2621
+ readonly=False,
2622
+ )
876
2623
 
877
2624
  inss_wh_tax_id = fields.Many2one(
878
2625
  comodel_name="l10n_br_fiscal.tax",
879
2626
  string="Tax INSS RET",
880
2627
  domain=[("tax_domain", "=", TAX_DOMAIN_INSS_WH)],
2628
+ compute="_compute_tax_fields",
2629
+ store=True,
2630
+ precompute=True,
2631
+ readonly=False,
881
2632
  )
882
2633
 
883
- inss_wh_base = fields.Monetary(string="INSS RET Base")
2634
+ inss_wh_base = fields.Monetary(
2635
+ string="INSS RET Base",
2636
+ compute="_compute_tax_fields",
2637
+ store=True,
2638
+ precompute=True,
2639
+ readonly=False,
2640
+ )
884
2641
 
885
- inss_wh_percent = fields.Float(string="INSS RET %")
2642
+ inss_wh_percent = fields.Float(
2643
+ string="INSS RET %",
2644
+ compute="_compute_tax_fields",
2645
+ store=True,
2646
+ precompute=True,
2647
+ readonly=False,
2648
+ )
886
2649
 
887
- inss_wh_reduction = fields.Float(string="INSS RET % Reduction")
2650
+ inss_wh_reduction = fields.Float(
2651
+ string="INSS RET % Reduction",
2652
+ compute="_compute_tax_fields",
2653
+ store=True,
2654
+ precompute=True,
2655
+ readonly=False,
2656
+ )
888
2657
 
889
- inss_wh_value = fields.Monetary(string="INSS RET Value")
2658
+ inss_wh_value = fields.Monetary(
2659
+ string="INSS RET Value",
2660
+ compute="_compute_tax_fields",
2661
+ store=True,
2662
+ precompute=True,
2663
+ readonly=False,
2664
+ )
890
2665
 
891
- simple_value = fields.Monetary(string="National Simple Taxes")
2666
+ simple_value = fields.Monetary(
2667
+ string="National Simple Taxes",
2668
+ compute="_compute_tax_fields",
2669
+ store=True,
2670
+ precompute=True,
2671
+ readonly=False,
2672
+ )
892
2673
 
893
2674
  simple_without_icms_value = fields.Monetary(
894
- string="National Simple Taxes without ICMS"
2675
+ string="National Simple Taxes without ICMS",
2676
+ compute="_compute_tax_fields",
2677
+ store=True,
2678
+ precompute=True,
2679
+ readonly=False,
895
2680
  )
896
2681
 
897
2682
  comment_ids = fields.Many2many(
898
2683
  comodel_name="l10n_br_fiscal.comment",
899
2684
  string="Comments",
900
2685
  domain=[("object", "=", FISCAL_COMMENT_LINE)],
2686
+ compute="_compute_comment_ids",
2687
+ store=True,
2688
+ precompute=True,
2689
+ readonly=False,
901
2690
  )
902
2691
 
903
- additional_data = fields.Text()
904
-
905
2692
  manual_additional_data = fields.Text(
906
2693
  help="Additional data manually entered by user"
907
2694
  )
908
2695
 
909
- estimate_tax = fields.Monetary()
2696
+ estimate_tax = fields.Monetary(
2697
+ compute="_compute_tax_fields",
2698
+ store=True,
2699
+ precompute=True,
2700
+ readonly=False,
2701
+ )
910
2702
 
911
2703
  cnae_id = fields.Many2one(
2704
+ related="city_taxation_code_id.cnae_id",
912
2705
  comodel_name="l10n_br_fiscal.cnae",
913
2706
  string="CNAE Code",
2707
+ store=True,
2708
+ precompute=True,
2709
+ readonly=False,
914
2710
  )
915
2711
 
916
2712
  @api.depends("company_id")