portal_publico/portal_api/custo_contratacao/calculo.py

252 lines
9.1 KiB
Python

"""Cálculo do custo de contratação — regime Empregado CLT.
Fórmulas portadas 1:1 da planilha de referência do escritório
(`projects/planilha de custo/1972 - CUSTO EMPREGADO SALÁRIO.xlsx`), com duas
correções deliberadas e explicitamente pedidas pelo usuário:
1. A planilha original nunca soma a dedução por dependente à base do IRRF
quando usa o desconto real de INSS (só quando usa o desconto simplificado
— onde a dedução por dependente não se aplica por lei, já que os dois
métodos são mutuamente exclusivos). Aqui, quando o desconto real de INSS
é o escolhido, a dedução por dependente também é subtraída da base do
IRRF.
2. A partir de janeiro/2026, a Lei nº 15.270/2025 (art. 3º-A da Lei nº
9.250/1995) passou a reduzir o IRRF já calculado pela tabela progressiva
tradicional — ver `_reducao_lei_15270` abaixo. Essa lei não mudou a
tabela progressiva em si, só acrescenta essa redução por cima.
Os parâmetros fiscais (faixas de INSS/IRRF, dedução por dependente, os
coeficientes da Lei 15.270/2025 etc.) não são mais constantes deste módulo —
mudam todo ano, então vêm de fora via `ParametrosFiscais` (montado a partir
de `ParametroFiscalCustoContratacao`, editável pela própria tela; ver
`portal_api/models.py`). `tabelas.py` continua existindo só como o
seed/default dessa configuração.
"""
from dataclasses import dataclass
@dataclass
class ParametrosFiscais:
faixas_inss: list[tuple[float, float, float]]
teto_desconto_inss: float
faixas_irrf: list[tuple[float, float, float]]
aliquota_irrf_topo: float
deduzir_irrf_topo: float
desconto_simplificado_irrf: float
deducao_por_dependente: float
reducao_lei_15270_coeficiente_a: float
reducao_lei_15270_coeficiente_b: float
reducao_lei_15270_limite: float
@dataclass
class EntradaSimulacaoEmpregado:
nome_referencia: str
empresa: str
cargo: str
salario_contratual: float
adicional_art62: float
comissao: float
dsr: float
outros_itens_remuneracao: list[tuple[str, float]] # somam à base de INSS/FGTS/13º/férias/IRRF, como salário
percentual_inss_empregador: float # fração, ex.: 0.26
percentual_fgts: float # fração, ex.: 0.08
dependentes: int
vale_transporte: float
seguro_vida: float
vale_alimentacao: float
assiduidade: float
fundo_formacao: float
outros_beneficios: list[tuple[str, float]] # custo variável do empregador, cada item some no PDF
desconto_vale_transporte: float
desconto_vale_alimentacao: float
desconto_sindicato: float
outros_descontos: list[tuple[str, float]] # descontado direto do líquido do empregado
@dataclass
class ResultadoSimulacaoEmpregado:
entrada: EntradaSimulacaoEmpregado
inss_salario: float
fgts_salario: float
decimo_terceiro_avo: float
inss_decimo_terceiro: float
fgts_decimo_terceiro: float
ferias_avo: float
ferias_um_terco: float
inss_ferias: float
fgts_ferias: float
multa_40_fgts: float
subtotal_custos_fixos: float
subtotal_custos_variaveis: float
custo_total_empresa: float
base_inss_empregado: float
aliquota_inss_empregado: float
desconto_inss_empregado: float
base_irrf: float
aliquota_irrf: float
desconto_irrf_tabela: float
reducao_lei_15270: float
desconto_irrf: float
liquido_empregado: float
def _desconto_inss(base: float, parametros: ParametrosFiscais) -> tuple[float, float]:
"""(alíquota, desconto) do INSS do empregado — progressivo, com teto fixo."""
for limite, aliquota, deduzir in parametros.faixas_inss:
if base <= limite:
return aliquota, (base * aliquota) - deduzir
return 0.0, parametros.teto_desconto_inss
def _desconto_irrf_tabela(base: float, parametros: ParametrosFiscais) -> tuple[float, float]:
"""(alíquota, desconto) do IRRF pela tabela progressiva tradicional;
desconto zerado se <= R$10 (regra de dispensa de retenção pra valores
muito baixos, já presente na planilha original)."""
aliquota, deduzir = parametros.aliquota_irrf_topo, parametros.deduzir_irrf_topo
for limite, faixa_aliquota, faixa_deduzir in parametros.faixas_irrf:
if base <= limite:
aliquota, deduzir = faixa_aliquota, faixa_deduzir
break
desconto_bruto = (base * aliquota) - deduzir
return aliquota, desconto_bruto if desconto_bruto > 10 else 0.0
def _reducao_lei_15270(rendimento_bruto_mensal: float, parametros: ParametrosFiscais) -> float:
"""Redução adicional de IRRF da Lei nº 15.270/2025 — isenção total até
R$5.000,00 de rendimento bruto mensal, decrescente até zerar em
`reducao_lei_15270_limite` (R$7.350,00 na regra vigente). Aplicada sobre
o rendimento bruto (antes do INSS), não sobre a base já líquida de INSS."""
if rendimento_bruto_mensal >= parametros.reducao_lei_15270_limite:
return 0.0
reducao = parametros.reducao_lei_15270_coeficiente_a - (
parametros.reducao_lei_15270_coeficiente_b * rendimento_bruto_mensal
)
return max(0.0, reducao)
def calcula_custo_empregado(
entrada: EntradaSimulacaoEmpregado, parametros: ParametrosFiscais
) -> ResultadoSimulacaoEmpregado:
perc_inss = entrada.percentual_inss_empregador
perc_fgts = entrada.percentual_fgts
base_remuneracao = (
entrada.salario_contratual
+ entrada.adicional_art62
+ entrada.comissao
+ entrada.dsr
+ sum(valor for _, valor in entrada.outros_itens_remuneracao)
)
inss_salario = base_remuneracao * perc_inss
fgts_salario = base_remuneracao * perc_fgts
decimo_terceiro_avo = base_remuneracao / 12
inss_decimo_terceiro = decimo_terceiro_avo * perc_inss
fgts_decimo_terceiro = decimo_terceiro_avo * perc_fgts
ferias_avo = base_remuneracao / 12
ferias_um_terco = ferias_avo / 3
inss_ferias = (ferias_avo + ferias_um_terco) * perc_inss
fgts_ferias = (ferias_avo + ferias_um_terco) * perc_fgts
multa_40_fgts = (fgts_salario + fgts_ferias + fgts_decimo_terceiro) * 0.4
subtotal_custos_fixos = (
base_remuneracao
+ inss_salario
+ fgts_salario
+ decimo_terceiro_avo
+ inss_decimo_terceiro
+ fgts_decimo_terceiro
+ ferias_avo
+ ferias_um_terco
+ inss_ferias
+ fgts_ferias
+ multa_40_fgts
)
subtotal_custos_variaveis = (
entrada.vale_transporte
+ entrada.seguro_vida
+ entrada.vale_alimentacao
+ entrada.assiduidade
+ entrada.fundo_formacao
+ sum(valor for _, valor in entrada.outros_beneficios)
)
custo_total_empresa = subtotal_custos_fixos + subtotal_custos_variaveis
base_inss_empregado = base_remuneracao
aliquota_inss_empregado, desconto_inss_empregado = _desconto_inss(base_inss_empregado, parametros)
if desconto_inss_empregado >= parametros.desconto_simplificado_irrf:
base_irrf = (
base_inss_empregado
- desconto_inss_empregado
- (entrada.dependentes * parametros.deducao_por_dependente)
)
else:
base_irrf = base_inss_empregado - parametros.desconto_simplificado_irrf
aliquota_irrf, desconto_irrf_tabela = _desconto_irrf_tabela(base_irrf, parametros)
reducao_lei_15270 = _reducao_lei_15270(base_remuneracao, parametros)
desconto_irrf = max(0.0, desconto_irrf_tabela - reducao_lei_15270)
total_descontos_diversos = (
entrada.desconto_vale_transporte
+ entrada.desconto_vale_alimentacao
+ entrada.desconto_sindicato
+ sum(valor for _, valor in entrada.outros_descontos)
)
liquido_empregado = base_remuneracao - desconto_inss_empregado - desconto_irrf - total_descontos_diversos
return ResultadoSimulacaoEmpregado(
entrada=entrada,
inss_salario=inss_salario,
fgts_salario=fgts_salario,
decimo_terceiro_avo=decimo_terceiro_avo,
inss_decimo_terceiro=inss_decimo_terceiro,
fgts_decimo_terceiro=fgts_decimo_terceiro,
ferias_avo=ferias_avo,
ferias_um_terco=ferias_um_terco,
inss_ferias=inss_ferias,
fgts_ferias=fgts_ferias,
multa_40_fgts=multa_40_fgts,
subtotal_custos_fixos=subtotal_custos_fixos,
subtotal_custos_variaveis=subtotal_custos_variaveis,
custo_total_empresa=custo_total_empresa,
base_inss_empregado=base_inss_empregado,
aliquota_inss_empregado=aliquota_inss_empregado,
desconto_inss_empregado=desconto_inss_empregado,
base_irrf=base_irrf,
aliquota_irrf=aliquota_irrf,
desconto_irrf_tabela=desconto_irrf_tabela,
reducao_lei_15270=reducao_lei_15270,
desconto_irrf=desconto_irrf,
liquido_empregado=liquido_empregado,
)
def formata_moeda(valor: float) -> str:
"""8500.0 -> 'R$ 8.500,00'; -12.3 -> '-R$ 12,30'."""
negativo = valor < 0
inteiro, decimal = f"{abs(valor):,.2f}".split(".")
texto = f"R$ {inteiro.replace(',', '.')},{decimal}"
return f"-{texto}" if negativo else texto
def formata_percentual(fracao: float) -> str:
"""0.26 -> '26,00%'."""
return f"{fracao * 100:.2f}".replace(".", ",") + "%"