odoo-addon-l10n-br-fiscal 17.0.1.0.0.11__py3-none-any.whl → 18.0.5.0.0.1__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 (120) hide show
  1. odoo/addons/l10n_br_fiscal/README.rst +10 -10
  2. odoo/addons/l10n_br_fiscal/__init__.py +1 -0
  3. odoo/addons/l10n_br_fiscal/__manifest__.py +3 -2
  4. odoo/addons/l10n_br_fiscal/constants/fiscal.py +51 -24
  5. odoo/addons/l10n_br_fiscal/data/ir_cron.xml +19 -34
  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_cfop_data.xml +0 -2
  8. odoo/addons/l10n_br_fiscal/data/l10n_br_fiscal_data.xml +6 -8
  9. odoo/addons/l10n_br_fiscal/data/l10n_br_fiscal_icms_tax_definition_data.xml +4055 -4033
  10. odoo/addons/l10n_br_fiscal/data/l10n_br_fiscal_server_action.xml +0 -2
  11. odoo/addons/l10n_br_fiscal/data/l10n_br_fiscal_tax_icms_data.xml +54 -50
  12. odoo/addons/l10n_br_fiscal/data/operation_data.xml +198 -182
  13. odoo/addons/l10n_br_fiscal/data/product_data.xml +0 -2
  14. odoo/addons/l10n_br_fiscal/data/res_partner_data.xml +0 -2
  15. odoo/addons/l10n_br_fiscal/data/simplified_tax_data.xml +0 -2
  16. odoo/addons/l10n_br_fiscal/data/uom_data.xml +0 -2
  17. odoo/addons/l10n_br_fiscal/demo/city_taxation_code_demo.xml +0 -2
  18. odoo/addons/l10n_br_fiscal/demo/company_demo.xml +0 -3
  19. odoo/addons/l10n_br_fiscal/demo/fiscal_document_demo.xml +40 -228
  20. odoo/addons/l10n_br_fiscal/demo/fiscal_document_nfse_demo.xml +0 -5
  21. odoo/addons/l10n_br_fiscal/demo/fiscal_operation_demo.xml +2 -4
  22. odoo/addons/l10n_br_fiscal/demo/icms_tax_definition_demo.xml +0 -2
  23. odoo/addons/l10n_br_fiscal/demo/partner_demo.xml +0 -2
  24. odoo/addons/l10n_br_fiscal/demo/product_demo.xml +0 -1705
  25. odoo/addons/l10n_br_fiscal/demo/res_users_demo.xml +0 -2
  26. odoo/addons/l10n_br_fiscal/hooks.py +68 -0
  27. odoo/addons/l10n_br_fiscal/i18n/l10n_br_fiscal.pot +232 -201
  28. odoo/addons/l10n_br_fiscal/i18n/pt_BR.po +1272 -1344
  29. odoo/addons/l10n_br_fiscal/migrations/18.0.2.0.0/pre-migration.py +25 -0
  30. odoo/addons/l10n_br_fiscal/migrations/18.0.3.0.0/pre-migration.py +30 -0
  31. odoo/addons/l10n_br_fiscal/models/cfop.py +1 -1
  32. odoo/addons/l10n_br_fiscal/models/cnae.py +2 -2
  33. odoo/addons/l10n_br_fiscal/models/comment.py +12 -27
  34. odoo/addons/l10n_br_fiscal/models/cst.py +2 -2
  35. odoo/addons/l10n_br_fiscal/models/data_abstract.py +11 -24
  36. odoo/addons/l10n_br_fiscal/models/document.py +57 -9
  37. odoo/addons/l10n_br_fiscal/models/document_line.py +65 -5
  38. odoo/addons/l10n_br_fiscal/models/document_line_mixin.py +118 -38
  39. odoo/addons/l10n_br_fiscal/models/document_line_mixin_methods.py +261 -295
  40. odoo/addons/l10n_br_fiscal/models/document_mixin.py +8 -16
  41. odoo/addons/l10n_br_fiscal/models/document_mixin_methods.py +49 -177
  42. odoo/addons/l10n_br_fiscal/models/document_related.py +1 -1
  43. odoo/addons/l10n_br_fiscal/models/document_serie.py +35 -2
  44. odoo/addons/l10n_br_fiscal/models/document_type.py +0 -1
  45. odoo/addons/l10n_br_fiscal/models/ibpt.py +1 -1
  46. odoo/addons/l10n_br_fiscal/models/icms_regulation.py +1 -1
  47. odoo/addons/l10n_br_fiscal/models/invalidate_number.py +6 -7
  48. odoo/addons/l10n_br_fiscal/models/legal_nature.py +1 -1
  49. odoo/addons/l10n_br_fiscal/models/nbm.py +2 -2
  50. odoo/addons/l10n_br_fiscal/models/nbs.py +4 -4
  51. odoo/addons/l10n_br_fiscal/models/ncm.py +4 -4
  52. odoo/addons/l10n_br_fiscal/models/operation.py +2 -2
  53. odoo/addons/l10n_br_fiscal/models/operation_dashboard.py +3 -2
  54. odoo/addons/l10n_br_fiscal/models/operation_line.py +1 -1
  55. odoo/addons/l10n_br_fiscal/models/partner_profile.py +7 -1
  56. odoo/addons/l10n_br_fiscal/models/product_template.py +1 -1
  57. odoo/addons/l10n_br_fiscal/models/res_partner.py +9 -0
  58. odoo/addons/l10n_br_fiscal/models/tax.py +12 -4
  59. odoo/addons/l10n_br_fiscal/models/tax_group.py +6 -6
  60. odoo/addons/l10n_br_fiscal/models/tax_pis_cofins.py +4 -4
  61. odoo/addons/l10n_br_fiscal/models/tax_pis_cofins_base.py +3 -3
  62. odoo/addons/l10n_br_fiscal/models/tax_pis_cofins_credit.py +3 -3
  63. odoo/addons/l10n_br_fiscal/security/fiscal_security.xml +6 -18
  64. odoo/addons/l10n_br_fiscal/security/ir.model.access.csv +1 -2
  65. odoo/addons/l10n_br_fiscal/static/description/index.html +8 -8
  66. odoo/addons/l10n_br_fiscal/tests/__init__.py +1 -0
  67. odoo/addons/l10n_br_fiscal/tests/test_document_edition.py +200 -14
  68. odoo/addons/l10n_br_fiscal/tests/test_fiscal_document_generic.py +16 -44
  69. odoo/addons/l10n_br_fiscal/tests/test_fiscal_document_nfse.py +0 -5
  70. odoo/addons/l10n_br_fiscal/tests/test_fiscal_document_serie.py +60 -0
  71. odoo/addons/l10n_br_fiscal/tests/test_tax_benefit.py +2 -5
  72. odoo/addons/l10n_br_fiscal/views/cest_view.xml +2 -2
  73. odoo/addons/l10n_br_fiscal/views/cfop_view.xml +2 -2
  74. odoo/addons/l10n_br_fiscal/views/city_taxation_code.xml +2 -2
  75. odoo/addons/l10n_br_fiscal/views/cnae_view.xml +2 -2
  76. odoo/addons/l10n_br_fiscal/views/comment_view.xml +2 -2
  77. odoo/addons/l10n_br_fiscal/views/cst_view.xml +2 -2
  78. odoo/addons/l10n_br_fiscal/views/document_line_mixin_view.xml +1 -1
  79. odoo/addons/l10n_br_fiscal/views/document_line_view.xml +6 -4
  80. odoo/addons/l10n_br_fiscal/views/document_related_view.xml +2 -2
  81. odoo/addons/l10n_br_fiscal/views/document_serie_view.xml +2 -2
  82. odoo/addons/l10n_br_fiscal/views/document_type_view.xml +2 -2
  83. odoo/addons/l10n_br_fiscal/views/document_view.xml +29 -29
  84. odoo/addons/l10n_br_fiscal/views/icms_regulation_view.xml +2 -2
  85. odoo/addons/l10n_br_fiscal/views/icms_relief_view.xml +2 -2
  86. odoo/addons/l10n_br_fiscal/views/invalidate_number_view.xml +2 -2
  87. odoo/addons/l10n_br_fiscal/views/l10n_br_fiscal_action.xml +36 -36
  88. odoo/addons/l10n_br_fiscal/views/l10n_br_fiscal_menu.xml +0 -9
  89. odoo/addons/l10n_br_fiscal/views/legal_nature_view.xml +2 -2
  90. odoo/addons/l10n_br_fiscal/views/nbm_view.xml +5 -5
  91. odoo/addons/l10n_br_fiscal/views/nbs_view.xml +5 -5
  92. odoo/addons/l10n_br_fiscal/views/ncm_view.xml +5 -5
  93. odoo/addons/l10n_br_fiscal/views/operation_dashboard_view.xml +7 -8
  94. odoo/addons/l10n_br_fiscal/views/operation_line_view.xml +2 -2
  95. odoo/addons/l10n_br_fiscal/views/operation_view.xml +4 -4
  96. odoo/addons/l10n_br_fiscal/views/partner_profile_view.xml +2 -2
  97. odoo/addons/l10n_br_fiscal/views/product_genre_view.xml +2 -2
  98. odoo/addons/l10n_br_fiscal/views/product_product_view.xml +38 -11
  99. odoo/addons/l10n_br_fiscal/views/product_template_view.xml +22 -9
  100. odoo/addons/l10n_br_fiscal/views/res_config_settings_view.xml +8 -8
  101. odoo/addons/l10n_br_fiscal/views/res_partner_view.xml +9 -0
  102. odoo/addons/l10n_br_fiscal/views/service_type_view.xml +5 -5
  103. odoo/addons/l10n_br_fiscal/views/simplified_tax_range_view.xml +2 -2
  104. odoo/addons/l10n_br_fiscal/views/simplified_tax_view.xml +4 -4
  105. odoo/addons/l10n_br_fiscal/views/tax_definition_view.xml +4 -4
  106. odoo/addons/l10n_br_fiscal/views/tax_estimate_view.xml +2 -2
  107. odoo/addons/l10n_br_fiscal/views/tax_group_view.xml +2 -2
  108. odoo/addons/l10n_br_fiscal/views/tax_ipi_control_seal_view.xml +2 -2
  109. odoo/addons/l10n_br_fiscal/views/tax_ipi_guideline_class_view.xml +2 -2
  110. odoo/addons/l10n_br_fiscal/views/tax_ipi_guideline_view.xml +2 -2
  111. odoo/addons/l10n_br_fiscal/views/tax_pis_cofins_base_view.xml +2 -2
  112. odoo/addons/l10n_br_fiscal/views/tax_pis_cofins_credit_view.xml +2 -2
  113. odoo/addons/l10n_br_fiscal/views/tax_pis_cofins_view.xml +2 -2
  114. odoo/addons/l10n_br_fiscal/views/tax_view.xml +2 -2
  115. odoo/addons/l10n_br_fiscal/views/uom_uom.xml +2 -2
  116. odoo/addons/l10n_br_fiscal/wizards/base_wizard_mixin.py +1 -1
  117. {odoo_addon_l10n_br_fiscal-17.0.1.0.0.11.dist-info → odoo_addon_l10n_br_fiscal-18.0.5.0.0.1.dist-info}/METADATA +16 -16
  118. {odoo_addon_l10n_br_fiscal-17.0.1.0.0.11.dist-info → odoo_addon_l10n_br_fiscal-18.0.5.0.0.1.dist-info}/RECORD +120 -116
  119. {odoo_addon_l10n_br_fiscal-17.0.1.0.0.11.dist-info → odoo_addon_l10n_br_fiscal-18.0.5.0.0.1.dist-info}/WHEEL +0 -0
  120. {odoo_addon_l10n_br_fiscal-17.0.1.0.0.11.dist-info → odoo_addon_l10n_br_fiscal-18.0.5.0.0.1.dist-info}/top_level.txt +0 -0
@@ -8,7 +8,6 @@ from ..constants.fiscal import (
8
8
  DOCUMENT_ISSUER,
9
9
  DOCUMENT_ISSUER_COMPANY,
10
10
  FINAL_CUSTOMER,
11
- FINAL_CUSTOMER_YES,
12
11
  FISCAL_COMMENT_DOCUMENT,
13
12
  NFE_IND_PRES,
14
13
  NFE_IND_PRES_DEFAULT,
@@ -48,10 +47,6 @@ class FiscalDocumentMixin(models.AbstractModel):
48
47
  def _date_server_format(self):
49
48
  return fields.Datetime.now().strftime(DEFAULT_SERVER_DATETIME_FORMAT)
50
49
 
51
- @api.model
52
- def _default_operation(self):
53
- return False
54
-
55
50
  @api.model
56
51
  def _operation_domain(self):
57
52
  domain = (
@@ -66,7 +61,6 @@ class FiscalDocumentMixin(models.AbstractModel):
66
61
  comodel_name="l10n_br_fiscal.operation",
67
62
  string="Operation",
68
63
  domain=lambda self: self._operation_domain(),
69
- default=_default_operation,
70
64
  )
71
65
 
72
66
  operation_name = fields.Char(
@@ -105,14 +99,10 @@ class FiscalDocumentMixin(models.AbstractModel):
105
99
  store=True,
106
100
  )
107
101
 
108
- fiscal_additional_data = fields.Text()
109
-
110
102
  manual_fiscal_additional_data = fields.Text(
111
103
  help="Fiscal Additional data manually entered by user",
112
104
  )
113
105
 
114
- customer_additional_data = fields.Text()
115
-
116
106
  manual_customer_additional_data = fields.Text(
117
107
  help="Customer Additional data manually entered by user",
118
108
  )
@@ -120,7 +110,11 @@ class FiscalDocumentMixin(models.AbstractModel):
120
110
  ind_final = fields.Selection(
121
111
  selection=FINAL_CUSTOMER,
122
112
  string="Final Consumption Operation",
123
- default=FINAL_CUSTOMER_YES,
113
+ compute="_compute_ind_final",
114
+ inverse="_inverse_ind_final",
115
+ store=True,
116
+ precompute=True,
117
+ readonly=False,
124
118
  )
125
119
 
126
120
  currency_id = fields.Many2one(
@@ -135,7 +129,7 @@ class FiscalDocumentMixin(models.AbstractModel):
135
129
  help="Amount without discount.",
136
130
  )
137
131
 
138
- amount_untaxed = fields.Monetary(
132
+ fiscal_amount_untaxed = fields.Monetary(
139
133
  compute="_compute_fiscal_amount",
140
134
  store=True,
141
135
  )
@@ -403,12 +397,12 @@ class FiscalDocumentMixin(models.AbstractModel):
403
397
  store=True,
404
398
  )
405
399
 
406
- amount_tax = fields.Monetary(
400
+ fiscal_amount_tax = fields.Monetary(
407
401
  compute="_compute_fiscal_amount",
408
402
  store=True,
409
403
  )
410
404
 
411
- amount_total = fields.Monetary(
405
+ fiscal_amount_total = fields.Monetary(
412
406
  compute="_compute_fiscal_amount",
413
407
  store=True,
414
408
  )
@@ -501,14 +495,12 @@ class FiscalDocumentMixin(models.AbstractModel):
501
495
  document_number = fields.Char(
502
496
  copy=False,
503
497
  index=True,
504
- unaccent=False,
505
498
  )
506
499
 
507
500
  document_key = fields.Char(
508
501
  string="Key",
509
502
  copy=False,
510
503
  index=True,
511
- unaccent=False,
512
504
  )
513
505
 
514
506
  key_random_code = fields.Char(string="Document Key Random Code")
@@ -4,8 +4,6 @@
4
4
  from odoo import api, models
5
5
 
6
6
  from ..constants.fiscal import (
7
- COMMENT_TYPE_COMMERCIAL,
8
- COMMENT_TYPE_FISCAL,
9
7
  DOCUMENT_ISSUER_COMPANY,
10
8
  )
11
9
 
@@ -75,7 +73,8 @@ class FiscalDocumentMixinMethods(models.AbstractModel):
75
73
  def _get_amount_fields(self):
76
74
  """Get all fields with 'amount_' prefix"""
77
75
  fields = self.env["l10n_br_fiscal.document.mixin"]._fields.keys()
78
- amount_fields = [f for f in fields if f.startswith("amount_")]
76
+ prefixes = ("amount_", "fiscal_amount_")
77
+ amount_fields = [f for f in fields if f.startswith(prefixes)]
79
78
  return amount_fields
80
79
 
81
80
  @api.depends("document_serie_id", "issuer")
@@ -89,7 +88,11 @@ class FiscalDocumentMixinMethods(models.AbstractModel):
89
88
  @api.depends("document_type_id", "issuer")
90
89
  def _compute_document_serie_id(self):
91
90
  for doc in self:
92
- if doc.document_type_id and doc.issuer == DOCUMENT_ISSUER_COMPANY:
91
+ if (
92
+ not doc.document_serie_id
93
+ and doc.document_type_id
94
+ and doc.issuer == DOCUMENT_ISSUER_COMPANY
95
+ ):
93
96
  doc.document_serie_id = doc.document_type_id.get_document_serie(
94
97
  doc.company_id, doc.fiscal_operation_id
95
98
  )
@@ -159,30 +162,6 @@ class FiscalDocumentMixinMethods(models.AbstractModel):
159
162
 
160
163
  doc.update(values)
161
164
 
162
- def __document_comment_vals(self):
163
- return {
164
- "user": self.env.user,
165
- "ctx": self._context,
166
- "doc": self,
167
- }
168
-
169
- def _document_comment(self):
170
- for d in self:
171
- # Fiscal Comments
172
- d.fiscal_additional_data = d.comment_ids.filtered(
173
- lambda c: c.comment_type == COMMENT_TYPE_FISCAL
174
- ).compute_message(
175
- d.__document_comment_vals(), d.manual_fiscal_additional_data
176
- )
177
-
178
- # Commercial Comments
179
- d.customer_additional_data = d.comment_ids.filtered(
180
- lambda c: c.comment_type == COMMENT_TYPE_COMMERCIAL
181
- ).compute_message(
182
- d.__document_comment_vals(), d.manual_customer_additional_data
183
- )
184
- d.fiscal_line_ids._document_comment()
185
-
186
165
  def _get_fiscal_partner(self):
187
166
  """
188
167
  Hook method to determine the fiscal partner for the document.
@@ -199,14 +178,22 @@ class FiscalDocumentMixinMethods(models.AbstractModel):
199
178
  self.ensure_one()
200
179
  return self.partner_id
201
180
 
202
- @api.onchange("partner_id")
203
- def _onchange_partner_id_fiscal(self):
204
- partner = self._get_fiscal_partner()
205
- if partner:
206
- self.ind_final = partner.ind_final
207
- for line in self._get_amount_lines():
208
- # reload fiscal data, operation line, cfop, taxes, etc.
209
- line._onchange_fiscal_operation_id()
181
+ @api.depends("partner_id")
182
+ def _compute_ind_final(self):
183
+ for doc in self:
184
+ partner = doc._get_fiscal_partner()
185
+ if partner:
186
+ doc.ind_final = partner.ind_final
187
+ else:
188
+ # Default Value
189
+ doc.ind_final = "1" # Yes
190
+
191
+ @api.onchange("ind_final")
192
+ def _inverse_ind_final(self):
193
+ for doc in self:
194
+ for line in doc._get_amount_lines():
195
+ if line.ind_final != doc.ind_final:
196
+ line.ind_final = doc.ind_final
210
197
 
211
198
  @api.depends("fiscal_operation_id")
212
199
  def _compute_operation_name(self):
@@ -224,152 +211,37 @@ class FiscalDocumentMixinMethods(models.AbstractModel):
224
211
  elif doc.comment_ids is None:
225
212
  doc.comment_ids = []
226
213
 
227
- def _inverse_amount_freight(self):
228
- for record in self.filtered(lambda doc: doc._get_product_amount_lines()):
229
- if (
214
+ def _distribute_amount_to_lines(self, amount_field_name, line_field_name):
215
+ for record in self:
216
+ if not (
230
217
  record.delivery_costs == "total"
231
218
  or record.force_compute_delivery_costs_by_total
232
219
  ):
233
- amount_freight_value = record.amount_freight_value
234
- if all(record._get_product_amount_lines().mapped("freight_value")):
235
- amount_freight_old = sum(
236
- record._get_product_amount_lines().mapped("freight_value")
237
- )
238
- for line in record._get_product_amount_lines()[:-1]:
239
- line.freight_value = amount_freight_value * (
240
- line.freight_value / amount_freight_old
241
- )
242
- record._get_product_amount_lines()[-1].freight_value = (
243
- amount_freight_value
244
- - sum(
245
- line.freight_value
246
- for line in record._get_product_amount_lines()[:-1]
247
- )
248
- )
249
- else:
250
- amount_total = sum(
251
- record._get_product_amount_lines().mapped("price_gross")
252
- )
253
- for line in record._get_product_amount_lines()[:-1]:
254
- if line.price_gross and amount_total:
255
- line.freight_value = amount_freight_value * (
256
- line.price_gross / amount_total
257
- )
258
- record._get_product_amount_lines()[-1].freight_value = (
259
- amount_freight_value
260
- - sum(
261
- line.freight_value
262
- for line in record._get_product_amount_lines()[:-1]
263
- )
220
+ continue
221
+ lines = record._get_product_amount_lines()
222
+ if not lines:
223
+ continue
224
+ amount_to_distribute = record[amount_field_name]
225
+ total_gross = sum(lines.mapped("price_gross"))
226
+ if total_gross > 0:
227
+ distributed_amount = 0
228
+ for line in lines[:-1]:
229
+ proportional_amount = record.currency_id.round(
230
+ amount_to_distribute * (line.price_gross / total_gross)
264
231
  )
265
- for line in record._get_product_amount_lines():
266
- line._onchange_fiscal_taxes()
267
- record._fields["amount_total"].compute_value(record)
268
- record.write(
269
- {
270
- name: value
271
- for name, value in record._cache.items()
272
- if record._fields[name].compute == "_amount_all"
273
- and not record._fields[name].inverse
274
- }
275
- )
232
+ line[line_field_name] = proportional_amount
233
+ distributed_amount += proportional_amount
234
+ lines[-1][line_field_name] = amount_to_distribute - distributed_amount
235
+ else:
236
+ lines.write({line_field_name: 0.0})
237
+ if lines:
238
+ lines[0][line_field_name] = amount_to_distribute
239
+
240
+ def _inverse_amount_freight(self):
241
+ self._distribute_amount_to_lines("amount_freight_value", "freight_value")
276
242
 
277
243
  def _inverse_amount_insurance(self):
278
- for record in self.filtered(lambda doc: doc._get_product_amount_lines()):
279
- if (
280
- record.delivery_costs == "total"
281
- or record.force_compute_delivery_costs_by_total
282
- ):
283
- amount_insurance_value = record.amount_insurance_value
284
- if all(record._get_product_amount_lines().mapped("insurance_value")):
285
- amount_insurance_old = sum(
286
- record._get_product_amount_lines().mapped("insurance_value")
287
- )
288
- for line in record._get_product_amount_lines()[:-1]:
289
- line.insurance_value = amount_insurance_value * (
290
- line.insurance_value / amount_insurance_old
291
- )
292
- record._get_product_amount_lines()[-1].insurance_value = (
293
- amount_insurance_value
294
- - sum(
295
- line.insurance_value
296
- for line in record._get_product_amount_lines()[:-1]
297
- )
298
- )
299
- else:
300
- amount_total = sum(
301
- record._get_product_amount_lines().mapped("price_gross")
302
- )
303
- for line in record._get_product_amount_lines()[:-1]:
304
- if line.price_gross and amount_total:
305
- line.insurance_value = amount_insurance_value * (
306
- line.price_gross / amount_total
307
- )
308
- record._get_product_amount_lines()[-1].insurance_value = (
309
- amount_insurance_value
310
- - sum(
311
- line.insurance_value
312
- for line in record._get_product_amount_lines()[:-1]
313
- )
314
- )
315
- for line in record._get_product_amount_lines():
316
- line._onchange_fiscal_taxes()
317
- record._fields["amount_total"].compute_value(record)
318
- record.write(
319
- {
320
- name: value
321
- for name, value in record._cache.items()
322
- if record._fields[name].compute == "_amount_all"
323
- and not record._fields[name].inverse
324
- }
325
- )
244
+ self._distribute_amount_to_lines("amount_insurance_value", "insurance_value")
326
245
 
327
246
  def _inverse_amount_other(self):
328
- for record in self.filtered(lambda doc: doc._get_product_amount_lines()):
329
- if (
330
- record.delivery_costs == "total"
331
- or record.force_compute_delivery_costs_by_total
332
- ):
333
- amount_other_value = record.amount_other_value
334
- if all(record._get_product_amount_lines().mapped("other_value")):
335
- amount_other_old = sum(
336
- record._get_product_amount_lines().mapped("other_value")
337
- )
338
- for line in record._get_product_amount_lines()[:-1]:
339
- line.other_value = amount_other_value * (
340
- line.other_value / amount_other_old
341
- )
342
- record._get_product_amount_lines()[-1].other_value = (
343
- amount_other_value
344
- - sum(
345
- line.other_value
346
- for line in record._get_product_amount_lines()[:-1]
347
- )
348
- )
349
- else:
350
- amount_total = sum(
351
- record._get_product_amount_lines().mapped("price_gross")
352
- )
353
- for line in record._get_product_amount_lines()[:-1]:
354
- if line.price_gross and amount_total:
355
- line.other_value = amount_other_value * (
356
- line.price_gross / amount_total
357
- )
358
- record._get_product_amount_lines()[-1].other_value = (
359
- amount_other_value
360
- - sum(
361
- line.other_value
362
- for line in record._get_product_amount_lines()[:-1]
363
- )
364
- )
365
- for line in record._get_product_amount_lines():
366
- line._onchange_fiscal_taxes()
367
- record._fields["amount_total"].compute_value(record)
368
- record.write(
369
- {
370
- name: value
371
- for name, value in record._cache.items()
372
- if record._fields[name].compute == "_amount_all"
373
- and not record._fields[name].inverse
374
- }
375
- )
247
+ self._distribute_amount_to_lines("amount_other_value", "other_value")
@@ -104,7 +104,7 @@ class DocumentRelated(models.Model):
104
104
  return False
105
105
 
106
106
  self.document_type_id = related.document_type_id
107
- self.document_total_amount = related.amount_total
107
+ self.document_total_amount = related.fiscal_amount_total
108
108
  self.document_total_weight = related.total_weight
109
109
 
110
110
  if related.document_type_id.electronic:
@@ -3,11 +3,13 @@
3
3
  # License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html
4
4
 
5
5
  from odoo import _, api, fields, models
6
+ from odoo.exceptions import ValidationError
6
7
 
7
8
  from ..constants.fiscal import (
8
9
  DOCUMENT_ISSUER_COMPANY,
9
10
  FISCAL_IN_OUT,
10
11
  FISCAL_IN_OUT_DEFAULT,
12
+ SITUACAO_EDOC_EM_DIGITACAO,
11
13
  )
12
14
 
13
15
 
@@ -16,9 +18,9 @@ class DocumentSerie(models.Model):
16
18
  _description = "Fiscal Document Serie"
17
19
  _inherit = "l10n_br_fiscal.data.abstract"
18
20
 
19
- code = fields.Char(size=3, unaccent=False)
21
+ code = fields.Char(size=3)
20
22
 
21
- name = fields.Char(required=True, unaccent=False)
23
+ name = fields.Char(required=True)
22
24
 
23
25
  active = fields.Boolean(default=True)
24
26
 
@@ -55,6 +57,14 @@ class DocumentSerie(models.Model):
55
57
  string="Invalidate Number Range",
56
58
  )
57
59
 
60
+ _sql_constraints = [
61
+ (
62
+ "document_serie_unique",
63
+ "unique(code, document_type_id, company_id)",
64
+ "A Fiscal Document Serie already exists for this document type.",
65
+ )
66
+ ]
67
+
58
68
  @api.model
59
69
  def _create_sequence(self, values):
60
70
  """Create new no_gap entry sequence for every
@@ -83,6 +93,29 @@ class DocumentSerie(models.Model):
83
93
  for record in self:
84
94
  record.display_name = record.name
85
95
 
96
+ def write(self, vals):
97
+ if "internal_sequence_id" in vals:
98
+ raise ValidationError(_("You cannot change the internal sequence."))
99
+ if "code" in vals:
100
+ for serie in self:
101
+ if serie.code == vals["code"]:
102
+ continue
103
+ if self.env["l10n_br_fiscal.document"].search_count(
104
+ [
105
+ ("document_serie_id", "=", serie.id),
106
+ ("state_edoc", "not in", [SITUACAO_EDOC_EM_DIGITACAO]),
107
+ ],
108
+ limit=1,
109
+ ):
110
+ raise ValidationError(
111
+ _(
112
+ "You cannot change the code of a document "
113
+ "serie %(name)s that is already in use.",
114
+ name=serie.name,
115
+ )
116
+ )
117
+ return super().write(vals)
118
+
86
119
  def _is_invalid_number(self, document_number):
87
120
  self.ensure_one()
88
121
  is_invalid_number = True
@@ -14,7 +14,6 @@ class DocumentType(models.Model):
14
14
 
15
15
  code = fields.Char(
16
16
  size=8,
17
- unaccent=False,
18
17
  )
19
18
 
20
19
  name = fields.Char(
@@ -45,7 +45,7 @@ def _request(ws_url, params, ibpt_request_timeout=30):
45
45
  elif response.status_code == requests.codes.service_unavailable:
46
46
  raise UserError(_("IBPT Service Unavailable - {!r}").format(ws_url))
47
47
  except Exception as e:
48
- raise UserError(_("Error in the request: {}").format(e)) from e
48
+ raise UserError(f"Error in the request: {e}") from e
49
49
 
50
50
 
51
51
  def get_ibpt_product(
@@ -2101,7 +2101,7 @@ class ICMSRegulation(models.Model):
2101
2101
  company.state_id != partner.state_id
2102
2102
  and partner.ind_ie_dest == NFE_IND_IE_DEST_9
2103
2103
  and operation_line.fiscal_operation_type == FISCAL_OUT
2104
- or operation_line.fiscal_operation_id.fiscal_type == "return_in"
2104
+ or operation_line.fiscal_operation_id.fiscal_type != "return_in"
2105
2105
  and operation_line.fiscal_operation_type == FISCAL_IN
2106
2106
  ):
2107
2107
  domain = self._build_map_tax_def_domain(
@@ -68,8 +68,8 @@ class InvalidateNumber(models.Model):
68
68
 
69
69
  state = fields.Selection(
70
70
  selection=[
71
- ("draft", _("Draft")),
72
- ("done", _("Done")),
71
+ ("draft", "Draft"),
72
+ ("done", "Done"),
73
73
  ],
74
74
  string="Status",
75
75
  readonly=True,
@@ -99,11 +99,10 @@ class InvalidateNumber(models.Model):
99
99
  @api.depends("document_type_id", "document_serie_id", "number_start", "number_end")
100
100
  def _compute_name(self):
101
101
  for record in self:
102
- record.name = "{type}/({serie}): {start} - {end}".format(
103
- type=record.document_type_id.type,
104
- serie=record.document_serie_id.name,
105
- start=record.number_start,
106
- end=record.number_end,
102
+ record.name = (
103
+ f"{record.document_type_id.type}/"
104
+ f"({record.document_serie_id.name}): "
105
+ f"{record.number_start} - {record.number_end}"
107
106
  )
108
107
 
109
108
  def unlink(self):
@@ -15,6 +15,6 @@ class LegalNature(models.Model):
15
15
  (
16
16
  "fiscal_legal_nature_code_uniq",
17
17
  "unique (code)",
18
- "Legal Nature already exists with this code !",
18
+ "Legal Nature already exists with this code!",
19
19
  )
20
20
  ]
@@ -11,9 +11,9 @@ class Nbm(models.Model):
11
11
  _inherit = "l10n_br_fiscal.data.product.abstract"
12
12
  _description = "NBM"
13
13
 
14
- code = fields.Char(size=12, unaccent=False)
14
+ code = fields.Char(size=12)
15
15
 
16
- code_unmasked = fields.Char(size=10, unaccent=False)
16
+ code_unmasked = fields.Char(size=10)
17
17
 
18
18
  product_tmpl_ids = fields.One2many(inverse_name="nbm_id")
19
19
 
@@ -1,7 +1,7 @@
1
1
  # Copyright (C) 2019 Renato Lima - Akretion
2
2
  # License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html
3
3
 
4
- from odoo import _, fields, models
4
+ from odoo import fields, models
5
5
 
6
6
  from .ibpt import get_ibpt_service
7
7
 
@@ -15,9 +15,9 @@ class Nbs(models.Model):
15
15
  ]
16
16
  _description = "NBS"
17
17
 
18
- code = fields.Char(size=12, unaccent=False)
18
+ code = fields.Char(size=12)
19
19
 
20
- code_unmasked = fields.Char(size=10, unaccent=False)
20
+ code_unmasked = fields.Char(size=10)
21
21
 
22
22
  tax_estimate_ids = fields.One2many(inverse_name="nbs_id")
23
23
 
@@ -27,7 +27,7 @@ class Nbs(models.Model):
27
27
  (
28
28
  "fiscal_nbs_code_uniq",
29
29
  "unique (code)",
30
- _("NBS already exists with this code !"),
30
+ "NBS already exists with this code!",
31
31
  )
32
32
  ]
33
33
 
@@ -1,7 +1,7 @@
1
1
  # Copyright (C) 2012 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 _, fields, models
4
+ from odoo import fields, models
5
5
 
6
6
  from ..constants.fiscal import TAX_DOMAIN_II, TAX_DOMAIN_IPI
7
7
  from .ibpt import get_ibpt_product
@@ -16,9 +16,9 @@ class Ncm(models.Model):
16
16
  ]
17
17
  _description = "NCM"
18
18
 
19
- code = fields.Char(size=10, unaccent=False)
19
+ code = fields.Char(size=10)
20
20
 
21
- code_unmasked = fields.Char(size=8, unaccent=False)
21
+ code_unmasked = fields.Char(size=8)
22
22
 
23
23
  exception = fields.Char(size=2)
24
24
 
@@ -70,7 +70,7 @@ class Ncm(models.Model):
70
70
  (
71
71
  "fiscal_ncm_code_exception_uniq",
72
72
  "unique (code, exception)",
73
- _("NCM already exists with this code !"),
73
+ "NCM already exists with this code!",
74
74
  )
75
75
  ]
76
76
 
@@ -98,7 +98,7 @@ class Operation(models.Model):
98
98
  )
99
99
 
100
100
  default_price_unit = fields.Selection(
101
- selection=[("sale_price", _("Sale Price")), ("cost_price", _("Cost Price"))],
101
+ selection=[("sale_price", "Sale Price"), ("cost_price", "Cost Price")],
102
102
  string="Default Price Unit?",
103
103
  default="sale_price",
104
104
  readonly=True,
@@ -173,7 +173,7 @@ class Operation(models.Model):
173
173
  (
174
174
  "fiscal_operation_code_uniq",
175
175
  "unique (code)",
176
- _("Fiscal Operation already exists with this code !"),
176
+ "Fiscal Operation already exists with this code!",
177
177
  )
178
178
  ]
179
179
 
@@ -127,7 +127,7 @@ class Operation(models.Model):
127
127
  }
128
128
 
129
129
  def open_action(self):
130
- """return action based on type for related journals"""
130
+ """Return action based on type for related journals"""
131
131
 
132
132
  _fiscal_type_map = {
133
133
  "purchase": "in",
@@ -157,7 +157,8 @@ class Operation(models.Model):
157
157
  }
158
158
  )
159
159
 
160
- [action] = self.env.ref("l10n_br_fiscal.%s" % action_name).read()
160
+ xmlid = f"l10n_br_fiscal.{action_name}"
161
+ [action] = self.env.ref(xmlid).read()
161
162
  action["context"] = ctx
162
163
  action["domain"] = self._context.get("use_domain", [])
163
164
  action["domain"] += [
@@ -139,7 +139,7 @@ class OperationLine(models.Model):
139
139
  (
140
140
  "fiscal_operation_name_uniq",
141
141
  "unique (name, fiscal_operation_id)",
142
- _("Fiscal Operation Line already exists with this name !"),
142
+ "Fiscal Operation Line already exists with this name!",
143
143
  )
144
144
  ]
145
145
 
@@ -8,6 +8,7 @@ from odoo.exceptions import ValidationError
8
8
  from ..constants.fiscal import (
9
9
  NFE_IND_IE_DEST,
10
10
  NFE_IND_IE_DEST_DEFAULT,
11
+ PUBLIC_ENTIRY_TYPE,
11
12
  TAX_FRAMEWORK,
12
13
  TAX_FRAMEWORK_NORMAL,
13
14
  )
@@ -32,6 +33,11 @@ class PartnerProfile(models.Model):
32
33
  "other government-controlled organizations.",
33
34
  )
34
35
 
36
+ public_entity_type = fields.Selection(
37
+ selection=PUBLIC_ENTIRY_TYPE,
38
+ string="Tipo de Entidade Governamental",
39
+ )
40
+
35
41
  default = fields.Boolean(string="Default Profile", default=True)
36
42
 
37
43
  ind_ie_dest = fields.Selection(
@@ -63,7 +69,7 @@ class PartnerProfile(models.Model):
63
69
  (
64
70
  "fiscal_partner_profile_code_uniq",
65
71
  "unique (code)",
66
- "Fiscal Partner Profile already exists with this code !",
72
+ "Fiscal Partner Profile already exists with this code!",
67
73
  )
68
74
  ]
69
75
 
@@ -83,7 +83,7 @@ class ProductTemplate(models.Model):
83
83
  domain="[('internal_type', '=', 'normal')]",
84
84
  )
85
85
 
86
- city_taxation_code_id = fields.Many2many(
86
+ city_taxation_code_ids = fields.Many2many(
87
87
  comodel_name="l10n_br_fiscal.city.taxation.code", string="City Taxation Code"
88
88
  )
89
89