UNPKG

@dlivr.io/salary-calculator-egypt

Version:

Javascript SDK for calculating Net/Gross salary in Egypt.

436 lines (419 loc) 9.94 kB
'use strict'; function thousand(number) { return number * 1000; } function million(number) { return number * 1000000; } function calculateTax(salaryBracket, yearlySalary) { let baseYearlySalaryTax = 0; salaryBracket.stages.forEach(stage => { if (yearlySalary > stage.min) baseYearlySalaryTax += (Math.min(yearlySalary, stage.max) - stage.min) * stage.percentage; }); return baseYearlySalaryTax; } function isSupported(bracket, yearlySalary) { return yearlySalary > bracket.min && yearlySalary <= bracket.max; } const FIRST_BRACKET$2 = { min: 1, max: thousand(600), stages: [{ min: thousand(15), max: thousand(30), percentage: 0.025 }, { min: thousand(30), max: thousand(45), percentage: 0.1 }, { min: thousand(45), max: thousand(60), percentage: 0.15 }, { min: thousand(60), max: thousand(200), percentage: 0.2 }, { min: thousand(200), max: thousand(400), percentage: 0.225 }, { min: thousand(400), max: Infinity, percentage: 0.25 }] }; const SECOND_BRACKET$1 = { min: thousand(600), max: thousand(700), stages: [{ min: 0, max: thousand(30), percentage: 0.025 }, { min: thousand(30), max: thousand(45), percentage: 0.1 }, { min: thousand(45), max: thousand(60), percentage: 0.15 }, { min: thousand(60), max: thousand(200), percentage: 0.2 }, { min: thousand(200), max: thousand(400), percentage: 0.225 }, { min: thousand(400), max: Infinity, percentage: 0.25 }] }; const THIRD_BRACKET$1 = { min: thousand(700), max: thousand(800), stages: [{ min: 0, max: thousand(45), percentage: 0.1 }, { min: thousand(45), max: thousand(60), percentage: 0.15 }, { min: thousand(60), max: thousand(200), percentage: 0.2 }, { min: thousand(200), max: thousand(400), percentage: 0.225 }, { min: thousand(400), max: Infinity, percentage: 0.25 }] }; const FOURTH_BRACKET$1 = { min: thousand(800), max: thousand(900), stages: [{ min: 0, max: thousand(60), percentage: 0.15 }, { min: thousand(60), max: thousand(200), percentage: 0.2 }, { min: thousand(200), max: thousand(400), percentage: 0.225 }, { min: thousand(400), max: Infinity, percentage: 0.25 }] }; //diff applied const FIFTH_BRACKET$2 = { min: thousand(900), max: million(1), stages: [{ min: 0, max: thousand(200), percentage: 0.2 }, { min: thousand(200), max: thousand(400), percentage: 0.225 }, { min: thousand(400), max: Infinity, percentage: 0.25 }] }; //diff applied const SIXTH_BRACKET$2 = { min: million(1), max: Infinity, stages: [{ min: 0, max: thousand(400), percentage: 0.255 }, { min: thousand(400), max: Infinity, percentage: 0.25 }] }; const TWENTY_TWO = { brackets: [FIRST_BRACKET$2, SECOND_BRACKET$1, THIRD_BRACKET$1, FOURTH_BRACKET$1, FIFTH_BRACKET$2, SIXTH_BRACKET$2], exemptionThreshold: thousand(9), MaxGrossSalary: 9400, MinGrossSalary: 1400 }; const FIRST_BRACKET$1 = { ...TWENTY_TWO.brackets[0], stages: [{ ...TWENTY_TWO.brackets[0].stages[0], min: thousand(21) }, ...TWENTY_TWO.brackets[0].stages.slice(1)] }; const FIFTH_BRACKET$1 = { ...TWENTY_TWO.brackets[4], max: million(1.2) }; const SIXTH_BRACKET$1 = { min: million(1.2), max: Infinity, stages: [{ min: 0, max: million(1.2), percentage: 0.25 }, { min: million(1.2), max: Infinity, percentage: 0.275 }] }; const TWENTY_THREE = { brackets: [FIRST_BRACKET$1, TWENTY_TWO.brackets[1], TWENTY_TWO.brackets[2], TWENTY_TWO.brackets[3], FIFTH_BRACKET$1, SIXTH_BRACKET$1], exemptionThreshold: thousand(15), MaxGrossSalary: 10900, MinGrossSalary: 1700 }; const FIRST_BRACKET = { min: 1, max: thousand(600), stages: [{ min: thousand(40), max: thousand(55), percentage: 0.1 }, { min: thousand(55), max: thousand(70), percentage: 0.15 }, { min: thousand(70), max: thousand(200), percentage: 0.2 }, { min: thousand(200), max: thousand(400), percentage: 0.225 }, { min: thousand(400), max: Infinity, percentage: 0.25 }] }; const SECOND_BRACKET = { min: thousand(600), max: thousand(700), stages: [{ min: 0, max: thousand(55), percentage: 0.1 }, { min: thousand(55), max: thousand(70), percentage: 0.15 }, { min: thousand(70), max: thousand(200), percentage: 0.2 }, { min: thousand(200), max: thousand(400), percentage: 0.225 }, { min: thousand(400), max: Infinity, percentage: 0.25 }] }; const THIRD_BRACKET = { min: thousand(700), max: thousand(800), stages: [{ min: 0, max: thousand(70), percentage: 0.15 }, { min: thousand(70), max: thousand(200), percentage: 0.2 }, { min: thousand(200), max: thousand(400), percentage: 0.225 }, { min: thousand(400), max: Infinity, percentage: 0.25 }] }; const FOURTH_BRACKET = { min: thousand(800), max: thousand(900), stages: [{ min: 0, max: thousand(200), percentage: 0.2 }, { min: thousand(200), max: thousand(400), percentage: 0.225 }, { min: thousand(400), max: Infinity, percentage: 0.25 }] }; //diff applied const FIFTH_BRACKET = { min: thousand(900), max: million(1.2), stages: [{ min: 0, max: thousand(400), percentage: 0.225 }, { min: thousand(400), max: Infinity, percentage: 0.25 }] }; //diff applied const SIXTH_BRACKET = { min: million(1.2), max: Infinity, stages: [{ min: 0, max: million(1.2), percentage: 0.25 }, { min: million(1.2), max: Infinity, percentage: 0.275 }] }; const TWENTY_FOUR = { brackets: [FIRST_BRACKET, SECOND_BRACKET, THIRD_BRACKET, FOURTH_BRACKET, FIFTH_BRACKET, SIXTH_BRACKET], exemptionThreshold: thousand(20), MaxGrossSalary: 14500, MinGrossSalary: 2300 }; exports.LawYear = void 0; (function (LawYear) { LawYear["TWENTY_TWO"] = "2022"; LawYear["TWENTY_THREE"] = "2023"; LawYear["TWENTY_FOUR"] = "2024"; })(exports.LawYear || (exports.LawYear = {})); const laws = { [exports.LawYear.TWENTY_TWO]: TWENTY_TWO, [exports.LawYear.TWENTY_THREE]: TWENTY_THREE, [exports.LawYear.TWENTY_FOUR]: TWENTY_FOUR }; const calculateInsuranceWage = (grossSalary, lawYear) => { return Math.max(laws[lawYear].MinGrossSalary, Math.min(grossSalary, laws[lawYear].MaxGrossSalary)); }; const calculateYearlySalaryTax = (lawYear, yearlySalary) => { const taxBracket = laws[lawYear].brackets.find(item => { return isSupported(item, yearlySalary) ? item : false; }); return calculateTax(taxBracket, yearlySalary); }; const calculateSalaryTax = ({ grossSalary, socialInsuranceWorkerShare, lawYear }) => { const monthlyTaxExemption = laws[lawYear].exemptionThreshold / 12; const salaryAfterSocialInsurance = grossSalary - socialInsuranceWorkerShare; const salaryAfterSocialInsuranceAndExemption = salaryAfterSocialInsurance - monthlyTaxExemption; const yearlySalary = salaryAfterSocialInsuranceAndExemption * 12; const yearlySalaryTax = calculateYearlySalaryTax(lawYear, yearlySalary); return yearlySalaryTax / 12; }; const calculateSocialInsurance = insuranceWage => { return insuranceWage * 0.11; }; const calculateSocialInsuranceEmployerShare = insuranceWage => { return insuranceWage * 0.1875; }; const calculateNetSalary = ({ grossSalary, insuranceWage, bonus = 0, deduction = 0, isInsured = true, lawYear = exports.LawYear.TWENTY_FOUR }) => { grossSalary += bonus; grossSalary -= deduction; // TODO: check if the input insurance wage is allowed insuranceWage = isInsured ? insuranceWage ?? calculateInsuranceWage(grossSalary, lawYear) : 0; const socialInsuranceWorkerShare = calculateSocialInsurance(insuranceWage); const socialInsuranceEmployerShare = calculateSocialInsuranceEmployerShare(insuranceWage); const martyrsFamiliesFunds = grossSalary * 0.0005; const salaryTax = calculateSalaryTax({ grossSalary, socialInsuranceWorkerShare, lawYear }); const totalDeduction = socialInsuranceWorkerShare + martyrsFamiliesFunds + salaryTax; const netSalary = grossSalary - totalDeduction; return [netSalary, { insuranceWage, socialInsuranceWorkerShare, salaryTax, martyrsFamiliesFunds, socialInsuranceEmployerShare, totalDeduction }]; }; class NetSalaryGoalSeek { seek(netSalary, { tolerancePercentage = 0.0001, ...options }) { const MAX_INT = 2 ** 31 - 1; let lowestGrossSalary = netSalary, highestGrossSalary = MAX_INT; while (lowestGrossSalary <= highestGrossSalary) { const grossSalary = lowestGrossSalary + (highestGrossSalary - lowestGrossSalary) / 2; const [approximateNetSalary, variantCalculations] = calculateNetSalary({ grossSalary, ...options }); const errorPercentage = Math.abs(approximateNetSalary - netSalary) / netSalary * 100; if (errorPercentage <= tolerancePercentage) return [grossSalary, variantCalculations];else if (approximateNetSalary < netSalary) lowestGrossSalary = grossSalary + tolerancePercentage;else highestGrossSalary = grossSalary - tolerancePercentage; } return [-1, {}]; } } const calculateGrossSalary = ({ netSalary, insuranceWage, bonus = 0, deduction = 0, lawYear = exports.LawYear.TWENTY_FOUR }) => { const netSalaryGoalSeek = new NetSalaryGoalSeek(); const [grossSalary, variantCalculations] = netSalaryGoalSeek.seek(netSalary, { insuranceWage, bonus, deduction, lawYear }); return [grossSalary, variantCalculations]; }; exports.calculateGrossSalary = calculateGrossSalary; exports.calculateNetSalary = calculateNetSalary; //# sourceMappingURL=index.js.map