@dlivr.io/salary-calculator-egypt
Version:
Javascript SDK for calculating Net/Gross salary in Egypt.
436 lines (419 loc) • 9.94 kB
JavaScript
'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