Speed / src /calculators /icms.py
LesterCerioli's picture
Building Speed LLM
d9d7b41
Raw
History Blame Contribute Delete
4.73 kB
"""Calculadora de ICMS com suporte a ST, DIFAL e FCP."""
from __future__ import annotations
from dataclasses import dataclass, field
from decimal import Decimal
from typing import Optional
from src.calculators import ResultadoCalculo, arred
from src.fiscal.constants import ALIQ_ICMS_INTERNA, aliq_icms_interestadual
@dataclass
class ParametrosICMS:
valor_mercadoria: Decimal
aliquota: Decimal
cst: str = "000"
uf_origem: str = "SP"
uf_destino: str = "SP"
reducao_base: Decimal = Decimal("0")
frete: Decimal = Decimal("0")
seguro: Decimal = Decimal("0")
outras_despesas: Decimal = Decimal("0")
desconto: Decimal = Decimal("0")
# Substituição Tributária
aliq_st: Optional[Decimal] = None
mva: Optional[Decimal] = None
base_st_retido: Decimal = Decimal("0")
# FCP (Fundo de Combate à Pobreza)
aliq_fcp: Decimal = Decimal("0")
aliq_fcp_st: Decimal = Decimal("0")
# DIFAL (Diferencial de Alíquota - EMENDA 87)
calcular_difal: bool = False
consumidor_final: bool = False
@dataclass
class ResultadoICMS:
base_calculo: Decimal = Decimal("0")
aliquota: Decimal = Decimal("0")
valor_icms: Decimal = Decimal("0")
# ST
base_st: Decimal = Decimal("0")
aliq_st: Decimal = Decimal("0")
valor_st: Decimal = Decimal("0")
# FCP
base_fcp: Decimal = Decimal("0")
valor_fcp: Decimal = Decimal("0")
valor_fcp_st: Decimal = Decimal("0")
# DIFAL
valor_difal_origem: Decimal = Decimal("0")
valor_difal_destino: Decimal = Decimal("0")
# Total
valor_total_icms: Decimal = Decimal("0")
def calcular_icms(p: ParametrosICMS) -> ResultadoICMS:
r = ResultadoICMS()
if p.cst in {"040", "041", "050", "051", "060"}:
return r
base_bruta = (
p.valor_mercadoria + p.frete + p.seguro + p.outras_despesas - p.desconto
)
if p.cst in {"020", "070"}:
r.base_calculo = arred(base_bruta * (1 - p.reducao_base / 100))
else:
r.base_calculo = arred(base_bruta)
r.aliquota = p.aliquota
r.valor_icms = arred(r.base_calculo * p.aliquota / 100)
# FCP
if p.aliq_fcp > 0:
r.base_fcp = r.base_calculo
r.valor_fcp = arred(r.base_fcp * p.aliq_fcp / 100)
# Substituição Tributária
if p.cst in {"010", "030", "070"} and p.aliq_st is not None and p.mva is not None:
aliq_interna_dest = ALIQ_ICMS_INTERNA.get(p.uf_destino, Decimal("18"))
r.base_st = arred(r.base_calculo * (1 + p.mva / 100))
r.aliq_st = aliq_interna_dest
icms_proprio_dest = arred(r.base_st * aliq_interna_dest / 100)
r.valor_st = max(Decimal("0"), arred(icms_proprio_dest - r.valor_icms))
if p.aliq_fcp_st > 0:
r.valor_fcp_st = arred(r.base_st * p.aliq_fcp_st / 100)
# DIFAL (EC 87/2015) para operações interestaduais para consumidor final
if p.calcular_difal and p.consumidor_final and p.uf_origem != p.uf_destino:
aliq_interestadual = aliq_icms_interestadual(p.uf_origem, p.uf_destino)
aliq_interna_dest = ALIQ_ICMS_INTERNA.get(p.uf_destino, Decimal("18"))
difal = arred(r.base_calculo * (aliq_interna_dest - aliq_interestadual) / 100)
# Partilha DIFAL: 2019+ => 100% destino
r.valor_difal_destino = arred(difal * Decimal("0.60"))
r.valor_difal_origem = arred(difal * Decimal("0.40"))
r.valor_total_icms = arred(
r.valor_icms + r.valor_st + r.valor_fcp + r.valor_fcp_st
+ r.valor_difal_destino + r.valor_difal_origem
)
return r
def calcular_icms_credito_entrada(
valor_nf: Decimal,
aliquota: Decimal,
percentual_aproveitamento: Decimal = Decimal("100"),
) -> Decimal:
credito_bruto = arred(valor_nf * aliquota / 100)
return arred(credito_bruto * percentual_aproveitamento / 100)
def calcular_icms_apuracao(
debitos: list[Decimal],
creditos: list[Decimal],
saldo_anterior: Decimal = Decimal("0"),
) -> ResultadoCalculo:
total_debitos = arred(sum(debitos))
total_creditos = arred(sum(creditos) + saldo_anterior)
saldo = total_creditos - total_debitos
valor_a_recolher = max(Decimal("0"), arred(total_debitos - total_creditos))
saldo_credor = max(Decimal("0"), arred(total_creditos - total_debitos))
return ResultadoCalculo(
base_calculo=total_debitos,
aliquota=Decimal("0"),
valor_tributo=total_debitos,
deducoes=Decimal("0"),
creditos=total_creditos,
valor_a_recolher=valor_a_recolher,
detalhes={
"total_debitos": total_debitos,
"total_creditos": total_creditos,
"saldo_devedor": valor_a_recolher,
"saldo_credor": saldo_credor,
},
)