@novha/calc-engines 4.0.0 → 6.0.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/capital-gains/australia/AustraliaCapitalGainsService.js +3 -0
- package/dist/capital-gains/australia/AustraliaCapitalGainsServiceImpl.js +67 -0
- package/dist/capital-gains/australia/domain/types.js +3 -0
- package/dist/capital-gains/canada/CanadaCapitalGainsService.js +3 -0
- package/dist/capital-gains/canada/CanadaCapitalGainsServiceImpl.js +66 -0
- package/dist/capital-gains/canada/domain/types.js +3 -0
- package/dist/capital-gains/domain/types.js +3 -0
- package/dist/capital-gains/france/FranceCapitalGainsService.js +3 -0
- package/dist/capital-gains/france/FranceCapitalGainsServiceImpl.js +51 -0
- package/dist/capital-gains/france/domain/types.js +3 -0
- package/dist/capital-gains/germany/GermanyCapitalGainsService.js +3 -0
- package/dist/capital-gains/germany/GermanyCapitalGainsServiceImpl.js +68 -0
- package/dist/capital-gains/germany/domain/types.js +3 -0
- package/dist/capital-gains/index.js +25 -0
- package/dist/capital-gains/south-africa/SouthAfricaCapitalGainsService.js +3 -0
- package/dist/capital-gains/south-africa/SouthAfricaCapitalGainsServiceImpl.js +83 -0
- package/dist/capital-gains/south-africa/domain/types.js +3 -0
- package/dist/capital-gains/uk/UKCapitalGainsService.js +3 -0
- package/dist/capital-gains/uk/UKCapitalGainsServiceImpl.js +86 -0
- package/dist/capital-gains/uk/domain/types.js +3 -0
- package/dist/capital-gains/usa/USACapitalGainsService.js +3 -0
- package/dist/capital-gains/usa/USACapitalGainsServiceImpl.js +77 -0
- package/dist/capital-gains/usa/domain/types.js +3 -0
- package/dist/corporate/index.js +18 -0
- package/dist/income-tax/index.js +24 -0
- package/dist/index.js +18 -51
- package/dist/mortgage/france/FranceMortgageService.js +1 -1
- package/dist/mortgage/france/FranceMortgageServiceImpl.js +1 -1
- package/dist/mortgage/index.js +25 -0
- package/dist/shared/domain/types.js +2 -1
- package/dist/types/capital-gains/australia/AustraliaCapitalGainsService.d.ts +4 -0
- package/dist/types/capital-gains/australia/AustraliaCapitalGainsServiceImpl.d.ts +10 -0
- package/dist/types/capital-gains/australia/domain/types.d.ts +15 -0
- package/dist/types/capital-gains/canada/CanadaCapitalGainsService.d.ts +4 -0
- package/dist/types/capital-gains/canada/CanadaCapitalGainsServiceImpl.d.ts +10 -0
- package/dist/types/capital-gains/canada/domain/types.d.ts +13 -0
- package/dist/types/capital-gains/domain/types.d.ts +15 -0
- package/dist/types/capital-gains/france/FranceCapitalGainsService.d.ts +4 -0
- package/dist/types/capital-gains/france/FranceCapitalGainsServiceImpl.d.ts +9 -0
- package/dist/types/capital-gains/france/domain/types.d.ts +7 -0
- package/dist/types/capital-gains/germany/GermanyCapitalGainsService.d.ts +4 -0
- package/dist/types/capital-gains/germany/GermanyCapitalGainsServiceImpl.d.ts +9 -0
- package/dist/types/capital-gains/germany/domain/types.d.ts +8 -0
- package/dist/types/capital-gains/index.d.ts +15 -0
- package/dist/types/capital-gains/south-africa/SouthAfricaCapitalGainsService.d.ts +4 -0
- package/dist/types/capital-gains/south-africa/SouthAfricaCapitalGainsServiceImpl.d.ts +10 -0
- package/dist/types/capital-gains/south-africa/domain/types.d.ts +14 -0
- package/dist/types/capital-gains/uk/UKCapitalGainsService.d.ts +4 -0
- package/dist/types/capital-gains/uk/UKCapitalGainsServiceImpl.d.ts +9 -0
- package/dist/types/capital-gains/uk/domain/types.d.ts +10 -0
- package/dist/types/capital-gains/usa/USACapitalGainsService.d.ts +4 -0
- package/dist/types/capital-gains/usa/USACapitalGainsServiceImpl.d.ts +10 -0
- package/dist/types/capital-gains/usa/domain/types.d.ts +26 -0
- package/dist/types/corporate/index.d.ts +15 -0
- package/dist/types/income-tax/index.d.ts +15 -0
- package/dist/types/index.d.ts +4 -42
- package/dist/types/mortgage/france/FranceMortgageService.d.ts +1 -1
- package/dist/types/mortgage/france/FranceMortgageServiceImpl.d.ts +1 -1
- package/dist/types/mortgage/index.d.ts +15 -0
- package/dist/types/shared/domain/types.d.ts +2 -1
- package/package.json +1 -1
- package/src/capital-gains/australia/AustraliaCapitalGainsService.ts +5 -0
- package/src/capital-gains/australia/AustraliaCapitalGainsServiceImpl.ts +84 -0
- package/src/capital-gains/australia/domain/types.ts +17 -0
- package/src/capital-gains/canada/CanadaCapitalGainsService.ts +5 -0
- package/src/capital-gains/canada/CanadaCapitalGainsServiceImpl.ts +82 -0
- package/src/capital-gains/canada/domain/types.ts +15 -0
- package/src/capital-gains/domain/types.ts +15 -0
- package/src/capital-gains/france/FranceCapitalGainsService.ts +5 -0
- package/src/capital-gains/france/FranceCapitalGainsServiceImpl.ts +58 -0
- package/src/capital-gains/france/domain/types.ts +8 -0
- package/src/capital-gains/germany/GermanyCapitalGainsService.ts +5 -0
- package/src/capital-gains/germany/GermanyCapitalGainsServiceImpl.ts +77 -0
- package/src/capital-gains/germany/domain/types.ts +10 -0
- package/src/capital-gains/index.ts +72 -0
- package/src/capital-gains/south-africa/SouthAfricaCapitalGainsService.ts +5 -0
- package/src/capital-gains/south-africa/SouthAfricaCapitalGainsServiceImpl.ts +101 -0
- package/src/capital-gains/south-africa/domain/types.ts +16 -0
- package/src/capital-gains/uk/UKCapitalGainsService.ts +5 -0
- package/src/capital-gains/uk/UKCapitalGainsServiceImpl.ts +98 -0
- package/src/capital-gains/uk/domain/types.ts +11 -0
- package/src/capital-gains/usa/USACapitalGainsService.ts +5 -0
- package/src/capital-gains/usa/USACapitalGainsServiceImpl.ts +96 -0
- package/src/capital-gains/usa/domain/types.ts +27 -0
- package/src/corporate/index.ts +79 -0
- package/src/income-tax/index.ts +72 -0
- package/src/index.ts +6 -146
- package/src/mortgage/france/FranceMortgageService.ts +1 -1
- package/src/mortgage/france/FranceMortgageServiceImpl.ts +1 -1
- package/src/mortgage/index.ts +87 -0
- package/src/shared/domain/types.ts +1 -0
- package/test/australia-capital-gains.test.ts +80 -0
- package/test/canada-capital-gains.test.ts +71 -0
- package/test/france-capital-gains.test.ts +66 -0
- package/test/germany-capital-gains.test.ts +85 -0
- package/test/south-africa-capital-gains.test.ts +84 -0
- package/test/uk-capital-gains.test.ts +79 -0
- package/test/usa-capital-gains.test.ts +88 -0
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
// Capital Gains - Canada
|
|
2
|
+
import { CanadaCapitalGainsServiceImpl as CanadaCapitalGainsService } from './canada/CanadaCapitalGainsServiceImpl';
|
|
3
|
+
import {
|
|
4
|
+
Input as CanadaCapitalGainsInput,
|
|
5
|
+
Rules as CanadaCapitalGainsRules
|
|
6
|
+
} from './canada/domain/types';
|
|
7
|
+
|
|
8
|
+
// Capital Gains - France
|
|
9
|
+
import { FranceCapitalGainsServiceImpl as FranceCapitalGainsService } from './france/FranceCapitalGainsServiceImpl';
|
|
10
|
+
import {
|
|
11
|
+
Input as FranceCapitalGainsInput,
|
|
12
|
+
Rules as FranceCapitalGainsRules
|
|
13
|
+
} from './france/domain/types';
|
|
14
|
+
|
|
15
|
+
// Capital Gains - South Africa
|
|
16
|
+
import { SouthAfricaCapitalGainsServiceImpl as SouthAfricaCapitalGainsService } from './south-africa/SouthAfricaCapitalGainsServiceImpl';
|
|
17
|
+
import {
|
|
18
|
+
Input as SouthAfricaCapitalGainsInput,
|
|
19
|
+
Rules as SouthAfricaCapitalGainsRules
|
|
20
|
+
} from './south-africa/domain/types';
|
|
21
|
+
|
|
22
|
+
// Capital Gains - Australia
|
|
23
|
+
import { AustraliaCapitalGainsServiceImpl as AustraliaCapitalGainsService } from './australia/AustraliaCapitalGainsServiceImpl';
|
|
24
|
+
import {
|
|
25
|
+
Input as AustraliaCapitalGainsInput,
|
|
26
|
+
Rules as AustraliaCapitalGainsRules
|
|
27
|
+
} from './australia/domain/types';
|
|
28
|
+
|
|
29
|
+
// Capital Gains - UK
|
|
30
|
+
import { UKCapitalGainsServiceImpl as UKCapitalGainsService } from './uk/UKCapitalGainsServiceImpl';
|
|
31
|
+
import {
|
|
32
|
+
Input as UKCapitalGainsInput,
|
|
33
|
+
Rules as UKCapitalGainsRules
|
|
34
|
+
} from './uk/domain/types';
|
|
35
|
+
|
|
36
|
+
// Capital Gains - USA
|
|
37
|
+
import { USACapitalGainsServiceImpl as USACapitalGainsService } from './usa/USACapitalGainsServiceImpl';
|
|
38
|
+
import {
|
|
39
|
+
Input as USACapitalGainsInput,
|
|
40
|
+
Rules as USACapitalGainsRules
|
|
41
|
+
} from './usa/domain/types';
|
|
42
|
+
|
|
43
|
+
// Capital Gains - Germany
|
|
44
|
+
import { GermanyCapitalGainsServiceImpl as GermanyCapitalGainsService } from './germany/GermanyCapitalGainsServiceImpl';
|
|
45
|
+
import {
|
|
46
|
+
Input as GermanyCapitalGainsInput,
|
|
47
|
+
Rules as GermanyCapitalGainsRules
|
|
48
|
+
} from './germany/domain/types';
|
|
49
|
+
|
|
50
|
+
export {
|
|
51
|
+
CanadaCapitalGainsService,
|
|
52
|
+
CanadaCapitalGainsInput,
|
|
53
|
+
CanadaCapitalGainsRules,
|
|
54
|
+
FranceCapitalGainsService,
|
|
55
|
+
FranceCapitalGainsInput,
|
|
56
|
+
FranceCapitalGainsRules,
|
|
57
|
+
SouthAfricaCapitalGainsService,
|
|
58
|
+
SouthAfricaCapitalGainsInput,
|
|
59
|
+
SouthAfricaCapitalGainsRules,
|
|
60
|
+
AustraliaCapitalGainsService,
|
|
61
|
+
AustraliaCapitalGainsInput,
|
|
62
|
+
AustraliaCapitalGainsRules,
|
|
63
|
+
UKCapitalGainsService,
|
|
64
|
+
UKCapitalGainsInput,
|
|
65
|
+
UKCapitalGainsRules,
|
|
66
|
+
USACapitalGainsService,
|
|
67
|
+
USACapitalGainsInput,
|
|
68
|
+
USACapitalGainsRules,
|
|
69
|
+
GermanyCapitalGainsService,
|
|
70
|
+
GermanyCapitalGainsInput,
|
|
71
|
+
GermanyCapitalGainsRules
|
|
72
|
+
};
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { Breakdown, Result } from "../domain/types";
|
|
2
|
+
import { SouthAfricaCapitalGainsService } from "./SouthAfricaCapitalGainsService";
|
|
3
|
+
import { Input, Rules, TaxBracket } from "./domain/types";
|
|
4
|
+
|
|
5
|
+
export class SouthAfricaCapitalGainsServiceImpl implements SouthAfricaCapitalGainsService {
|
|
6
|
+
private _input: Input;
|
|
7
|
+
private _rules: Rules;
|
|
8
|
+
|
|
9
|
+
constructor(input: Input, rules: Rules) {
|
|
10
|
+
this._input = input;
|
|
11
|
+
this._rules = rules;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
calculate(): Result {
|
|
15
|
+
const gain = this._input.capitalGain;
|
|
16
|
+
|
|
17
|
+
if (gain <= 0) {
|
|
18
|
+
return {
|
|
19
|
+
taxableGain: 0,
|
|
20
|
+
capitalGainTax: 0,
|
|
21
|
+
socialContributions: 0,
|
|
22
|
+
netInvestmentIncomeTax: 0,
|
|
23
|
+
totalTax: 0,
|
|
24
|
+
effectiveRate: 0,
|
|
25
|
+
breakdowns: []
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const netGain = Math.max(0, gain - this._rules.annualExclusion);
|
|
30
|
+
const taxableGain = netGain * this._rules.inclusionRate;
|
|
31
|
+
|
|
32
|
+
if (taxableGain <= 0) {
|
|
33
|
+
return {
|
|
34
|
+
taxableGain: 0,
|
|
35
|
+
capitalGainTax: 0,
|
|
36
|
+
socialContributions: 0,
|
|
37
|
+
netInvestmentIncomeTax: 0,
|
|
38
|
+
totalTax: 0,
|
|
39
|
+
effectiveRate: 0,
|
|
40
|
+
breakdowns: [{
|
|
41
|
+
from: '0',
|
|
42
|
+
to: `${this._rules.annualExclusion}`,
|
|
43
|
+
rate: 0,
|
|
44
|
+
amount: 0,
|
|
45
|
+
}],
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const otherIncome = this._input.totalTaxableIncome - gain;
|
|
50
|
+
const { tax, breakdowns } = this.applyBrackets(taxableGain, otherIncome, this._rules.taxBrackets);
|
|
51
|
+
|
|
52
|
+
return {
|
|
53
|
+
taxableGain,
|
|
54
|
+
capitalGainTax: tax,
|
|
55
|
+
socialContributions: 0,
|
|
56
|
+
netInvestmentIncomeTax: 0,
|
|
57
|
+
totalTax: tax,
|
|
58
|
+
effectiveRate: gain > 0 ? (tax / gain) * 100 : 0,
|
|
59
|
+
breakdowns,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
private applyBrackets(
|
|
64
|
+
taxableGain: number,
|
|
65
|
+
otherIncome: number,
|
|
66
|
+
brackets: TaxBracket[],
|
|
67
|
+
): { tax: number; breakdowns: Breakdown[] } {
|
|
68
|
+
let tax = 0;
|
|
69
|
+
const breakdowns: Breakdown[] = [];
|
|
70
|
+
let remaining = taxableGain;
|
|
71
|
+
let incomeUsed = otherIncome;
|
|
72
|
+
|
|
73
|
+
for (const bracket of brackets) {
|
|
74
|
+
if (remaining <= 0) break;
|
|
75
|
+
|
|
76
|
+
const upper = bracket.to ?? Infinity;
|
|
77
|
+
|
|
78
|
+
if (incomeUsed >= upper) continue;
|
|
79
|
+
|
|
80
|
+
const bracketStart = Math.max(bracket.from, incomeUsed);
|
|
81
|
+
const bracketSpace = upper - bracketStart;
|
|
82
|
+
const taxable = Math.min(bracketSpace, remaining);
|
|
83
|
+
|
|
84
|
+
if (taxable > 0) {
|
|
85
|
+
const bracketTax = taxable * bracket.rate;
|
|
86
|
+
tax += bracketTax;
|
|
87
|
+
remaining -= taxable;
|
|
88
|
+
incomeUsed += taxable;
|
|
89
|
+
|
|
90
|
+
breakdowns.push({
|
|
91
|
+
from: `${bracket.from}`,
|
|
92
|
+
to: `${bracket.to ?? 'Above'}`,
|
|
93
|
+
rate: bracket.rate,
|
|
94
|
+
amount: bracketTax,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return { tax, breakdowns };
|
|
100
|
+
}
|
|
101
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface TaxBracket {
|
|
2
|
+
from: number;
|
|
3
|
+
to: number | null;
|
|
4
|
+
rate: number;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export interface Rules {
|
|
8
|
+
inclusionRate: number;
|
|
9
|
+
annualExclusion: number;
|
|
10
|
+
taxBrackets: TaxBracket[];
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface Input {
|
|
14
|
+
capitalGain: number;
|
|
15
|
+
totalTaxableIncome: number;
|
|
16
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { Breakdown, Result } from "../domain/types";
|
|
2
|
+
import { UKCapitalGainsService } from "./UKCapitalGainsService";
|
|
3
|
+
import { Input, Rules } from "./domain/types";
|
|
4
|
+
|
|
5
|
+
export class UKCapitalGainsServiceImpl implements UKCapitalGainsService {
|
|
6
|
+
private _input: Input;
|
|
7
|
+
private _rules: Rules;
|
|
8
|
+
|
|
9
|
+
constructor(input: Input, rules: Rules) {
|
|
10
|
+
this._input = input;
|
|
11
|
+
this._rules = rules;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
calculate(): Result {
|
|
15
|
+
const gain = this._input.capitalGain;
|
|
16
|
+
|
|
17
|
+
if (gain <= 0) {
|
|
18
|
+
return {
|
|
19
|
+
taxableGain: 0,
|
|
20
|
+
capitalGainTax: 0,
|
|
21
|
+
socialContributions: 0,
|
|
22
|
+
netInvestmentIncomeTax: 0,
|
|
23
|
+
totalTax: 0,
|
|
24
|
+
effectiveRate: 0,
|
|
25
|
+
breakdowns: []
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const taxableGain = Math.max(0, gain - this._rules.annualExemption);
|
|
30
|
+
|
|
31
|
+
if (taxableGain <= 0) {
|
|
32
|
+
return {
|
|
33
|
+
taxableGain: 0,
|
|
34
|
+
capitalGainTax: 0,
|
|
35
|
+
socialContributions: 0,
|
|
36
|
+
netInvestmentIncomeTax: 0,
|
|
37
|
+
totalTax: 0,
|
|
38
|
+
effectiveRate: 0,
|
|
39
|
+
breakdowns: [{
|
|
40
|
+
from: '0',
|
|
41
|
+
to: `${this._rules.annualExemption}`,
|
|
42
|
+
rate: 0,
|
|
43
|
+
amount: 0,
|
|
44
|
+
}],
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const basicRateRemaining = Math.max(0, this._rules.basicRateLimit - this._input.totalTaxableIncome);
|
|
49
|
+
const breakdowns: Breakdown[] = [];
|
|
50
|
+
let tax = 0;
|
|
51
|
+
|
|
52
|
+
if (basicRateRemaining > 0) {
|
|
53
|
+
const basicRateGain = Math.min(taxableGain, basicRateRemaining);
|
|
54
|
+
const basicTax = basicRateGain * this._rules.basicRate;
|
|
55
|
+
tax += basicTax;
|
|
56
|
+
|
|
57
|
+
breakdowns.push({
|
|
58
|
+
from: '0',
|
|
59
|
+
to: `${basicRateRemaining}`,
|
|
60
|
+
rate: this._rules.basicRate,
|
|
61
|
+
amount: basicTax,
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
const higherRateGain = taxableGain - basicRateGain;
|
|
65
|
+
if (higherRateGain > 0) {
|
|
66
|
+
const higherTax = higherRateGain * this._rules.higherRate;
|
|
67
|
+
tax += higherTax;
|
|
68
|
+
|
|
69
|
+
breakdowns.push({
|
|
70
|
+
from: `${basicRateRemaining}`,
|
|
71
|
+
to: 'Above',
|
|
72
|
+
rate: this._rules.higherRate,
|
|
73
|
+
amount: higherTax,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
} else {
|
|
77
|
+
const higherTax = taxableGain * this._rules.higherRate;
|
|
78
|
+
tax += higherTax;
|
|
79
|
+
|
|
80
|
+
breakdowns.push({
|
|
81
|
+
from: '0',
|
|
82
|
+
to: 'Above',
|
|
83
|
+
rate: this._rules.higherRate,
|
|
84
|
+
amount: higherTax,
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return {
|
|
89
|
+
taxableGain,
|
|
90
|
+
capitalGainTax: tax,
|
|
91
|
+
socialContributions: 0,
|
|
92
|
+
netInvestmentIncomeTax: 0,
|
|
93
|
+
totalTax: tax,
|
|
94
|
+
effectiveRate: gain > 0 ? (tax / gain) * 100 : 0,
|
|
95
|
+
breakdowns,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { Breakdown, Result } from "../domain/types";
|
|
2
|
+
import { USACapitalGainsService } from "./USACapitalGainsService";
|
|
3
|
+
import { Input, LongTermBracket, Rules } from "./domain/types";
|
|
4
|
+
|
|
5
|
+
export class USACapitalGainsServiceImpl implements USACapitalGainsService {
|
|
6
|
+
private _input: Input;
|
|
7
|
+
private _rules: Rules;
|
|
8
|
+
|
|
9
|
+
constructor(input: Input, rules: Rules) {
|
|
10
|
+
this._input = input;
|
|
11
|
+
this._rules = rules;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
calculate(): Result {
|
|
15
|
+
const gain = this._input.capitalGain;
|
|
16
|
+
|
|
17
|
+
if (gain <= 0) {
|
|
18
|
+
return {
|
|
19
|
+
taxableGain: 0,
|
|
20
|
+
capitalGainTax: 0,
|
|
21
|
+
socialContributions: 0,
|
|
22
|
+
netInvestmentIncomeTax: 0,
|
|
23
|
+
totalTax: 0,
|
|
24
|
+
effectiveRate: 0,
|
|
25
|
+
breakdowns: []
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const isLongTerm = this._input.holdingPeriodMonths > 12;
|
|
30
|
+
const brackets = isLongTerm ? this._rules.longTermBrackets : this._rules.shortTermBrackets;
|
|
31
|
+
|
|
32
|
+
const { tax, breakdowns } = this.applyBrackets(gain, this._input.totalTaxableIncome, brackets);
|
|
33
|
+
|
|
34
|
+
let niit = 0;
|
|
35
|
+
if (this._input.totalTaxableIncome > this._rules.netInvestmentIncomeTax.threshold) {
|
|
36
|
+
niit = gain * this._rules.netInvestmentIncomeTax.rate;
|
|
37
|
+
breakdowns.push({
|
|
38
|
+
from: 'NIIT',
|
|
39
|
+
to: 'All Gain',
|
|
40
|
+
rate: this._rules.netInvestmentIncomeTax.rate,
|
|
41
|
+
amount: niit,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const totalTax = tax + niit;
|
|
46
|
+
|
|
47
|
+
return {
|
|
48
|
+
taxableGain: gain,
|
|
49
|
+
capitalGainTax: tax,
|
|
50
|
+
socialContributions: 0,
|
|
51
|
+
netInvestmentIncomeTax: niit,
|
|
52
|
+
totalTax,
|
|
53
|
+
effectiveRate: gain > 0 ? (totalTax / gain) * 100 : 0,
|
|
54
|
+
breakdowns,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
private applyBrackets(
|
|
59
|
+
gain: number,
|
|
60
|
+
totalIncome: number,
|
|
61
|
+
brackets: LongTermBracket[],
|
|
62
|
+
): { tax: number; breakdowns: Breakdown[] } {
|
|
63
|
+
let tax = 0;
|
|
64
|
+
const breakdowns: Breakdown[] = [];
|
|
65
|
+
let remaining = gain;
|
|
66
|
+
let incomeUsed = totalIncome - gain;
|
|
67
|
+
|
|
68
|
+
for (const bracket of brackets) {
|
|
69
|
+
if (remaining <= 0) break;
|
|
70
|
+
|
|
71
|
+
const upper = bracket.to ?? Infinity;
|
|
72
|
+
|
|
73
|
+
if (incomeUsed >= upper) continue;
|
|
74
|
+
|
|
75
|
+
const bracketStart = Math.max(bracket.from, incomeUsed);
|
|
76
|
+
const bracketSpace = upper - bracketStart;
|
|
77
|
+
const taxable = Math.min(bracketSpace, remaining);
|
|
78
|
+
|
|
79
|
+
if (taxable > 0) {
|
|
80
|
+
const bracketTax = taxable * bracket.rate;
|
|
81
|
+
tax += bracketTax;
|
|
82
|
+
remaining -= taxable;
|
|
83
|
+
incomeUsed += taxable;
|
|
84
|
+
|
|
85
|
+
breakdowns.push({
|
|
86
|
+
from: `${bracket.from}`,
|
|
87
|
+
to: `${bracket.to ?? 'Above'}`,
|
|
88
|
+
rate: bracket.rate,
|
|
89
|
+
amount: bracketTax,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return { tax, breakdowns };
|
|
95
|
+
}
|
|
96
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Breakdown } from "../../domain/types";
|
|
2
|
+
|
|
3
|
+
export interface LongTermBracket {
|
|
4
|
+
from: number;
|
|
5
|
+
to: number | null;
|
|
6
|
+
rate: number;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface Rules {
|
|
10
|
+
longTermBrackets: LongTermBracket[];
|
|
11
|
+
shortTermBrackets: LongTermBracket[];
|
|
12
|
+
netInvestmentIncomeTax: { rate: number; threshold: number };
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface Input {
|
|
16
|
+
capitalGain: number;
|
|
17
|
+
totalTaxableIncome: number;
|
|
18
|
+
holdingPeriodMonths: number;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface Result {
|
|
22
|
+
capitalGainsTax: number;
|
|
23
|
+
netInvestmentIncomeTax: number;
|
|
24
|
+
totalTax: number;
|
|
25
|
+
effectiveRate: number;
|
|
26
|
+
breakdowns: Breakdown[];
|
|
27
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { USACorporateTaxServiceImpl as USACorporateTaxService } from './usa/USACorporateTaxServiceImpl';
|
|
2
|
+
import {
|
|
3
|
+
Input as USACorporateTaxInput,
|
|
4
|
+
Rules as USACorporateTaxRules,
|
|
5
|
+
Result as USACorporateTaxResult,
|
|
6
|
+
} from './usa/domain/types';
|
|
7
|
+
|
|
8
|
+
import { GermanyCorporateTaxServiceImpl as GermanyCorporateTaxService } from './germany/GermanyCorporateTaxServiceImpl';
|
|
9
|
+
import {
|
|
10
|
+
Input as GermanyCorporateTaxInput,
|
|
11
|
+
Rules as GermanyCorporateTaxRules,
|
|
12
|
+
Result as GermanyCorporateTaxResult,
|
|
13
|
+
} from './germany/domain/types';
|
|
14
|
+
|
|
15
|
+
import { UKCorporateTaxServiceImpl as UKCorporateTaxService } from './uk/UKCorporateTaxServiceImpl';
|
|
16
|
+
import {
|
|
17
|
+
Input as UKCorporateTaxInput,
|
|
18
|
+
Rules as UKCorporateTaxRules,
|
|
19
|
+
Result as UKCorporateTaxResult,
|
|
20
|
+
} from './uk/domain/types';
|
|
21
|
+
|
|
22
|
+
import { AustraliaCorporateTaxServiceImpl as AustraliaCorporateTaxService } from './australia/AustraliaCorporateTaxServiceImpl';
|
|
23
|
+
import {
|
|
24
|
+
Input as AustraliaCorporateTaxInput,
|
|
25
|
+
Rules as AustraliaCorporateTaxRules,
|
|
26
|
+
Result as AustraliaCorporateTaxResult,
|
|
27
|
+
} from './australia/domain/types';
|
|
28
|
+
|
|
29
|
+
import { SouthAfricaCorporateTaxServiceImpl as SouthAfricaCorporateTaxService } from './south-africa/SouthAfricaCorporateTaxServiceImpl';
|
|
30
|
+
import {
|
|
31
|
+
Rules as SouthAfricaCorporateTaxRules,
|
|
32
|
+
Input as SouthAfricaCorporateTaxInput,
|
|
33
|
+
Result as SouthAfricaCorporateTaxResult,
|
|
34
|
+
} from './south-africa/domain/types';
|
|
35
|
+
|
|
36
|
+
import { FranceCorporateTaxServiceImpl as FranceCorporateTaxService } from './france/FranceCorporateTaxServiceImpl';
|
|
37
|
+
import {
|
|
38
|
+
Input as FranceCorporateTaxInput,
|
|
39
|
+
Rules as FranceCorporateTaxRules,
|
|
40
|
+
Result as FranceCorporateTaxResult,
|
|
41
|
+
} from './france/domain/types';
|
|
42
|
+
|
|
43
|
+
import { CanadaCorporateTaxServiceImpl as CanadaCorporateTaxService } from './canada/CanadaCorporateTaxServiceImpl';
|
|
44
|
+
import {
|
|
45
|
+
Input as CanadaCorporateTaxInput,
|
|
46
|
+
Rules as CanadaCorporateTaxRules,
|
|
47
|
+
Result as CanadaCorporateTaxResult,
|
|
48
|
+
} from './canada/domain/types';
|
|
49
|
+
|
|
50
|
+
export {
|
|
51
|
+
USACorporateTaxService,
|
|
52
|
+
USACorporateTaxInput,
|
|
53
|
+
USACorporateTaxRules,
|
|
54
|
+
USACorporateTaxResult,
|
|
55
|
+
GermanyCorporateTaxService,
|
|
56
|
+
GermanyCorporateTaxInput,
|
|
57
|
+
GermanyCorporateTaxRules,
|
|
58
|
+
GermanyCorporateTaxResult,
|
|
59
|
+
UKCorporateTaxService,
|
|
60
|
+
UKCorporateTaxInput,
|
|
61
|
+
UKCorporateTaxRules,
|
|
62
|
+
UKCorporateTaxResult,
|
|
63
|
+
AustraliaCorporateTaxService,
|
|
64
|
+
AustraliaCorporateTaxInput,
|
|
65
|
+
AustraliaCorporateTaxRules,
|
|
66
|
+
AustraliaCorporateTaxResult,
|
|
67
|
+
SouthAfricaCorporateTaxService,
|
|
68
|
+
SouthAfricaCorporateTaxInput,
|
|
69
|
+
SouthAfricaCorporateTaxRules,
|
|
70
|
+
SouthAfricaCorporateTaxResult,
|
|
71
|
+
FranceCorporateTaxService,
|
|
72
|
+
FranceCorporateTaxInput,
|
|
73
|
+
FranceCorporateTaxRules,
|
|
74
|
+
FranceCorporateTaxResult,
|
|
75
|
+
CanadaCorporateTaxService,
|
|
76
|
+
CanadaCorporateTaxInput,
|
|
77
|
+
CanadaCorporateTaxRules,
|
|
78
|
+
CanadaCorporateTaxResult
|
|
79
|
+
};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
// Canada
|
|
2
|
+
import { CanadaIncomeTaxServiceImpl as CanadaIncomeTaxService } from './canada/CanadaIncomeTaxServiceImpl';
|
|
3
|
+
import {
|
|
4
|
+
ComputedIncomeTaxValues as CanadaComputedIncomeTaxValues,
|
|
5
|
+
IncomeTaxRules as CanadaIncomeTaxRules,
|
|
6
|
+
} from './canada/domain/types';
|
|
7
|
+
import { FranceIncomeTaxServiceImpl as FranceIncomeTaxService } from './france/FranceIncomeTaxServiceImpl';
|
|
8
|
+
|
|
9
|
+
// France
|
|
10
|
+
import {
|
|
11
|
+
ComputedIncomeTaxValues as FranceComputedIncomeTaxValues,
|
|
12
|
+
IncomeTaxRules as FranceIncomeTaxRules,
|
|
13
|
+
} from './france/domain/types';
|
|
14
|
+
|
|
15
|
+
// South Africa
|
|
16
|
+
import { SouthAfricaIncomeTaxServiceImpl as SouthAfricaIncomeTaxService } from './south-africa/SouthAfricaIncomeTaxServiceImpl';
|
|
17
|
+
import {
|
|
18
|
+
ComputedIncomeTaxValues as SouthAfricaComputedIncomeTaxValues,
|
|
19
|
+
IncomeTaxRules as SouthAfricaIncomeTaxRules,
|
|
20
|
+
} from './south-africa/domain/types';
|
|
21
|
+
|
|
22
|
+
// Australia
|
|
23
|
+
import { AustraliaIncomeTaxServiceImpl as AustraliaIncomeTaxService } from './australia/AustraliaIncomeTaxServiceImpl';
|
|
24
|
+
import {
|
|
25
|
+
ComputedIncomeTaxValues as AustraliaComputedIncomeTaxValues,
|
|
26
|
+
IncomeTaxRules as AustraliaIncomeTaxRules,
|
|
27
|
+
} from './australia/domain/types';
|
|
28
|
+
|
|
29
|
+
// UK
|
|
30
|
+
import { UKIncomeTaxServiceImpl as UKIncomeTaxService } from './uk/UKIncomeTaxServiceImpl';
|
|
31
|
+
import {
|
|
32
|
+
ComputedIncomeTaxValues as UKComputedIncomeTaxValues,
|
|
33
|
+
IncomeTaxRules as UKIncomeTaxRules,
|
|
34
|
+
} from './uk/domain/types';
|
|
35
|
+
|
|
36
|
+
// USA
|
|
37
|
+
import { USAIncomeTaxServiceImpl as USAIncomeTaxService } from './usa/USAIncomeTaxServiceImpl';
|
|
38
|
+
import {
|
|
39
|
+
ComputedIncomeTaxValues as USAComputedIncomeTaxValues,
|
|
40
|
+
IncomeTaxRules as USAIncomeTaxRules,
|
|
41
|
+
} from './usa/domain/types';
|
|
42
|
+
|
|
43
|
+
// Germany
|
|
44
|
+
import { GermanyIncomeTaxServiceImpl as GermanyIncomeTaxService } from './germany/GermanyIncomeTaxServiceImpl';
|
|
45
|
+
import {
|
|
46
|
+
ComputedIncomeTaxValues as GermanyComputedIncomeTaxValues,
|
|
47
|
+
IncomeTaxRules as GermanyIncomeTaxRules,
|
|
48
|
+
} from './germany/domain/types';
|
|
49
|
+
|
|
50
|
+
export {
|
|
51
|
+
CanadaIncomeTaxService,
|
|
52
|
+
CanadaComputedIncomeTaxValues,
|
|
53
|
+
CanadaIncomeTaxRules,
|
|
54
|
+
FranceIncomeTaxService,
|
|
55
|
+
FranceComputedIncomeTaxValues,
|
|
56
|
+
FranceIncomeTaxRules,
|
|
57
|
+
SouthAfricaIncomeTaxService,
|
|
58
|
+
SouthAfricaComputedIncomeTaxValues,
|
|
59
|
+
SouthAfricaIncomeTaxRules,
|
|
60
|
+
AustraliaIncomeTaxService,
|
|
61
|
+
AustraliaComputedIncomeTaxValues,
|
|
62
|
+
AustraliaIncomeTaxRules,
|
|
63
|
+
UKIncomeTaxService,
|
|
64
|
+
UKComputedIncomeTaxValues,
|
|
65
|
+
UKIncomeTaxRules,
|
|
66
|
+
USAIncomeTaxService,
|
|
67
|
+
USAComputedIncomeTaxValues,
|
|
68
|
+
USAIncomeTaxRules,
|
|
69
|
+
GermanyIncomeTaxService,
|
|
70
|
+
GermanyComputedIncomeTaxValues,
|
|
71
|
+
GermanyIncomeTaxRules,
|
|
72
|
+
};
|