aboutsummaryrefslogtreecommitdiff
path: root/api/src/utils/tax-calculator.ts
diff options
context:
space:
mode:
Diffstat (limited to 'api/src/utils/tax-calculator.ts')
-rw-r--r--api/src/utils/tax-calculator.ts111
1 files changed, 111 insertions, 0 deletions
diff --git a/api/src/utils/tax-calculator.ts b/api/src/utils/tax-calculator.ts
new file mode 100644
index 0000000..36ffc7e
--- /dev/null
+++ b/api/src/utils/tax-calculator.ts
@@ -0,0 +1,111 @@
+/**
+ * Calculadora de impostos brasileiros (INSS + IRRF).
+ * Tabelas vigentes: 2025.
+ *
+ * IMPORTANTE: As alíquotas e faixas mudam anualmente por decreto.
+ * Verifique a legislação vigente a cada ano fiscal.
+ *
+ * Fonte: Portaria MPS / IN RFB 2.141/2023 e atualizações.
+ */
+
+// ---------------------------------------------------------------------------
+// INSS — Tabela Progressiva 2025
+// ---------------------------------------------------------------------------
+const INSS_TABLE = [
+ { upTo: 1_518.0, rate: 0.075 },
+ { upTo: 2_793.88, rate: 0.09 },
+ { upTo: 4_190.83, rate: 0.12 },
+ { upTo: 8_157.41, rate: 0.14 },
+] as const;
+
+const INSS_TETO = 908.86; // Valor máximo de desconto do INSS
+
+/**
+ * Calcula o desconto do INSS com a tabela progressiva.
+ * Cada faixa incide apenas sobre a parte do salário dentro dela.
+ */
+export function calcularINSS(salarioBruto: number): number {
+ if (salarioBruto <= 0) return 0;
+ if (salarioBruto > INSS_TABLE[INSS_TABLE.length - 1].upTo) return INSS_TETO;
+
+ let inss = 0;
+ let salarioRestante = salarioBruto;
+ let limiteAnterior = 0;
+
+ for (const faixa of INSS_TABLE) {
+ if (salarioRestante <= 0) break;
+
+ const baseNaFaixa = Math.min(salarioBruto, faixa.upTo) - limiteAnterior;
+ inss += baseNaFaixa * faixa.rate;
+
+ salarioRestante -= baseNaFaixa;
+ limiteAnterior = faixa.upTo;
+ }
+
+ return parseFloat(inss.toFixed(2));
+}
+
+// ---------------------------------------------------------------------------
+// IRRF — Tabela Progressiva 2025
+// ---------------------------------------------------------------------------
+interface FaixaIRRF {
+ upTo: number | null; // null = sem limite superior
+ rate: number;
+ deduction: number;
+}
+
+const IRRF_TABLE: FaixaIRRF[] = [
+ { upTo: 2_259.2, rate: 0, deduction: 0 },
+ { upTo: 2_826.65, rate: 0.075, deduction: 169.44 },
+ { upTo: 3_751.05, rate: 0.15, deduction: 381.44 },
+ { upTo: 4_664.68, rate: 0.225, deduction: 662.77 },
+ { upTo: null, rate: 0.275, deduction: 896.0 },
+];
+
+/**
+ * Calcula o desconto do IRRF.
+ * Base de cálculo: Salário Bruto − INSS (sem considerar dependentes).
+ */
+export function calcularIRRF(salarioBruto: number, inss: number): number {
+ const baseCalculo = salarioBruto - inss;
+ if (baseCalculo <= 0) return 0;
+
+ const faixa = IRRF_TABLE.find(
+ (f) => f.upTo === null || baseCalculo <= f.upTo,
+ )!;
+
+ const irrf = baseCalculo * faixa.rate - faixa.deduction;
+ return parseFloat(Math.max(0, irrf).toFixed(2));
+}
+
+// ---------------------------------------------------------------------------
+// Resultado consolidado
+// ---------------------------------------------------------------------------
+export interface ResultadoCalculo {
+ salarioBruto: number;
+ descontoINSS: number;
+ descontoIRRF: number;
+ totalDescontos: number;
+ salarioLiquidoCalculado: number;
+}
+
+/**
+ * Calcula o salário líquido completo a partir do salário bruto.
+ * Retorna um objeto com o detalhamento de cada desconto.
+ */
+export function calcularSalarioLiquido(salarioBruto: number): ResultadoCalculo {
+ const descontoINSS = calcularINSS(salarioBruto);
+ const descontoIRRF = calcularIRRF(salarioBruto, descontoINSS);
+ const totalDescontos = parseFloat((descontoINSS + descontoIRRF).toFixed(2));
+ const salarioLiquidoCalculado = parseFloat(
+ (salarioBruto - totalDescontos).toFixed(2),
+ );
+
+ return {
+ salarioBruto,
+ descontoINSS,
+ descontoIRRF,
+ totalDescontos,
+ salarioLiquidoCalculado,
+ };
+}