Published
Edited
Feb 6, 2022
1 star
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
expensesUK = ({
rent: 900,
bills: 150,
food: 300
})
Insert cell
expensesGermany = ({
rent: 800,
bills: 0,
food: 300
})
Insert cell
Insert cell
takeHomePayGermany = getTakeHomePay(netIncomeGermany["netPay"], expensesGermany)
Insert cell
takeHomePayUK = getTakeHomePay(netIncomeUK["netPay"], expensesUK)
Insert cell
getNetIncome = (income, country) => {
const taxes = {};
console.log(taxes);
taxRanges[country].forEach(
({ min = 0, max = 10000000, getRate, label, of }) => {
const rate = _.isFunction(getRate)
? getRate(income > max ? max : income, taxes)
: getRate;

let ofAmount;
if (of) {
ofAmount = _.isFunction(of) ? of(income, taxes) : taxes[of];
} else {
ofAmount = income;
}
const amountToApplyTaxOn = ofAmount > max ? max - min : ofAmount - min;

let value = 0;
if (ofAmount > min) {
value = _.round((rate * amountToApplyTaxOn) / 100, 0);
}

console.log({
label,
min,
max,
getRate,
rate,
of,
amountToApplyTaxOn,
ofAmount,
value
});

if (label in taxes) {
taxes[label] += value;
} else {
taxes[label] = value;
}
}
);

let totalTax = 0;
Object.entries(taxes).forEach(([key, value]) => (totalTax += value));
const netPay = income - totalTax;
return { netPay: netPay, ...taxes };
}
Insert cell
Insert cell
test("getNetIncome", () => {
expect(getNetIncome(80000, "UK")).toEqual({
incomeTax: 19432,
nationalInsurance: 5479,
netPay: 55089
});
})
Insert cell
test("getNetIncome", () => {
expect(getNetIncome(80000, "Germany")).toEqual({
pension: 7440,
healthInsurance: 4238,
additionalHealthInsurance: 290,
longTermCareInsurance: 1030,
unemploymentInsurance: 960,
incomeTax: 16738, //TODO: This is an underestimate.
netPay: 49304
});
})
Insert cell
getGermanTaxableIncome = (
income,
{
pension,
unemploymentInsurance,
healthInsurance,
additionalHealthInsurance,
longTermCareInsurance
}
) =>
income -
(pension +
unemploymentInsurance +
healthInsurance +
additionalHealthInsurance +
longTermCareInsurance)
Insert cell
taxRanges = ({
UK: [
// https://www.gov.uk/income-tax-rates
{
max: 12570,
getRate: 0,
label: "incomeTax"
},
{
min: 12570,
max: 50270,
getRate: 20,
label: "incomeTax"
},
{
min: 50270,
max: 150000,
getRate: 40,
label: "incomeTax"
},
{
min: 150000,
getRate: 45,
label: "incomeTax"
},
{
// https://www.gov.uk/national-insurance/how-much-you-pay
label: "nationalInsurance",
min: 9564,
max: 50268,
getRate: 12
},
{
label: "nationalInsurance",
min: 50268,
getRate: 2
}
],
Germany: [
// https://www.iamexpat.de/expat-info/taxation-germany/german-tax-system
// https://www.steuergo.de/en/rechner/brutto_netto_rechner
// https://taxsummaries.pwc.com/germany/individual/other-taxes
{
getRate: 9.3,
max: 85200,
label: "pension"
},
{
getRate: 1.2,
max: 85200,
label: "unemploymentInsurance"
},
{
getRate: 7.3,
max: 58050,
label: "healthInsurance"
},
{
getRate: 1 / 2,
max: 58050,
label: "additionalHealthInsurance"
},
{
getRate: 1.775,
max: 58050,
label: "longTermCareInsurance"
},
{
max: 9984,
getRate: 0,
label: "incomeTax",
of: getGermanTaxableIncome
},
{
min: 9984,
max: 58596,
getRate: (income, taxes) =>
14 + ((income - 9984) * (42 - 14)) / 2 / (58596 - 9984),
label: "incomeTax",
of: getGermanTaxableIncome
},
{
min: 58596,
max: 277825,
getRate: 42,
label: "incomeTax",
of: getGermanTaxableIncome
},
{
min: 277826,
getRate: 45,
label: "incomeTax"
}
// TODO: Add solidarity surcharge
]
})
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more