@novha/calc-engines 1.0.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/domain/types.js +1 -1
- package/dist/income-tax/canada/CanadaIncomeTaxServiceImpl.js +5 -5
- package/dist/income-tax/canada/domain/types.js +1 -1
- package/dist/income-tax/france/FranceIncomeTaxService.js +3 -0
- package/dist/income-tax/france/FranceIncomeTaxServiceImpl.js +48 -0
- package/dist/income-tax/france/domain/types.js +3 -0
- package/dist/index.js +19 -2
- package/dist/types/domain/types.d.ts +7 -2
- package/dist/types/income-tax/canada/domain/types.d.ts +11 -9
- package/dist/types/income-tax/france/FranceIncomeTaxService.d.ts +4 -0
- package/dist/types/income-tax/france/FranceIncomeTaxServiceImpl.d.ts +11 -0
- package/dist/types/income-tax/france/domain/types.d.ts +29 -0
- package/dist/types/index.d.ts +4 -1
- package/package.json +1 -1
- package/src/domain/types.ts +8 -2
- package/src/income-tax/canada/CanadaIncomeTaxServiceImpl.ts +5 -5
- package/src/income-tax/canada/domain/types.ts +13 -10
- package/src/income-tax/france/FranceIncomeTaxService.ts +5 -0
- package/src/income-tax/france/FranceIncomeTaxServiceImpl.ts +64 -0
- package/src/income-tax/france/domain/types.ts +32 -0
- package/src/index.ts +12 -1
package/dist/domain/types.js
CHANGED
|
@@ -7,4 +7,4 @@ var CalculatorType;
|
|
|
7
7
|
CalculatorType["MORTGAGE"] = "MORTGAGE";
|
|
8
8
|
CalculatorType["LOAN"] = "LOAN";
|
|
9
9
|
})(CalculatorType || (exports.CalculatorType = CalculatorType = {}));
|
|
10
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
10
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvZG9tYWluL3R5cGVzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLElBQVksY0FJWDtBQUpELFdBQVksY0FBYztJQUN0QiwyQ0FBeUIsQ0FBQTtJQUN6Qix1Q0FBcUIsQ0FBQTtJQUNyQiwrQkFBYSxDQUFBO0FBQ2pCLENBQUMsRUFKVyxjQUFjLDhCQUFkLGNBQWMsUUFJekIiLCJzb3VyY2VzQ29udGVudCI6WyJleHBvcnQgZW51bSBDYWxjdWxhdG9yVHlwZSB7XG4gICAgSU5DT01FX1RBWCA9ICdJTkNPTUVfVEFYJyxcbiAgICBNT1JUR0FHRSA9ICdNT1JUR0FHRScsXG4gICAgTE9BTiA9ICdMT0FOJ1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFJ1bGVNZXRhIHtcbiAgICBpZDogc3RyaW5nO1xuICAgIGNvdW50cnk6IHN0cmluZztcbiAgICByZWdpb246IHN0cmluZztcbiAgICBjYWxjdWxhdG9yOiBDYWxjdWxhdG9yVHlwZTtcbiAgICB2ZXJzaW9uOiBzdHJpbmc7XG4gICAgZWZmZWN0aXZlZnJvbTogc3RyaW5nO1xuICAgIGVmZmVjdGl2ZXRvOiBzdHJpbmcgfCBudWxsO1xuICAgIHNvdXJjZT86IFJ1bGVTb3VyY2VbXTtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBSdWxlU291cmNlIHtcbiAgICBuYW1lOiBzdHJpbmc7XG4gICAgdXJsOiBzdHJpbmc7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgUnVsZUlucHV0IHtcbiAgICBuYW1lOiBzdHJpbmc7XG4gICAgdHlwZTogJ251bWJlcicgfCAnc2VsZWN0JyB8ICd0ZXh0JztcbiAgICByZXF1aXJlZDogYm9vbGVhbjtcbiAgICB1bml0Pzogc3RyaW5nO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFJ1bGVPdXRwdXQge1xuICAgIG5hbWU6IHN0cmluZztcbiAgICB0eXBlOiAnbnVtYmVyJyB8ICdzdHJpbmcnO1xuICAgIHVuaXQ/OiBzdHJpbmc7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgVGF4QnJhY2tldCB7XG4gICAgZnJvbTogbnVtYmVyO1xuICAgIHRvOiBudW1iZXIgfCBudWxsO1xuICAgIHJhdGU6IG51bWJlcjtcbn0iXX0=
|
|
@@ -7,7 +7,7 @@ class CanadaIncomeTaxServiceImpl {
|
|
|
7
7
|
this._rules = rules;
|
|
8
8
|
}
|
|
9
9
|
calculateNetIncome() {
|
|
10
|
-
const grossTax = this.computeGrossTax(this._income, this._rules.
|
|
10
|
+
const grossTax = this.computeGrossTax(this._income, this._rules.taxBrackets);
|
|
11
11
|
const netTax = this.applyCredits(grossTax, this._rules.credits);
|
|
12
12
|
const cpp = this.computeCPP(this._income, this._rules.contributions?.cpp);
|
|
13
13
|
const ei = this.computeEI(this._income, this._rules.contributions?.ei);
|
|
@@ -38,14 +38,14 @@ class CanadaIncomeTaxServiceImpl {
|
|
|
38
38
|
if (!cpp || income <= cpp.exemption)
|
|
39
39
|
return 0;
|
|
40
40
|
const contributable = income - cpp.exemption;
|
|
41
|
-
return Math.min(contributable * cpp.rate, cpp.
|
|
41
|
+
return Math.min(contributable * cpp.rate, cpp.maxContribution);
|
|
42
42
|
}
|
|
43
43
|
computeEI(income, ei) {
|
|
44
44
|
if (!ei)
|
|
45
45
|
return 0;
|
|
46
|
-
const insurableIncome = Math.min(income, ei.
|
|
47
|
-
return Math.min(insurableIncome * ei.rate, ei.
|
|
46
|
+
const insurableIncome = Math.min(income, ei.maxInsurableEarnings);
|
|
47
|
+
return Math.min(insurableIncome * ei.rate, ei.maxContribution);
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
50
|
exports.CanadaIncomeTaxServiceImpl = CanadaIncomeTaxServiceImpl;
|
|
51
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
51
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQ2FuYWRhSW5jb21lVGF4U2VydmljZUltcGwuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvaW5jb21lLXRheC9jYW5hZGEvQ2FuYWRhSW5jb21lVGF4U2VydmljZUltcGwudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBV0EsTUFBYSwwQkFBMEI7SUFJbkMsWUFBWSxNQUFjLEVBQUUsS0FBcUI7UUFDN0MsSUFBSSxDQUFDLE9BQU8sR0FBRyxNQUFNLENBQUM7UUFDdEIsSUFBSSxDQUFDLE1BQU0sR0FBRyxLQUFLLENBQUM7SUFDeEIsQ0FBQztJQUVNLGtCQUFrQjtRQUVyQixNQUFNLFFBQVEsR0FBRyxJQUFJLENBQUMsZUFBZSxDQUFDLElBQUksQ0FBQyxPQUFPLEVBQUUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxXQUFXLENBQUMsQ0FBQztRQUM3RSxNQUFNLE1BQU0sR0FBRyxJQUFJLENBQUMsWUFBWSxDQUFDLFFBQVEsRUFBRSxJQUFJLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ2hFLE1BQU0sR0FBRyxHQUFHLElBQUksQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBRSxJQUFJLENBQUMsTUFBTSxDQUFDLGFBQWEsRUFBRSxHQUFHLENBQUMsQ0FBQztRQUMxRSxNQUFNLEVBQUUsR0FBRyxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxPQUFPLEVBQUUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxhQUFhLEVBQUUsRUFBRSxDQUFDLENBQUM7UUFFdkUsT0FBTztZQUNILFdBQVcsRUFBRSxJQUFJLENBQUMsT0FBTztZQUN6QixTQUFTLEVBQUUsTUFBTTtZQUNqQixHQUFHO1lBQ0gsRUFBRTtZQUNGLGVBQWUsRUFBRSxNQUFNLEdBQUcsR0FBRyxHQUFHLEVBQUU7WUFDbEMsU0FBUyxFQUFFLElBQUksQ0FBQyxPQUFPLEdBQUcsTUFBTSxHQUFHLEdBQUcsR0FBRyxFQUFFO1lBQzNDLGdCQUFnQixFQUFFLE1BQU0sR0FBRyxJQUFJLENBQUMsT0FBTztTQUMxQyxDQUFDO0lBQ04sQ0FBQztJQUVPLGVBQWUsQ0FBQyxNQUFjLEVBQUUsUUFBc0I7UUFDMUQsT0FBTyxRQUFRLENBQUMsTUFBTSxDQUFDLENBQUMsS0FBSyxFQUFFLENBQUMsRUFBRSxFQUFFO1lBQ2hDLElBQUksTUFBTSxJQUFJLENBQUMsQ0FBQyxJQUFJO2dCQUFFLE9BQU8sS0FBSyxDQUFDO1lBRW5DLE1BQU0sS0FBSyxHQUFHLENBQUMsQ0FBQyxFQUFFLElBQUksTUFBTSxDQUFDO1lBQzdCLE1BQU0sT0FBTyxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsTUFBTSxFQUFFLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQyxJQUFJLENBQUM7WUFFakQsT0FBTyxLQUFLLEdBQUcsT0FBTyxHQUFHLENBQUMsQ0FBQyxJQUFJLENBQUM7UUFDcEMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO0lBQ1YsQ0FBQztJQUVPLFlBQVksQ0FBQyxHQUFXLEVBQUUsVUFBcUMsRUFBRTtRQUNyRSxNQUFNLFlBQVksR0FBRyxNQUFNLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxDQUFDLE1BQU0sQ0FDOUMsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxHQUFHLEdBQUcsQ0FBQyxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUMsSUFBSSxFQUNuQyxDQUFDLENBQ0osQ0FBQztRQUVGLE9BQU8sSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsR0FBRyxHQUFHLFlBQVksQ0FBQyxDQUFDO0lBQzNDLENBQUM7SUFFTyxVQUFVLENBQUMsTUFBYyxFQUFFLEdBQXFCO1FBQ3BELElBQUksQ0FBQyxHQUFHLElBQUksTUFBTSxJQUFJLEdBQUcsQ0FBQyxTQUFTO1lBQUUsT0FBTyxDQUFDLENBQUM7UUFFOUMsTUFBTSxhQUFhLEdBQUcsTUFBTSxHQUFHLEdBQUcsQ0FBQyxTQUFTLENBQUM7UUFDN0MsT0FBTyxJQUFJLENBQUMsR0FBRyxDQUNYLGFBQWEsR0FBRyxHQUFHLENBQUMsSUFBSSxFQUN4QixHQUFHLENBQUMsZUFBZSxDQUN0QixDQUFDO0lBQ04sQ0FBQztJQUVPLFNBQVMsQ0FBQyxNQUFjLEVBQUUsRUFBbUI7UUFDakQsSUFBSSxDQUFDLEVBQUU7WUFBRSxPQUFPLENBQUMsQ0FBQztRQUVsQixNQUFNLGVBQWUsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUM1QixNQUFNLEVBQ04sRUFBRSxDQUFDLG9CQUFvQixDQUMxQixDQUFDO1FBRUYsT0FBTyxJQUFJLENBQUMsR0FBRyxDQUNYLGVBQWUsR0FBRyxFQUFFLENBQUMsSUFBSSxFQUN6QixFQUFFLENBQUMsZUFBZSxDQUNyQixDQUFDO0lBQ04sQ0FBQztDQUNKO0FBdEVELGdFQXNFQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IFRheEJyYWNrZXQgfSBmcm9tIFwiLi4vLi4vZG9tYWluL3R5cGVzXCI7XG5pbXBvcnQgeyBDYW5hZGFJbmNvbWVUYXhTZXJ2aWNlIH0gZnJvbSBcIi4vQ2FuYWRhSW5jb21lVGF4U2VydmljZVwiO1xuaW1wb3J0IHtcbiAgICBDUFBDb250cmlidXRpb24sXG4gICAgQ29tcHV0ZWRJbmNvbWVUYXhWYWx1ZXMsXG4gICAgRUlDb250cmlidXRpb24sXG4gICAgSW5jb21lVGF4UnVsZXMsXG4gICAgVGF4Q3JlZGl0XG59IGZyb20gXCIuL2RvbWFpbi90eXBlc1wiO1xuXG5cbmV4cG9ydCBjbGFzcyBDYW5hZGFJbmNvbWVUYXhTZXJ2aWNlSW1wbCBpbXBsZW1lbnRzIENhbmFkYUluY29tZVRheFNlcnZpY2Uge1xuICAgIHByaXZhdGUgX2luY29tZTogbnVtYmVyO1xuICAgIHByaXZhdGUgX3J1bGVzOiBJbmNvbWVUYXhSdWxlcztcblxuICAgIGNvbnN0cnVjdG9yKGluY29tZTogbnVtYmVyLCBydWxlczogSW5jb21lVGF4UnVsZXMpIHtcbiAgICAgICAgdGhpcy5faW5jb21lID0gaW5jb21lO1xuICAgICAgICB0aGlzLl9ydWxlcyA9IHJ1bGVzO1xuICAgIH1cblxuICAgIHB1YmxpYyBjYWxjdWxhdGVOZXRJbmNvbWUoKTogQ29tcHV0ZWRJbmNvbWVUYXhWYWx1ZXMge1xuXG4gICAgICAgIGNvbnN0IGdyb3NzVGF4ID0gdGhpcy5jb21wdXRlR3Jvc3NUYXgodGhpcy5faW5jb21lLCB0aGlzLl9ydWxlcy50YXhCcmFja2V0cyk7XG4gICAgICAgIGNvbnN0IG5ldFRheCA9IHRoaXMuYXBwbHlDcmVkaXRzKGdyb3NzVGF4LCB0aGlzLl9ydWxlcy5jcmVkaXRzKTtcbiAgICAgICAgY29uc3QgY3BwID0gdGhpcy5jb21wdXRlQ1BQKHRoaXMuX2luY29tZSwgdGhpcy5fcnVsZXMuY29udHJpYnV0aW9ucz8uY3BwKTtcbiAgICAgICAgY29uc3QgZWkgPSB0aGlzLmNvbXB1dGVFSSh0aGlzLl9pbmNvbWUsIHRoaXMuX3J1bGVzLmNvbnRyaWJ1dGlvbnM/LmVpKTtcblxuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgZ3Jvc3NJbmNvbWU6IHRoaXMuX2luY29tZSxcbiAgICAgICAgICAgIGluY29tZVRheDogbmV0VGF4LFxuICAgICAgICAgICAgY3BwLFxuICAgICAgICAgICAgZWksXG4gICAgICAgICAgICB0b3RhbERlZHVjdGlvbnM6IG5ldFRheCArIGNwcCArIGVpLFxuICAgICAgICAgICAgbmV0SW5jb21lOiB0aGlzLl9pbmNvbWUgLSBuZXRUYXggLSBjcHAgLSBlaSxcbiAgICAgICAgICAgIGVmZmVjdGl2ZVRheFJhdGU6IG5ldFRheCAvIHRoaXMuX2luY29tZSxcbiAgICAgICAgfTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGNvbXB1dGVHcm9zc1RheChpbmNvbWU6IG51bWJlciwgYnJhY2tldHM6IFRheEJyYWNrZXRbXSk6IG51bWJlciB7XG4gICAgICAgIHJldHVybiBicmFja2V0cy5yZWR1Y2UoKHRvdGFsLCBiKSA9PiB7XG4gICAgICAgICAgICBpZiAoaW5jb21lIDw9IGIuZnJvbSkgcmV0dXJuIHRvdGFsO1xuICAgIFxuICAgICAgICAgICAgY29uc3QgdXBwZXIgPSBiLnRvID8/IGluY29tZTtcbiAgICAgICAgICAgIGNvbnN0IHRheGFibGUgPSBNYXRoLm1pbihpbmNvbWUsIHVwcGVyKSAtIGIuZnJvbTtcbiAgICBcbiAgICAgICAgICAgIHJldHVybiB0b3RhbCArIHRheGFibGUgKiBiLnJhdGU7XG4gICAgICAgIH0sIDApO1xuICAgIH1cblxuICAgIHByaXZhdGUgYXBwbHlDcmVkaXRzKHRheDogbnVtYmVyLCBjcmVkaXRzOiBSZWNvcmQ8c3RyaW5nLCBUYXhDcmVkaXQ+ID0ge30pOiBudW1iZXIge1xuICAgICAgICBjb25zdCB0b3RhbENyZWRpdHMgPSBPYmplY3QudmFsdWVzKGNyZWRpdHMpLnJlZHVjZShcbiAgICAgICAgICAgIChzdW0sIGMpID0+IHN1bSArIGMuYW1vdW50ICogYy5yYXRlLFxuICAgICAgICAgICAgMCxcbiAgICAgICAgKTtcbiAgICBcbiAgICAgICAgcmV0dXJuIE1hdGgubWF4KDAsIHRheCAtIHRvdGFsQ3JlZGl0cyk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBjb21wdXRlQ1BQKGluY29tZTogbnVtYmVyLCBjcHA/OiBDUFBDb250cmlidXRpb24pOiBudW1iZXIge1xuICAgICAgICBpZiAoIWNwcCB8fCBpbmNvbWUgPD0gY3BwLmV4ZW1wdGlvbikgcmV0dXJuIDA7XG4gICAgXG4gICAgICAgIGNvbnN0IGNvbnRyaWJ1dGFibGUgPSBpbmNvbWUgLSBjcHAuZXhlbXB0aW9uO1xuICAgICAgICByZXR1cm4gTWF0aC5taW4oXG4gICAgICAgICAgICBjb250cmlidXRhYmxlICogY3BwLnJhdGUsXG4gICAgICAgICAgICBjcHAubWF4Q29udHJpYnV0aW9uLFxuICAgICAgICApO1xuICAgIH1cblxuICAgIHByaXZhdGUgY29tcHV0ZUVJKGluY29tZTogbnVtYmVyLCBlaT86IEVJQ29udHJpYnV0aW9uKTogbnVtYmVyIHtcbiAgICAgICAgaWYgKCFlaSkgcmV0dXJuIDA7XG4gICAgXG4gICAgICAgIGNvbnN0IGluc3VyYWJsZUluY29tZSA9IE1hdGgubWluKFxuICAgICAgICAgICAgaW5jb21lLFxuICAgICAgICAgICAgZWkubWF4SW5zdXJhYmxlRWFybmluZ3MsXG4gICAgICAgICk7XG4gICAgXG4gICAgICAgIHJldHVybiBNYXRoLm1pbihcbiAgICAgICAgICAgIGluc3VyYWJsZUluY29tZSAqIGVpLnJhdGUsXG4gICAgICAgICAgICBlaS5tYXhDb250cmlidXRpb24sXG4gICAgICAgICk7XG4gICAgfVxufSJdfQ==
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
3
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvaW5jb21lLXRheC9jYW5hZGEvZG9tYWluL3R5cGVzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiIiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBSdWxlSW5wdXQsIFJ1bGVNZXRhLCBSdWxlT3V0cHV0LCBUYXhCcmFja2V0IH0gZnJvbSBcIi4uLy4uLy4uL2RvbWFpbi90eXBlc1wiO1xuXG5leHBvcnQgaW50ZXJmYWNlIEluY29tZVRheFJ1bGVzIHtcbiAgICB0YXhCcmFja2V0czogVGF4QnJhY2tldFtdO1xuICAgIGNyZWRpdHM/OiBSZWNvcmQ8c3RyaW5nLCBUYXhDcmVkaXQ+O1xuICAgIGNvbnRyaWJ1dGlvbnM/OiBDb250cmlidXRpb25zO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFRheENyZWRpdCB7XG4gICAgYW1vdW50OiBudW1iZXI7XG4gICAgdHlwZTogJ25vblJlZnVuZGFibGUnIHwgJ3JlZnVuZGFibGUnO1xuICAgIHJhdGU6IG51bWJlcjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBDb250cmlidXRpb25zIHtcbiAgICBjcHA/OiBDUFBDb250cmlidXRpb247XG4gICAgZWk/OiBFSUNvbnRyaWJ1dGlvbjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBDUFBDb250cmlidXRpb24ge1xuICAgIHJhdGU6IG51bWJlcjtcbiAgICBtYXhDb250cmlidXRpb246IG51bWJlcjtcbiAgICBleGVtcHRpb246IG51bWJlcjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBFSUNvbnRyaWJ1dGlvbiB7XG4gICAgcmF0ZTogbnVtYmVyO1xuICAgIG1heEluc3VyYWJsZUVhcm5pbmdzOiBudW1iZXI7XG4gICAgbWF4Q29udHJpYnV0aW9uOiBudW1iZXI7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgQ29tcHV0ZWRJbmNvbWVUYXhWYWx1ZXMge1xuICAgIGdyb3NzSW5jb21lOiBudW1iZXI7XG4gICAgaW5jb21lVGF4OiBudW1iZXI7XG4gICAgY3BwOiBudW1iZXI7XG4gICAgZWk6IG51bWJlcjtcbiAgICB0b3RhbERlZHVjdGlvbnM6IG51bWJlcjtcbiAgICBuZXRJbmNvbWU6IG51bWJlcjtcbiAgICBlZmZlY3RpdmVUYXhSYXRlOiBudW1iZXI7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgSW5jb21lVGF4Q2FsY3VsYXRvclNjaGVtYSB7XG5cdG1ldGE6IFJ1bGVNZXRhO1xuXHRpbnB1dHM6IFJ1bGVJbnB1dFtdO1xuXHRvdXRwdXRzOiBSdWxlT3V0cHV0W107XG5cdHJ1bGVzOiBJbmNvbWVUYXhSdWxlcztcbn1cbiJdfQ==
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRnJhbmNlSW5jb21lVGF4U2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9pbmNvbWUtdGF4L2ZyYW5jZS9GcmFuY2VJbmNvbWVUYXhTZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiIiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDb21wdXRlZEluY29tZVRheFZhbHVlcyB9IGZyb20gXCIuL2RvbWFpbi90eXBlc1wiO1xuXG5leHBvcnQgaW50ZXJmYWNlIEZyYW5jZUluY29tZVRheFNlcnZpY2Uge1xuICAgIGNhbGN1bGF0ZU5ldEluY29tZShpbmNvbWU6IG51bWJlcik6IENvbXB1dGVkSW5jb21lVGF4VmFsdWVzO1xufSJdfQ==
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FranceIncomeTaxServiceImpl = void 0;
|
|
4
|
+
class FranceIncomeTaxServiceImpl {
|
|
5
|
+
constructor(income, rules, familyParts) {
|
|
6
|
+
this._income = income;
|
|
7
|
+
this._rules = rules;
|
|
8
|
+
this._familyParts = familyParts;
|
|
9
|
+
}
|
|
10
|
+
calculateNetIncome() {
|
|
11
|
+
const taxablePerPart = this._familyParts * this._income / this._familyParts;
|
|
12
|
+
const { tax: taxPerPart, marginalRate } = this.calculateProgressiveTax(taxablePerPart);
|
|
13
|
+
const incomeTax = taxPerPart * this._familyParts;
|
|
14
|
+
const socialContributions = this._income * this._rules.socialContributions.employee.rate;
|
|
15
|
+
const totalDeductions = incomeTax + socialContributions;
|
|
16
|
+
const netIncome = this._income - totalDeductions;
|
|
17
|
+
return {
|
|
18
|
+
grossIncome: this._income,
|
|
19
|
+
incomeTax: this.round(incomeTax),
|
|
20
|
+
socialContributions: this.round(socialContributions),
|
|
21
|
+
totalDeductions: this.round(totalDeductions),
|
|
22
|
+
netIncome: this.round(netIncome),
|
|
23
|
+
averageTaxRate: this.round(incomeTax / this._income),
|
|
24
|
+
marginalTaxRate: marginalRate,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
calculateProgressiveTax(income) {
|
|
28
|
+
let tax = 0;
|
|
29
|
+
let marginalRate = 0;
|
|
30
|
+
for (const bracket of this._rules.taxBrackets) {
|
|
31
|
+
const upperBound = bracket.to ?? income;
|
|
32
|
+
if (income <= bracket.from) {
|
|
33
|
+
break;
|
|
34
|
+
}
|
|
35
|
+
const taxableAmount = Math.min(upperBound, income) - bracket.from;
|
|
36
|
+
if (taxableAmount > 0) {
|
|
37
|
+
tax += taxableAmount * bracket.rate;
|
|
38
|
+
marginalRate = bracket.rate;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return { tax, marginalRate };
|
|
42
|
+
}
|
|
43
|
+
round(value) {
|
|
44
|
+
return Math.round(value * 100) / 100;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
exports.FranceIncomeTaxServiceImpl = FranceIncomeTaxServiceImpl;
|
|
48
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRnJhbmNlSW5jb21lVGF4U2VydmljZUltcGwuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvaW5jb21lLXRheC9mcmFuY2UvRnJhbmNlSW5jb21lVGF4U2VydmljZUltcGwudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBR0EsTUFBYSwwQkFBMEI7SUFLbkMsWUFBWSxNQUFjLEVBQUUsS0FBcUIsRUFBRSxXQUFtQjtRQUNsRSxJQUFJLENBQUMsT0FBTyxHQUFHLE1BQU0sQ0FBQztRQUN0QixJQUFJLENBQUMsTUFBTSxHQUFHLEtBQUssQ0FBQztRQUNwQixJQUFJLENBQUMsWUFBWSxHQUFHLFdBQVcsQ0FBQztJQUNwQyxDQUFDO0lBRU0sa0JBQWtCO1FBRTNCLE1BQU0sY0FBYyxHQUFHLElBQUksQ0FBQyxZQUFZLEdBQUcsSUFBSSxDQUFDLE9BQU8sR0FBRyxJQUFJLENBQUMsWUFBWSxDQUFDO1FBQzVFLE1BQU0sRUFBRSxHQUFHLEVBQUUsVUFBVSxFQUFFLFlBQVksRUFBRSxHQUFHLElBQUksQ0FBQyx1QkFBdUIsQ0FBQyxjQUFjLENBQUMsQ0FBQztRQUN2RixNQUFNLFNBQVMsR0FBRyxVQUFVLEdBQUcsSUFBSSxDQUFDLFlBQVksQ0FBQztRQUNqRCxNQUFNLG1CQUFtQixHQUFHLElBQUksQ0FBQyxPQUFPLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxtQkFBbUIsQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDO1FBQ3pGLE1BQU0sZUFBZSxHQUFHLFNBQVMsR0FBRyxtQkFBbUIsQ0FBQztRQUN4RCxNQUFNLFNBQVMsR0FBRyxJQUFJLENBQUMsT0FBTyxHQUFHLGVBQWUsQ0FBQztRQUVqRCxPQUFPO1lBQ04sV0FBVyxFQUFFLElBQUksQ0FBQyxPQUFPO1lBQ3pCLFNBQVMsRUFBRSxJQUFJLENBQUMsS0FBSyxDQUFDLFNBQVMsQ0FBQztZQUNoQyxtQkFBbUIsRUFBRSxJQUFJLENBQUMsS0FBSyxDQUFDLG1CQUFtQixDQUFDO1lBQ3BELGVBQWUsRUFBRSxJQUFJLENBQUMsS0FBSyxDQUFDLGVBQWUsQ0FBQztZQUM1QyxTQUFTLEVBQUUsSUFBSSxDQUFDLEtBQUssQ0FBQyxTQUFTLENBQUM7WUFDaEMsY0FBYyxFQUFFLElBQUksQ0FBQyxLQUFLLENBQUMsU0FBUyxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUM7WUFDcEQsZUFBZSxFQUFFLFlBQVk7U0FDN0IsQ0FBQztJQUNILENBQUM7SUFHVSx1QkFBdUIsQ0FBQyxNQUFjO1FBSWhELElBQUksR0FBRyxHQUFHLENBQUMsQ0FBQztRQUNaLElBQUksWUFBWSxHQUFHLENBQUMsQ0FBQztRQUVyQixLQUFLLE1BQU0sT0FBTyxJQUFJLElBQUksQ0FBQyxNQUFNLENBQUMsV0FBVyxFQUFFLENBQUM7WUFDL0MsTUFBTSxVQUFVLEdBQUcsT0FBTyxDQUFDLEVBQUUsSUFBSSxNQUFNLENBQUM7WUFFeEMsSUFBSSxNQUFNLElBQUksT0FBTyxDQUFDLElBQUksRUFBRSxDQUFDO2dCQUM1QixNQUFNO1lBQ1AsQ0FBQztZQUVELE1BQU0sYUFBYSxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsVUFBVSxFQUFFLE1BQU0sQ0FBQyxHQUFHLE9BQU8sQ0FBQyxJQUFJLENBQUM7WUFFbEUsSUFBSSxhQUFhLEdBQUcsQ0FBQyxFQUFFLENBQUM7Z0JBQ3ZCLEdBQUcsSUFBSSxhQUFhLEdBQUcsT0FBTyxDQUFDLElBQUksQ0FBQztnQkFDcEMsWUFBWSxHQUFHLE9BQU8sQ0FBQyxJQUFJLENBQUM7WUFDN0IsQ0FBQztRQUNGLENBQUM7UUFFRCxPQUFPLEVBQUUsR0FBRyxFQUFFLFlBQVksRUFBRSxDQUFDO0lBQzlCLENBQUM7SUFFVSxLQUFLLENBQUMsS0FBYTtRQUM3QixPQUFPLElBQUksQ0FBQyxLQUFLLENBQUMsS0FBSyxHQUFHLEdBQUcsQ0FBQyxHQUFHLEdBQUcsQ0FBQztJQUN0QyxDQUFDO0NBQ0Q7QUE1REQsZ0VBNERDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ29tcHV0ZWRJbmNvbWVUYXhWYWx1ZXMsIEluY29tZVRheFJ1bGVzIH0gZnJvbSBcIi4vZG9tYWluL3R5cGVzXCI7XG5pbXBvcnQgeyBGcmFuY2VJbmNvbWVUYXhTZXJ2aWNlIH0gZnJvbSBcIi4vRnJhbmNlSW5jb21lVGF4U2VydmljZVwiO1xuXG5leHBvcnQgY2xhc3MgRnJhbmNlSW5jb21lVGF4U2VydmljZUltcGwgaW1wbGVtZW50cyBGcmFuY2VJbmNvbWVUYXhTZXJ2aWNlIHtcbiAgICBwcml2YXRlIF9pbmNvbWU6IG51bWJlcjtcbiAgICBwcml2YXRlIF9ydWxlczogSW5jb21lVGF4UnVsZXM7XG4gICAgcHJpdmF0ZSBfZmFtaWx5UGFydHM6IG51bWJlcjtcblxuICAgIGNvbnN0cnVjdG9yKGluY29tZTogbnVtYmVyLCBydWxlczogSW5jb21lVGF4UnVsZXMsIGZhbWlseVBhcnRzOiBudW1iZXIpIHtcbiAgICAgICAgdGhpcy5faW5jb21lID0gaW5jb21lO1xuICAgICAgICB0aGlzLl9ydWxlcyA9IHJ1bGVzO1xuICAgICAgICB0aGlzLl9mYW1pbHlQYXJ0cyA9IGZhbWlseVBhcnRzO1xuICAgIH1cblxuICAgIHB1YmxpYyBjYWxjdWxhdGVOZXRJbmNvbWUoKTogQ29tcHV0ZWRJbmNvbWVUYXhWYWx1ZXMge1xuXG5cdFx0Y29uc3QgdGF4YWJsZVBlclBhcnQgPSB0aGlzLl9mYW1pbHlQYXJ0cyAqIHRoaXMuX2luY29tZSAvIHRoaXMuX2ZhbWlseVBhcnRzO1xuXHRcdGNvbnN0IHsgdGF4OiB0YXhQZXJQYXJ0LCBtYXJnaW5hbFJhdGUgfSA9IHRoaXMuY2FsY3VsYXRlUHJvZ3Jlc3NpdmVUYXgodGF4YWJsZVBlclBhcnQpO1xuXHRcdGNvbnN0IGluY29tZVRheCA9IHRheFBlclBhcnQgKiB0aGlzLl9mYW1pbHlQYXJ0cztcblx0XHRjb25zdCBzb2NpYWxDb250cmlidXRpb25zID0gdGhpcy5faW5jb21lICogdGhpcy5fcnVsZXMuc29jaWFsQ29udHJpYnV0aW9ucy5lbXBsb3llZS5yYXRlO1xuXHRcdGNvbnN0IHRvdGFsRGVkdWN0aW9ucyA9IGluY29tZVRheCArIHNvY2lhbENvbnRyaWJ1dGlvbnM7XG5cdFx0Y29uc3QgbmV0SW5jb21lID0gdGhpcy5faW5jb21lIC0gdG90YWxEZWR1Y3Rpb25zO1xuXG5cdFx0cmV0dXJuIHtcblx0XHRcdGdyb3NzSW5jb21lOiB0aGlzLl9pbmNvbWUsXG5cdFx0XHRpbmNvbWVUYXg6IHRoaXMucm91bmQoaW5jb21lVGF4KSxcblx0XHRcdHNvY2lhbENvbnRyaWJ1dGlvbnM6IHRoaXMucm91bmQoc29jaWFsQ29udHJpYnV0aW9ucyksXG5cdFx0XHR0b3RhbERlZHVjdGlvbnM6IHRoaXMucm91bmQodG90YWxEZWR1Y3Rpb25zKSxcblx0XHRcdG5ldEluY29tZTogdGhpcy5yb3VuZChuZXRJbmNvbWUpLFxuXHRcdFx0YXZlcmFnZVRheFJhdGU6IHRoaXMucm91bmQoaW5jb21lVGF4IC8gdGhpcy5faW5jb21lKSxcblx0XHRcdG1hcmdpbmFsVGF4UmF0ZTogbWFyZ2luYWxSYXRlLFxuXHRcdH07XG5cdH1cblxuXG4gICAgcHJpdmF0ZSBjYWxjdWxhdGVQcm9ncmVzc2l2ZVRheChpbmNvbWU6IG51bWJlcik6IHtcbiAgICAgICAgdGF4OiBudW1iZXI7XG4gICAgICAgIG1hcmdpbmFsUmF0ZTogbnVtYmVyXG4gICAgfSB7XG5cdFx0bGV0IHRheCA9IDA7XG5cdFx0bGV0IG1hcmdpbmFsUmF0ZSA9IDA7XG5cblx0XHRmb3IgKGNvbnN0IGJyYWNrZXQgb2YgdGhpcy5fcnVsZXMudGF4QnJhY2tldHMpIHtcblx0XHRcdGNvbnN0IHVwcGVyQm91bmQgPSBicmFja2V0LnRvID8/IGluY29tZTtcblxuXHRcdFx0aWYgKGluY29tZSA8PSBicmFja2V0LmZyb20pIHtcblx0XHRcdFx0YnJlYWs7XG5cdFx0XHR9XG5cblx0XHRcdGNvbnN0IHRheGFibGVBbW91bnQgPSBNYXRoLm1pbih1cHBlckJvdW5kLCBpbmNvbWUpIC0gYnJhY2tldC5mcm9tO1xuXG5cdFx0XHRpZiAodGF4YWJsZUFtb3VudCA+IDApIHtcblx0XHRcdFx0dGF4ICs9IHRheGFibGVBbW91bnQgKiBicmFja2V0LnJhdGU7XG5cdFx0XHRcdG1hcmdpbmFsUmF0ZSA9IGJyYWNrZXQucmF0ZTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHRyZXR1cm4geyB0YXgsIG1hcmdpbmFsUmF0ZSB9O1xuXHR9XG5cbiAgICBwcml2YXRlIHJvdW5kKHZhbHVlOiBudW1iZXIpOiBudW1iZXIge1xuXHRcdHJldHVybiBNYXRoLnJvdW5kKHZhbHVlICogMTAwKSAvIDEwMDtcblx0fVxufVxuIl19
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvaW5jb21lLXRheC9mcmFuY2UvZG9tYWluL3R5cGVzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiIiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBSdWxlSW5wdXQsIFJ1bGVNZXRhLCBSdWxlT3V0cHV0LCBUYXhCcmFja2V0IH0gZnJvbSBcIi4uLy4uLy4uL2RvbWFpbi90eXBlc1wiO1xuXG5leHBvcnQgaW50ZXJmYWNlIEluY29tZVRheFJ1bGVzIHtcbiAgICB0YXhCcmFja2V0czogVGF4QnJhY2tldFtdO1xuICAgIHF1b3RpZW50RmFtaWxpYWw6IFF1b3RpZW50RmFtaWxpYWw7XG4gICAgc29jaWFsQ29udHJpYnV0aW9uczogQ29udHJpYnV0aW9ucztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBDb250cmlidXRpb25zIHtcbiAgICBlbXBsb3llZTogeyByYXRlOiBudW1iZXI7IH07XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgUXVvdGllbnRGYW1pbGlhbCB7XG4gICAgZW5hYmxlZDogYm9vbGVhbjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBJbmNvbWVUYXhDYWxjdWxhdG9yU2NoZW1hIHtcbiAgICBtZXRhOiBSdWxlTWV0YTtcbiAgICBpbnB1dHM6IFJ1bGVJbnB1dFtdO1xuICAgIG91dHB1dHM6IFJ1bGVPdXRwdXRbXTtcbiAgICBydWxlczogSW5jb21lVGF4UnVsZXM7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgQ29tcHV0ZWRJbmNvbWVUYXhWYWx1ZXMge1xuICAgIGdyb3NzSW5jb21lOiBudW1iZXI7XG5cdGluY29tZVRheDogbnVtYmVyO1xuXHRzb2NpYWxDb250cmlidXRpb25zOiBudW1iZXI7XG5cdHRvdGFsRGVkdWN0aW9uczogbnVtYmVyO1xuXHRuZXRJbmNvbWU6IG51bWJlcjtcblx0YXZlcmFnZVRheFJhdGU6IG51bWJlcjtcblx0bWFyZ2luYWxUYXhSYXRlOiBudW1iZXI7XG59Il19
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,23 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
2
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.CanadaIncomeTaxService = void 0;
|
|
17
|
+
exports.FranceIncomeTaxService = exports.CanadaIncomeTaxService = void 0;
|
|
4
18
|
var CanadaIncomeTaxServiceImpl_1 = require("./income-tax/canada/CanadaIncomeTaxServiceImpl");
|
|
5
19
|
Object.defineProperty(exports, "CanadaIncomeTaxService", { enumerable: true, get: function () { return CanadaIncomeTaxServiceImpl_1.CanadaIncomeTaxServiceImpl; } });
|
|
6
|
-
|
|
20
|
+
var FranceIncomeTaxServiceImpl_1 = require("./income-tax/france/FranceIncomeTaxServiceImpl");
|
|
21
|
+
Object.defineProperty(exports, "FranceIncomeTaxService", { enumerable: true, get: function () { return FranceIncomeTaxServiceImpl_1.FranceIncomeTaxServiceImpl; } });
|
|
22
|
+
__exportStar(require("./domain/types"), exports);
|
|
23
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQSw2RkFBc0g7QUFBN0csb0lBQUEsMEJBQTBCLE9BQTBCO0FBQzdELDZGQUFzSDtBQUE3RyxvSUFBQSwwQkFBMEIsT0FBMEI7QUFXN0QsaURBQStCIiwic291cmNlc0NvbnRlbnQiOlsiZXhwb3J0IHsgQ2FuYWRhSW5jb21lVGF4U2VydmljZUltcGwgYXMgQ2FuYWRhSW5jb21lVGF4U2VydmljZSB9IGZyb20gJy4vaW5jb21lLXRheC9jYW5hZGEvQ2FuYWRhSW5jb21lVGF4U2VydmljZUltcGwnO1xuZXhwb3J0IHsgRnJhbmNlSW5jb21lVGF4U2VydmljZUltcGwgYXMgRnJhbmNlSW5jb21lVGF4U2VydmljZSB9IGZyb20gJy4vaW5jb21lLXRheC9mcmFuY2UvRnJhbmNlSW5jb21lVGF4U2VydmljZUltcGwnO1xuZXhwb3J0IHtcbiAgICBDb21wdXRlZEluY29tZVRheFZhbHVlcyBhcyBDYW5hZGFDb21wdXRlZEluY29tZVRheFZhbHVlcyxcbiAgICBJbmNvbWVUYXhSdWxlcyBhcyBDYW5hZGFJbmNvbWVUYXhSdWxlcyxcbiAgICBJbmNvbWVUYXhDYWxjdWxhdG9yU2NoZW1hIGFzIENhbmFkYUluY29tZVRheENhbGN1bGF0b3JTY2hlbWFcbn0gZnJvbSAnLi9pbmNvbWUtdGF4L2NhbmFkYS9kb21haW4vdHlwZXMnO1xuZXhwb3J0IHsgXG4gICAgQ29tcHV0ZWRJbmNvbWVUYXhWYWx1ZXMgYXMgRnJhbmNlQ29tcHV0ZWRJbmNvbWVUYXhWYWx1ZXMsXG4gICAgSW5jb21lVGF4UnVsZXMgYXMgRnJhbmNlSW5jb21lVGF4UnVsZXMsXG4gICAgSW5jb21lVGF4Q2FsY3VsYXRvclNjaGVtYSBhcyBGcmFuY2VJbmNvbWVUYXhDYWxjdWxhdG9yU2NoZW1hXG59IGZyb20gJy4vaW5jb21lLXRheC9mcmFuY2UvZG9tYWluL3R5cGVzJztcbmV4cG9ydCAqIGZyb20gJy4vZG9tYWluL3R5cGVzJzsiXX0=
|
|
@@ -9,8 +9,8 @@ export interface RuleMeta {
|
|
|
9
9
|
region: string;
|
|
10
10
|
calculator: CalculatorType;
|
|
11
11
|
version: string;
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
effectivefrom: string;
|
|
13
|
+
effectiveto: string | null;
|
|
14
14
|
source?: RuleSource[];
|
|
15
15
|
}
|
|
16
16
|
export interface RuleSource {
|
|
@@ -28,3 +28,8 @@ export interface RuleOutput {
|
|
|
28
28
|
type: 'number' | 'string';
|
|
29
29
|
unit?: string;
|
|
30
30
|
}
|
|
31
|
+
export interface TaxBracket {
|
|
32
|
+
from: number;
|
|
33
|
+
to: number | null;
|
|
34
|
+
rate: number;
|
|
35
|
+
}
|
|
@@ -1,13 +1,9 @@
|
|
|
1
|
+
import { RuleInput, RuleMeta, RuleOutput, TaxBracket } from "../../../domain/types";
|
|
1
2
|
export interface IncomeTaxRules {
|
|
2
|
-
|
|
3
|
+
taxBrackets: TaxBracket[];
|
|
3
4
|
credits?: Record<string, TaxCredit>;
|
|
4
5
|
contributions?: Contributions;
|
|
5
6
|
}
|
|
6
|
-
export interface TaxBracket {
|
|
7
|
-
from: number;
|
|
8
|
-
to: number | null;
|
|
9
|
-
rate: number;
|
|
10
|
-
}
|
|
11
7
|
export interface TaxCredit {
|
|
12
8
|
amount: number;
|
|
13
9
|
type: 'nonRefundable' | 'refundable';
|
|
@@ -19,13 +15,13 @@ export interface Contributions {
|
|
|
19
15
|
}
|
|
20
16
|
export interface CPPContribution {
|
|
21
17
|
rate: number;
|
|
22
|
-
|
|
18
|
+
maxContribution: number;
|
|
23
19
|
exemption: number;
|
|
24
20
|
}
|
|
25
21
|
export interface EIContribution {
|
|
26
22
|
rate: number;
|
|
27
|
-
|
|
28
|
-
|
|
23
|
+
maxInsurableEarnings: number;
|
|
24
|
+
maxContribution: number;
|
|
29
25
|
}
|
|
30
26
|
export interface ComputedIncomeTaxValues {
|
|
31
27
|
grossIncome: number;
|
|
@@ -36,3 +32,9 @@ export interface ComputedIncomeTaxValues {
|
|
|
36
32
|
netIncome: number;
|
|
37
33
|
effectiveTaxRate: number;
|
|
38
34
|
}
|
|
35
|
+
export interface IncomeTaxCalculatorSchema {
|
|
36
|
+
meta: RuleMeta;
|
|
37
|
+
inputs: RuleInput[];
|
|
38
|
+
outputs: RuleOutput[];
|
|
39
|
+
rules: IncomeTaxRules;
|
|
40
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { ComputedIncomeTaxValues, IncomeTaxRules } from "./domain/types";
|
|
2
|
+
import { FranceIncomeTaxService } from "./FranceIncomeTaxService";
|
|
3
|
+
export declare class FranceIncomeTaxServiceImpl implements FranceIncomeTaxService {
|
|
4
|
+
private _income;
|
|
5
|
+
private _rules;
|
|
6
|
+
private _familyParts;
|
|
7
|
+
constructor(income: number, rules: IncomeTaxRules, familyParts: number);
|
|
8
|
+
calculateNetIncome(): ComputedIncomeTaxValues;
|
|
9
|
+
private calculateProgressiveTax;
|
|
10
|
+
private round;
|
|
11
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { RuleInput, RuleMeta, RuleOutput, TaxBracket } from "../../../domain/types";
|
|
2
|
+
export interface IncomeTaxRules {
|
|
3
|
+
taxBrackets: TaxBracket[];
|
|
4
|
+
quotientFamilial: QuotientFamilial;
|
|
5
|
+
socialContributions: Contributions;
|
|
6
|
+
}
|
|
7
|
+
export interface Contributions {
|
|
8
|
+
employee: {
|
|
9
|
+
rate: number;
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
export interface QuotientFamilial {
|
|
13
|
+
enabled: boolean;
|
|
14
|
+
}
|
|
15
|
+
export interface IncomeTaxCalculatorSchema {
|
|
16
|
+
meta: RuleMeta;
|
|
17
|
+
inputs: RuleInput[];
|
|
18
|
+
outputs: RuleOutput[];
|
|
19
|
+
rules: IncomeTaxRules;
|
|
20
|
+
}
|
|
21
|
+
export interface ComputedIncomeTaxValues {
|
|
22
|
+
grossIncome: number;
|
|
23
|
+
incomeTax: number;
|
|
24
|
+
socialContributions: number;
|
|
25
|
+
totalDeductions: number;
|
|
26
|
+
netIncome: number;
|
|
27
|
+
averageTaxRate: number;
|
|
28
|
+
marginalTaxRate: number;
|
|
29
|
+
}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1,2 +1,5 @@
|
|
|
1
1
|
export { CanadaIncomeTaxServiceImpl as CanadaIncomeTaxService } from './income-tax/canada/CanadaIncomeTaxServiceImpl';
|
|
2
|
-
export {
|
|
2
|
+
export { FranceIncomeTaxServiceImpl as FranceIncomeTaxService } from './income-tax/france/FranceIncomeTaxServiceImpl';
|
|
3
|
+
export { ComputedIncomeTaxValues as CanadaComputedIncomeTaxValues, IncomeTaxRules as CanadaIncomeTaxRules, IncomeTaxCalculatorSchema as CanadaIncomeTaxCalculatorSchema } from './income-tax/canada/domain/types';
|
|
4
|
+
export { ComputedIncomeTaxValues as FranceComputedIncomeTaxValues, IncomeTaxRules as FranceIncomeTaxRules, IncomeTaxCalculatorSchema as FranceIncomeTaxCalculatorSchema } from './income-tax/france/domain/types';
|
|
5
|
+
export * from './domain/types';
|
package/package.json
CHANGED
package/src/domain/types.ts
CHANGED
|
@@ -10,8 +10,8 @@ export interface RuleMeta {
|
|
|
10
10
|
region: string;
|
|
11
11
|
calculator: CalculatorType;
|
|
12
12
|
version: string;
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
effectivefrom: string;
|
|
14
|
+
effectiveto: string | null;
|
|
15
15
|
source?: RuleSource[];
|
|
16
16
|
}
|
|
17
17
|
|
|
@@ -31,4 +31,10 @@ export interface RuleOutput {
|
|
|
31
31
|
name: string;
|
|
32
32
|
type: 'number' | 'string';
|
|
33
33
|
unit?: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface TaxBracket {
|
|
37
|
+
from: number;
|
|
38
|
+
to: number | null;
|
|
39
|
+
rate: number;
|
|
34
40
|
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
+
import { TaxBracket } from "../../domain/types";
|
|
1
2
|
import { CanadaIncomeTaxService } from "./CanadaIncomeTaxService";
|
|
2
3
|
import {
|
|
3
4
|
CPPContribution,
|
|
4
5
|
ComputedIncomeTaxValues,
|
|
5
6
|
EIContribution,
|
|
6
7
|
IncomeTaxRules,
|
|
7
|
-
TaxBracket,
|
|
8
8
|
TaxCredit
|
|
9
9
|
} from "./domain/types";
|
|
10
10
|
|
|
@@ -20,7 +20,7 @@ export class CanadaIncomeTaxServiceImpl implements CanadaIncomeTaxService {
|
|
|
20
20
|
|
|
21
21
|
public calculateNetIncome(): ComputedIncomeTaxValues {
|
|
22
22
|
|
|
23
|
-
const grossTax = this.computeGrossTax(this._income, this._rules.
|
|
23
|
+
const grossTax = this.computeGrossTax(this._income, this._rules.taxBrackets);
|
|
24
24
|
const netTax = this.applyCredits(grossTax, this._rules.credits);
|
|
25
25
|
const cpp = this.computeCPP(this._income, this._rules.contributions?.cpp);
|
|
26
26
|
const ei = this.computeEI(this._income, this._rules.contributions?.ei);
|
|
@@ -62,7 +62,7 @@ export class CanadaIncomeTaxServiceImpl implements CanadaIncomeTaxService {
|
|
|
62
62
|
const contributable = income - cpp.exemption;
|
|
63
63
|
return Math.min(
|
|
64
64
|
contributable * cpp.rate,
|
|
65
|
-
cpp.
|
|
65
|
+
cpp.maxContribution,
|
|
66
66
|
);
|
|
67
67
|
}
|
|
68
68
|
|
|
@@ -71,12 +71,12 @@ export class CanadaIncomeTaxServiceImpl implements CanadaIncomeTaxService {
|
|
|
71
71
|
|
|
72
72
|
const insurableIncome = Math.min(
|
|
73
73
|
income,
|
|
74
|
-
ei.
|
|
74
|
+
ei.maxInsurableEarnings,
|
|
75
75
|
);
|
|
76
76
|
|
|
77
77
|
return Math.min(
|
|
78
78
|
insurableIncome * ei.rate,
|
|
79
|
-
ei.
|
|
79
|
+
ei.maxContribution,
|
|
80
80
|
);
|
|
81
81
|
}
|
|
82
82
|
}
|
|
@@ -1,15 +1,11 @@
|
|
|
1
|
+
import { RuleInput, RuleMeta, RuleOutput, TaxBracket } from "../../../domain/types";
|
|
2
|
+
|
|
1
3
|
export interface IncomeTaxRules {
|
|
2
|
-
|
|
4
|
+
taxBrackets: TaxBracket[];
|
|
3
5
|
credits?: Record<string, TaxCredit>;
|
|
4
6
|
contributions?: Contributions;
|
|
5
7
|
}
|
|
6
8
|
|
|
7
|
-
export interface TaxBracket {
|
|
8
|
-
from: number;
|
|
9
|
-
to: number | null;
|
|
10
|
-
rate: number;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
9
|
export interface TaxCredit {
|
|
14
10
|
amount: number;
|
|
15
11
|
type: 'nonRefundable' | 'refundable';
|
|
@@ -23,14 +19,14 @@ export interface Contributions {
|
|
|
23
19
|
|
|
24
20
|
export interface CPPContribution {
|
|
25
21
|
rate: number;
|
|
26
|
-
|
|
22
|
+
maxContribution: number;
|
|
27
23
|
exemption: number;
|
|
28
24
|
}
|
|
29
25
|
|
|
30
26
|
export interface EIContribution {
|
|
31
27
|
rate: number;
|
|
32
|
-
|
|
33
|
-
|
|
28
|
+
maxInsurableEarnings: number;
|
|
29
|
+
maxContribution: number;
|
|
34
30
|
}
|
|
35
31
|
|
|
36
32
|
export interface ComputedIncomeTaxValues {
|
|
@@ -42,3 +38,10 @@ export interface ComputedIncomeTaxValues {
|
|
|
42
38
|
netIncome: number;
|
|
43
39
|
effectiveTaxRate: number;
|
|
44
40
|
}
|
|
41
|
+
|
|
42
|
+
export interface IncomeTaxCalculatorSchema {
|
|
43
|
+
meta: RuleMeta;
|
|
44
|
+
inputs: RuleInput[];
|
|
45
|
+
outputs: RuleOutput[];
|
|
46
|
+
rules: IncomeTaxRules;
|
|
47
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { ComputedIncomeTaxValues, IncomeTaxRules } from "./domain/types";
|
|
2
|
+
import { FranceIncomeTaxService } from "./FranceIncomeTaxService";
|
|
3
|
+
|
|
4
|
+
export class FranceIncomeTaxServiceImpl implements FranceIncomeTaxService {
|
|
5
|
+
private _income: number;
|
|
6
|
+
private _rules: IncomeTaxRules;
|
|
7
|
+
private _familyParts: number;
|
|
8
|
+
|
|
9
|
+
constructor(income: number, rules: IncomeTaxRules, familyParts: number) {
|
|
10
|
+
this._income = income;
|
|
11
|
+
this._rules = rules;
|
|
12
|
+
this._familyParts = familyParts;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
public calculateNetIncome(): ComputedIncomeTaxValues {
|
|
16
|
+
|
|
17
|
+
const taxablePerPart = this._familyParts * this._income / this._familyParts;
|
|
18
|
+
const { tax: taxPerPart, marginalRate } = this.calculateProgressiveTax(taxablePerPart);
|
|
19
|
+
const incomeTax = taxPerPart * this._familyParts;
|
|
20
|
+
const socialContributions = this._income * this._rules.socialContributions.employee.rate;
|
|
21
|
+
const totalDeductions = incomeTax + socialContributions;
|
|
22
|
+
const netIncome = this._income - totalDeductions;
|
|
23
|
+
|
|
24
|
+
return {
|
|
25
|
+
grossIncome: this._income,
|
|
26
|
+
incomeTax: this.round(incomeTax),
|
|
27
|
+
socialContributions: this.round(socialContributions),
|
|
28
|
+
totalDeductions: this.round(totalDeductions),
|
|
29
|
+
netIncome: this.round(netIncome),
|
|
30
|
+
averageTaxRate: this.round(incomeTax / this._income),
|
|
31
|
+
marginalTaxRate: marginalRate,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
private calculateProgressiveTax(income: number): {
|
|
37
|
+
tax: number;
|
|
38
|
+
marginalRate: number
|
|
39
|
+
} {
|
|
40
|
+
let tax = 0;
|
|
41
|
+
let marginalRate = 0;
|
|
42
|
+
|
|
43
|
+
for (const bracket of this._rules.taxBrackets) {
|
|
44
|
+
const upperBound = bracket.to ?? income;
|
|
45
|
+
|
|
46
|
+
if (income <= bracket.from) {
|
|
47
|
+
break;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const taxableAmount = Math.min(upperBound, income) - bracket.from;
|
|
51
|
+
|
|
52
|
+
if (taxableAmount > 0) {
|
|
53
|
+
tax += taxableAmount * bracket.rate;
|
|
54
|
+
marginalRate = bracket.rate;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return { tax, marginalRate };
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
private round(value: number): number {
|
|
62
|
+
return Math.round(value * 100) / 100;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { RuleInput, RuleMeta, RuleOutput, TaxBracket } from "../../../domain/types";
|
|
2
|
+
|
|
3
|
+
export interface IncomeTaxRules {
|
|
4
|
+
taxBrackets: TaxBracket[];
|
|
5
|
+
quotientFamilial: QuotientFamilial;
|
|
6
|
+
socialContributions: Contributions;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface Contributions {
|
|
10
|
+
employee: { rate: number; };
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface QuotientFamilial {
|
|
14
|
+
enabled: boolean;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface IncomeTaxCalculatorSchema {
|
|
18
|
+
meta: RuleMeta;
|
|
19
|
+
inputs: RuleInput[];
|
|
20
|
+
outputs: RuleOutput[];
|
|
21
|
+
rules: IncomeTaxRules;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface ComputedIncomeTaxValues {
|
|
25
|
+
grossIncome: number;
|
|
26
|
+
incomeTax: number;
|
|
27
|
+
socialContributions: number;
|
|
28
|
+
totalDeductions: number;
|
|
29
|
+
netIncome: number;
|
|
30
|
+
averageTaxRate: number;
|
|
31
|
+
marginalTaxRate: number;
|
|
32
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,2 +1,13 @@
|
|
|
1
1
|
export { CanadaIncomeTaxServiceImpl as CanadaIncomeTaxService } from './income-tax/canada/CanadaIncomeTaxServiceImpl';
|
|
2
|
-
export {
|
|
2
|
+
export { FranceIncomeTaxServiceImpl as FranceIncomeTaxService } from './income-tax/france/FranceIncomeTaxServiceImpl';
|
|
3
|
+
export {
|
|
4
|
+
ComputedIncomeTaxValues as CanadaComputedIncomeTaxValues,
|
|
5
|
+
IncomeTaxRules as CanadaIncomeTaxRules,
|
|
6
|
+
IncomeTaxCalculatorSchema as CanadaIncomeTaxCalculatorSchema
|
|
7
|
+
} from './income-tax/canada/domain/types';
|
|
8
|
+
export {
|
|
9
|
+
ComputedIncomeTaxValues as FranceComputedIncomeTaxValues,
|
|
10
|
+
IncomeTaxRules as FranceIncomeTaxRules,
|
|
11
|
+
IncomeTaxCalculatorSchema as FranceIncomeTaxCalculatorSchema
|
|
12
|
+
} from './income-tax/france/domain/types';
|
|
13
|
+
export * from './domain/types';
|