odoo-addon-l10n-br-fiscal 18.0.5.0.0.1__py3-none-any.whl → 18.0.7.1.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.

Potentially problematic release.


This version of odoo-addon-l10n-br-fiscal might be problematic. Click here for more details.

Files changed (54) hide show
  1. odoo/addons/l10n_br_fiscal/README.rst +1 -1
  2. odoo/addons/l10n_br_fiscal/__manifest__.py +6 -2
  3. odoo/addons/l10n_br_fiscal/constants/fiscal.py +18 -0
  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.operation.indicator.csv +27 -0
  7. odoo/addons/l10n_br_fiscal/data/l10n_br_fiscal.tax.classification.csv +163 -0
  8. odoo/addons/l10n_br_fiscal/data/l10n_br_fiscal.tax.csv +31 -0
  9. odoo/addons/l10n_br_fiscal/data/l10n_br_fiscal.tax.group.csv +3 -0
  10. odoo/addons/l10n_br_fiscal/i18n/l10n_br_fiscal.pot +523 -43
  11. odoo/addons/l10n_br_fiscal/i18n/pt_BR.po +523 -44
  12. odoo/addons/l10n_br_fiscal/models/__init__.py +2 -2
  13. odoo/addons/l10n_br_fiscal/models/data_abstract.py +9 -6
  14. odoo/addons/l10n_br_fiscal/models/document_line_mixin.py +993 -8
  15. odoo/addons/l10n_br_fiscal/models/document_mixin.py +236 -1
  16. odoo/addons/l10n_br_fiscal/models/operation_indicator.py +58 -0
  17. odoo/addons/l10n_br_fiscal/models/operation_line.py +28 -0
  18. odoo/addons/l10n_br_fiscal/models/product_template.py +4 -0
  19. odoo/addons/l10n_br_fiscal/models/res_company.py +17 -0
  20. odoo/addons/l10n_br_fiscal/models/res_partner.py +10 -0
  21. odoo/addons/l10n_br_fiscal/models/simplified_tax_range.py +8 -0
  22. odoo/addons/l10n_br_fiscal/models/tax_classification.py +81 -0
  23. odoo/addons/l10n_br_fiscal/security/ir.model.access.csv +7 -1
  24. odoo/addons/l10n_br_fiscal/static/description/index.html +1 -1
  25. odoo/addons/l10n_br_fiscal/tests/__init__.py +1 -0
  26. odoo/addons/l10n_br_fiscal/tests/test_tax_classification.py +110 -0
  27. odoo/addons/l10n_br_fiscal/views/document_line_mixin_view.xml +106 -4
  28. odoo/addons/l10n_br_fiscal/views/document_line_view.xml +4 -0
  29. odoo/addons/l10n_br_fiscal/views/document_view.xml +14 -0
  30. odoo/addons/l10n_br_fiscal/views/icms_regulation_view.xml +1 -5
  31. odoo/addons/l10n_br_fiscal/views/l10n_br_fiscal_action.xml +30 -0
  32. odoo/addons/l10n_br_fiscal/views/l10n_br_fiscal_menu.xml +16 -0
  33. odoo/addons/l10n_br_fiscal/views/nbs_view.xml +1 -5
  34. odoo/addons/l10n_br_fiscal/views/ncm_view.xml +1 -5
  35. odoo/addons/l10n_br_fiscal/views/operation_indicator_view.xml +75 -0
  36. odoo/addons/l10n_br_fiscal/views/operation_line_view.xml +4 -5
  37. odoo/addons/l10n_br_fiscal/views/operation_view.xml +1 -5
  38. odoo/addons/l10n_br_fiscal/views/product_template_view.xml +5 -0
  39. odoo/addons/l10n_br_fiscal/views/res_company_view.xml +6 -0
  40. odoo/addons/l10n_br_fiscal/views/res_partner_view.xml +4 -0
  41. odoo/addons/l10n_br_fiscal/views/service_type_view.xml +1 -5
  42. odoo/addons/l10n_br_fiscal/views/tax_classification.xml +108 -0
  43. odoo/addons/l10n_br_fiscal/views/tax_definition_view.xml +1 -5
  44. odoo/addons/l10n_br_fiscal/views/tax_view.xml +2 -2
  45. odoo/addons/l10n_br_fiscal/wizards/__init__.py +1 -1
  46. odoo/addons/l10n_br_fiscal/wizards/document_import_wizard.py +234 -0
  47. odoo/addons/l10n_br_fiscal/wizards/{document_import_wizard_mixin.xml → document_import_wizard.xml} +26 -7
  48. {odoo_addon_l10n_br_fiscal-18.0.5.0.0.1.dist-info → odoo_addon_l10n_br_fiscal-18.0.7.1.0.dist-info}/METADATA +2 -2
  49. {odoo_addon_l10n_br_fiscal-18.0.5.0.0.1.dist-info → odoo_addon_l10n_br_fiscal-18.0.7.1.0.dist-info}/RECORD +51 -46
  50. odoo/addons/l10n_br_fiscal/models/document_line_mixin_methods.py +0 -818
  51. odoo/addons/l10n_br_fiscal/models/document_mixin_methods.py +0 -247
  52. odoo/addons/l10n_br_fiscal/wizards/document_import_wizard_mixin.py +0 -129
  53. {odoo_addon_l10n_br_fiscal-18.0.5.0.0.1.dist-info → odoo_addon_l10n_br_fiscal-18.0.7.1.0.dist-info}/WHEEL +0 -0
  54. {odoo_addon_l10n_br_fiscal-18.0.5.0.0.1.dist-info → odoo_addon_l10n_br_fiscal-18.0.7.1.0.dist-info}/top_level.txt +0 -0
@@ -1,818 +0,0 @@
1
- # Copyright (C) 2019 Renato Lima - Akretion <renato.lima@akretion.com.br>
2
- # License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html
3
-
4
- from copy import deepcopy
5
-
6
- from lxml import etree
7
- from lxml.builder import E
8
-
9
- from odoo import Command, api, models
10
-
11
- from ..constants.fiscal import (
12
- CFOP_DESTINATION_EXPORT,
13
- FISCAL_IN,
14
- FISCAL_TAX_ID_FIELDS,
15
- TAX_BASE_TYPE_PERCENT,
16
- TAX_DOMAIN_ICMS,
17
- )
18
- from ..constants.icms import (
19
- ICMS_BASE_TYPE_DEFAULT,
20
- ICMS_ORIGIN_DEFAULT,
21
- ICMS_ST_BASE_TYPE_DEFAULT,
22
- )
23
-
24
-
25
- class FiscalDocumentLineMixinMethods(models.AbstractModel):
26
- """
27
- Provides the method implementations for l10n_br_fiscal.document.line.mixin.
28
-
29
- These methods are extracted into this separate mixin due to the way
30
- l10n_br_fiscal.document.line is incorporated into account.move.line
31
- by the l10n_br_account module (decorator pattern).
32
-
33
- Specifically:
34
- - In l10n_br_account, fields from l10n_br_fiscal.document.line
35
- are added to account.move.line using Odoo's `_inherits` (composition)
36
- mechanism.
37
- - The methods in *this* mixin, however, are intended to be inherited
38
- using the standard `_inherit` mechanism.
39
-
40
- This separation is crucial because `_inherits` handles field composition
41
- but does not inherit methods. Thus, `_inherit` is used to bring in
42
- these methods. If these methods were defined in the same class as the
43
- fields of l10n_br_fiscal.document.line.mixin (which are subject to
44
- `_inherits`), and account.move.line also used `_inherit` on that
45
- single class, the fields would be duplicated.
46
- """
47
-
48
- _name = "l10n_br_fiscal.document.line.mixin.methods"
49
- _description = "Fiscal Document Mixin Methods"
50
-
51
- @api.model
52
- def inject_fiscal_fields(
53
- self,
54
- doc,
55
- view_ref="l10n_br_fiscal.document_fiscal_line_mixin_form",
56
- xpath_mappings=None,
57
- ):
58
- """
59
- Inject common fiscal fields into view placeholder elements.
60
- Used for invoice line, sale order line, purchase order line...
61
- """
62
-
63
- # the list of computed fields we will add to the view when missing
64
- missing_line_fields = set(
65
- [
66
- fname
67
- for fname, _field in filter(
68
- lambda item: item[1].compute
69
- in (
70
- "_compute_tax_fields",
71
- "_compute_fiscal_tax_ids",
72
- "_compute_product_fiscal_fields",
73
- ),
74
- self.env["l10n_br_fiscal.document.line.mixin"]._fields.items(),
75
- )
76
- ]
77
- )
78
-
79
- fiscal_view = self.env.ref(
80
- "l10n_br_fiscal.document_fiscal_line_mixin_form"
81
- ).sudo()
82
- fsc_doc = etree.fromstring(
83
- fiscal_view.with_context(inherit_branding=True).get_combined_arch()
84
- )
85
-
86
- if xpath_mappings is None:
87
- xpath_mappings = (
88
- # (placeholder_xpath, fiscal_xpath)
89
- (".//group[@name='fiscal_fields']", "//group[@name='fiscal_fields']"),
90
- (".//page[@name='fiscal_taxes']", "//page[@name='fiscal_taxes']"),
91
- (
92
- ".//page[@name='fiscal_line_extra_info']",
93
- "//page[@name='fiscal_line_extra_info']",
94
- ),
95
- # these will only collect (invisible) fields for onchanges:
96
- (
97
- ".//control[@name='fiscal_fields']...",
98
- "//group[@name='fiscal_fields']//field",
99
- ),
100
- (
101
- ".//control[@name='fiscal_taxes_fields']...",
102
- "//page[@name='fiscal_taxes']//field",
103
- ),
104
- (
105
- ".//control[@name='fiscal_line_extra_info_fields']...",
106
- "//page[@name='fiscal_line_extra_info']//field",
107
- ),
108
- )
109
- for placeholder_xpath, fiscal_xpath in xpath_mappings:
110
- placeholder_nodes = doc.findall(placeholder_xpath)
111
- if not placeholder_nodes:
112
- continue
113
- fiscal_nodes = fsc_doc.xpath(fiscal_xpath)
114
- for target_node in placeholder_nodes:
115
- if len(fiscal_nodes) == 1:
116
- # replace unique placeholder
117
- # (deepcopy is required to inject fiscal nodes in possible
118
- # next places)
119
- replace_node = deepcopy(fiscal_nodes[0])
120
- target_node.getparent().replace(target_node, replace_node)
121
- else:
122
- # append multiple fields to placeholder container
123
- existing_fields = [
124
- e.attrib["name"] for e in target_node if e.tag == "field"
125
- ]
126
- for fiscal_node in fiscal_nodes:
127
- if fiscal_node.attrib["name"] in missing_line_fields:
128
- missing_line_fields.remove(fiscal_node.attrib["name"])
129
- if fiscal_node.attrib["name"] in existing_fields:
130
- continue
131
- field = deepcopy(fiscal_node)
132
- if not field.attrib.get("optional"):
133
- field.attrib["optional"] = "hide"
134
- target_node.append(field)
135
- for fname in missing_line_fields:
136
- if fname not in existing_fields:
137
- target_node.append(
138
- E.field(name=fname, string=fname, optional="hide")
139
- )
140
- return doc
141
-
142
- @api.model
143
- def _get_view(self, view_id=None, view_type="form", **options):
144
- arch, view = super()._get_view(view_id, view_type, **options)
145
- if view_type == "form":
146
- arch = self.inject_fiscal_fields(arch)
147
- return arch, view
148
-
149
- @api.depends(
150
- "discount_value",
151
- "amount_tax_not_included",
152
- "amount_tax_withholding",
153
- "price_unit",
154
- "quantity",
155
- "fiscal_operation_line_id",
156
- "cfop_id",
157
- "icms_relief_value",
158
- "insurance_value",
159
- "other_value",
160
- "freight_value",
161
- "pis_value",
162
- "cofins_value",
163
- "icms_value",
164
- "ii_value",
165
- "ii_customhouse_charges",
166
- )
167
- def _compute_fiscal_amounts(self):
168
- for record in self:
169
- round_curr = record.currency_id or self.env.ref("base.BRL")
170
-
171
- # Total value of products or services
172
- record.price_gross = round_curr.round(record.price_unit * record.quantity)
173
- record.amount_fiscal = record.price_gross - record.discount_value
174
- record.fiscal_amount_tax = record.amount_tax_not_included
175
-
176
- add_to_amount = sum(record[a] for a in record._add_fields_to_amount())
177
- rm_to_amount = sum(record[r] for r in record._rm_fields_to_amount())
178
- record.fiscal_amount_untaxed = (
179
- record.price_gross
180
- - record.discount_value
181
- + add_to_amount
182
- - rm_to_amount
183
- )
184
-
185
- # Valor do documento (NF)
186
- record.fiscal_amount_total = (
187
- record.fiscal_amount_untaxed + record.fiscal_amount_tax
188
- )
189
-
190
- # Valor Liquido (TOTAL + IMPOSTOS - RETENÇÕES)
191
- record.amount_taxed = (
192
- record.fiscal_amount_total - record.amount_tax_withholding
193
- )
194
-
195
- # Valor do documento (NF) - RETENÇÕES
196
- record.fiscal_amount_total = record.amount_taxed
197
-
198
- # Valor financeiro
199
- if (
200
- record.fiscal_operation_line_id
201
- and record.fiscal_operation_line_id.add_to_amount
202
- and (not record.cfop_id or record.cfop_id.finance_move)
203
- ):
204
- record.financial_total = record.amount_taxed
205
- record.financial_total_gross = (
206
- record.financial_total + record.discount_value
207
- )
208
- record.financial_discount_value = record.discount_value
209
- else:
210
- record.financial_total_gross = record.financial_total = 0.0
211
- record.financial_discount_value = 0.0
212
-
213
- @api.depends("tax_icms_or_issqn", "partner_id")
214
- def _compute_allow_csll_irpj(self):
215
- """Calculates the possibility of 'CSLL' and 'IRPJ' tax charges."""
216
- for line in self:
217
- # Determine if 'CSLL' and 'IRPJ' taxes may apply:
218
- # 1. When providing services (tax_icms_or_issqn == "issqn")
219
- # 2. When supplying products to public entities (partner_is_public_entity
220
- # is True)
221
- if line.tax_icms_or_issqn == "issqn" or line.partner_is_public_entity:
222
- line.allow_csll_irpj = True # Tax charges may apply
223
- else:
224
- line.allow_csll_irpj = False # No tax charges expected
225
-
226
- def _prepare_br_fiscal_dict(self, default=False):
227
- self.ensure_one()
228
- fields = self.env["l10n_br_fiscal.document.line.mixin"]._fields.keys()
229
-
230
- # we now read the record fiscal fields except the m2m tax:
231
- vals = self._convert_to_write(self.read(fields)[0])
232
-
233
- # remove id field to avoid conflicts
234
- vals.pop("id", None)
235
-
236
- if default: # in case you want to use new rather than write later
237
- return {f"default_{k}": vals[k] for k in vals.keys()}
238
- return vals
239
-
240
- @api.depends("fiscal_operation_id", "partner_id", "product_id")
241
- def _compute_fiscal_operation_line_id(self):
242
- for line in self:
243
- if line.fiscal_operation_id:
244
- line.fiscal_operation_line_id = (
245
- line.fiscal_operation_id.line_definition(
246
- company=line.company_id,
247
- partner=line.partner_id,
248
- product=line.product_id,
249
- )
250
- )
251
-
252
- @api.depends(
253
- "partner_id",
254
- "fiscal_operation_line_id",
255
- "product_id",
256
- "ncm_id",
257
- "nbs_id",
258
- "nbm_id",
259
- "cest_id",
260
- "city_taxation_code_id",
261
- "service_type_id",
262
- "ind_final",
263
- )
264
- def _compute_fiscal_tax_ids(self):
265
- for line in self:
266
- if line.fiscal_operation_line_id:
267
- mapping_result = line.fiscal_operation_line_id.map_fiscal_taxes(
268
- company=line.company_id,
269
- partner=line._get_fiscal_partner(),
270
- product=line.product_id,
271
- ncm=line.ncm_id,
272
- nbm=line.nbm_id,
273
- nbs=line.nbs_id,
274
- cest=line.cest_id,
275
- city_taxation_code=line.city_taxation_code_id,
276
- service_type=line.service_type_id,
277
- ind_final=line.ind_final,
278
- )
279
- line.cfop_id = mapping_result["cfop"]
280
- line.ipi_guideline_id = mapping_result["ipi_guideline"]
281
- line.icms_tax_benefit_id = mapping_result["icms_tax_benefit_id"]
282
-
283
- if line._is_imported():
284
- continue
285
-
286
- taxes = line.env["l10n_br_fiscal.tax"]
287
- for tax in mapping_result["taxes"].values():
288
- taxes |= tax
289
- line.fiscal_tax_ids = taxes
290
-
291
- @api.depends("fiscal_operation_line_id")
292
- def _compute_comment_ids(self):
293
- for line in self:
294
- line.comment_ids = [
295
- Command.set(line.fiscal_operation_line_id.comment_ids.ids)
296
- ]
297
-
298
- @api.model
299
- def _build_null_mask_dict(self) -> dict:
300
- """
301
- Build a null values mask dict to reset all fiscal fields.
302
- """
303
- mask_dict = {
304
- f[0]: False
305
- for f in filter(
306
- lambda f: f[1].compute == "_compute_tax_fields",
307
- self.env["l10n_br_fiscal.document.line.mixin"]._fields.items(),
308
- )
309
- }
310
- for fiscal_tax_field in FISCAL_TAX_ID_FIELDS:
311
- mask_dict[fiscal_tax_field] = False
312
- return mask_dict
313
-
314
- def write(self, vals):
315
- res = super().write(vals)
316
-
317
- # Verifica se algum campo de imposto relevante foi alterado no 'write'
318
- tax_fields_in_vals = [fld for fld in vals if fld in FISCAL_TAX_ID_FIELDS]
319
-
320
- if tax_fields_in_vals:
321
- # Por segurança, sempre recalcula se um campo relevante mudou.
322
- self._update_fiscal_tax_ids()
323
-
324
- return res
325
-
326
- def _update_fiscal_tax_ids(self):
327
- taxes = self.env["l10n_br_fiscal.tax"]
328
- for fiscal_tax_field in FISCAL_TAX_ID_FIELDS:
329
- taxes |= self[fiscal_tax_field]
330
-
331
- for line in self:
332
- taxes_groups = line.fiscal_tax_ids.mapped("tax_domain")
333
- fiscal_taxes = line.fiscal_tax_ids.filtered(
334
- lambda ft, taxes_groups=taxes_groups: ft.tax_domain not in taxes_groups
335
- )
336
- line.fiscal_tax_ids = fiscal_taxes + taxes
337
-
338
- @api.onchange(*FISCAL_TAX_ID_FIELDS)
339
- def _onchange_fiscal_taxes(self):
340
- self._update_fiscal_tax_ids()
341
-
342
- @api.depends(
343
- "partner_id",
344
- "fiscal_tax_ids",
345
- "product_id",
346
- "price_unit",
347
- "quantity",
348
- "uom_id",
349
- "fiscal_price",
350
- "fiscal_quantity",
351
- "uot_id",
352
- "discount_value",
353
- "insurance_value",
354
- "ii_customhouse_charges",
355
- "ii_iof_value",
356
- "other_value",
357
- "freight_value",
358
- "ncm_id",
359
- "nbs_id",
360
- "nbm_id",
361
- "cest_id",
362
- "fiscal_operation_line_id",
363
- "cfop_id",
364
- "icmssn_range_id",
365
- "icms_origin",
366
- "icms_cst_id",
367
- "ind_final",
368
- "icms_relief_id",
369
- )
370
- def _compute_tax_fields(self):
371
- """
372
- Compute base, percent, value... tax fields for ICMS, IPI, PIS, COFINS... taxes.
373
- """
374
- null_mask = None
375
- for line in self.filtered(lambda line: not line._is_imported()):
376
- if null_mask is None:
377
- null_mask = self._build_null_mask_dict()
378
- to_update = null_mask.copy()
379
- # prepare with default values
380
- to_update.update(
381
- {
382
- "icms_base_type": ICMS_BASE_TYPE_DEFAULT,
383
- "icmsst_base_type": ICMS_ST_BASE_TYPE_DEFAULT,
384
- "ipi_base_type": TAX_BASE_TYPE_PERCENT,
385
- "cofins_base_type": TAX_BASE_TYPE_PERCENT,
386
- "cofinsst_base_type": TAX_BASE_TYPE_PERCENT,
387
- "cofins_wh_base_type": TAX_BASE_TYPE_PERCENT,
388
- "pis_base_type": TAX_BASE_TYPE_PERCENT,
389
- "pisst_base_type": TAX_BASE_TYPE_PERCENT,
390
- "pis_wh_base_type": TAX_BASE_TYPE_PERCENT,
391
- }
392
- )
393
- if line.fiscal_operation_line_id:
394
- compute_result = line.fiscal_tax_ids.compute_taxes(
395
- company=line.company_id,
396
- partner=line._get_fiscal_partner(),
397
- product=line.product_id,
398
- price_unit=line.price_unit,
399
- quantity=line.quantity,
400
- uom_id=line.uom_id,
401
- fiscal_price=line.fiscal_price,
402
- fiscal_quantity=line.fiscal_quantity,
403
- uot_id=line.uot_id,
404
- discount_value=line.discount_value,
405
- insurance_value=line.insurance_value,
406
- ii_customhouse_charges=line.ii_customhouse_charges,
407
- ii_iof_value=line.ii_iof_value,
408
- other_value=line.other_value,
409
- freight_value=line.freight_value,
410
- ncm=line.ncm_id,
411
- nbs=line.nbs_id,
412
- nbm=line.nbm_id,
413
- cest=line.cest_id,
414
- operation_line=line.fiscal_operation_line_id,
415
- cfop=line.cfop_id,
416
- icmssn_range=line.icmssn_range_id,
417
- icms_origin=line.icms_origin,
418
- icms_cst_id=line.icms_cst_id,
419
- ind_final=line.ind_final,
420
- icms_relief_id=line.icms_relief_id,
421
- )
422
- to_update.update(line._prepare_tax_fields(compute_result))
423
- else:
424
- compute_result = {}
425
- to_update.update(
426
- {
427
- "amount_tax_included": compute_result.get("amount_included", 0.0),
428
- "amount_tax_not_included": compute_result.get(
429
- "amount_not_included", 0.0
430
- ),
431
- "amount_tax_withholding": compute_result.get(
432
- "amount_withholding", 0.0
433
- ),
434
- "estimate_tax": compute_result.get("estimate_tax", 0.0),
435
- }
436
- )
437
- in_draft_mode = line != line._origin
438
- if in_draft_mode:
439
- line.update(to_update)
440
- else:
441
- line.write(to_update)
442
-
443
- def _prepare_tax_fields(self, compute_result):
444
- self.ensure_one()
445
- tax_values = {}
446
- if self._is_imported():
447
- return tax_values
448
- computed_taxes = compute_result.get("taxes", {})
449
- for tax in self.fiscal_tax_ids:
450
- computed_tax = computed_taxes.get(tax.tax_domain, {})
451
- tax_field_name = f"{tax.tax_domain}_tax_id"
452
- if hasattr(self, tax_field_name):
453
- tax_values[tax_field_name] = tax.ids[0]
454
- method = getattr(self, f"_prepare_fields_{tax.tax_domain}", None)
455
- if method and computed_tax:
456
- prepared_fields = method(computed_tax)
457
- if prepared_fields:
458
- tax_values.update(prepared_fields)
459
- return tax_values
460
-
461
- @api.depends(
462
- "product_id",
463
- "fiscal_operation_id",
464
- )
465
- def _compute_price_unit_fiscal(self): # OK when edited from aml?? c-> check
466
- for line in self:
467
- line.price_unit = {
468
- "sale_price": line.product_id.list_price,
469
- "cost_price": line.product_id.standard_price,
470
- }.get(line.fiscal_operation_id.default_price_unit, 0)
471
-
472
- def _get_document(self):
473
- self.ensure_one()
474
- return self.document_id
475
-
476
- def _get_fiscal_partner(self):
477
- """
478
- Meant to be overriden when the l10n_br_fiscal.document partner_id should not
479
- be the same as the sale.order, purchase.order, account.move (...) partner_id.
480
-
481
- (In the case of invoicing, the invoicing partner set by the user should
482
- get priority over any invoicing contact returned by address_get.)
483
- """
484
- self.ensure_one()
485
- return self.partner_id
486
-
487
- @api.depends("product_id")
488
- def _compute_product_fiscal_fields(self):
489
- for line in self:
490
- if not line.product_id:
491
- # reset to default values:
492
- line.fiscal_type = False
493
- line.ncm_id = False
494
- line.nbm_id = False
495
- line.tax_icms_or_issqn = TAX_DOMAIN_ICMS
496
- line.icms_origin = ICMS_ORIGIN_DEFAULT
497
- line.cest_id = False
498
- line.nbs_id = False
499
- line.fiscal_genre_id = False
500
- line.service_type_id = False
501
- continue
502
- p = line.product_id
503
- line.fiscal_type = p.fiscal_type
504
- line.ncm_id = p.ncm_id
505
- line.nbm_id = p.nbm_id
506
- line.tax_icms_or_issqn = p.tax_icms_or_issqn
507
- line.icms_origin = p.icms_origin
508
- line.cest_id = p.cest_id
509
- line.nbs_id = p.nbs_id
510
- line.fiscal_genre_id = p.fiscal_genre_id
511
- line.service_type_id = p.service_type_id
512
-
513
- @api.depends("product_id")
514
- def _compute_city_taxation_code_id(self):
515
- for line in self:
516
- if not line.product_id:
517
- line.city_taxation_code_id = False
518
- continue
519
- company_city = line.company_id.city_id
520
- city_tax_codes = line.product_id.city_taxation_code_ids
521
- city_tax_code = city_tax_codes.filtered(
522
- lambda r, _city_id=company_city: r.city_id == _city_id
523
- )
524
- if city_tax_code:
525
- line.city_taxation_code_id = city_tax_code
526
- else:
527
- line.city_taxation_code_id = False
528
-
529
- def _prepare_fields_issqn(self, tax_dict):
530
- self.ensure_one()
531
- return {
532
- "issqn_base": tax_dict.get("base"),
533
- "issqn_percent": tax_dict.get("percent_amount"),
534
- "issqn_reduction": tax_dict.get("percent_reduction"),
535
- "issqn_value": tax_dict.get("tax_value"),
536
- }
537
-
538
- def _prepare_fields_issqn_wh(self, tax_dict):
539
- self.ensure_one()
540
- return {
541
- "issqn_wh_base": tax_dict.get("base"),
542
- "issqn_wh_percent": tax_dict.get("percent_amount"),
543
- "issqn_wh_reduction": tax_dict.get("percent_reduction"),
544
- "issqn_wh_value": tax_dict.get("tax_value"),
545
- }
546
-
547
- def _prepare_fields_csll(self, tax_dict):
548
- self.ensure_one()
549
- return {
550
- "csll_base": tax_dict.get("base"),
551
- "csll_percent": tax_dict.get("percent_amount"),
552
- "csll_reduction": tax_dict.get("percent_reduction"),
553
- "csll_value": tax_dict.get("tax_value"),
554
- }
555
-
556
- def _prepare_fields_csll_wh(self, tax_dict):
557
- self.ensure_one()
558
- return {
559
- "csll_wh_base": tax_dict.get("base"),
560
- "csll_wh_percent": tax_dict.get("percent_amount"),
561
- "csll_wh_reduction": tax_dict.get("percent_reduction"),
562
- "csll_wh_value": tax_dict.get("tax_value"),
563
- }
564
-
565
- def _prepare_fields_irpj(self, tax_dict):
566
- self.ensure_one()
567
- return {
568
- "irpj_base": tax_dict.get("base"),
569
- "irpj_percent": tax_dict.get("percent_amount"),
570
- "irpj_reduction": tax_dict.get("percent_reduction"),
571
- "irpj_value": tax_dict.get("tax_value"),
572
- }
573
-
574
- def _prepare_fields_irpj_wh(self, tax_dict):
575
- self.ensure_one()
576
- return {
577
- "irpj_wh_base": tax_dict.get("base"),
578
- "irpj_wh_percent": tax_dict.get("percent_amount"),
579
- "irpj_wh_reduction": tax_dict.get("percent_reduction"),
580
- "irpj_wh_value": tax_dict.get("tax_value"),
581
- }
582
-
583
- def _prepare_fields_inss(self, tax_dict):
584
- self.ensure_one()
585
- return {
586
- "inss_base": tax_dict.get("base"),
587
- "inss_percent": tax_dict.get("percent_amount"),
588
- "inss_reduction": tax_dict.get("percent_reduction"),
589
- "inss_value": tax_dict.get("tax_value"),
590
- }
591
-
592
- def _prepare_fields_inss_wh(self, tax_dict):
593
- self.ensure_one()
594
- return {
595
- "inss_wh_base": tax_dict.get("base"),
596
- "inss_wh_percent": tax_dict.get("percent_amount"),
597
- "inss_wh_reduction": tax_dict.get("percent_reduction"),
598
- "inss_wh_value": tax_dict.get("tax_value"),
599
- }
600
-
601
- def _prepare_fields_icms(self, tax_dict):
602
- self.ensure_one()
603
- cst_id = tax_dict.get("cst_id").id if tax_dict.get("cst_id") else False
604
- return {
605
- "icms_cst_id": cst_id,
606
- "icms_base_type": tax_dict.get("icms_base_type", ICMS_BASE_TYPE_DEFAULT),
607
- "icms_base": tax_dict.get("base", 0.0),
608
- "icms_percent": tax_dict.get("percent_amount", 0.0),
609
- "icms_reduction": tax_dict.get("percent_reduction", 0.0),
610
- "icms_value": tax_dict.get("tax_value", 0.0),
611
- "icms_origin_percent": tax_dict.get("icms_origin_perc", 0.0),
612
- "icms_destination_percent": tax_dict.get("icms_dest_perc", 0.0),
613
- "icms_sharing_percent": tax_dict.get("icms_sharing_percent", 0.0),
614
- "icms_destination_base": tax_dict.get("icms_dest_base", 0.0),
615
- "icms_origin_value": tax_dict.get("icms_origin_value", 0.0),
616
- "icms_destination_value": tax_dict.get("icms_dest_value", 0.0),
617
- "icms_relief_value": tax_dict.get("icms_relief", 0.0),
618
- }
619
-
620
- @api.onchange(
621
- "icms_base",
622
- "icms_percent",
623
- "icms_reduction",
624
- "icms_value",
625
- "icms_destination_base",
626
- "icms_origin_percent",
627
- "icms_destination_percent",
628
- "icms_sharing_percent",
629
- "icms_origin_value",
630
- "icms_tax_benefit_id",
631
- )
632
- def _onchange_icms_fields(self):
633
- if self.icms_tax_benefit_id:
634
- self.icms_tax_id = self.icms_tax_benefit_id.tax_id
635
-
636
- def _prepare_fields_icmssn(self, tax_dict):
637
- self.ensure_one()
638
- cst_id = tax_dict.get("cst_id").id if tax_dict.get("cst_id") else False
639
- icmssn_base = tax_dict.get("base", 0.0)
640
- icmssn_credit_value = tax_dict.get("tax_value", 0.0)
641
- simple_value = icmssn_base * self.icmssn_range_id.total_tax_percent
642
- simple_without_icms_value = simple_value - icmssn_credit_value
643
- return {
644
- "icms_cst_id": cst_id,
645
- "icmssn_base": icmssn_base,
646
- "icmssn_percent": tax_dict.get("percent_amount"),
647
- "icmssn_reduction": tax_dict.get("percent_reduction"),
648
- "icmssn_credit_value": icmssn_credit_value,
649
- "simple_value": simple_value,
650
- "simple_without_icms_value": simple_without_icms_value,
651
- }
652
-
653
- def _prepare_fields_icmsst(self, tax_dict):
654
- self.ensure_one()
655
- return {
656
- "icmsst_base_type": tax_dict.get(
657
- "icmsst_base_type", ICMS_ST_BASE_TYPE_DEFAULT
658
- ),
659
- "icmsst_mva_percent": tax_dict.get("icmsst_mva_percent"),
660
- "icmsst_percent": tax_dict.get("percent_amount"),
661
- "icmsst_reduction": tax_dict.get("percent_reduction"),
662
- "icmsst_base": tax_dict.get("base"),
663
- "icmsst_value": tax_dict.get("tax_value"),
664
- }
665
-
666
- def _prepare_fields_icmsfcp(self, tax_dict):
667
- self.ensure_one()
668
- return {
669
- "icmsfcp_base": tax_dict.get("base", 0.0),
670
- "icmsfcp_percent": tax_dict.get("percent_amount", 0.0),
671
- "icmsfcp_value": tax_dict.get("tax_value", 0.0),
672
- }
673
-
674
- def _prepare_fields_icmsfcpst(self, tax_dict):
675
- self.ensure_one()
676
- return {
677
- "icmsfcpst_base": self.icmsst_base,
678
- "icmsfcpst_percent": tax_dict.get("percent_amount", 0.0),
679
- "icmsfcpst_value": tax_dict.get("tax_value", 0.0),
680
- }
681
-
682
- def _prepare_fields_ipi(self, tax_dict):
683
- self.ensure_one()
684
- cst_id = tax_dict.get("cst_id").id if tax_dict.get("cst_id") else False
685
- return {
686
- "ipi_cst_id": cst_id,
687
- "ipi_base_type": tax_dict.get("base_type", False),
688
- "ipi_base": tax_dict.get("base", 0.00),
689
- "ipi_percent": tax_dict.get("percent_amount", 0.00),
690
- "ipi_reduction": tax_dict.get("percent_reduction", 0.00),
691
- "ipi_value": tax_dict.get("tax_value", 0.00),
692
- }
693
-
694
- def _prepare_fields_ii(self, tax_dict):
695
- self.ensure_one()
696
- return {
697
- "ii_base": tax_dict.get("base", 0.00),
698
- "ii_percent": tax_dict.get("percent_amount", 0.00),
699
- "ii_value": tax_dict.get("tax_value", 0.00),
700
- }
701
-
702
- def _prepare_fields_pis(self, tax_dict):
703
- self.ensure_one()
704
- cst_id = tax_dict.get("cst_id").id if tax_dict.get("cst_id") else False
705
- return {
706
- "pis_cst_id": cst_id,
707
- "pis_base_type": tax_dict.get("base_type"),
708
- "pis_base": tax_dict.get("base", 0.00),
709
- "pis_percent": tax_dict.get("percent_amount", 0.00),
710
- "pis_reduction": tax_dict.get("percent_reduction", 0.00),
711
- "pis_value": tax_dict.get("tax_value", 0.00),
712
- }
713
-
714
- def _prepare_fields_pis_wh(self, tax_dict):
715
- self.ensure_one()
716
- return {
717
- "pis_wh_base_type": tax_dict.get("base_type"),
718
- "pis_wh_base": tax_dict.get("base", 0.00),
719
- "pis_wh_percent": tax_dict.get("percent_amount", 0.00),
720
- "pis_wh_reduction": tax_dict.get("percent_reduction", 0.00),
721
- "pis_wh_value": tax_dict.get("tax_value", 0.00),
722
- }
723
-
724
- def _prepare_fields_pisst(self, tax_dict):
725
- self.ensure_one()
726
- cst_id = tax_dict.get("cst_id").id if tax_dict.get("cst_id") else False
727
- return {
728
- "pisst_cst_id": cst_id,
729
- "pisst_base_type": tax_dict.get("base_type"),
730
- "pisst_base": tax_dict.get("base", 0.00),
731
- "pisst_percent": tax_dict.get("percent_amount", 0.00),
732
- "pisst_reduction": tax_dict.get("percent_reduction", 0.00),
733
- "pisst_value": tax_dict.get("tax_value", 0.00),
734
- }
735
-
736
- def _prepare_fields_cofins(self, tax_dict):
737
- self.ensure_one()
738
- cst_id = tax_dict.get("cst_id").id if tax_dict.get("cst_id") else False
739
- return {
740
- "cofins_cst_id": cst_id,
741
- "cofins_base_type": tax_dict.get("base_type"),
742
- "cofins_base": tax_dict.get("base", 0.00),
743
- "cofins_percent": tax_dict.get("percent_amount", 0.00),
744
- "cofins_reduction": tax_dict.get("percent_reduction", 0.00),
745
- "cofins_value": tax_dict.get("tax_value", 0.00),
746
- }
747
-
748
- def _prepare_fields_cofins_wh(self, tax_dict):
749
- self.ensure_one()
750
- return {
751
- "cofins_wh_base_type": tax_dict.get("base_type"),
752
- "cofins_wh_base": tax_dict.get("base", 0.00),
753
- "cofins_wh_percent": tax_dict.get("percent_amount", 0.00),
754
- "cofins_wh_reduction": tax_dict.get("percent_reduction", 0.00),
755
- "cofins_wh_value": tax_dict.get("tax_value", 0.00),
756
- }
757
-
758
- def _prepare_fields_cofinsst(self, tax_dict):
759
- self.ensure_one()
760
- cst_id = tax_dict.get("cst_id").id if tax_dict.get("cst_id") else False
761
- return {
762
- "cofinsst_cst_id": cst_id,
763
- "cofinsst_base_type": tax_dict.get("base_type"),
764
- "cofinsst_base": tax_dict.get("base", 0.00),
765
- "cofinsst_percent": tax_dict.get("percent_amount", 0.00),
766
- "cofinsst_reduction": tax_dict.get("percent_reduction", 0.00),
767
- "cofinsst_value": tax_dict.get("tax_value", 0.00),
768
- }
769
-
770
- @api.depends("product_id", "uom_id")
771
- def _compute_uot_id(self):
772
- for line in self:
773
- p = line.product_id
774
- line.uot_id = (p.uot_id if p else False) or line.uom_id
775
-
776
- @api.depends("price_unit")
777
- def _compute_fiscal_price(self):
778
- for line in self:
779
- if line.product_id and line.price_unit:
780
- line.fiscal_price = line.price_unit / (
781
- line.product_id.uot_factor or 1.0
782
- )
783
- else:
784
- line.fiscal_price = line.price_unit
785
-
786
- @api.depends("quantity")
787
- def _compute_fiscal_quantity(self):
788
- for line in self:
789
- if line.product_id and line.quantity:
790
- line.fiscal_quantity = line.quantity * (
791
- line.product_id.uot_factor or 1.0
792
- )
793
- else:
794
- line.fiscal_quantity = line.quantity
795
-
796
- @api.model
797
- def _add_fields_to_amount(self):
798
- fields_to_amount = ["insurance_value", "other_value", "freight_value"]
799
- if (
800
- self.cfop_id.destination == CFOP_DESTINATION_EXPORT
801
- and self.fiscal_operation_id.fiscal_operation_type == FISCAL_IN
802
- ):
803
- fields_to_amount.append("pis_value")
804
- fields_to_amount.append("cofins_value")
805
- fields_to_amount.append("icms_value")
806
- fields_to_amount.append("ii_value")
807
- fields_to_amount.append("ii_customhouse_charges")
808
- return fields_to_amount
809
-
810
- @api.model
811
- def _rm_fields_to_amount(self):
812
- return ["icms_relief_value"]
813
-
814
- def _is_imported(self):
815
- # When the mixin is used for instance
816
- # in a PO line or SO line, there is no document_id
817
- # and we consider the document is not imported
818
- return hasattr(self, "document_id") and self.document_id.imported_document