Pular para conteúdo

Cálculo de Impostos

Objetivo

Documentar o motor de cálculo de impostos da localização brasileira CIEL IT, que é o componente mais complexo do sistema. Este motor determina automaticamente os impostos aplicáveis em cada transação, baseando-se em operações fiscais, tabelas NCM/UF e configurações da empresa.


Implementação Técnica

Métodos Principais

Método Modelo Arquivo Linha Responsabilidade
simulate_impostos() SaleOrder sale_order.py 673 Simulação fiscal completa para pedidos de venda
_handle_taxes() SaleOrderLine sale_order.py 3407 Cria/busca account.tax e aplica ao item
_handle_taxes() AccountMoveLine account.py 8931 Cria/busca account.tax e aplica à linha da fatura
_handle_taxes() PurchaseOrderLine purchase.py 953 Variante para compras
generate_all_taxes() ResCompany res_company.py 461 Pré-geração de template de impostos
_get_ibpt() ResCompany res_company.py 433 Cálculo do valor aproximado de tributos

Fluxo Geral do Cálculo

flowchart TD
    A["Pedido/Fatura<br/>(trigger)"] --> B["Determinar Tipo<br/>de Produto"]
    B --> C["Determinar Tipo<br/>de Cliente"]
    C --> D["Determinar Destino<br/>(Intra/Inter/Ext)"]
    D --> E["Buscar NCM/UF<br/>(4 tabelas)"]
    E --> F["Buscar Operação<br/>(domain + order)"]
    F --> G["Selecionar CFOP<br/>(Intra/Inter/Ext)"]
    G --> H{"Operação<br/>encontrada?"}
    H -->|Sim| I["Aplicar Parâmetros<br/>da Operação"]
    H -->|Não| J["Erro / Sem impostos"]
    I --> K["Calcular ICMS"]
    K --> L["Calcular ICMS ST"]
    L --> M["Calcular IPI"]
    M --> N["Calcular PIS/COFINS"]
    N --> O["Calcular ISS"]
    O --> P["Calcular Retenções"]
    P --> Q["Calcular IBS/CBS/IS"]
    Q --> R["Calcular DIFAL/FCP"]
    R --> S["Calcular IBPT"]
    S --> T["Gerar account.tax<br/>(_handle_taxes)"]

Etapa 1: Determinação do Contexto

Tipo de Produto (l10n_br_tipo_produto)

if product.type == 'service' or product.l10n_br_codigo_servico:
    tipo_produto = 'servico'
elif product.type == 'consu':
    tipo_produto = 'consumivel'
elif product.purchase_ok:
    tipo_produto = 'comprado'
else:
    tipo_produto = 'produzido'

Tipo de Cliente (l10n_br_tipo_cliente)

if partner.l10n_br_cpf:
    tipo_cliente = 'pf'  # Pessoa Física
if company.country_id != partner.country_id:
    tipo_cliente = 'ex'  # Exterior
if partner.l10n_br_is:
    tipo_cliente = 'zf'  # Zona Franca
# default: 'pj' (Pessoa Jurídica)

Destino da Operação

if company.state_id == partner.state_id:
    destino = '1'  # Interna (mesma UF)
elif company.country_id != partner.country_id:
    destino = '3'  # Exterior
else:
    destino = '2'  # Interestadual

Etapa 2: Busca de Exceções NCM/UF

O motor consulta 4 tabelas de exceção na seguinte ordem de prioridade (a mais específica sobrescreve):

1. l10n_br_ciel_it_account.ncm.uf
   → Filtro: NCM + UF Origem + UF Destino

2. l10n_br_ciel_it_account.ncm.origem.uf
   → Filtro: NCM + UF Origem + UF Destino + Origem Mercadoria
   → Sobrescreve (1) se encontrada

3. l10n_br_ciel_it_account.ncm.ie.uf
   → Filtro: NCM + UF Origem + UF Destino + Origem + Indicador IE
   → Sobrescreve (2) se encontrada

4. l10n_br_ciel_it_account.ncm.cliente.uf
   → Filtro: NCM + UF Origem + UF Destino + Cliente específico
   → Sobrescreve (3) se encontrada

Se encontrada, a tabela NCM/UF pode alterar: CST ICMS, alíquota ICMS, redução de base, ICMS ST (MVA, alíquota), FCP e mensagens fiscais.


Etapa 3: Busca da Operação Fiscal

O motor monta um domínio dinâmico (ORM domain) que combina todos os critérios do contexto:

Critério Fonte
Tipo de operação Fixo: saida ou entrada
Tipo de pedido l10n_br_tipo_pedido do pedido
Empresa company_id do pedido
Tipo de produto Derivado do product.type
Tipo de cliente Derivado do partner
Regime tributário Do parceiro
Órgão público Do parceiro
Indicador IE Do parceiro
Origem mercadoria Do produto
Destino operação Derivado (Intra/Inter/Ext)
Tipo destinação Do pedido (l10n_br_compra_indcom)
Operação ICMS ST Se NCM/UF tem ICMS ST
Categoria produto categ_id do produto
NCM l10n_br_ncm_id do produto
Código serviço l10n_br_codigo_servico
Produto específico product_id
Tags fiscais Do produto e do parceiro
UF do parceiro state_id do parceiro
Município l10n_br_municipio_id
Parceiro específico partner_id
Valor mínimo Total da NF

Cada critério usa OR — aceita o valor específico OU o campo vazio (para match com operações genéricas).

A busca retorna 1 resultado (limit=1) com a ordem de prioridade definida no _order da operação (campos mais específicos primeiro, com _is_set DESC para priorizar registros com Many2many preenchidos).


Etapa 4: Determinação do CFOP

Após encontrar a operação, o CFOP é selecionado conforme o destino:

if company.state_id == partner.state_id:
    cfop = operacao.l10n_br_intra_cfop_id   # Mesmo estado
elif company.country_id != partner.country_id:
    cfop = operacao.l10n_br_ext_cfop_id     # Exterior
else:
    cfop = operacao.l10n_br_inter_cfop_id   # Interestadual

Etapa 5: Cálculo Individual dos Impostos

Para cada imposto, o motor: 1. Obtém a CST e alíquota da Operação Fiscal encontrada 2. Pode sobrescrever com dados do NCM/UF (se houver exceção) 3. Calcula a base de cálculo (preço unitário × quantidade + frete + seguro + despesas acessórias, com possíveis exclusões) 4. Calcula o valor do imposto (base × alíquota / 100) 5. Chama _handle_taxes() para criar ou reutilizar um registro account.tax

Cálculo do ICMS

  1. CST vem da Operação ou NCM/UF
  2. Base = Preço + Frete + Seguro + Despesas - (IPI se incluso) - (Desconto)
  3. Reduções aplicadas conforme l10n_br_icms_reducao_base (%)
  4. Alíquota pode vir da Operação ou NCM/UF
  5. Se empresa é Simples Nacional, pode aplicar l10n_br_icms_credito_aliquota

Cálculo do ICMS ST

  1. Só calcula se CST indica ST (CST 10, 30, 60, 70, 201, 202, 203, 900)
  2. Base ST = (Base × MVA + FCP) ou conforme modalidade de base
  3. Valor ST = (Base ST × Alíquota ST) - ICMS Próprio
  4. Flag l10n_br_icmsst_icmsfora: não subtrai ICMS próprio

Cálculo do IPI

  1. CST vem do CFOP ou da Operação
  2. Base = Preço + Frete + Seguro + Despesas
  3. Pode ser zerado (l10n_br_ipi_zerar_base)

Cálculo do PIS/COFINS

  1. CST vem da Operação
  2. Base = Preço + Frete + Seguro + Despesas
  3. Se l10n_br_exclui_icms_piscofins = True: Base -= ICMS ("Tese do Século")
  4. Se l10n_br_exclui_difal_piscofins = True: Base -= DIFAL
  5. Pode ter redução de base (l10n_br_pis_reducao_base, l10n_br_cofins_reducao_base)

Cálculo de Retenções

Para cada imposto retido (IRPJ, CSLL, PIS, COFINS, INSS, ISS): 1. Alíquota vem da Operação 2. Verifica valor mínimo de retenção do parceiro (l10n_br_irpj_ret_valor, etc.) 3. Só retém se o valor exceder o mínimo

Cálculo do DIFAL e FCP

  • DIFAL: diferença entre alíquota interna da UF destino e alíquota interestadual
  • FCP: alíquota adicional do Fundo de Combate à Pobreza (vem do NCM/UF)
  • Controlado por l10n_br_difal_regra na Operação

Cálculo IBS/CBS/IS (Reforma Tributária)

  • CST vem da Operação
  • l10n_br_ibs_uf_aliquota × base + l10n_br_ibs_mun_aliquota × base + l10n_br_cbs_aliquota × base
  • Pode ter diferimento ou redução de alíquota

Etapa 6: Geração dos Impostos (_handle_taxes)

O método _handle_taxes() é chamado para cada imposto calculado. Ele:

  1. Busca um account.tax template (master) com nome no formato {IMPOSTO}[*] ou {IMPOSTO}-{UF}[*]
  2. Se encontra o master, busca ou cria um imposto filho com os valores específicos
  3. Vincula o imposto à linha do documento (tax_ids)

Convenção de nomes

Padrão Exemplo Descrição
{IMPOSTO}[*] ICMS[*] Template genérico
{IMPOSTO}-{UF}[*] ICMS-SP[*] Template por UF de destino
{IMPOSTO} {ALIQ}% ICMS 18% Imposto real com alíquota

Hierarquia de busca do template

1. Tax com nome, amount_type, price_include, l10n_br_tipo_pedido + l10n_br_tipo_pedido_entrada, UF destino, empresa atual
2. Tax com nome, amount_type, price_include, UF destino, empresa atual
3. Tax com nome, amount_type, price_include, l10n_br_tipo_pedido, empresa pai
4. Tax com nome, amount_type, price_include, empresa pai
5. (sem UF) mesma sequência

IBPT — Valor Aproximado de Tributos

Método: _get_ibpt(ncm, l10n_br_origem, valor, servico=False)

Arquivo: res_company.py, linha 433

Fluxo

  1. Se produto é serviço: usa l10n_br_ibpt_aliquota_servico da empresa
  2. Busca arquivo CSV em static/ibpt/TabelaIBPTax{UF}{versão}.csv
  3. Se encontrar o NCM no CSV: soma alíquotas (estadual + federal)
  4. Diferencia entre origem nacional e importada
  5. Fallback: usa alíquotas padrão configuradas na empresa

Cenários de Uso / Troubleshooting

1. Impostos não estão sendo calculados

  • Verificar: generate_all_taxes() foi executado na empresa?
  • Verificar: Existem templates {IMPOSTO}[*] no registro de impostos?
  • Verificar: O tipo de uso do imposto (type_tax_use) corresponde ao tipo do documento?

2. ICMS com alíquota incorreta

  • Verificar: Existe registro na tabela NCM/UF que está sobrescrevendo a operação?
  • Verificar: A operação mais específica está sendo selecionada (verificar _order)?

3. PIS/COFINS com base incorreta

  • Verificar: l10n_br_exclui_icms_piscofins está configurado corretamente na empresa?
  • Verificar: A CST de PIS/COFINS na operação corresponde ao regime (cumulativo vs. não-cumulativo)?

4. Retenções não estão sendo aplicadas

  • Verificar: Os valores mínimos de retenção no parceiro (l10n_br_irpj_ret_valor, etc.)
  • Verificar: As alíquotas de retenção na operação estão preenchidas

5. ICMS ST não calculado

  • Verificar: NCM/UF tem l10n_br_icmsst_modalidade_base preenchido?
  • Verificar: Operação tem l10n_br_operacao_icmsst correto?
  • Verificar: IE ST cadastrada para a combinação UF na tabela iest.uf

Referências Cruzadas