Skip to content

Commit

Permalink
[IMP] l10n_br_fiscal: icms benefit
Browse files Browse the repository at this point in the history
  • Loading branch information
CristianoMafraJunior committed Feb 28, 2025
1 parent fe5920c commit d296764
Show file tree
Hide file tree
Showing 14 changed files with 182 additions and 85 deletions.
1 change: 1 addition & 0 deletions l10n_br_fiscal/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
"views/tax_group_view.xml",
"views/tax_view.xml",
"views/tax_definition_view.xml",
"views/icms_benefit_view.xml",
"views/icms_regulation_view.xml",
"views/icms_relief_view.xml",
"views/tax_pis_cofins_view.xml",
Expand Down
1 change: 1 addition & 0 deletions l10n_br_fiscal/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
from . import tax_ipi_guideline_class
from . import tax_estimate
from . import tax_definition
from . import icms_benefit
from . import icms_regulation
from . import icms_relief
from . import document_type
Expand Down
7 changes: 1 addition & 6 deletions l10n_br_fiscal/models/document_line_mixin.py
Original file line number Diff line number Diff line change
Expand Up @@ -347,12 +347,7 @@ def _operation_domain(self):
)

icms_tax_benefit_id = fields.Many2one(
comodel_name="l10n_br_fiscal.tax.definition",
string="Tax Benefit",
domain=[
("is_benefit", "=", True),
("tax_domain", "=", TAX_DOMAIN_ICMS),
],
"l10n_br_fiscal.icms.benefit", string="Fiscal Benefit"
)

icms_tax_benefit_code = fields.Char(
Expand Down
22 changes: 5 additions & 17 deletions l10n_br_fiscal/models/document_line_mixin_methods.py
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,11 @@ def _onchange_fiscal_operation_id(self):
product=self.product_id,
)
self._onchange_fiscal_operation_line_id()
for line in self.fiscal_operation_id.line_ids:
for tax_def in line.tax_definition_ids.icms_tax_benefit_id:
if tax_def.code:
self.icms_tax_benefit_id = tax_def.id
return

@api.onchange("fiscal_operation_line_id")
def _onchange_fiscal_operation_line_id(self):
Expand Down Expand Up @@ -405,7 +410,6 @@ def _onchange_fiscal_operation_line_id(self):

def _process_fiscal_mapping(self, mapping_result):
self.ipi_guideline_id = mapping_result["ipi_guideline"]
self.icms_tax_benefit_id = mapping_result["icms_tax_benefit_id"]
taxes = self.env["l10n_br_fiscal.tax"]
for tax in mapping_result["taxes"].values():
taxes |= tax
Expand Down Expand Up @@ -585,22 +589,6 @@ def _prepare_fields_icms(self, tax_dict):
"icms_relief_value": tax_dict.get("icms_relief", 0.0),
}

@api.onchange(
"icms_base",
"icms_percent",
"icms_reduction",
"icms_value",
"icms_destination_base",
"icms_origin_percent",
"icms_destination_percent",
"icms_sharing_percent",
"icms_origin_value",
"icms_tax_benefit_id",
)
def _onchange_icms_fields(self):
if self.icms_tax_benefit_id:
self.icms_tax_id = self.icms_tax_benefit_id.tax_id

def _prepare_fields_icmssn(self, tax_dict):
self.ensure_one()
cst_id = tax_dict.get("cst_id").id if tax_dict.get("cst_id") else False
Expand Down
76 changes: 76 additions & 0 deletions l10n_br_fiscal/models/icms_benefit.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
from odoo import _, api, fields, models
from odoo.exceptions import UserError, ValidationError

from ..constants.icms import ICMS_TAX_BENEFIT_TYPE


class IcmsBenefit(models.Model):
_name = "l10n_br_fiscal.icms.benefit"

code = fields.Char(size=8, required=True)

description = fields.Text()

type = fields.Selection(
selection=ICMS_TAX_BENEFIT_TYPE,
compute="_compute_type",
)

state = fields.Many2one(
comodel_name="res.country.state",
domain=[("country_id.code", "=", "BR")],
compute="_compute_state",
)

display_name = fields.Char(compute="_compute_display_name", store=True)

def name_get(self):
result = []
for record in self:
result.append((record.id, record.code))
return result

@api.depends("code")
def _compute_display_name(self):
for record in self:
record.display_name = f"{record.code}"

@api.constrains("code")
def _check_tax_benefit_code(self):
for record in self:
if record.code:
if len(record.code) != 8:
raise ValidationError(_("Tax benefit code must be 8 characters!"))

@api.depends("code")
def _compute_type(self):
valid_types = {choice[0] for choice in self._fields["type"].selection}
for record in self:
if record.code and len(record.code) >= 4:
extracted_type = record.code[3]
if extracted_type in valid_types:
record.type = extracted_type
else:
raise UserError(

Check warning on line 54 in l10n_br_fiscal/models/icms_benefit.py

View check run for this annotation

Codecov / codecov/patch

l10n_br_fiscal/models/icms_benefit.py#L54

Added line #L54 was not covered by tests
f"Invalid type '{extracted_type}' extracted from code "
f"'{record.code}'."
)
else:
record.type = False

Check warning on line 59 in l10n_br_fiscal/models/icms_benefit.py

View check run for this annotation

Codecov / codecov/patch

l10n_br_fiscal/models/icms_benefit.py#L59

Added line #L59 was not covered by tests

@api.depends("code")
def _compute_state(self):
for record in self:
record.state = (
self.env["res.country.state"]
.search(
[
("country_id.code", "=", "BR"),
("code", "=", record.code[:2].upper()),
],
limit=1,
)
.id
if record.code
else False
)
1 change: 0 additions & 1 deletion l10n_br_fiscal/models/operation_line.py
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,6 @@ def map_fiscal_taxes(
"taxes": {},
"cfop": False,
"ipi_guideline": self.env.ref("l10n_br_fiscal.tax_guideline_999"),
"icms_tax_benefit_id": False,
}

self.ensure_one()
Expand Down
47 changes: 11 additions & 36 deletions l10n_br_fiscal/models/tax_definition.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
OPERATION_STATE,
OPERATION_STATE_DEFAULT,
)
from ..constants.icms import ICMS_TAX_BENEFIT_TYPE


class TaxDefinition(models.Model):
Expand All @@ -21,6 +20,13 @@ class TaxDefinition(models.Model):
_description = "Tax Definition"

def _get_complete_name(self):
if self.is_benefit and self.tax_id.name:
return (
f"{self.tax_group_id.name}-{self.tax_id.name}-"
f"{self.cst_code}-{self.code}"
)
elif self.is_benefit:
return f"{self.tax_group_id.name}-{self.code}"

Check warning on line 29 in l10n_br_fiscal/models/tax_definition.py

View check run for this annotation

Codecov / codecov/patch

l10n_br_fiscal/models/tax_definition.py#L29

Added line #L29 was not covered by tests
return f"{self.tax_group_id.name}-{self.tax_id.name}-{self.cst_code}"

@api.depends("tax_group_id", "tax_id", "cst_code")
Expand All @@ -38,19 +44,10 @@ def name_get(self):

display_name = fields.Char(compute="_compute_display_name", store=True)

code = fields.Char(
size=8,
states={"draft": [("readonly", False)]},
)

name = fields.Char(
states={"draft": [("readonly", False)]},
)

description = fields.Text(
states={"draft": [("readonly", False)]},
)

type_in_out = fields.Selection(
selection=FISCAL_IN_OUT,
string="Type",
Expand Down Expand Up @@ -276,11 +273,12 @@ def name_get(self):
states={"draft": [("readonly", False)]},
)

benefit_type = fields.Selection(
selection=ICMS_TAX_BENEFIT_TYPE,
states={"draft": [("readonly", False)]},
icms_tax_benefit_id = fields.Many2one(
"l10n_br_fiscal.icms.benefit", string="Fiscal Benefit"
)

code = fields.Char(related="icms_tax_benefit_id.code", store=True)

def _get_search_domain(self, tax_definition):
"""Create domain to be used in contraints methods"""
domain = [
Expand Down Expand Up @@ -588,26 +586,3 @@ def _check_cfop_id(self):
"for this CFOP and Tax Group !"
)
)

@api.constrains("is_benefit", "code", "benefit_type", "state_from_id")
def _check_tax_benefit_code(self):
for record in self:
if record.is_benefit:
if record.code:
if len(record.code) != 8:
raise ValidationError(
_("Tax benefit code must be 8 characters!")
)

if record.code[:2].upper() != record.state_from_id.code.upper():
raise ValidationError(
_("Tax benefit code must be start with state code!")
)

if record.code[3:4] != record.benefit_type:
raise ValidationError(
_(
"The tax benefit code must contain "
"the type of benefit!"
)
)
2 changes: 2 additions & 0 deletions l10n_br_fiscal/security/ir.model.access.csv
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@
"l10n_br_fiscal_comment_manager","Comment for Manager","model_l10n_br_fiscal_comment","l10n_br_fiscal.group_manager",1,1,1,1
"l10n_br_fiscal_tax_definition_user","Tax Definition for User","model_l10n_br_fiscal_tax_definition","base.group_user",1,0,0,0
"l10n_br_fiscal_tax_definition_manager","Tax Definition for Manager","model_l10n_br_fiscal_tax_definition","l10n_br_fiscal.group_manager",1,1,1,1
"l10n_br_fiscal_icms_benefit_user","Icms Benefit for User","model_l10n_br_fiscal_icms_benefit","base.group_user",1,0,0,0
"l10n_br_fiscal_icms_benefit_manager","Icms Benefit for Manager","model_l10n_br_fiscal_icms_benefit","l10n_br_fiscal.group_manager",1,1,1,1
"l10n_br_fiscal_tax_pis_cofins_user","Tax PIS COFINS for User","model_l10n_br_fiscal_tax_pis_cofins","l10n_br_fiscal.group_user",1,0,0,0
"l10n_br_fiscal_tax_pis_cofins_manager","Tax PIS COFINS for Manager","model_l10n_br_fiscal_tax_pis_cofins","l10n_br_fiscal.group_manager",1,0,0,0
"l10n_br_fiscal_tax_pis_cofins_maintenance","Tax PIS COFINS for Maintenance","model_l10n_br_fiscal_tax_pis_cofins","l10n_br_fiscal.group_data_maintenance",1,1,1,1
Expand Down
11 changes: 4 additions & 7 deletions l10n_br_fiscal/static/description/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,10 @@

/*
:Author: David Goodger (goodger@python.org)
:Id: $Id: html4css1.css 9511 2024-01-13 09:50:07Z milde $
:Id: $Id: html4css1.css 8954 2022-01-20 10:10:25Z milde $
:Copyright: This stylesheet has been placed in the public domain.
Default cascading style sheet for the HTML output of Docutils.
Despite the name, some widely supported CSS2 features are used.
See https://docutils.sourceforge.io/docs/howto/html-stylesheets.html for how to
customize this style sheet.
Expand Down Expand Up @@ -275,7 +274,7 @@
margin-left: 2em ;
margin-right: 2em }

pre.code .ln { color: gray; } /* line numbers */
pre.code .ln { color: grey; } /* line numbers */
pre.code, code { background-color: #eeeeee }
pre.code .comment, code .comment { color: #5C6576 }
pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold }
Expand All @@ -301,7 +300,7 @@
span.pre {
white-space: pre }

span.problematic, pre.problematic {
span.problematic {
color: red }

span.section-subtitle {
Expand Down Expand Up @@ -534,9 +533,7 @@ <h1>Contributors</h1>
<div class="section" id="maintainers">
<h1>Maintainers</h1>
<p>This module is maintained by the OCA.</p>
<a class="reference external image-reference" href="https://odoo-community.org">
<img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" />
</a>
<a class="reference external image-reference" href="https://odoo-community.org"><img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" /></a>
<p>OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.</p>
Expand Down
36 changes: 31 additions & 5 deletions l10n_br_fiscal/tests/test_tax_benefit.py
Original file line number Diff line number Diff line change
@@ -1,34 +1,38 @@
# Copyright 2023 Akretion - Renato Lima <renato.lima@akretion.com.br>
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

from odoo.exceptions import ValidationError
from odoo.tests import SavepointCase


class TestTaxBenefit(SavepointCase):
def setUp(self):
super().setUp()
self.nfe_tax_benefit = self.env.ref("l10n_br_fiscal.demo_nfe_tax_benefit")
self.icms_benefit = self.env["l10n_br_fiscal.icms.benefit"].create(
{
"code": "SP810001",
"description": "TAX BENEFIT DEMO",
}
)
self.tax_benefit = self.env["l10n_br_fiscal.tax.definition"].create(
{
"icms_regulation_id": self.env.ref(
"l10n_br_fiscal.tax_icms_regulation"
).id,
"tax_group_id": self.env.ref("l10n_br_fiscal.tax_group_icms").id,
"code": "SP810001",
"name": "TAX BENEFIT DEMO",
"description": "TAX BENEFIT DEMO",
"benefit_type": "1",
"is_benefit": True,
"is_taxed": True,
"is_debit_credit": True,
"custom_tax": True,
"tax_id": self.env.ref("l10n_br_fiscal.tax_icms_12_red_26_57").id,
"cst_id": self.env.ref("l10n_br_fiscal.cst_icms_20").id,
"state_from_id": self.env.ref("base.state_br_sp").id,
"state_to_ids": [(6, 0, self.env.ref("base.state_br_mg").ids)],
"ncms": "73269090",
"ncm_ids": [(6, 0, self.env.ref("l10n_br_fiscal.ncm_73269090").ids)],
"state": "approved",
"icms_tax_benefit_id": self.icms_benefit.id,
}
)

Expand All @@ -37,6 +41,9 @@ def test_nfe_tax_benefit(self):

self.nfe_tax_benefit._onchange_document_serie_id()
self.nfe_tax_benefit._onchange_fiscal_operation_id()
self.tax_benefit.fiscal_operation_line_id = (
self.nfe_tax_benefit.fiscal_operation_id.line_ids[:1]
)

for line in self.nfe_tax_benefit.fiscal_line_ids:
line._onchange_product_id_fiscal()
Expand All @@ -48,6 +55,25 @@ def test_nfe_tax_benefit(self):

self.assertEqual(
line.icms_tax_benefit_id,
self.tax_benefit,
self.tax_benefit.icms_tax_benefit_id,
"Document line must have tax benefit",
)
self.assertEqual(
self.tax_benefit.display_name,
"ICMS-ICMS 12% Com Red. 26,57%-20-SP810001",
)
self.assertEqual(self.icms_benefit.type, "1")
self.assertEqual(self.icms_benefit.display_name, "SP810001")
self.assertEqual(self.icms_benefit.state.code, "SP")
self.assertEqual(
self.icms_benefit.name_get(), [(self.icms_benefit.id, "SP810001")]
)

def test_invalid_tax_benefit_code(self):
with self.assertRaises(ValidationError):
self.icms_benefit = self.env["l10n_br_fiscal.icms.benefit"].create(
{
"code": "SP81",
"description": "Invalid Tax Benefit",
}
)
Loading

0 comments on commit d296764

Please sign in to comment.