Speed / src /calculators /simples_nacional.py
LesterCerioli's picture
Building Speed LLM
d9d7b41
Raw
History Blame Contribute Delete
12.8 kB
from __future__ import annotations
from dataclasses import dataclass, field
from datetime import date
from decimal import Decimal
from typing import Optional
from src.calculators import ResultadoCalculo, arred
# ---------------------------------------------------------------------------
# Tabelas do Simples Nacional (LC 123/2006 com alterações da LC 155/2016)
# Vigência: a partir de 01/01/2018
# Faixas: (limite_acumulado_12m, aliq_nominal, deducao)
# ---------------------------------------------------------------------------
TABELA_SIMPLES: dict[str, list[tuple[Decimal, Decimal, Decimal]]] = {
"I": [ # Comércio
(Decimal("180000.00"), Decimal("4.00"), Decimal("0.00")),
(Decimal("360000.00"), Decimal("7.30"), Decimal("5940.00")),
(Decimal("720000.00"), Decimal("9.50"), Decimal("13860.00")),
(Decimal("1800000.00"), Decimal("10.70"), Decimal("22500.00")),
(Decimal("3600000.00"), Decimal("14.30"), Decimal("87300.00")),
(Decimal("4800000.00"), Decimal("19.00"), Decimal("378000.00")),
],
"II": [ # Indústria
(Decimal("180000.00"), Decimal("4.50"), Decimal("0.00")),
(Decimal("360000.00"), Decimal("7.80"), Decimal("5940.00")),
(Decimal("720000.00"), Decimal("10.00"), Decimal("13860.00")),
(Decimal("1800000.00"), Decimal("11.20"), Decimal("22500.00")),
(Decimal("3600000.00"), Decimal("14.70"), Decimal("85500.00")),
(Decimal("4800000.00"), Decimal("30.00"), Decimal("720000.00")),
],
"III": [ # Serviços (com CPP)
(Decimal("180000.00"), Decimal("6.00"), Decimal("0.00")),
(Decimal("360000.00"), Decimal("11.20"), Decimal("9360.00")),
(Decimal("720000.00"), Decimal("13.50"), Decimal("17640.00")),
(Decimal("1800000.00"), Decimal("16.00"), Decimal("35640.00")),
(Decimal("3600000.00"), Decimal("21.00"), Decimal("125640.00")),
(Decimal("4800000.00"), Decimal("33.00"), Decimal("648000.00")),
],
"IV": [ # Serviços (sem CPP — INSS pago separado)
(Decimal("180000.00"), Decimal("4.50"), Decimal("0.00")),
(Decimal("360000.00"), Decimal("9.00"), Decimal("8100.00")),
(Decimal("720000.00"), Decimal("10.20"), Decimal("12420.00")),
(Decimal("1800000.00"), Decimal("14.00"), Decimal("39780.00")),
(Decimal("3600000.00"), Decimal("22.00"), Decimal("183780.00")),
(Decimal("4800000.00"), Decimal("33.00"), Decimal("828000.00")),
],
"V": [ # Serviços com fator R (profissões regulamentadas)
(Decimal("180000.00"), Decimal("15.50"), Decimal("0.00")),
(Decimal("360000.00"), Decimal("18.00"), Decimal("4500.00")),
(Decimal("720000.00"), Decimal("19.50"), Decimal("9900.00")),
(Decimal("1800000.00"), Decimal("20.50"), Decimal("17100.00")),
(Decimal("3600000.00"), Decimal("23.00"), Decimal("62100.00")),
(Decimal("4800000.00"), Decimal("30.50"), Decimal("540000.00")),
],
}
PARTILHA_DAS: dict[str, list[dict[str, Decimal]]] = {
"I": [
{"IRPJ": Decimal("5.5"), "CSLL": Decimal("3.5"), "COFINS": Decimal("12.74"), "PIS": Decimal("2.76"), "CPP": Decimal("41.50"), "ICMS": Decimal("34.00")},
{"IRPJ": Decimal("5.5"), "CSLL": Decimal("3.5"), "COFINS": Decimal("12.74"), "PIS": Decimal("2.76"), "CPP": Decimal("41.50"), "ICMS": Decimal("34.00")},
{"IRPJ": Decimal("5.5"), "CSLL": Decimal("3.5"), "COFINS": Decimal("12.74"), "PIS": Decimal("2.76"), "CPP": Decimal("42.00"), "ICMS": Decimal("33.50")},
{"IRPJ": Decimal("5.5"), "CSLL": Decimal("3.5"), "COFINS": Decimal("12.74"), "PIS": Decimal("2.76"), "CPP": Decimal("42.00"), "ICMS": Decimal("33.50")},
{"IRPJ": Decimal("5.5"), "CSLL": Decimal("3.5"), "COFINS": Decimal("12.74"), "PIS": Decimal("2.76"), "CPP": Decimal("42.00"), "ICMS": Decimal("33.50")},
{"IRPJ": Decimal("13.5"), "CSLL": Decimal("10.0"), "COFINS": Decimal("28.27"), "PIS": Decimal("6.13"), "CPP": Decimal("42.10"), "ICMS": Decimal("0.00")},
],
"II": [
{"IRPJ": Decimal("5.5"), "CSLL": Decimal("3.5"), "COFINS": Decimal("11.51"), "PIS": Decimal("2.49"), "CPP": Decimal("37.50"), "IPI": Decimal("7.50"), "ICMS": Decimal("32.00")},
{"IRPJ": Decimal("5.5"), "CSLL": Decimal("3.5"), "COFINS": Decimal("11.51"), "PIS": Decimal("2.49"), "CPP": Decimal("37.50"), "IPI": Decimal("7.50"), "ICMS": Decimal("32.00")},
{"IRPJ": Decimal("5.5"), "CSLL": Decimal("3.5"), "COFINS": Decimal("11.51"), "PIS": Decimal("2.49"), "CPP": Decimal("37.50"), "IPI": Decimal("7.50"), "ICMS": Decimal("32.00")},
{"IRPJ": Decimal("5.5"), "CSLL": Decimal("3.5"), "COFINS": Decimal("11.51"), "PIS": Decimal("2.49"), "CPP": Decimal("37.50"), "IPI": Decimal("7.50"), "ICMS": Decimal("32.00")},
{"IRPJ": Decimal("5.5"), "CSLL": Decimal("3.5"), "COFINS": Decimal("11.51"), "PIS": Decimal("2.49"), "CPP": Decimal("37.50"), "IPI": Decimal("7.50"), "ICMS": Decimal("32.00")},
{"IRPJ": Decimal("8.0"), "CSLL": Decimal("7.5"), "COFINS": Decimal("20.96"), "PIS": Decimal("4.54"), "CPP": Decimal("23.50"), "IPI": Decimal("35.50"), "ICMS": Decimal("0.00")},
],
"III": [
{"IRPJ": Decimal("4.0"), "CSLL": Decimal("3.5"), "COFINS": Decimal("12.82"), "PIS": Decimal("2.78"), "CPP": Decimal("43.40"), "ISS": Decimal("33.50")},
{"IRPJ": Decimal("4.0"), "CSLL": Decimal("3.5"), "COFINS": Decimal("14.05"), "PIS": Decimal("3.05"), "CPP": Decimal("43.40"), "ISS": Decimal("32.00")},
{"IRPJ": Decimal("4.0"), "CSLL": Decimal("3.5"), "COFINS": Decimal("13.64"), "PIS": Decimal("2.96"), "CPP": Decimal("43.40"), "ISS": Decimal("32.50")},
{"IRPJ": Decimal("4.0"), "CSLL": Decimal("3.5"), "COFINS": Decimal("13.64"), "PIS": Decimal("2.96"), "CPP": Decimal("43.40"), "ISS": Decimal("32.50")},
{"IRPJ": Decimal("4.0"), "CSLL": Decimal("3.5"), "COFINS": Decimal("12.82"), "PIS": Decimal("2.78"), "CPP": Decimal("43.40"), "ISS": Decimal("33.50")},
{"IRPJ": Decimal("35.0"), "CSLL": Decimal("15.0"), "COFINS": Decimal("16.03"), "PIS": Decimal("3.47"), "CPP": Decimal("30.50"), "ISS": Decimal("0.00")},
],
"IV": [
{"IRPJ": Decimal("18.8"), "CSLL": Decimal("15.2"), "COFINS": Decimal("17.67"), "PIS": Decimal("3.83"), "ISS": Decimal("44.50")},
{"IRPJ": Decimal("19.8"), "CSLL": Decimal("15.2"), "COFINS": Decimal("20.55"), "PIS": Decimal("4.45"), "ISS": Decimal("40.00")},
{"IRPJ": Decimal("20.8"), "CSLL": Decimal("15.2"), "COFINS": Decimal("19.73"), "PIS": Decimal("4.27"), "ISS": Decimal("40.00")},
{"IRPJ": Decimal("17.8"), "CSLL": Decimal("19.2"), "COFINS": Decimal("18.90"), "PIS": Decimal("4.10"), "ISS": Decimal("40.00")},
{"IRPJ": Decimal("18.8"), "CSLL": Decimal("19.2"), "COFINS": Decimal("18.08"), "PIS": Decimal("3.92"), "ISS": Decimal("40.00")},
{"IRPJ": Decimal("53.5"), "CSLL": Decimal("21.5"), "COFINS": Decimal("20.55"), "PIS": Decimal("4.45"), "ISS": Decimal("0.00")},
],
}
LIMITE_SIMPLES = Decimal("4800000.00")
LIMITE_MEI = Decimal("81000.00")
@dataclass
class ResultadoSimples:
receita_bruta_mes: Decimal
receita_bruta_acumulada_12m: Decimal
anexo: str
faixa: int
aliq_nominal: Decimal
deducao: Decimal
aliq_efetiva: Decimal
valor_das: Decimal
partilha: dict[str, Decimal] = field(default_factory=dict)
periodo: str = ""
dentro_limite: bool = True
def _calcular_aliq_efetiva(
rec_12m: Decimal,
aliq_nominal: Decimal,
deducao: Decimal,
) -> Decimal:
if rec_12m <= 0:
return Decimal("0")
return arred(((rec_12m * aliq_nominal / 100) - deducao) / rec_12m * 100, 6)
def _obter_faixa(rec_12m: Decimal, tabela: list) -> tuple[int, Decimal, Decimal]:
"""Retorna (índice_faixa, aliq_nominal, deducao)."""
for i, (limite, aliq, ded) in enumerate(tabela):
if rec_12m <= limite:
return i, aliq, ded
return len(tabela) - 1, tabela[-1][1], tabela[-1][2]
def calcular_das(
receita_bruta_mes: Decimal,
receita_bruta_acumulada_12m: Decimal,
anexo: str = "I",
periodo: str = "",
) -> ResultadoSimples:
"""
Calcula o DAS (Documento de Arrecadação do Simples Nacional) mensal.
Args:
receita_bruta_mes: Receita bruta do mês de referência
receita_bruta_acumulada_12m: Soma dos últimos 12 meses (ou desde o início)
anexo: "I", "II", "III", "IV" ou "V"
periodo: "YYYY-MM"
"""
dentro_limite = receita_bruta_acumulada_12m <= LIMITE_SIMPLES
tabela = TABELA_SIMPLES.get(anexo, TABELA_SIMPLES["I"])
faixa_idx, aliq_nominal, deducao = _obter_faixa(receita_bruta_acumulada_12m, tabela)
aliq_efetiva = _calcular_aliq_efetiva(receita_bruta_acumulada_12m, aliq_nominal, deducao)
valor_das = arred(receita_bruta_mes * aliq_efetiva / 100)
partilha_tabela = PARTILHA_DAS.get(anexo, [])
partilha: dict[str, Decimal] = {}
if partilha_tabela and faixa_idx < len(partilha_tabela):
perc_faixa = partilha_tabela[faixa_idx]
for tributo, perc in perc_faixa.items():
partilha[tributo] = arred(valor_das * perc / 100)
return ResultadoSimples(
receita_bruta_mes=receita_bruta_mes,
receita_bruta_acumulada_12m=receita_bruta_acumulada_12m,
anexo=anexo,
faixa=faixa_idx + 1,
aliq_nominal=aliq_nominal,
deducao=deducao,
aliq_efetiva=aliq_efetiva,
valor_das=valor_das,
partilha=partilha,
periodo=periodo,
dentro_limite=dentro_limite,
)
def calcular_fator_r(
folha_12m: Decimal,
rec_12m: Decimal,
) -> Decimal:
"""
Fator R: relação folha de pagamento / receita bruta nos últimos 12 meses.
Se Fator R >= 28%, o contribuinte pode optar pelo Anexo III ao invés do V.
"""
if rec_12m <= 0:
return Decimal("0")
return arred(folha_12m / rec_12m * 100, 4)
def determinar_anexo_servicos(
fator_r: Decimal,
lista_servico: str,
) -> str:
"""
Determina o anexo aplicável para empresas de serviços.
Serviços do Anexo V com Fator R >= 28% podem usar o Anexo III.
"""
anexo_iv = {
"construcao_civil", "servicos_vigilancia", "limpeza",
"transporte_cargas", "cuidados_pessoais",
}
anexo_iii = {
"agencia_viagens", "academias", "agronegocio",
"arquitetura_engenharia_simples",
}
fator_r_atividades = {
"medicina", "odontologia", "psicologia", "fisioterapia",
"advocacia", "contabilidade", "consultoria", "ti_software",
"engenharia", "arquitetura",
}
if lista_servico in anexo_iv:
return "IV"
if lista_servico in anexo_iii:
return "III"
if lista_servico in fator_r_atividades:
return "III" if fator_r >= Decimal("28") else "V"
return "III"
@dataclass
class ResultadoPGDAS:
"""Resultado do PGDAS-D mensal."""
cnpj: str
periodo: str
receita_bruta_total: Decimal
das_total: Decimal
das_por_estabelecimento: list[ResultadoSimples] = field(default_factory=list)
data_vencimento: Optional[date] = None
@property
def resumo_partilha(self) -> dict[str, Decimal]:
totais: dict[str, Decimal] = {}
for r in self.das_por_estabelecimento:
for tributo, valor in r.partilha.items():
totais[tributo] = totais.get(tributo, Decimal("0")) + valor
return totais
def calcular_pgdas(
cnpj: str,
periodo: str,
receitas_por_atividade: list[dict],
receita_acumulada_12m: Decimal,
) -> ResultadoPGDAS:
"""
Calcula o PGDAS-D completo para um período.
Args:
cnpj: CNPJ da empresa
periodo: "YYYY-MM"
receitas_por_atividade: [{"valor": ..., "anexo": "I/II/III/IV/V"}]
receita_acumulada_12m: Receita dos últimos 12 meses
"""
das_total = Decimal("0")
resultados = []
for ativ in receitas_por_atividade:
valor = Decimal(str(ativ.get("valor", 0)))
anexo = ativ.get("anexo", "I")
resultado = calcular_das(valor, receita_acumulada_12m, anexo, periodo)
das_total += resultado.valor_das
resultados.append(resultado)
ano, mes = map(int, periodo.split("-"))
mes_vcto = mes + 1 if mes < 12 else 1
ano_vcto = ano if mes < 12 else ano + 1
vcto = date(ano_vcto, mes_vcto, 20)
return ResultadoPGDAS(
cnpj=cnpj,
periodo=periodo,
receita_bruta_total=sum(Decimal(str(a["valor"])) for a in receitas_por_atividade),
das_total=arred(das_total),
das_por_estabelecimento=resultados,
data_vencimento=vcto,
)
MEI_VALORES_FIXOS = {
"comercio_industria": Decimal("70.60"), # R$ 70,60/mês (2024)
"servicos": Decimal("79.60"),
"comercio_servicos": Decimal("80.60"),
}