odoo-addon-l10n-br-fiscal 18.0.2.0.0.10__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 (47) hide show
  1. odoo/addons/l10n_br_fiscal/README.rst +1 -1
  2. odoo/addons/l10n_br_fiscal/__manifest__.py +2 -2
  3. odoo/addons/l10n_br_fiscal/constants/fiscal.py +46 -18
  4. odoo/addons/l10n_br_fiscal/data/l10n_br_fiscal.document.type.csv +1 -0
  5. odoo/addons/l10n_br_fiscal/data/operation_data.xml +1 -1
  6. odoo/addons/l10n_br_fiscal/demo/fiscal_document_demo.xml +3 -179
  7. odoo/addons/l10n_br_fiscal/demo/fiscal_document_nfse_demo.xml +0 -4
  8. odoo/addons/l10n_br_fiscal/demo/fiscal_operation_demo.xml +2 -2
  9. odoo/addons/l10n_br_fiscal/i18n/l10n_br_fiscal.pot +142 -36
  10. odoo/addons/l10n_br_fiscal/i18n/pt_BR.po +190 -58
  11. odoo/addons/l10n_br_fiscal/migrations/18.0.3.0.0/pre-migration.py +30 -0
  12. odoo/addons/l10n_br_fiscal/models/comment.py +3 -1
  13. odoo/addons/l10n_br_fiscal/models/document.py +27 -8
  14. odoo/addons/l10n_br_fiscal/models/document_line.py +51 -8
  15. odoo/addons/l10n_br_fiscal/models/document_line_mixin.py +118 -31
  16. odoo/addons/l10n_br_fiscal/models/document_line_mixin_methods.py +263 -282
  17. odoo/addons/l10n_br_fiscal/models/document_mixin.py +8 -5
  18. odoo/addons/l10n_br_fiscal/models/document_mixin_methods.py +49 -151
  19. odoo/addons/l10n_br_fiscal/models/document_related.py +1 -1
  20. odoo/addons/l10n_br_fiscal/models/document_serie.py +33 -0
  21. odoo/addons/l10n_br_fiscal/models/icms_regulation.py +1 -1
  22. odoo/addons/l10n_br_fiscal/models/operation_dashboard.py +3 -2
  23. odoo/addons/l10n_br_fiscal/models/partner_profile.py +6 -0
  24. odoo/addons/l10n_br_fiscal/models/res_partner.py +7 -0
  25. odoo/addons/l10n_br_fiscal/models/tax.py +7 -3
  26. odoo/addons/l10n_br_fiscal/security/fiscal_security.xml +6 -16
  27. odoo/addons/l10n_br_fiscal/security/ir.model.access.csv +0 -1
  28. odoo/addons/l10n_br_fiscal/static/description/index.html +1 -1
  29. odoo/addons/l10n_br_fiscal/tests/__init__.py +1 -0
  30. odoo/addons/l10n_br_fiscal/tests/test_document_edition.py +175 -10
  31. odoo/addons/l10n_br_fiscal/tests/test_fiscal_document_generic.py +13 -42
  32. odoo/addons/l10n_br_fiscal/tests/test_fiscal_document_nfse.py +0 -5
  33. odoo/addons/l10n_br_fiscal/tests/test_fiscal_document_serie.py +60 -0
  34. odoo/addons/l10n_br_fiscal/tests/test_tax_benefit.py +2 -5
  35. odoo/addons/l10n_br_fiscal/views/document_line_mixin_view.xml +1 -0
  36. odoo/addons/l10n_br_fiscal/views/document_line_view.xml +3 -3
  37. odoo/addons/l10n_br_fiscal/views/document_view.xml +20 -15
  38. odoo/addons/l10n_br_fiscal/views/l10n_br_fiscal_menu.xml +0 -9
  39. odoo/addons/l10n_br_fiscal/views/operation_dashboard_view.xml +3 -3
  40. odoo/addons/l10n_br_fiscal/views/product_product_view.xml +33 -6
  41. odoo/addons/l10n_br_fiscal/views/product_template_view.xml +17 -4
  42. odoo/addons/l10n_br_fiscal/views/res_partner_view.xml +6 -0
  43. odoo/addons/l10n_br_fiscal/wizards/base_wizard_mixin.py +1 -1
  44. {odoo_addon_l10n_br_fiscal-18.0.2.0.0.10.dist-info → odoo_addon_l10n_br_fiscal-18.0.5.0.0.1.dist-info}/METADATA +3 -3
  45. {odoo_addon_l10n_br_fiscal-18.0.2.0.0.10.dist-info → odoo_addon_l10n_br_fiscal-18.0.5.0.0.1.dist-info}/RECORD +47 -45
  46. {odoo_addon_l10n_br_fiscal-18.0.2.0.0.10.dist-info → odoo_addon_l10n_br_fiscal-18.0.5.0.0.1.dist-info}/WHEEL +0 -0
  47. {odoo_addon_l10n_br_fiscal-18.0.2.0.0.10.dist-info → odoo_addon_l10n_br_fiscal-18.0.5.0.0.1.dist-info}/top_level.txt +0 -0
@@ -4,9 +4,10 @@
4
4
  from unittest import mock
5
5
 
6
6
  from odoo import Command
7
- from odoo.tests import Form, TransactionCase
7
+ from odoo.tests import Form, TransactionCase, tagged
8
8
 
9
9
 
10
+ @tagged("post_install", "-at_install")
10
11
  class TestDocumentEdition(TransactionCase):
11
12
  @classmethod
12
13
  def setUpClass(cls):
@@ -35,6 +36,10 @@ class TestDocumentEdition(TransactionCase):
35
36
  cls.env = cls.env(
36
37
  user=cls.user, context=dict(cls.env.context, tracking_disable=True)
37
38
  )
39
+ cls.user = cls.env.user
40
+ cls.company = cls.env.ref("l10n_br_base.empresa_lucro_presumido")
41
+ cls.user.company_ids |= cls.company
42
+ cls.user.company_id = cls.company.id
38
43
 
39
44
  def test_basic_doc_edition(self):
40
45
  doc_form = Form(
@@ -98,20 +103,46 @@ class TestDocumentEdition(TransactionCase):
98
103
  line_form.fiscal_operation_line_id,
99
104
  self.env.ref("l10n_br_fiscal.fo_venda_revenda"),
100
105
  )
106
+ self.assertEqual(
107
+ line_form.ipi_tax_id, self.env.ref("l10n_br_fiscal.tax_ipi_nt")
108
+ )
101
109
 
102
- # line_form.fiscal_operation_line_id = False
103
- # self.assertEqual(len(line_form.fiscal_tax_ids), 0)
110
+ line_form.fiscal_operation_line_id = self.env.ref(
111
+ "l10n_br_fiscal.fo_venda_venda"
112
+ )
113
+ self.assertEqual(
114
+ line_form.ipi_tax_id, self.env.ref("l10n_br_fiscal.tax_ipi_3_25")
115
+ )
116
+
117
+ # ensure manually setting a xx_tax_id is properly saved (not recomputed):
118
+ line_form.icms_tax_id = self.env.ref("l10n_br_fiscal.tax_icms_18")
119
+ self.assertEqual(line_form.icms_value, 37.17)
120
+ self.assertEqual(
121
+ line_form.ipi_tax_id, self.env.ref("l10n_br_fiscal.tax_ipi_3_25")
122
+ )
123
+ line_form.icmsfcp_base = line_form.price_unit
124
+ line_form.icmsfcp_value = 3 # ensure manually setting FCP value works
104
125
 
105
126
  doc = doc_form.save()
106
- self.assertEqual(doc.fiscal_line_ids[0].price_unit, 100)
107
- self.assertEqual(doc.fiscal_line_ids[0].fiscal_price, 100)
108
- self.assertEqual(doc.fiscal_line_ids[0].quantity, 2)
109
- self.assertEqual(doc.fiscal_line_ids[0].fiscal_quantity, 2)
110
- self.assertEqual(len(doc.fiscal_line_ids[0].fiscal_tax_ids), 4)
127
+ line = doc.fiscal_line_ids[0]
128
+ self.assertEqual(line.price_unit, 100)
129
+ self.assertEqual(line.fiscal_price, 100)
130
+ self.assertEqual(line.quantity, 2)
131
+ self.assertEqual(line.fiscal_quantity, 2)
132
+ self.assertEqual(len(line.fiscal_tax_ids), 4)
133
+
134
+ self.assertEqual(
135
+ line.fiscal_operation_line_id,
136
+ self.env.ref("l10n_br_fiscal.fo_venda_venda"),
137
+ )
111
138
  self.assertEqual(
112
- doc.fiscal_line_ids[0].icms_tax_id.id,
113
- self.ref("l10n_br_fiscal.tax_icms_12"),
139
+ line.icms_tax_id.id,
140
+ self.ref("l10n_br_fiscal.tax_icms_18"),
114
141
  )
142
+ self.assertEqual(line.ipi_tax_id, self.env.ref("l10n_br_fiscal.tax_ipi_3_25"))
143
+ self.assertEqual(line.icms_value, 37.17)
144
+ self.assertEqual(line.icmsfcp_base, line.price_unit)
145
+ self.assertEqual(line.icmsfcp_value, 3)
115
146
 
116
147
  def test_product_fiscal_factor(self):
117
148
  doc_form = Form(
@@ -162,3 +193,137 @@ class TestDocumentEdition(TransactionCase):
162
193
  self.assertEqual(doc.fiscal_line_ids[0].fiscal_price, 112)
163
194
  self.assertEqual(doc.fiscal_line_ids[0].quantity, 10)
164
195
  self.assertEqual(doc.fiscal_line_ids[0].fiscal_quantity, 5)
196
+
197
+ def test_landed_costs_by_line_and_by_total(self):
198
+ """
199
+ Tests both landed cost scenarios: 'by line' and 'by total'.
200
+ 1. By Line: Enters costs on lines and verifies the header totals.
201
+ 2. By Total: Enters costs on the header and verifies lines distribution.
202
+ """
203
+ self.env.user.groups_id |= self.env.ref("l10n_br_fiscal.group_user")
204
+ product1 = self.env.ref("product.product_product_6")
205
+ product2 = self.env.ref("product.product_product_7")
206
+
207
+ # Part 1: Test with delivery_costs = 'line'
208
+ # ----------------------------------------------------
209
+ self.company.delivery_costs = "line"
210
+ doc_form = Form(self.env["l10n_br_fiscal.document"])
211
+ doc_form.company_id = self.company
212
+ doc_form.partner_id = self.env.ref("l10n_br_base.res_partner_cliente1_sp")
213
+ doc_form.fiscal_operation_id = self.env.ref("l10n_br_fiscal.fo_venda")
214
+
215
+ with doc_form.fiscal_line_ids.new() as line1:
216
+ line1.product_id = product1
217
+ line1.fiscal_operation_line_id = self.env.ref(
218
+ "l10n_br_fiscal.fo_venda_venda"
219
+ )
220
+ line1.price_unit = 1000.0
221
+ line1.quantity = 2.0 # Gross: 2000
222
+ line1.freight_value = 10.0
223
+ line1.insurance_value = 20.0
224
+ line1.other_value = 5.0
225
+
226
+ with doc_form.fiscal_line_ids.new() as line2:
227
+ line2.product_id = product2
228
+ line2.fiscal_operation_line_id = self.env.ref(
229
+ "l10n_br_fiscal.fo_venda_venda"
230
+ )
231
+ line2.price_unit = 500.0
232
+ line2.quantity = 1.0 # Gross: 500
233
+ line2.freight_value = 4.0
234
+ line2.insurance_value = 6.0
235
+ line2.other_value = 2.0
236
+
237
+ doc = doc_form.save()
238
+
239
+ self.assertEqual(doc.company_id.delivery_costs, "line")
240
+ # Assert header totals are the SUM of line values
241
+ self.assertAlmostEqual(doc.amount_freight_value, 14.0) # 10.0 + 4.0
242
+ self.assertAlmostEqual(doc.amount_insurance_value, 26.0) # 20.0 + 6.0
243
+ self.assertAlmostEqual(doc.amount_other_value, 7.0) # 5.0 + 2.0
244
+
245
+ # Assert final fiscal totals (bottom-up calculation)
246
+ # price_gross = (1000*2) + (500*1) = 2500
247
+ # landed_costs = 14 + 26 + 7 = 47
248
+ # fiscal_amount_untaxed (IPI Base) = 2500 + 47 = 2547
249
+ self.assertAlmostEqual(doc.fiscal_amount_untaxed, 2547.00)
250
+ # fiscal_amount_tax (IPI) = (2035 * 3.25%) + (512 * 5%) = 66.14 + 25.60 = 91.74
251
+ self.assertAlmostEqual(doc.fiscal_amount_tax, 91.74, places=2)
252
+ # fiscal_amount_total = 2547.00 + 91.74 = 2638.74
253
+ self.assertAlmostEqual(doc.fiscal_amount_total, 2638.74, places=2)
254
+
255
+ # Part 2: Test with delivery_costs = 'total'
256
+ # ----------------------------------------------------
257
+ self.company.delivery_costs = "total"
258
+ doc_form_edit = Form(doc)
259
+ # Set new header totals, which should trigger inverse methods to distribute
260
+ doc_form_edit.amount_freight_value = 30.0
261
+ doc_form_edit.amount_insurance_value = 60.0
262
+ doc_form_edit.amount_other_value = 90.0
263
+ doc_after_total_update = doc_form_edit.save()
264
+
265
+ line1 = doc_after_total_update.fiscal_line_ids[0]
266
+ line2 = doc_after_total_update.fiscal_line_ids[1]
267
+
268
+ # Assert values were distributed proportionally to price_gross
269
+ # (2000 vs 500 -> 80% vs 20%)
270
+ # Freight: 30.0 * 0.8 = 24.0 | 30.0 * 0.2 = 6.0
271
+ self.assertAlmostEqual(line1.freight_value, 24.0)
272
+ self.assertAlmostEqual(line2.freight_value, 6.0)
273
+ # Insurance: 60.0 * 0.8 = 48.0 | 60.0 * 0.2 = 12.0
274
+ self.assertAlmostEqual(line1.insurance_value, 48.0)
275
+ self.assertAlmostEqual(line2.insurance_value, 12.0)
276
+ # Other: 90.0 * 0.8 = 72.0 | 90.0 * 0.2 = 18.0
277
+ self.assertAlmostEqual(line1.other_value, 72.0)
278
+ self.assertAlmostEqual(line2.other_value, 18.0)
279
+
280
+ # Assert final fiscal totals are recomputed correctly (top-down calculation)
281
+ # price_gross = 2500
282
+ # landed_costs = 30 + 60 + 90 = 180
283
+ # fiscal_amount_untaxed (IPI Base) = 2500 + 180 = 2680
284
+ self.assertAlmostEqual(doc_after_total_update.fiscal_amount_untaxed, 2680.00)
285
+ # Line 1 IPI Base = 2000 (product) + 24 (freight) + 48 (insurance)
286
+ # + 72 (other) = 2144
287
+ # Line 1 IPI Value = 2144 * 3.25% = 69.68
288
+ self.assertAlmostEqual(line1.ipi_base, 2144.00)
289
+ self.assertAlmostEqual(line1.ipi_value, 69.68, places=2)
290
+
291
+ # Line 2 IPI Base = 500 (product) + 6 (freight) + 12 (insurance)
292
+ # + 18 (other) = 536
293
+ # Line 2 IPI Value = 536 * 5% = 26.80
294
+ self.assertAlmostEqual(line2.ipi_base, 536.00)
295
+ self.assertAlmostEqual(line2.ipi_value, 26.80, places=2)
296
+
297
+ # fiscal_amount_tax (IPI) = 69.68 + 26.80 = 96.48
298
+ self.assertAlmostEqual(
299
+ doc_after_total_update.fiscal_amount_tax, 96.48, places=2
300
+ )
301
+ # fiscal_amount_total = 2680.00 + 96.48 = 2776.48
302
+ self.assertAlmostEqual(
303
+ doc_after_total_update.fiscal_amount_total, 2776.48, places=2
304
+ )
305
+
306
+ def test_difal_calculation(self):
307
+ partner = self.env.ref("l10n_br_base.res_partner_cliente5_pe")
308
+ partner.ind_ie_dest = "9"
309
+ doc_form = Form(
310
+ self.env["l10n_br_fiscal.document"].with_context(
311
+ default_fiscal_operation_type="out",
312
+ )
313
+ )
314
+ doc_form.company_id = self.company
315
+ doc_form.partner_id = partner
316
+ doc_form.fiscal_operation_id = self.env.ref("l10n_br_fiscal.fo_venda")
317
+
318
+ product = self.env.ref("product.product_product_6")
319
+ with doc_form.fiscal_line_ids.new() as line_form:
320
+ line_form.product_id = product
321
+ line_form.price_unit = 100.0
322
+ line_form.quantity = 1.0
323
+
324
+ doc = doc_form.save()
325
+ line = doc.fiscal_line_ids[0]
326
+ self.assertEqual(line.icms_destination_base, 100.0)
327
+ self.assertEqual(line.icms_origin_percent, 7.0)
328
+ self.assertEqual(line.icms_destination_percent, 20.5)
329
+ self.assertEqual(line.icms_destination_value, 13.5)
@@ -40,15 +40,10 @@ class TestFiscalDocumentGeneric(TransactionCase):
40
40
  def test_nfe_same_state(self):
41
41
  """Test NFe same state."""
42
42
  for line in self.nfe_same_state.fiscal_line_ids:
43
- line._onchange_product_id_fiscal()
44
-
45
43
  # Restore the original price_unit value,
46
44
  # as the product change might have altered it.
47
45
  line.price_unit = 100
48
46
 
49
- line._onchange_fiscal_operation_id()
50
- line._onchange_fiscal_taxes()
51
-
52
47
  if "Revenda" in line.fiscal_operation_line_id.name:
53
48
  self.assertEqual(
54
49
  line.cfop_id.code,
@@ -163,10 +158,6 @@ class TestFiscalDocumentGeneric(TransactionCase):
163
158
  def test_nfe_other_state(self):
164
159
  """Test NFe other state."""
165
160
  for line in self.nfe_other_state.fiscal_line_ids:
166
- line._onchange_product_id_fiscal()
167
- line._onchange_fiscal_operation_id()
168
- line._onchange_fiscal_taxes()
169
-
170
161
  if "Revenda" in line.fiscal_operation_line_id.name:
171
162
  self.assertEqual(
172
163
  line.cfop_id.code,
@@ -278,10 +269,6 @@ class TestFiscalDocumentGeneric(TransactionCase):
278
269
  def test_nfe_not_taxpayer(self):
279
270
  """Test NFe not taxpayer."""
280
271
  for line in self.nfe_not_taxpayer.fiscal_line_ids:
281
- line._onchange_product_id_fiscal()
282
- line._onchange_fiscal_operation_id()
283
- line._onchange_fiscal_taxes()
284
-
285
272
  if "Revenda" in line.fiscal_operation_line_id.name:
286
273
  self.assertEqual(
287
274
  line.cfop_id.code,
@@ -380,10 +367,6 @@ class TestFiscalDocumentGeneric(TransactionCase):
380
367
  def test_nfe_not_taxpayer_not_company(self):
381
368
  """Test NFe not taxpayer not Company."""
382
369
  for line in self.nfe_not_taxpayer_pf.fiscal_line_ids:
383
- line._onchange_product_id_fiscal()
384
- line._onchange_fiscal_operation_id()
385
- line._onchange_fiscal_taxes()
386
-
387
370
  if "Revenda" in line.fiscal_operation_line_id.name:
388
371
  self.assertEqual(
389
372
  line.cfop_id.code,
@@ -482,10 +465,6 @@ class TestFiscalDocumentGeneric(TransactionCase):
482
465
  def test_nfe_export(self):
483
466
  """Test NFe export."""
484
467
  for line in self.nfe_export.fiscal_line_ids:
485
- line._onchange_product_id_fiscal()
486
- line._onchange_fiscal_operation_id()
487
- line._onchange_fiscal_taxes()
488
-
489
468
  if "Revenda" in line.fiscal_operation_line_id.name:
490
469
  self.assertEqual(
491
470
  line.cfop_id.code,
@@ -576,8 +555,6 @@ class TestFiscalDocumentGeneric(TransactionCase):
576
555
  def test_nfe_sn_same_state(self):
577
556
  """Test NFe Simples Nacional same state."""
578
557
  for line in self.nfe_sn_same_state.fiscal_line_ids:
579
- line._onchange_product_id_fiscal()
580
-
581
558
  # set fake estimate tax
582
559
  line.ncm_id.tax_estimate_ids.create(
583
560
  {
@@ -588,9 +565,9 @@ class TestFiscalDocumentGeneric(TransactionCase):
588
565
  "federal_taxes_national": 33.00,
589
566
  }
590
567
  )
591
-
592
- line._onchange_fiscal_operation_id()
593
- line._onchange_fiscal_taxes()
568
+ # força o compute, pois não é chamado automaticamente
569
+ # quando uma informação externa muda.
570
+ line._compute_tax_fields()
594
571
 
595
572
  if "Revenda" in line.fiscal_operation_line_id.name:
596
573
  self.assertEqual(
@@ -689,10 +666,6 @@ class TestFiscalDocumentGeneric(TransactionCase):
689
666
  def test_nfe_sn_other_state(self):
690
667
  """Test NFe SN other state."""
691
668
  for line in self.nfe_sn_other_state.fiscal_line_ids:
692
- line._onchange_product_id_fiscal()
693
- line._onchange_fiscal_operation_id()
694
- line._onchange_fiscal_taxes()
695
-
696
669
  if "Revenda" in line.fiscal_operation_line_id.name:
697
670
  self.assertEqual(
698
671
  line.cfop_id.code,
@@ -787,10 +760,6 @@ class TestFiscalDocumentGeneric(TransactionCase):
787
760
  def test_nfe_sn_not_taxpayer(self):
788
761
  """Test NFe SN not taxpayer."""
789
762
  for line in self.nfe_sn_not_taxpayer.fiscal_line_ids:
790
- line._onchange_product_id_fiscal()
791
- line._onchange_fiscal_operation_id()
792
- line._onchange_fiscal_taxes()
793
-
794
763
  if "Revenda" in line.fiscal_operation_line_id.name:
795
764
  self.assertEqual(
796
765
  line.cfop_id.code,
@@ -872,10 +841,6 @@ class TestFiscalDocumentGeneric(TransactionCase):
872
841
  def test_nfe_sn_export(self):
873
842
  """Test NFe SN export."""
874
843
  for line in self.nfe_sn_export.fiscal_line_ids:
875
- line._onchange_product_id_fiscal()
876
- line._onchange_fiscal_operation_id()
877
- line._onchange_fiscal_taxes()
878
-
879
844
  if "Revenda" in line.fiscal_operation_line_id.name:
880
845
  self.assertEqual(
881
846
  line.cfop_id.code,
@@ -983,10 +948,16 @@ class TestFiscalDocumentGeneric(TransactionCase):
983
948
  def test_nfe_comments(self):
984
949
  self.nfe_not_taxpayer._document_comment()
985
950
  additional_data = self.nfe_not_taxpayer.fiscal_line_ids[0].additional_data
986
- self.assertEqual(
987
- additional_data,
988
- "manual comment test",
989
- )
951
+ if self.env.ref("base.lang_pt_BR").active:
952
+ self.assertEqual(
953
+ additional_data,
954
+ "manual comment test - Valor Aprox. dos Tributos: R$\xa00,00",
955
+ )
956
+ else: # no pt_BR amount formatting available
957
+ self.assertEqual(
958
+ additional_data,
959
+ "manual comment test - Valor Aprox. dos Tributos: R$\xa00.00",
960
+ )
990
961
 
991
962
  def test_fields_freight_insurance_other_costs(self):
992
963
  """Test fields Freight, Insurance and Other Costs when
@@ -13,12 +13,7 @@ class TestFiscalDocumentNFSe(TransactionCase):
13
13
 
14
14
  def test_nfse_same_state(self):
15
15
  """Test NFSe same state."""
16
-
17
16
  for line in self.nfse_same_state.fiscal_line_ids:
18
- line._onchange_product_id_fiscal()
19
- line._onchange_fiscal_operation_id()
20
- line._onchange_fiscal_taxes()
21
-
22
17
  self.assertEqual(
23
18
  line.fiscal_operation_line_id.name,
24
19
  "Prestação de Serviço",
@@ -0,0 +1,60 @@
1
+ # Copyright (C) 2025 Renato Lima - Akretion <renato.lima@akretion.com.br>
2
+ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
3
+
4
+ from psycopg2 import IntegrityError
5
+
6
+ from odoo.exceptions import ValidationError
7
+ from odoo.tests import TransactionCase
8
+ from odoo.tools import mute_logger
9
+
10
+
11
+ class TestFiscalDocumentSerie(TransactionCase):
12
+ @classmethod
13
+ def setUpClass(cls):
14
+ super().setUpClass()
15
+ cls.env = cls.env(context=dict(cls.env.context, tracking_disable=True))
16
+
17
+ # Company
18
+ cls.company_sn = cls.env.ref("l10n_br_base.empresa_simples_nacional")
19
+
20
+ # Fiscal Document Type
21
+ cls.document_type_nfe = cls.env.ref("l10n_br_fiscal.document_55")
22
+
23
+ cls.document_serie_nfe_5 = cls.env["l10n_br_fiscal.document.serie"].create(
24
+ {
25
+ "code": "5",
26
+ "name": "Serie 5",
27
+ "document_type_id": cls.document_type_nfe.id,
28
+ "company_id": cls.company_sn.id,
29
+ }
30
+ )
31
+
32
+ # Fiscal Document
33
+ cls.document = cls.env["l10n_br_fiscal.document"].create(
34
+ {
35
+ "company_id": cls.company_sn.id,
36
+ "document_type_id": cls.document_type_nfe.id,
37
+ "document_serie_id": cls.document_serie_nfe_5.id,
38
+ "partner_id": cls.env.ref("l10n_br_base.res_partner_cliente1_sp").id,
39
+ "state_edoc": "cancelada",
40
+ }
41
+ )
42
+
43
+ def test_document_serie_duplicated(self):
44
+ """Test document serie duplicate constraint."""
45
+ document_serie = self.env["l10n_br_fiscal.document.serie"]
46
+ document_serie_values = {
47
+ "code": "10",
48
+ "name": "Serie 10",
49
+ "document_type_id": self.document_type_nfe.id,
50
+ "company_id": self.company_sn.id,
51
+ }
52
+
53
+ with self.assertRaises(IntegrityError), mute_logger("odoo.sql_db"):
54
+ for _ in range(2):
55
+ document_serie.create(document_serie_values)
56
+
57
+ def test_document_serie_code_in_use(self):
58
+ """Test document serie code in use constraint."""
59
+ with self.assertRaises(ValidationError):
60
+ self.document_serie_nfe_5.write({"code": "7"})
@@ -35,15 +35,12 @@ class TestTaxBenefit(TransactionCase):
35
35
  "state": "approved",
36
36
  }
37
37
  )
38
+ # force update
39
+ cls.nfe_tax_benefit.fiscal_line_ids._compute_fiscal_tax_ids()
38
40
 
39
41
  def test_nfe_tax_benefit(self):
40
42
  """Test NFe with tax benefit."""
41
-
42
43
  for line in self.nfe_tax_benefit.fiscal_line_ids:
43
- line._onchange_product_id_fiscal()
44
- line._onchange_fiscal_operation_id()
45
- line._onchange_fiscal_taxes()
46
-
47
44
  self.assertEqual(
48
45
  line.icms_tax_benefit_id,
49
46
  self.tax_benefit,
@@ -37,6 +37,7 @@
37
37
  <field name="service_type_id" force_save="1" invisible="1" />
38
38
  <field name="city_taxation_code_id" force_save="1" invisible="1" />
39
39
  <field name="uot_id" force_save="1" invisible="1" />
40
+ <field name="uom_id" force_save="1" invisible="1" />
40
41
  <field name="fiscal_price" force_save="1" invisible="1" />
41
42
  <field name="fiscal_quantity" force_save="1" invisible="1" />
42
43
  <field
@@ -102,13 +102,13 @@
102
102
  <page name="amounts" string="Amounts">
103
103
  <group>
104
104
  <group>
105
- <field name="amount_untaxed" />
105
+ <field name="fiscal_amount_untaxed" />
106
106
  <field name="amount_fiscal" />
107
- <field name="amount_tax" />
107
+ <field name="fiscal_amount_tax" />
108
108
  <field name="estimate_tax" />
109
109
  </group>
110
110
  <group>
111
- <field name="amount_total" />
111
+ <field name="fiscal_amount_total" />
112
112
  <field name="amount_tax_withholding" />
113
113
  <field name="amount_taxed" />
114
114
  </group>
@@ -71,9 +71,9 @@
71
71
  <field name="document_date" />
72
72
  <field name="fiscal_operation_id" />
73
73
  <field name="partner_id" />
74
- <field name="amount_untaxed" />
75
- <field name="amount_tax" />
76
- <field name="amount_total" />
74
+ <field name="fiscal_amount_untaxed" />
75
+ <field name="fiscal_amount_tax" />
76
+ <field name="fiscal_amount_total" />
77
77
  <field name="state" column_invisible="True" />
78
78
  <field
79
79
  name="state_edoc"
@@ -234,7 +234,10 @@
234
234
  />
235
235
  <field name="partner_shipping_id" />
236
236
  </group>
237
- <group name="l10n_br_fiscal">
237
+ <group
238
+ name="l10n_br_fiscal"
239
+ invisible="document_type in ('57', '08', '09', '10', '11', '26', '67', '8B')"
240
+ >
238
241
  <field
239
242
  name="fiscal_operation_id"
240
243
  options="{'no_create': True, 'no_create_edit': True}"
@@ -292,19 +295,21 @@
292
295
  />
293
296
  <field name="company_id" invisible="1" />
294
297
  </group>
295
- <group
296
- name="CT-e Info"
297
- invisible="[('document_type_id.code', 'in', ['57', '08', '09', '10', '11', '26', '67', '8B'])]"
298
- >
299
- <field name="transport_modal" />
300
- <field name="service_provider" />
301
- </group>
302
298
  </group>
303
299
  <notebook>
304
300
  <page name="products" string="Products and Services">
305
301
  <field
306
302
  name="fiscal_line_ids"
307
- context="{'form_view_ref': 'l10n_br_fiscal.document_line_form', 'default_document_id': id, 'default_company_id': company_id, 'default_partner_id': partner_id, 'default_fiscal_operation_type': fiscal_operation_type, 'default_fiscal_operation_id': fiscal_operation_id, 'no_subcall': True}"
303
+ context="{
304
+ 'form_view_ref': 'l10n_br_fiscal.document_line_form',
305
+ 'default_document_id': id,
306
+ 'default_company_id': company_id,
307
+ 'default_partner_id': partner_id,
308
+ 'default_fiscal_operation_type': fiscal_operation_type,
309
+ 'default_fiscal_operation_id': fiscal_operation_id,
310
+ 'default_ind_final': ind_final,
311
+ 'no_subcall': True,
312
+ }"
308
313
  >
309
314
  <list>
310
315
  <field name="product_id" />
@@ -315,7 +320,7 @@
315
320
  name="fiscal_tax_ids"
316
321
  widget="many2many_tags"
317
322
  />
318
- <field name="amount_total" sum="Total" />
323
+ <field name="fiscal_amount_total" sum="Total" />
319
324
  </list>
320
325
  </field>
321
326
  </page>
@@ -413,8 +418,8 @@
413
418
  readonly="delivery_costs == 'line' and not force_compute_delivery_costs_by_total"
414
419
  />
415
420
  <field name="amount_estimate_tax" />
416
- <field name="amount_tax" />
417
- <field name="amount_total" />
421
+ <field name="fiscal_amount_tax" />
422
+ <field name="fiscal_amount_total" />
418
423
  <field name="amount_tax_withholding" />
419
424
  <field name="amount_financial_total" />
420
425
  <field name="amount_financial_total_gross" />
@@ -75,15 +75,6 @@
75
75
  parent="document_sub_menu"
76
76
  sequence="20"
77
77
  />
78
- <!-- All Documents -->
79
- <menuitem
80
- id="document_all_menu"
81
- action="document_all_action"
82
- name="All low level Documents"
83
- groups="l10n_br_fiscal.group_user,l10n_br_fiscal.group_manager"
84
- parent="document_sub_menu"
85
- sequence="30"
86
- />
87
78
  <!-- Partners -->
88
79
  <menuitem
89
80
  id="partners_menu"
@@ -86,7 +86,7 @@
86
86
  <span title="A enviar">
87
87
  <t
88
88
  t-esc="dashboard.number_2confirm"
89
- />A enviar</span>
89
+ /> A enviar</span>
90
90
  </a>
91
91
  </div>
92
92
  </div>
@@ -100,7 +100,7 @@
100
100
  >
101
101
  <t
102
102
  t-esc="dashboard.number_authorized"
103
- />Autorizados</a>
103
+ /> Autorizados</a>
104
104
  </div>
105
105
  </div>
106
106
  <div class="row">
@@ -113,7 +113,7 @@
113
113
  <span title="Cancelados">
114
114
  <t
115
115
  t-esc="dashboard.number_cancelled"
116
- />Cancelados</span>
116
+ /> Cancelados</span>
117
117
  </a>
118
118
  </div>
119
119
  </div>
@@ -62,13 +62,21 @@
62
62
  <field
63
63
  name="icms_origin"
64
64
  invisible="fiscal_type == '09'"
65
- required="fiscal_type != '09'"
65
+ required="fiscal_type != '09' and (sale_ok or purchase_ok)"
66
+ />
67
+ <field
68
+ name="ncm_id"
69
+ required="sale_ok or purchase_ok"
70
+ options="{'no_create': True, 'no_create_edit': True}"
71
+ />
72
+ <field
73
+ name="tax_icms_or_issqn"
74
+ required="sale_ok or purchase_ok"
66
75
  />
67
- <field name="ncm_id" required="1" />
68
- <field name="tax_icms_or_issqn" required="1" />
69
76
  <field
70
77
  name="service_type_id"
71
78
  invisible="fiscal_type != '09'"
79
+ options="{'no_create': True, 'no_create_edit': True}"
72
80
  />
73
81
  <field
74
82
  name="city_taxation_code_ids"
@@ -85,16 +93,35 @@
85
93
  </field>
86
94
  </group>
87
95
  <group>
88
- <field name="fiscal_genre_id" required="1" />
89
- <field name="cest_id" invisible="fiscal_type == '09'" />
90
- <field name="nbs_id" invisible="fiscal_type != '09'" />
96
+ <field
97
+ name="fiscal_genre_id"
98
+ required="sale_ok"
99
+ options="{'no_create': True, 'no_create_edit': True}"
100
+ />
101
+ <field
102
+ name="cest_id"
103
+ invisible="fiscal_type == '09'"
104
+ options="{'no_create': True, 'no_create_edit': True}"
105
+ />
106
+ <field
107
+ name="nbm_id"
108
+ invisible="fiscal_type == '09'"
109
+ options="{'no_create': True, 'no_create_edit': True}"
110
+ />
111
+ <field
112
+ name="nbs_id"
113
+ invisible="fiscal_type != '09'"
114
+ options="{'no_create': True, 'no_create_edit': True}"
115
+ />
91
116
  <field
92
117
  name="ipi_guideline_class_id"
93
118
  invisible="fiscal_type == '09'"
119
+ options="{'no_create': True, 'no_create_edit': True}"
94
120
  />
95
121
  <field
96
122
  name="ipi_control_seal_id"
97
123
  invisible="fiscal_type == '09'"
124
+ options="{'no_create': True, 'no_create_edit': True}"
98
125
  />
99
126
  </group>
100
127
  <group string="Tax UOM">