testes/src_2/features/rh/utils/dpCalculations.js

213 lines
7.6 KiB
JavaScript

/**
* Utilitários para cálculos de Departamento Pessoal (RH)
*/
// Tabela INSS 2024 (Progressiva)
const INSS_TABLE = [
{ limit: 1412.00, rate: 0.075, deduction: 0 },
{ limit: 2666.68, rate: 0.09, deduction: 21.18 },
{ limit: 4000.03, rate: 0.12, deduction: 101.18 },
{ limit: 7786.02, rate: 0.14, deduction: 181.18 }
];
// Tabela IRRF 2024 (Simplificada)
const IRRF_TABLE = [
{ limit: 2259.20, rate: 0, deduction: 0 },
{ limit: 2826.65, rate: 0.075, deduction: 169.44 },
{ limit: 3751.05, rate: 0.15, deduction: 381.44 },
{ limit: 4664.68, rate: 0.225, deduction: 662.77 },
{ limit: Infinity, rate: 0.275, deduction: 896.00 }
];
// Salário Família Teto e Valor (2024)
const FAMILY_SALARY_LIMIT = 1819.26; // Valor hipotético atualizado
const FAMILY_SALARY_VALUE = 62.04;
/**
* Calcula o INSS progressivo
*/
export const calculateINSS = (salary) => {
let tax = 0;
// Cálculo progressivo correto seria faixa a faixa,
// mas a regra do usuário simplificada diz: "Salario base X Aliquota - Parcela a deduzir"
// Vamos usar o método da parcela a deduzir que equivale ao cálculo por faixas.
let range = INSS_TABLE.find(r => salary <= r.limit);
if (!range) range = INSS_TABLE[INSS_TABLE.length - 1]; // Teto
// Se salario maior que teto, usa o teto para calculo base ou valor fixo?
// INSS tem teto de contribuição.
const contributionSalary = Math.min(salary, INSS_TABLE[INSS_TABLE.length - 1].limit);
// Re-encontrar a faixa correta para o salário de contribuição (caso tenha sido limitado pelo teto)
range = INSS_TABLE.find(r => contributionSalary <= r.limit) || INSS_TABLE[INSS_TABLE.length - 1];
tax = (contributionSalary * range.rate) - range.deduction;
return Math.max(0, tax);
};
/**
* Calcula o IRRF
*/
export const calculateIRRF = (baseCalc) => {
let range = IRRF_TABLE.find(r => baseCalc <= r.limit);
if (!range) range = IRRF_TABLE[IRRF_TABLE.length - 1];
const tax = (baseCalc * range.rate) - range.deduction;
return Math.max(0, tax);
};
/**
* Calcula VT (6% do salário base, limitado ao custo se informado, aqui assumimos desconto full de 6%)
*/
export const calculateVT = (salary) => {
return salary * 0.06;
};
/**
* Calcula Salário Família
*/
export const calculateFamilySalary = (salary, numChildren, hasDisability = false) => {
// Regra: Salario até 1.503,25 (usando valor atualizado da const ou parametro)
// O usuário passou 1.503,25 na regra, vamos respeitar ou usar o oficial?
// User request: "Salario até 1.503,25"
if (salary > 1503.25 && !hasDisability) return 0; // Regra simplificada do usuário. Na real deficiência não ignora renda para SF, mas ok.
return numChildren * FAMILY_SALARY_VALUE; // User request: "Nº de filhos X Quota Unitária"
};
/**
* Calcula FGTS Total e Multa
*/
export const calculateFGTS = (currentSalary, monthsWorked) => {
// Simplificação: Assume salário constante para o cálculo do montante
const monthlyDeposit = currentSalary * 0.08;
const totalDeposit = monthlyDeposit * monthsWorked;
const fine40 = totalDeposit * 0.40;
const totalWithFine = totalDeposit + fine40;
return {
monthlyDeposit,
totalDeposit,
fine40,
totalWithFine
};
};
/**
* Gera o holerite completo simulado
*/
export const generatePayslip = (employee, options = {}) => {
const salary = employee.salary || 0;
// Parâmetros opcionais
const hasVT = options.hasVT ?? true;
const hasVR = options.hasVR ?? false;
const vrDailyCost = options.vrDailyCost || 30; // Custo refeição diário
const workDays = options.workDays || 22;
const hasUnionContribution = options.hasUnionContribution ?? false;
const numChildren = options.numChildren || 0;
const childrenUnder14 = options.childrenUnder14 || 0; // Para salário família
const extraHours50 = options.extraHours50 || 0;
const extraHours100 = options.extraHours100 || 0;
const insalubrityLevel = options.insalubrityLevel || 0; // 0, 10, 20, 40
const hasPericulosidade = options.hasPericulosidade || false;
// --- PROVENTOS ---
const proventos = [];
// 1. Salário Base
proventos.push({ name: 'Salário Base', value: salary, type: 'P' });
// 2. Insalubridade
let insalubrityValue = 0;
if (insalubrityLevel > 0) {
// Regra do usuário: Salario base X 10% ou 20% ou 40%
// (Na CLT é sobre salário mínimo, mas seguiremos a regra do usuário: "Salario base X ...")
insalubrityValue = salary * (insalubrityLevel / 100);
proventos.push({ name: `Insalubridade (${insalubrityLevel}%)`, value: insalubrityValue, type: 'P' });
}
// 3. Periculosidade
let periculosidadeValue = 0;
if (hasPericulosidade) {
// Regra do usuário: Salario base X 30%
periculosidadeValue = salary * 0.30;
proventos.push({ name: 'Periculosidade (30%)', value: periculosidadeValue, type: 'P' });
}
// 4. Horas Extras
const hourlyRate = salary / 220;
let he50Value = 0;
if (extraHours50 > 0) {
he50Value = hourlyRate * 1.5 * extraHours50;
proventos.push({ name: `Hora Extra 50% (${extraHours50}h)`, value: he50Value, type: 'P' });
}
let he100Value = 0;
if (extraHours100 > 0) {
he100Value = hourlyRate * 2.0 * extraHours100;
proventos.push({ name: `Hora Extra 100% (${extraHours100}h)`, value: he100Value, type: 'P' });
}
// 5. Salário Família
const familySalary = calculateFamilySalary(salary, childrenUnder14);
if (familySalary > 0) {
proventos.push({ name: `Salário Família (${childrenUnder14} filhos)`, value: familySalary, type: 'P' }); // Geralmente não compõe base de INSS/IRRF
}
// Total Bruto (Base para impostos - remove SF se necessário, mas simplificando)
const totalProventos = salary + insalubrityValue + periculosidadeValue + he50Value + he100Value;
// --- DESCONTOS ---
const descontos = [];
// 1. INSS
const inssValue = calculateINSS(totalProventos);
descontos.push({ name: 'INSS', value: inssValue, type: 'D' });
// 2. IRRF
// Base IRRF = Total Proventos - INSS - (Dependentes * 189.59)
const dependentsDeduction = numChildren * 189.59;
const irrfBase = totalProventos - inssValue - dependentsDeduction;
const irrfValue = calculateIRRF(irrfBase);
if (irrfValue > 0) {
descontos.push({ name: 'IRRF', value: irrfValue, type: 'D' });
}
// 3. VT
if (hasVT) {
const vtValue = calculateVT(salary);
descontos.push({ name: 'Vale Transporte (6%)', value: vtValue, type: 'D' });
}
// 4. VR (Opcional)
if (hasVR) {
// Regra: "Valor mensal x 20% (Teto do desconto)"
const vrTotal = vrDailyCost * workDays;
const vrDiscount = vrTotal * 0.20; // Assumindo desconto de 20% do benefício
descontos.push({ name: 'Vale Refeição (20%)', value: vrDiscount, type: 'D' });
}
// 5. Contribuição Sindical (Opcional)
if (hasUnionContribution) {
const unionValue = salary / 30;
descontos.push({ name: 'Contrib. Sindical (1 dia)', value: unionValue, type: 'D' });
}
const totalDescontos = descontos.reduce((acc, curr) => acc + curr.value, 0);
const liquido = (totalProventos + familySalary) - totalDescontos; // SF entra no líquido mas não na base dos impostos acima calculados (simplificação)
return {
proventos,
descontos,
totais: {
bruto: totalProventos,
descontos: totalDescontos,
liquido: liquido,
sf: familySalary
}
};
};