Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[12.0][REF] Cálculo da alíquota efetiva para empresas do Simples Nacional. #1831

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion l10n_br_account/models/account_invoice.py
Original file line number Diff line number Diff line change
Expand Up @@ -444,7 +444,7 @@ def get_taxes_values(self):
fiscal_price=line.fiscal_price,
fiscal_quantity=line.fiscal_quantity,
uot=line.uot_id,
icmssn_range=line.icmssn_range_id,
cfop_type_move=line.cfop_id.type_move,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

O campo icmssn_range não deveria ser eliminado pois deveria ser usado no calculo dos impostos

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

com a alteração dessa pr o uso deste campo dentro do calculo do imposto perde o sentido, pois com a pr já temos todos os impostos do simples nacional previamente calculados dentro das tabelas effective_tax, dentro desse modelo já é marcado qual é o range atual da empresa, na hora de calcular os impostos é só puxar desse modelo.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mas você precisa calcular o valor do percentual de crédito do ICMS para ser destacado no documento fiscal, isso deveria ser encapsulado no l10n_br_fiscal.tax

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tá tudo encapsulado no modelo effective_tax do simples nacional, que já é calculado no momento que informa a receita bruta dos 12 meses, isso facilita um contador revisar as informações. mas essas informações podem ser usadas pelo 10n_br_fiscal.tax.

ind_final=line.ind_final,
)["taxes"]

Expand Down
4 changes: 2 additions & 2 deletions l10n_br_account/models/account_tax.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def compute_all(
fiscal_price=None,
fiscal_quantity=None,
uot=None,
icmssn_range=None,
cfop_type_move=None,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deveria ser adicionado o argumento cfop no método compute_all pois além do type_move outros campos do l10n_br_fiscal.cfop pode ser nos método compute_all

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pode ser também, coloquei o type_move direto pois é só isso que precisei no momento.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

O campo icmssn_range não deveria ser eliminado pois deveria ser usado no calculo dos impostos

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

o mesmo que #1831 (comment)

icms_origin=None,
ind_final=FINAL_CUSTOMER_NO,
):
Expand Down Expand Up @@ -102,7 +102,7 @@ def compute_all(
other_value=other_value,
freight_value=freight_value,
operation_line=operation_line,
icmssn_range=icmssn_range,
cfop_type_move=cfop_type_move,
icms_origin=icms_origin or product.icms_origin,
ind_final=ind_final,
)
Expand Down
1 change: 1 addition & 0 deletions l10n_br_fiscal/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@
"views/dfe/dfe_views.xml",
"views/operation_dashboard_view.xml",
"views/document_event_view.xml",
"views/simplified_tax_effecitve_view.xml",
# Wizards
"wizards/document_cancel_wizard.xml",
"wizards/document_correction_wizard.xml",
Expand Down
22 changes: 19 additions & 3 deletions l10n_br_fiscal/data/l10n_br_fiscal_comment_data.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,25 @@

<record id="fiscal_comment_sn_permissao_credito" model="l10n_br_fiscal.comment">
<field name="name">Simples Nacional permissão de crédito</field>
<field
name="comment"
>SIMPLES NACIONAL - Documento emitido por ME ou EPP optante pelo simples nacional, não gera direito a credito fiscal de IPI. Permite o aproveitamento de crédito de ICMS no valor de ${format_amount(doc.amount_icmssn_credit_value)}, nos termos do artigo 23 da LC 123/2006.</field>
<field name="comment">
SIMPLES NACIONAL - Documento emitido por ME ou EPP optante pelo simples nacional, não gera direito a credito fiscal de IPI. Permite o aproveitamento de crédito de ICMS no valor de ${format_amount(doc.amount_icmssn_credit_value)}, correspondente à alíquota de
%- if doc.is_sale_industry():
%- if not doc.is_sale_commerce():
${doc.company_id.icmssn_credit_industry}%
%- endif
%- endif
%- if doc.is_sale_commerce():
%- if not doc.is_sale_industry():
${doc.company_id.icmssn_credit_commerce}%
%- endif
%- endif
%- if doc.is_sale_industry():
%- if doc.is_sale_commerce():
${doc.company_id.icmssn_credit_industry}% para indústrialização e de ${doc.company_id.icmssn_credit_commerce}% para revenda
%- endif
%- endif
, nos termos do artigo 23 da LC 123/2006.
</field>
<field name="comment_type">fiscal</field>
<field name="object">l10n_br_fiscal.document.mixin</field>
</record>
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 @@ -52,6 +52,7 @@
from . import product_product
from . import simplified_tax
from . import simplified_tax_range
from . import simplified_tax_effective
from . import operation
from . import operation_line
from . import operation_document_type
Expand Down
23 changes: 0 additions & 23 deletions l10n_br_fiscal/models/document_fiscal_line_mixin.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
TAX_DOMAIN_PIS,
TAX_DOMAIN_PIS_ST,
TAX_DOMAIN_PIS_WH,
TAX_FRAMEWORK_SIMPLES_ALL,
TAX_ICMS_OR_ISSQN,
)
from ..constants.icms import (
Expand Down Expand Up @@ -58,21 +57,6 @@ class FiscalDocumentLineMixin(models.AbstractModel):
def _default_operation(self):
return False

@api.model
def _default_icmssn_range_id(self):
company = self.env.user.company_id
stax_range_id = self.env["l10n_br_fiscal.simplified.tax.range"]

if self.env.context.get("default_company_id"):
company = self.env["res.company"].browse(
self.env.context.get("default_company_id")
)

if company.tax_framework in TAX_FRAMEWORK_SIMPLES_ALL:
stax_range_id = company.simplified_tax_range_id

return stax_range_id

@api.model
def _operation_domain(self):
domain = [("state", "=", "approved")]
Expand Down Expand Up @@ -488,7 +472,6 @@ def _operation_domain(self):
icmssn_range_id = fields.Many2one(
comodel_name="l10n_br_fiscal.simplified.tax.range",
string="Simplified Range Tax",
default=_default_icmssn_range_id,
)

icmssn_tax_id = fields.Many2one(
Expand Down Expand Up @@ -855,12 +838,6 @@ def _operation_domain(self):

inss_wh_value = fields.Monetary(string="INSS RET Value")

simple_value = fields.Monetary(string="National Simple Taxes")

simple_without_icms_value = fields.Monetary(
string="National Simple Taxes without ICMS"
)

comment_ids = fields.Many2many(
comodel_name="l10n_br_fiscal.comment",
relation="l10n_br_fiscal_document_line_mixin_comment_rel",
Expand Down
2 changes: 0 additions & 2 deletions l10n_br_fiscal/models/document_fiscal_line_mixin_methods.py
Original file line number Diff line number Diff line change
Expand Up @@ -546,8 +546,6 @@ def _set_fields_icmssn(self, tax_dict):
self.icmssn_percent = tax_dict.get("percent_amount")
self.icmssn_reduction = tax_dict.get("percent_reduction")
self.icmssn_credit_value = tax_dict.get("tax_value")
self.simple_value = self.icmssn_base * self.icmssn_range_id.total_tax_percent
self.simple_without_icms_value = self.simple_value - self.icmssn_credit_value

@api.onchange(
"icmssn_base", "icmssn_percent", "icmssn_reduction", "icmssn_credit_value"
Expand Down
8 changes: 8 additions & 0 deletions l10n_br_fiscal/models/document_fiscal_mixin_methods.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,14 @@ def _get_amount_lines(self):
"""Get object lines instaces used to compute fields"""
return self.mapped("line_ids")

def is_sale_industry(self):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Essa parte que define se é uma operação de industria ou comercio deveria estar no mapeamento dos impostos no fiscal.operation.line, lá se a empresa for do simples nacional deveria preencher o icmssn_range_id

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

esse método eu criei ele para facilitar o uso da informação na geração do comentário ( informações adicionais da nota fiscal) eu vou acessar pelo documento, por isso ele foi definido aqui, veja:

o icmssn_range_id no operation line deixa de ser usado com essa pr

types = self.line_ids.mapped("cfop_id").mapped("type_move")
return "sale_industry" in types

def is_sale_commerce(self):
types = self.line_ids.mapped("cfop_id").mapped("type_move")
return "sale_commerce" in types

@api.model
def _get_amount_fields(self):
"""Get all fields with 'amount_' prefix"""
Expand Down
151 changes: 79 additions & 72 deletions l10n_br_fiscal/models/res_company.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@

from odoo import api, fields, models

from odoo.addons import decimal_precision as dp

from ..constants.fiscal import (
COEFFICIENT_R,
INDUSTRY_TYPE,
Expand Down Expand Up @@ -49,12 +47,36 @@
rec["fiscal_dummy_id"] = self._default_fiscal_dummy_id().id
return rec

sn_effective_tax_ids = fields.One2many(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ao invés de criar outro objeto, esse campo poderia ser um m2m calculado para carregar os anexos que a empresa tem incidência pela dependendo dos CNAEs primário e secundários

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Com esse modelo que fiz acho que fica mais apresentável as informações, se eu por essas informações dentro do CNAEs acho que pode ficar um pouco confuso, não estou usando os CNAEs para determinar os impostos.
o proposito do effective_tax é reunir toda essa logica do calculo do imposto do simples nacional em um só lugar, esse modelo vai ter a informação de qual é o imposto total efetivo, qual é o range atual, qual é a alíquota para cada imposto separado ( icms, ipi, pis, etc.. ) e também fica mais simples de expor as informações ali no cadastro da empresa.
Como pode ver ali, o contador ao informar o faturamento da empresa já vai ter uma visualização completa de como vai ficar os impostos, inclusive para todos os anexos. fica mais simples para auditar as informações.

Antes dessa pr por exemplo, se quisesse saber qual era a alíquota do ICMS que o sistema tava calculando, tinha que primeiro emitir uma nota fiscal e ver dentro dela qual foi o ICMS calculado. Com a PR essa visualização já vem na hora.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cada anexo do simples nacional tem uma relação de CNAEs que a empresa deve ter para ser enquadrada naquele anexo por exemplo: Se a empresa tem o CNAE "4530702 - Comércio por atacado de pneumáticos e câmaras-de-ar" ela se enquadra no "ANEXO 1 Empresas de Comércio",

Era dessa forma que dependendo do CNAE Principal eu preenchia o campo do anexo na empresa e a faixa como você colocou alterou o campo para um o2m para outro objeto, o correto seria ter um campo m2m calculado para mostrar as faixas dos anexos que a empresa se enquadra mas usando o objeto l10n_br_fiscal.simplified.tax.range com o campo calculado da taxa efetiva como comentei no #1831 (comment)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sim, o CNAE é uma forma de ver se a empresa se enquadra no anexo 1 ou anexo 2 etc, mas se uma empresa tem vários CNAEs, pode não ser a melhor forma, pois é necessário identificar qual anexo cada linha da fatura se enquadra e a linha da fatura não tem a informação do CNAE dela, o produto também não trás essa informação. por exemplo, se você cria uma fatura com 2 itens:

  1. Produto: Picolé, CFOP 5101 - Venda de produção do estabelecimento. (indústria)
  2. Produto: Caixa de Isopor: CFOP 5102 - Venda de mercadoria adquirida ou recebida de terceiros (comércio)

supondo que o faturamento anual da empresa foi 815 mil no últimos 12 meses, o imposto efetivo para cada linha será:

linha 1) 8,44% simples nacional e permite aproveitamento do ICMS de 2,70%.
consigo chegar nessa informação pelo CFOP fazendo um mapeamento, se o CFOP for do tipo sale_industry eu pego o effective_tax da empresa em questão associada com o ANEXO 2 (Industria).

linha 2) 7,94% simples nacional e permite aproveitamento do ICMS de 2,66%.
neste caso, se o CFOP for do tipo sale_commerce, eu pego o effective_tax da empresa em questão associada com o ANEXO 2 (Industria).

image

por isso que acho que utilizar o CNAE não é a melhor forma de mapear os impostos do simples nacional.

comodel_name="l10n_br_fiscal.simplified.tax.effective",
inverse_name="company_id",
string="Effective Taxs",
help="Simples Nacional effective tax rate for each annex,"
"based on the range the company currently falls into.",
)

icmssn_credit_industry = fields.Float(
string="ICMS Credit rate for Industry",
help="Rate referring to the icms credit allowed when it is a sale of"
"industrialized product in the establishment."
"Applicable to Simple Nacional.",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo: "Simples Nacional."

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Vou corrigir obrigado!

readonly=True,
compute="_compute_icmssn",
)

icmssn_credit_commerce = fields.Float(
string="ICMS Credit rate for Commerce",
help="Rate referring to the icms credit allowed when it is a resale"
"of merchandise. Applicable to Simple Nacional.",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo: "Simples Nacional."

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Vou corrigir obrigado!

readonly=True,
compute="_compute_icmssn",
)

def _get_company_address_fields(self, partner):
"""Read the l10n_br specific functional fields."""
partner_fields = super()._get_company_address_fields(partner)
partner_fields.update(
{
"tax_framework": partner.tax_framework,
"cnae_main_id": partner.cnae_main_id,
}
)
Expand All @@ -65,6 +87,11 @@
for c in self:
c.partner_id.cnae_main_id = c.cnae_main_id

@api.depends("partner_id", "partner_id.tax_framework")
def _compute_tax_framework(self):
for c in self:
c.tax_framework = c.partner_id.tax_framework

def _inverse_tax_framework(self):
"""Write the l10n_br specific functional fields."""
for c in self:
Expand Down Expand Up @@ -101,53 +128,6 @@
)
return dummy_doc

@api.depends("cnae_main_id", "annual_revenue", "payroll_amount")
def _compute_simplified_tax(self):
for record in self:
record.coefficient_r = False
if record.payroll_amount and record.annual_revenue:
coefficient_r_percent = record.payroll_amount / record.annual_revenue
if coefficient_r_percent > COEFFICIENT_R:
record.coefficient_r = True
record.coefficient_r_percent = coefficient_r_percent

simplified_tax_id = self.env["l10n_br_fiscal.simplified.tax"].search(
[
("cnae_ids", "=", record.cnae_main_id.id),
("coefficient_r", "=", record.coefficient_r),
]
)
record.simplified_tax_id = simplified_tax_id

if simplified_tax_id:
tax_range = record.env["l10n_br_fiscal.simplified.tax.range"].search(
[
("simplified_tax_id", "=", simplified_tax_id.id),
("inital_revenue", "<=", record.annual_revenue),
("final_revenue", ">=", record.annual_revenue),
("simplified_tax_id.coefficient_r", "=", record.coefficient_r),
],
limit=1,
)
record.simplified_tax_range_id = tax_range

if record.simplified_tax_range_id and record.annual_revenue:
record.simplified_tax_percent = round(
(
(
(
record.annual_revenue
* record.simplified_tax_range_id.total_tax_percent
/ 100
)
- record.simplified_tax_range_id.amount_deduced
)
/ record.annual_revenue
)
* 100,
record.currency_id.decimal_places,
)

cnae_main_id = fields.Many2one(
comodel_name="l10n_br_fiscal.cnae",
compute="_compute_address",
Expand All @@ -169,8 +149,9 @@
tax_framework = fields.Selection(
selection=TAX_FRAMEWORK,
default=TAX_FRAMEWORK_NORMAL,
compute="_compute_address",
compute="_compute_tax_framework",
inverse="_inverse_tax_framework",
store=True,
string="Tax Framework",
)

Expand All @@ -197,27 +178,6 @@
currency_field="currency_id",
)

simplified_tax_id = fields.Many2one(
comodel_name="l10n_br_fiscal.simplified.tax",
compute="_compute_simplified_tax",
string="Simplified Tax",
readonly=True,
)

simplified_tax_range_id = fields.Many2one(
comodel_name="l10n_br_fiscal.simplified.tax.range",
compute="_compute_simplified_tax",
store=True,
readonly=True,
string="Simplified Tax Range",
)

simplified_tax_percent = fields.Float(
compute="_compute_simplified_tax",
store=True,
digits=dp.get_precision("Fiscal Tax Percent"),
)

payroll_amount = fields.Monetary(
string="Last Period Payroll Amount",
currency_field="currency_id",
Expand Down Expand Up @@ -555,3 +515,50 @@
self._set_tax_definition(self.tax_inss_wh_id)
else:
self._del_tax_definition(TAX_DOMAIN_INSS_WH)

@api.depends("annual_revenue", "payroll_amount")
def _compute_simplified_tax(self):
for record in self:
record._calculate_coefficient_r()

def _compute_icmssn(self):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Acho que seria informativo ter um docstring aqui para explicar, porque foi feito esse filtro

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No simples nacional a alíquota do ICMS quando é Comércio é um valor, quando é Industria é outro valor.
Eu uso o filtro para procurar o valor efetivo para quando for comércio e depois faço o mesmo para quando for indústria.
Esse compute está sendo usado para calcular essa duas variáveis : icmssn_credit_commerce, icmssn_credit_industry.
Eles são usados depois na emissão da nota fiscal do simples nacional.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Eu vou pedir pro @renatonlima comentar de novo sobre esse issue...

for rec in self:
rec.icmssn_credit_commerce = rec.sn_effective_tax_ids.filtered(
lambda t: t.simplified_tax_id.name == "Anexo 1 - Comércio"
).tax_icms_percent
rec.icmssn_credit_industry = rec.sn_effective_tax_ids.filtered(
lambda t: t.simplified_tax_id.name == "Anexo 2 - Indústria"
).tax_icms_percent

def _calculate_coefficient_r(self):
for record in self:
record.coefficient_r = False
if record.payroll_amount and record.annual_revenue:
coefficient_r_percent = record.payroll_amount / record.annual_revenue

Check warning on line 537 in l10n_br_fiscal/models/res_company.py

View check run for this annotation

Codecov / codecov/patch

l10n_br_fiscal/models/res_company.py#L537

Added line #L537 was not covered by tests
if coefficient_r_percent > COEFFICIENT_R:
record.coefficient_r = True
record.coefficient_r_percent = coefficient_r_percent

Check warning on line 540 in l10n_br_fiscal/models/res_company.py

View check run for this annotation

Codecov / codecov/patch

l10n_br_fiscal/models/res_company.py#L539-L540

Added lines #L539 - L540 were not covered by tests

def update_effective_tax_lines(self):
for record in self:
simplified_tax_model = self.env["l10n_br_fiscal.simplified.tax"]
for simplified_id in simplified_tax_model.search([]):
effective_tax = record.sn_effective_tax_ids.filtered(
lambda t: t.simplified_tax_id.id == simplified_id.id
)
if not effective_tax:
record.sn_effective_tax_ids.create(
{
"simplified_tax_id": simplified_id.id,
"company_id": record.id,
}
)

def write(self, vals):
result = super().write(vals)
if "tax_framework" in vals:
if vals["tax_framework"] == TAX_FRAMEWORK_SIMPLES:
self.update_effective_tax_lines()
else:
self.sn_effective_tax_ids = [(5, 0, 0)]
return result
15 changes: 14 additions & 1 deletion l10n_br_fiscal/models/simplified_tax.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
# Copyright (C) 2020 Luis Felipe Mileo - KMEE
# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html

from odoo import fields, models
from odoo import api, fields, models

from ..constants.fiscal import TAX_FRAMEWORK_SIMPLES


class SimplifiedTax(models.Model):
Expand Down Expand Up @@ -31,3 +33,14 @@
string="Coefficient R",
readonly=True,
)

@api.model
def create(self, vals):
"""Override create for update effective tax lines in all companys"""
record = super().create(vals)
companies = self.env["res.company"].search(
[("tax_framework", "=", TAX_FRAMEWORK_SIMPLES)]
)
for company in companies:
company.update_effective_tax_lines()

Check warning on line 45 in l10n_br_fiscal/models/simplified_tax.py

View check run for this annotation

Codecov / codecov/patch

l10n_br_fiscal/models/simplified_tax.py#L45

Added line #L45 was not covered by tests
return record
Loading
Loading