@novha/calc-engines 3.0.0 → 5.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.
Files changed (140) hide show
  1. package/dist/capital-gains/australia/AustraliaCapitalGainsService.js +3 -0
  2. package/dist/capital-gains/australia/AustraliaCapitalGainsServiceImpl.js +56 -0
  3. package/dist/capital-gains/australia/domain/types.js +3 -0
  4. package/dist/capital-gains/canada/CanadaCapitalGainsService.js +3 -0
  5. package/dist/capital-gains/canada/CanadaCapitalGainsServiceImpl.js +55 -0
  6. package/dist/capital-gains/canada/domain/types.js +3 -0
  7. package/dist/capital-gains/domain/types.js +3 -0
  8. package/dist/capital-gains/france/FranceCapitalGainsService.js +3 -0
  9. package/dist/capital-gains/france/FranceCapitalGainsServiceImpl.js +41 -0
  10. package/dist/capital-gains/france/domain/types.js +3 -0
  11. package/dist/capital-gains/germany/GermanyCapitalGainsService.js +3 -0
  12. package/dist/capital-gains/germany/GermanyCapitalGainsServiceImpl.js +65 -0
  13. package/dist/capital-gains/germany/domain/types.js +3 -0
  14. package/dist/capital-gains/south-africa/SouthAfricaCapitalGainsService.js +3 -0
  15. package/dist/capital-gains/south-africa/SouthAfricaCapitalGainsServiceImpl.js +69 -0
  16. package/dist/capital-gains/south-africa/domain/types.js +3 -0
  17. package/dist/capital-gains/uk/UKCapitalGainsService.js +3 -0
  18. package/dist/capital-gains/uk/UKCapitalGainsServiceImpl.js +72 -0
  19. package/dist/capital-gains/uk/domain/types.js +3 -0
  20. package/dist/capital-gains/usa/USACapitalGainsService.js +3 -0
  21. package/dist/capital-gains/usa/USACapitalGainsServiceImpl.js +67 -0
  22. package/dist/capital-gains/usa/domain/types.js +3 -0
  23. package/dist/corporate/germany/GermanyCorporateTaxService.js +3 -0
  24. package/dist/corporate/germany/GermanyCorporateTaxServiceImpl.js +56 -0
  25. package/dist/corporate/germany/domain/types.js +3 -0
  26. package/dist/corporate/usa/USACorporateTaxService.js +3 -0
  27. package/dist/corporate/usa/USACorporateTaxServiceImpl.js +29 -0
  28. package/dist/corporate/usa/domain/types.js +3 -0
  29. package/dist/income-tax/germany/GermanyIncomeTaxService.js +3 -0
  30. package/dist/income-tax/germany/GermanyIncomeTaxServiceImpl.js +86 -0
  31. package/dist/income-tax/germany/domain/types.js +3 -0
  32. package/dist/income-tax/usa/USAIncomeTaxService.js +3 -0
  33. package/dist/income-tax/usa/USAIncomeTaxServiceImpl.js +87 -0
  34. package/dist/income-tax/usa/domain/types.js +3 -0
  35. package/dist/index.js +37 -2
  36. package/dist/mortgage/germany/GermanyMortgageService.js +3 -0
  37. package/dist/mortgage/germany/GermanyMortgageServiceImpl.js +80 -0
  38. package/dist/mortgage/germany/domain/types.js +3 -0
  39. package/dist/mortgage/usa/USAMortgageService.js +3 -0
  40. package/dist/mortgage/usa/USAMortgageServiceImpl.js +92 -0
  41. package/dist/mortgage/usa/domain/types.js +3 -0
  42. package/dist/shared/domain/types.js +2 -1
  43. package/dist/types/capital-gains/australia/AustraliaCapitalGainsService.d.ts +4 -0
  44. package/dist/types/capital-gains/australia/AustraliaCapitalGainsServiceImpl.d.ts +9 -0
  45. package/dist/types/capital-gains/australia/domain/types.d.ts +22 -0
  46. package/dist/types/capital-gains/canada/CanadaCapitalGainsService.d.ts +4 -0
  47. package/dist/types/capital-gains/canada/CanadaCapitalGainsServiceImpl.d.ts +9 -0
  48. package/dist/types/capital-gains/canada/domain/types.d.ts +20 -0
  49. package/dist/types/capital-gains/domain/types.d.ts +6 -0
  50. package/dist/types/capital-gains/france/FranceCapitalGainsService.d.ts +4 -0
  51. package/dist/types/capital-gains/france/FranceCapitalGainsServiceImpl.d.ts +8 -0
  52. package/dist/types/capital-gains/france/domain/types.d.ts +15 -0
  53. package/dist/types/capital-gains/germany/GermanyCapitalGainsService.d.ts +4 -0
  54. package/dist/types/capital-gains/germany/GermanyCapitalGainsServiceImpl.d.ts +8 -0
  55. package/dist/types/capital-gains/germany/domain/types.d.ts +17 -0
  56. package/dist/types/capital-gains/south-africa/SouthAfricaCapitalGainsService.d.ts +4 -0
  57. package/dist/types/capital-gains/south-africa/SouthAfricaCapitalGainsServiceImpl.d.ts +9 -0
  58. package/dist/types/capital-gains/south-africa/domain/types.d.ts +21 -0
  59. package/dist/types/capital-gains/uk/UKCapitalGainsService.d.ts +4 -0
  60. package/dist/types/capital-gains/uk/UKCapitalGainsServiceImpl.d.ts +8 -0
  61. package/dist/types/capital-gains/uk/domain/types.d.ts +17 -0
  62. package/dist/types/capital-gains/usa/USACapitalGainsService.d.ts +4 -0
  63. package/dist/types/capital-gains/usa/USACapitalGainsServiceImpl.d.ts +9 -0
  64. package/dist/types/capital-gains/usa/domain/types.d.ts +26 -0
  65. package/dist/types/corporate/germany/GermanyCorporateTaxService.d.ts +4 -0
  66. package/dist/types/corporate/germany/GermanyCorporateTaxServiceImpl.d.ts +8 -0
  67. package/dist/types/corporate/germany/domain/types.d.ts +24 -0
  68. package/dist/types/corporate/usa/USACorporateTaxService.d.ts +4 -0
  69. package/dist/types/corporate/usa/USACorporateTaxServiceImpl.d.ts +8 -0
  70. package/dist/types/corporate/usa/domain/types.d.ts +15 -0
  71. package/dist/types/income-tax/germany/GermanyIncomeTaxService.d.ts +4 -0
  72. package/dist/types/income-tax/germany/GermanyIncomeTaxServiceImpl.d.ts +12 -0
  73. package/dist/types/income-tax/germany/domain/types.d.ts +23 -0
  74. package/dist/types/income-tax/usa/USAIncomeTaxService.d.ts +4 -0
  75. package/dist/types/income-tax/usa/USAIncomeTaxServiceImpl.d.ts +11 -0
  76. package/dist/types/income-tax/usa/domain/types.d.ts +30 -0
  77. package/dist/types/index.d.ts +26 -0
  78. package/dist/types/mortgage/germany/GermanyMortgageService.d.ts +4 -0
  79. package/dist/types/mortgage/germany/GermanyMortgageServiceImpl.d.ts +7 -0
  80. package/dist/types/mortgage/germany/domain/types.d.ts +42 -0
  81. package/dist/types/mortgage/usa/USAMortgageService.d.ts +4 -0
  82. package/dist/types/mortgage/usa/USAMortgageServiceImpl.d.ts +8 -0
  83. package/dist/types/mortgage/usa/domain/types.d.ts +44 -0
  84. package/dist/types/shared/domain/types.d.ts +2 -1
  85. package/package.json +1 -1
  86. package/src/capital-gains/australia/AustraliaCapitalGainsService.ts +5 -0
  87. package/src/capital-gains/australia/AustraliaCapitalGainsServiceImpl.ts +73 -0
  88. package/src/capital-gains/australia/domain/types.ts +26 -0
  89. package/src/capital-gains/canada/CanadaCapitalGainsService.ts +5 -0
  90. package/src/capital-gains/canada/CanadaCapitalGainsServiceImpl.ts +71 -0
  91. package/src/capital-gains/canada/domain/types.ts +24 -0
  92. package/src/capital-gains/domain/types.ts +6 -0
  93. package/src/capital-gains/france/FranceCapitalGainsService.ts +5 -0
  94. package/src/capital-gains/france/FranceCapitalGainsServiceImpl.ts +48 -0
  95. package/src/capital-gains/france/domain/types.ts +18 -0
  96. package/src/capital-gains/germany/GermanyCapitalGainsService.ts +5 -0
  97. package/src/capital-gains/germany/GermanyCapitalGainsServiceImpl.ts +74 -0
  98. package/src/capital-gains/germany/domain/types.ts +20 -0
  99. package/src/capital-gains/south-africa/SouthAfricaCapitalGainsService.ts +5 -0
  100. package/src/capital-gains/south-africa/SouthAfricaCapitalGainsServiceImpl.ts +87 -0
  101. package/src/capital-gains/south-africa/domain/types.ts +25 -0
  102. package/src/capital-gains/uk/UKCapitalGainsService.ts +5 -0
  103. package/src/capital-gains/uk/UKCapitalGainsServiceImpl.ts +84 -0
  104. package/src/capital-gains/uk/domain/types.ts +20 -0
  105. package/src/capital-gains/usa/USACapitalGainsService.ts +5 -0
  106. package/src/capital-gains/usa/USACapitalGainsServiceImpl.ts +86 -0
  107. package/src/capital-gains/usa/domain/types.ts +27 -0
  108. package/src/corporate/germany/GermanyCorporateTaxService.ts +5 -0
  109. package/src/corporate/germany/GermanyCorporateTaxServiceImpl.ts +64 -0
  110. package/src/corporate/germany/domain/types.ts +20 -0
  111. package/src/corporate/usa/USACorporateTaxService.ts +5 -0
  112. package/src/corporate/usa/USACorporateTaxServiceImpl.ts +35 -0
  113. package/src/corporate/usa/domain/types.ts +15 -0
  114. package/src/income-tax/germany/GermanyIncomeTaxService.ts +5 -0
  115. package/src/income-tax/germany/GermanyIncomeTaxServiceImpl.ts +121 -0
  116. package/src/income-tax/germany/domain/types.ts +27 -0
  117. package/src/income-tax/usa/USAIncomeTaxService.ts +5 -0
  118. package/src/income-tax/usa/USAIncomeTaxServiceImpl.ts +113 -0
  119. package/src/income-tax/usa/domain/types.ts +24 -0
  120. package/src/index.ts +98 -0
  121. package/src/mortgage/germany/GermanyMortgageService.ts +5 -0
  122. package/src/mortgage/germany/GermanyMortgageServiceImpl.ts +111 -0
  123. package/src/mortgage/germany/domain/types.ts +49 -0
  124. package/src/mortgage/usa/USAMortgageService.ts +5 -0
  125. package/src/mortgage/usa/USAMortgageServiceImpl.ts +134 -0
  126. package/src/mortgage/usa/domain/types.ts +52 -0
  127. package/src/shared/domain/types.ts +1 -0
  128. package/test/australia-capital-gains.test.ts +80 -0
  129. package/test/canada-capital-gains.test.ts +71 -0
  130. package/test/france-capital-gains.test.ts +66 -0
  131. package/test/germany-capital-gains.test.ts +85 -0
  132. package/test/germany-corporate-tax.test.ts +77 -0
  133. package/test/germany-income-tax.test.ts +114 -0
  134. package/test/germany-mortgage.test.ts +105 -0
  135. package/test/south-africa-capital-gains.test.ts +84 -0
  136. package/test/uk-capital-gains.test.ts +79 -0
  137. package/test/usa-capital-gains.test.ts +88 -0
  138. package/test/usa-corporate-tax.test.ts +59 -0
  139. package/test/usa-income-tax.test.ts +138 -0
  140. package/test/usa-mortgage.test.ts +97 -0
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQXVzdHJhbGlhQ2FwaXRhbEdhaW5zU2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9jYXBpdGFsLWdhaW5zL2F1c3RyYWxpYS9BdXN0cmFsaWFDYXBpdGFsR2FpbnNTZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiIiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBSZXN1bHQgfSBmcm9tIFwiLi9kb21haW4vdHlwZXNcIjtcblxuZXhwb3J0IGludGVyZmFjZSBBdXN0cmFsaWFDYXBpdGFsR2FpbnNTZXJ2aWNlIHtcbiAgICBjYWxjdWxhdGUoKTogUmVzdWx0O1xufVxuIl19
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AustraliaCapitalGainsServiceImpl = void 0;
4
+ class AustraliaCapitalGainsServiceImpl {
5
+ constructor(input, rules) {
6
+ this._input = input;
7
+ this._rules = rules;
8
+ }
9
+ calculate() {
10
+ const gain = this._input.capitalGain;
11
+ if (gain <= 0) {
12
+ return { taxableGain: 0, capitalGainsTax: 0, effectiveRate: 0, breakdowns: [] };
13
+ }
14
+ const eligible = this._input.holdingPeriodMonths >= this._rules.cgtDiscountMinMonths;
15
+ const taxableGain = eligible ? gain * (1 - this._rules.cgtDiscount) : gain;
16
+ const otherIncome = this._input.totalTaxableIncome - gain;
17
+ const { tax, breakdowns } = this.applyBrackets(taxableGain, otherIncome, this._rules.taxBrackets);
18
+ return {
19
+ taxableGain,
20
+ capitalGainsTax: tax,
21
+ effectiveRate: gain > 0 ? (tax / gain) * 100 : 0,
22
+ breakdowns,
23
+ };
24
+ }
25
+ applyBrackets(taxableGain, otherIncome, brackets) {
26
+ let tax = 0;
27
+ const breakdowns = [];
28
+ let remaining = taxableGain;
29
+ let incomeUsed = otherIncome;
30
+ for (const bracket of brackets) {
31
+ if (remaining <= 0)
32
+ break;
33
+ const upper = bracket.to ?? Infinity;
34
+ if (incomeUsed >= upper)
35
+ continue;
36
+ const bracketStart = Math.max(bracket.from, incomeUsed);
37
+ const bracketSpace = upper - bracketStart;
38
+ const taxable = Math.min(bracketSpace, remaining);
39
+ if (taxable > 0) {
40
+ const bracketTax = taxable * bracket.rate;
41
+ tax += bracketTax;
42
+ remaining -= taxable;
43
+ incomeUsed += taxable;
44
+ breakdowns.push({
45
+ from: `${bracket.from}`,
46
+ to: `${bracket.to ?? 'Above'}`,
47
+ rate: bracket.rate,
48
+ amount: bracketTax,
49
+ });
50
+ }
51
+ }
52
+ return { tax, breakdowns };
53
+ }
54
+ }
55
+ exports.AustraliaCapitalGainsServiceImpl = AustraliaCapitalGainsServiceImpl;
56
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQXVzdHJhbGlhQ2FwaXRhbEdhaW5zU2VydmljZUltcGwuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvY2FwaXRhbC1nYWlucy9hdXN0cmFsaWEvQXVzdHJhbGlhQ2FwaXRhbEdhaW5zU2VydmljZUltcGwudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBSUEsTUFBYSxnQ0FBZ0M7SUFJekMsWUFBWSxLQUFZLEVBQUUsS0FBWTtRQUNsQyxJQUFJLENBQUMsTUFBTSxHQUFHLEtBQUssQ0FBQztRQUNwQixJQUFJLENBQUMsTUFBTSxHQUFHLEtBQUssQ0FBQztJQUN4QixDQUFDO0lBRUQsU0FBUztRQUNMLE1BQU0sSUFBSSxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsV0FBVyxDQUFDO1FBRXJDLElBQUksSUFBSSxJQUFJLENBQUMsRUFBRSxDQUFDO1lBQ1osT0FBTyxFQUFFLFdBQVcsRUFBRSxDQUFDLEVBQUUsZUFBZSxFQUFFLENBQUMsRUFBRSxhQUFhLEVBQUUsQ0FBQyxFQUFFLFVBQVUsRUFBRSxFQUFFLEVBQUUsQ0FBQztRQUNwRixDQUFDO1FBRUQsTUFBTSxRQUFRLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxtQkFBbUIsSUFBSSxJQUFJLENBQUMsTUFBTSxDQUFDLG9CQUFvQixDQUFDO1FBQ3JGLE1BQU0sV0FBVyxHQUFHLFFBQVEsQ0FBQyxDQUFDLENBQUMsSUFBSSxHQUFHLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQztRQUUzRSxNQUFNLFdBQVcsR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLGtCQUFrQixHQUFHLElBQUksQ0FBQztRQUMxRCxNQUFNLEVBQUUsR0FBRyxFQUFFLFVBQVUsRUFBRSxHQUFHLElBQUksQ0FBQyxhQUFhLENBQUMsV0FBVyxFQUFFLFdBQVcsRUFBRSxJQUFJLENBQUMsTUFBTSxDQUFDLFdBQVcsQ0FBQyxDQUFDO1FBRWxHLE9BQU87WUFDSCxXQUFXO1lBQ1gsZUFBZSxFQUFFLEdBQUc7WUFDcEIsYUFBYSxFQUFFLElBQUksR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxHQUFHLElBQUksQ0FBQyxHQUFHLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUNoRCxVQUFVO1NBQ2IsQ0FBQztJQUNOLENBQUM7SUFFTyxhQUFhLENBQ2pCLFdBQW1CLEVBQ25CLFdBQW1CLEVBQ25CLFFBQXNCO1FBRXRCLElBQUksR0FBRyxHQUFHLENBQUMsQ0FBQztRQUNaLE1BQU0sVUFBVSxHQUFnQixFQUFFLENBQUM7UUFDbkMsSUFBSSxTQUFTLEdBQUcsV0FBVyxDQUFDO1FBQzVCLElBQUksVUFBVSxHQUFHLFdBQVcsQ0FBQztRQUU3QixLQUFLLE1BQU0sT0FBTyxJQUFJLFFBQVEsRUFBRSxDQUFDO1lBQzdCLElBQUksU0FBUyxJQUFJLENBQUM7Z0JBQUUsTUFBTTtZQUUxQixNQUFNLEtBQUssR0FBRyxPQUFPLENBQUMsRUFBRSxJQUFJLFFBQVEsQ0FBQztZQUVyQyxJQUFJLFVBQVUsSUFBSSxLQUFLO2dCQUFFLFNBQVM7WUFFbEMsTUFBTSxZQUFZLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsSUFBSSxFQUFFLFVBQVUsQ0FBQyxDQUFDO1lBQ3hELE1BQU0sWUFBWSxHQUFHLEtBQUssR0FBRyxZQUFZLENBQUM7WUFDMUMsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxZQUFZLEVBQUUsU0FBUyxDQUFDLENBQUM7WUFFbEQsSUFBSSxPQUFPLEdBQUcsQ0FBQyxFQUFFLENBQUM7Z0JBQ2QsTUFBTSxVQUFVLEdBQUcsT0FBTyxHQUFHLE9BQU8sQ0FBQyxJQUFJLENBQUM7Z0JBQzFDLEdBQUcsSUFBSSxVQUFVLENBQUM7Z0JBQ2xCLFNBQVMsSUFBSSxPQUFPLENBQUM7Z0JBQ3JCLFVBQVUsSUFBSSxPQUFPLENBQUM7Z0JBRXRCLFVBQVUsQ0FBQyxJQUFJLENBQUM7b0JBQ1osSUFBSSxFQUFFLEdBQUcsT0FBTyxDQUFDLElBQUksRUFBRTtvQkFDdkIsRUFBRSxFQUFFLEdBQUcsT0FBTyxDQUFDLEVBQUUsSUFBSSxPQUFPLEVBQUU7b0JBQzlCLElBQUksRUFBRSxPQUFPLENBQUMsSUFBSTtvQkFDbEIsTUFBTSxFQUFFLFVBQVU7aUJBQ3JCLENBQUMsQ0FBQztZQUNQLENBQUM7UUFDTCxDQUFDO1FBRUQsT0FBTyxFQUFFLEdBQUcsRUFBRSxVQUFVLEVBQUUsQ0FBQztJQUMvQixDQUFDO0NBQ0o7QUFwRUQsNEVBb0VDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQnJlYWtkb3duIH0gZnJvbSBcIi4uL2RvbWFpbi90eXBlc1wiO1xuaW1wb3J0IHsgQXVzdHJhbGlhQ2FwaXRhbEdhaW5zU2VydmljZSB9IGZyb20gXCIuL0F1c3RyYWxpYUNhcGl0YWxHYWluc1NlcnZpY2VcIjtcbmltcG9ydCB7IElucHV0LCBSZXN1bHQsIFJ1bGVzLCBUYXhCcmFja2V0IH0gZnJvbSBcIi4vZG9tYWluL3R5cGVzXCI7XG5cbmV4cG9ydCBjbGFzcyBBdXN0cmFsaWFDYXBpdGFsR2FpbnNTZXJ2aWNlSW1wbCBpbXBsZW1lbnRzIEF1c3RyYWxpYUNhcGl0YWxHYWluc1NlcnZpY2Uge1xuICAgIHByaXZhdGUgX2lucHV0OiBJbnB1dDtcbiAgICBwcml2YXRlIF9ydWxlczogUnVsZXM7XG5cbiAgICBjb25zdHJ1Y3RvcihpbnB1dDogSW5wdXQsIHJ1bGVzOiBSdWxlcykge1xuICAgICAgICB0aGlzLl9pbnB1dCA9IGlucHV0O1xuICAgICAgICB0aGlzLl9ydWxlcyA9IHJ1bGVzO1xuICAgIH1cblxuICAgIGNhbGN1bGF0ZSgpOiBSZXN1bHQge1xuICAgICAgICBjb25zdCBnYWluID0gdGhpcy5faW5wdXQuY2FwaXRhbEdhaW47XG5cbiAgICAgICAgaWYgKGdhaW4gPD0gMCkge1xuICAgICAgICAgICAgcmV0dXJuIHsgdGF4YWJsZUdhaW46IDAsIGNhcGl0YWxHYWluc1RheDogMCwgZWZmZWN0aXZlUmF0ZTogMCwgYnJlYWtkb3duczogW10gfTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGVsaWdpYmxlID0gdGhpcy5faW5wdXQuaG9sZGluZ1BlcmlvZE1vbnRocyA+PSB0aGlzLl9ydWxlcy5jZ3REaXNjb3VudE1pbk1vbnRocztcbiAgICAgICAgY29uc3QgdGF4YWJsZUdhaW4gPSBlbGlnaWJsZSA/IGdhaW4gKiAoMSAtIHRoaXMuX3J1bGVzLmNndERpc2NvdW50KSA6IGdhaW47XG5cbiAgICAgICAgY29uc3Qgb3RoZXJJbmNvbWUgPSB0aGlzLl9pbnB1dC50b3RhbFRheGFibGVJbmNvbWUgLSBnYWluO1xuICAgICAgICBjb25zdCB7IHRheCwgYnJlYWtkb3ducyB9ID0gdGhpcy5hcHBseUJyYWNrZXRzKHRheGFibGVHYWluLCBvdGhlckluY29tZSwgdGhpcy5fcnVsZXMudGF4QnJhY2tldHMpO1xuXG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICB0YXhhYmxlR2FpbixcbiAgICAgICAgICAgIGNhcGl0YWxHYWluc1RheDogdGF4LFxuICAgICAgICAgICAgZWZmZWN0aXZlUmF0ZTogZ2FpbiA+IDAgPyAodGF4IC8gZ2FpbikgKiAxMDAgOiAwLFxuICAgICAgICAgICAgYnJlYWtkb3ducyxcbiAgICAgICAgfTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGFwcGx5QnJhY2tldHMoXG4gICAgICAgIHRheGFibGVHYWluOiBudW1iZXIsXG4gICAgICAgIG90aGVySW5jb21lOiBudW1iZXIsXG4gICAgICAgIGJyYWNrZXRzOiBUYXhCcmFja2V0W10sXG4gICAgKTogeyB0YXg6IG51bWJlcjsgYnJlYWtkb3duczogQnJlYWtkb3duW10gfSB7XG4gICAgICAgIGxldCB0YXggPSAwO1xuICAgICAgICBjb25zdCBicmVha2Rvd25zOiBCcmVha2Rvd25bXSA9IFtdO1xuICAgICAgICBsZXQgcmVtYWluaW5nID0gdGF4YWJsZUdhaW47XG4gICAgICAgIGxldCBpbmNvbWVVc2VkID0gb3RoZXJJbmNvbWU7XG5cbiAgICAgICAgZm9yIChjb25zdCBicmFja2V0IG9mIGJyYWNrZXRzKSB7XG4gICAgICAgICAgICBpZiAocmVtYWluaW5nIDw9IDApIGJyZWFrO1xuXG4gICAgICAgICAgICBjb25zdCB1cHBlciA9IGJyYWNrZXQudG8gPz8gSW5maW5pdHk7XG5cbiAgICAgICAgICAgIGlmIChpbmNvbWVVc2VkID49IHVwcGVyKSBjb250aW51ZTtcblxuICAgICAgICAgICAgY29uc3QgYnJhY2tldFN0YXJ0ID0gTWF0aC5tYXgoYnJhY2tldC5mcm9tLCBpbmNvbWVVc2VkKTtcbiAgICAgICAgICAgIGNvbnN0IGJyYWNrZXRTcGFjZSA9IHVwcGVyIC0gYnJhY2tldFN0YXJ0O1xuICAgICAgICAgICAgY29uc3QgdGF4YWJsZSA9IE1hdGgubWluKGJyYWNrZXRTcGFjZSwgcmVtYWluaW5nKTtcblxuICAgICAgICAgICAgaWYgKHRheGFibGUgPiAwKSB7XG4gICAgICAgICAgICAgICAgY29uc3QgYnJhY2tldFRheCA9IHRheGFibGUgKiBicmFja2V0LnJhdGU7XG4gICAgICAgICAgICAgICAgdGF4ICs9IGJyYWNrZXRUYXg7XG4gICAgICAgICAgICAgICAgcmVtYWluaW5nIC09IHRheGFibGU7XG4gICAgICAgICAgICAgICAgaW5jb21lVXNlZCArPSB0YXhhYmxlO1xuXG4gICAgICAgICAgICAgICAgYnJlYWtkb3ducy5wdXNoKHtcbiAgICAgICAgICAgICAgICAgICAgZnJvbTogYCR7YnJhY2tldC5mcm9tfWAsXG4gICAgICAgICAgICAgICAgICAgIHRvOiBgJHticmFja2V0LnRvID8/ICdBYm92ZSd9YCxcbiAgICAgICAgICAgICAgICAgICAgcmF0ZTogYnJhY2tldC5yYXRlLFxuICAgICAgICAgICAgICAgICAgICBhbW91bnQ6IGJyYWNrZXRUYXgsXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4geyB0YXgsIGJyZWFrZG93bnMgfTtcbiAgICB9XG59XG4iXX0=
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvY2FwaXRhbC1nYWlucy9hdXN0cmFsaWEvZG9tYWluL3R5cGVzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiIiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBCcmVha2Rvd24gfSBmcm9tIFwiLi4vLi4vZG9tYWluL3R5cGVzXCI7XG5cbmV4cG9ydCBpbnRlcmZhY2UgVGF4QnJhY2tldCB7XG4gICAgZnJvbTogbnVtYmVyO1xuICAgIHRvOiBudW1iZXIgfCBudWxsO1xuICAgIHJhdGU6IG51bWJlcjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBSdWxlcyB7XG4gICAgY2d0RGlzY291bnQ6IG51bWJlcjtcbiAgICBjZ3REaXNjb3VudE1pbk1vbnRoczogbnVtYmVyO1xuICAgIHRheEJyYWNrZXRzOiBUYXhCcmFja2V0W107XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgSW5wdXQge1xuICAgIGNhcGl0YWxHYWluOiBudW1iZXI7XG4gICAgdG90YWxUYXhhYmxlSW5jb21lOiBudW1iZXI7XG4gICAgaG9sZGluZ1BlcmlvZE1vbnRoczogbnVtYmVyO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFJlc3VsdCB7XG4gICAgdGF4YWJsZUdhaW46IG51bWJlcjtcbiAgICBjYXBpdGFsR2FpbnNUYXg6IG51bWJlcjtcbiAgICBlZmZlY3RpdmVSYXRlOiBudW1iZXI7XG4gICAgYnJlYWtkb3duczogQnJlYWtkb3duW107XG59XG4iXX0=
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQ2FuYWRhQ2FwaXRhbEdhaW5zU2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9jYXBpdGFsLWdhaW5zL2NhbmFkYS9DYW5hZGFDYXBpdGFsR2FpbnNTZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiIiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBSZXN1bHQgfSBmcm9tIFwiLi9kb21haW4vdHlwZXNcIjtcblxuZXhwb3J0IGludGVyZmFjZSBDYW5hZGFDYXBpdGFsR2FpbnNTZXJ2aWNlIHtcbiAgICBjYWxjdWxhdGUoKTogUmVzdWx0O1xufVxuIl19
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CanadaCapitalGainsServiceImpl = void 0;
4
+ class CanadaCapitalGainsServiceImpl {
5
+ constructor(input, rules) {
6
+ this._input = input;
7
+ this._rules = rules;
8
+ }
9
+ calculate() {
10
+ const gain = this._input.capitalGain;
11
+ if (gain <= 0) {
12
+ return { taxableGain: 0, capitalGainsTax: 0, effectiveRate: 0, breakdowns: [] };
13
+ }
14
+ const taxableGain = gain * this._rules.inclusionRate;
15
+ const otherIncome = this._input.totalTaxableIncome - gain;
16
+ const { tax, breakdowns } = this.applyBrackets(taxableGain, otherIncome, this._rules.taxBrackets);
17
+ return {
18
+ taxableGain,
19
+ capitalGainsTax: tax,
20
+ effectiveRate: gain > 0 ? (tax / gain) * 100 : 0,
21
+ breakdowns,
22
+ };
23
+ }
24
+ applyBrackets(taxableGain, otherIncome, brackets) {
25
+ let tax = 0;
26
+ const breakdowns = [];
27
+ let remaining = taxableGain;
28
+ let incomeUsed = otherIncome;
29
+ for (const bracket of brackets) {
30
+ if (remaining <= 0)
31
+ break;
32
+ const upper = bracket.to ?? Infinity;
33
+ if (incomeUsed >= upper)
34
+ continue;
35
+ const bracketStart = Math.max(bracket.from, incomeUsed);
36
+ const bracketSpace = upper - bracketStart;
37
+ const taxable = Math.min(bracketSpace, remaining);
38
+ if (taxable > 0) {
39
+ const bracketTax = taxable * bracket.rate;
40
+ tax += bracketTax;
41
+ remaining -= taxable;
42
+ incomeUsed += taxable;
43
+ breakdowns.push({
44
+ from: `${bracket.from}`,
45
+ to: `${bracket.to ?? 'Above'}`,
46
+ rate: bracket.rate,
47
+ amount: bracketTax,
48
+ });
49
+ }
50
+ }
51
+ return { tax, breakdowns };
52
+ }
53
+ }
54
+ exports.CanadaCapitalGainsServiceImpl = CanadaCapitalGainsServiceImpl;
55
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQ2FuYWRhQ2FwaXRhbEdhaW5zU2VydmljZUltcGwuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvY2FwaXRhbC1nYWlucy9jYW5hZGEvQ2FuYWRhQ2FwaXRhbEdhaW5zU2VydmljZUltcGwudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBSUEsTUFBYSw2QkFBNkI7SUFJdEMsWUFBWSxLQUFZLEVBQUUsS0FBWTtRQUNsQyxJQUFJLENBQUMsTUFBTSxHQUFHLEtBQUssQ0FBQztRQUNwQixJQUFJLENBQUMsTUFBTSxHQUFHLEtBQUssQ0FBQztJQUN4QixDQUFDO0lBRUQsU0FBUztRQUNMLE1BQU0sSUFBSSxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsV0FBVyxDQUFDO1FBRXJDLElBQUksSUFBSSxJQUFJLENBQUMsRUFBRSxDQUFDO1lBQ1osT0FBTyxFQUFFLFdBQVcsRUFBRSxDQUFDLEVBQUUsZUFBZSxFQUFFLENBQUMsRUFBRSxhQUFhLEVBQUUsQ0FBQyxFQUFFLFVBQVUsRUFBRSxFQUFFLEVBQUUsQ0FBQztRQUNwRixDQUFDO1FBRUQsTUFBTSxXQUFXLEdBQUcsSUFBSSxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsYUFBYSxDQUFDO1FBQ3JELE1BQU0sV0FBVyxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsa0JBQWtCLEdBQUcsSUFBSSxDQUFDO1FBQzFELE1BQU0sRUFBRSxHQUFHLEVBQUUsVUFBVSxFQUFFLEdBQUcsSUFBSSxDQUFDLGFBQWEsQ0FBQyxXQUFXLEVBQUUsV0FBVyxFQUFFLElBQUksQ0FBQyxNQUFNLENBQUMsV0FBVyxDQUFDLENBQUM7UUFFbEcsT0FBTztZQUNILFdBQVc7WUFDWCxlQUFlLEVBQUUsR0FBRztZQUNwQixhQUFhLEVBQUUsSUFBSSxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLEdBQUcsSUFBSSxDQUFDLEdBQUcsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQ2hELFVBQVU7U0FDYixDQUFDO0lBQ04sQ0FBQztJQUVPLGFBQWEsQ0FDakIsV0FBbUIsRUFDbkIsV0FBbUIsRUFDbkIsUUFBc0I7UUFFdEIsSUFBSSxHQUFHLEdBQUcsQ0FBQyxDQUFDO1FBQ1osTUFBTSxVQUFVLEdBQWdCLEVBQUUsQ0FBQztRQUNuQyxJQUFJLFNBQVMsR0FBRyxXQUFXLENBQUM7UUFDNUIsSUFBSSxVQUFVLEdBQUcsV0FBVyxDQUFDO1FBRTdCLEtBQUssTUFBTSxPQUFPLElBQUksUUFBUSxFQUFFLENBQUM7WUFDN0IsSUFBSSxTQUFTLElBQUksQ0FBQztnQkFBRSxNQUFNO1lBRTFCLE1BQU0sS0FBSyxHQUFHLE9BQU8sQ0FBQyxFQUFFLElBQUksUUFBUSxDQUFDO1lBRXJDLElBQUksVUFBVSxJQUFJLEtBQUs7Z0JBQUUsU0FBUztZQUVsQyxNQUFNLFlBQVksR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxJQUFJLEVBQUUsVUFBVSxDQUFDLENBQUM7WUFDeEQsTUFBTSxZQUFZLEdBQUcsS0FBSyxHQUFHLFlBQVksQ0FBQztZQUMxQyxNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLFlBQVksRUFBRSxTQUFTLENBQUMsQ0FBQztZQUVsRCxJQUFJLE9BQU8sR0FBRyxDQUFDLEVBQUUsQ0FBQztnQkFDZCxNQUFNLFVBQVUsR0FBRyxPQUFPLEdBQUcsT0FBTyxDQUFDLElBQUksQ0FBQztnQkFDMUMsR0FBRyxJQUFJLFVBQVUsQ0FBQztnQkFDbEIsU0FBUyxJQUFJLE9BQU8sQ0FBQztnQkFDckIsVUFBVSxJQUFJLE9BQU8sQ0FBQztnQkFFdEIsVUFBVSxDQUFDLElBQUksQ0FBQztvQkFDWixJQUFJLEVBQUUsR0FBRyxPQUFPLENBQUMsSUFBSSxFQUFFO29CQUN2QixFQUFFLEVBQUUsR0FBRyxPQUFPLENBQUMsRUFBRSxJQUFJLE9BQU8sRUFBRTtvQkFDOUIsSUFBSSxFQUFFLE9BQU8sQ0FBQyxJQUFJO29CQUNsQixNQUFNLEVBQUUsVUFBVTtpQkFDckIsQ0FBQyxDQUFDO1lBQ1AsQ0FBQztRQUNMLENBQUM7UUFFRCxPQUFPLEVBQUUsR0FBRyxFQUFFLFVBQVUsRUFBRSxDQUFDO0lBQy9CLENBQUM7Q0FDSjtBQWxFRCxzRUFrRUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBCcmVha2Rvd24gfSBmcm9tIFwiLi4vZG9tYWluL3R5cGVzXCI7XG5pbXBvcnQgeyBDYW5hZGFDYXBpdGFsR2FpbnNTZXJ2aWNlIH0gZnJvbSBcIi4vQ2FuYWRhQ2FwaXRhbEdhaW5zU2VydmljZVwiO1xuaW1wb3J0IHsgSW5wdXQsIFJlc3VsdCwgUnVsZXMsIFRheEJyYWNrZXQgfSBmcm9tIFwiLi9kb21haW4vdHlwZXNcIjtcblxuZXhwb3J0IGNsYXNzIENhbmFkYUNhcGl0YWxHYWluc1NlcnZpY2VJbXBsIGltcGxlbWVudHMgQ2FuYWRhQ2FwaXRhbEdhaW5zU2VydmljZSB7XG4gICAgcHJpdmF0ZSBfaW5wdXQ6IElucHV0O1xuICAgIHByaXZhdGUgX3J1bGVzOiBSdWxlcztcblxuICAgIGNvbnN0cnVjdG9yKGlucHV0OiBJbnB1dCwgcnVsZXM6IFJ1bGVzKSB7XG4gICAgICAgIHRoaXMuX2lucHV0ID0gaW5wdXQ7XG4gICAgICAgIHRoaXMuX3J1bGVzID0gcnVsZXM7XG4gICAgfVxuXG4gICAgY2FsY3VsYXRlKCk6IFJlc3VsdCB7XG4gICAgICAgIGNvbnN0IGdhaW4gPSB0aGlzLl9pbnB1dC5jYXBpdGFsR2FpbjtcblxuICAgICAgICBpZiAoZ2FpbiA8PSAwKSB7XG4gICAgICAgICAgICByZXR1cm4geyB0YXhhYmxlR2FpbjogMCwgY2FwaXRhbEdhaW5zVGF4OiAwLCBlZmZlY3RpdmVSYXRlOiAwLCBicmVha2Rvd25zOiBbXSB9O1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgdGF4YWJsZUdhaW4gPSBnYWluICogdGhpcy5fcnVsZXMuaW5jbHVzaW9uUmF0ZTtcbiAgICAgICAgY29uc3Qgb3RoZXJJbmNvbWUgPSB0aGlzLl9pbnB1dC50b3RhbFRheGFibGVJbmNvbWUgLSBnYWluO1xuICAgICAgICBjb25zdCB7IHRheCwgYnJlYWtkb3ducyB9ID0gdGhpcy5hcHBseUJyYWNrZXRzKHRheGFibGVHYWluLCBvdGhlckluY29tZSwgdGhpcy5fcnVsZXMudGF4QnJhY2tldHMpO1xuXG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICB0YXhhYmxlR2FpbixcbiAgICAgICAgICAgIGNhcGl0YWxHYWluc1RheDogdGF4LFxuICAgICAgICAgICAgZWZmZWN0aXZlUmF0ZTogZ2FpbiA+IDAgPyAodGF4IC8gZ2FpbikgKiAxMDAgOiAwLFxuICAgICAgICAgICAgYnJlYWtkb3ducyxcbiAgICAgICAgfTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGFwcGx5QnJhY2tldHMoXG4gICAgICAgIHRheGFibGVHYWluOiBudW1iZXIsXG4gICAgICAgIG90aGVySW5jb21lOiBudW1iZXIsXG4gICAgICAgIGJyYWNrZXRzOiBUYXhCcmFja2V0W10sXG4gICAgKTogeyB0YXg6IG51bWJlcjsgYnJlYWtkb3duczogQnJlYWtkb3duW10gfSB7XG4gICAgICAgIGxldCB0YXggPSAwO1xuICAgICAgICBjb25zdCBicmVha2Rvd25zOiBCcmVha2Rvd25bXSA9IFtdO1xuICAgICAgICBsZXQgcmVtYWluaW5nID0gdGF4YWJsZUdhaW47XG4gICAgICAgIGxldCBpbmNvbWVVc2VkID0gb3RoZXJJbmNvbWU7XG5cbiAgICAgICAgZm9yIChjb25zdCBicmFja2V0IG9mIGJyYWNrZXRzKSB7XG4gICAgICAgICAgICBpZiAocmVtYWluaW5nIDw9IDApIGJyZWFrO1xuXG4gICAgICAgICAgICBjb25zdCB1cHBlciA9IGJyYWNrZXQudG8gPz8gSW5maW5pdHk7XG5cbiAgICAgICAgICAgIGlmIChpbmNvbWVVc2VkID49IHVwcGVyKSBjb250aW51ZTtcblxuICAgICAgICAgICAgY29uc3QgYnJhY2tldFN0YXJ0ID0gTWF0aC5tYXgoYnJhY2tldC5mcm9tLCBpbmNvbWVVc2VkKTtcbiAgICAgICAgICAgIGNvbnN0IGJyYWNrZXRTcGFjZSA9IHVwcGVyIC0gYnJhY2tldFN0YXJ0O1xuICAgICAgICAgICAgY29uc3QgdGF4YWJsZSA9IE1hdGgubWluKGJyYWNrZXRTcGFjZSwgcmVtYWluaW5nKTtcblxuICAgICAgICAgICAgaWYgKHRheGFibGUgPiAwKSB7XG4gICAgICAgICAgICAgICAgY29uc3QgYnJhY2tldFRheCA9IHRheGFibGUgKiBicmFja2V0LnJhdGU7XG4gICAgICAgICAgICAgICAgdGF4ICs9IGJyYWNrZXRUYXg7XG4gICAgICAgICAgICAgICAgcmVtYWluaW5nIC09IHRheGFibGU7XG4gICAgICAgICAgICAgICAgaW5jb21lVXNlZCArPSB0YXhhYmxlO1xuXG4gICAgICAgICAgICAgICAgYnJlYWtkb3ducy5wdXNoKHtcbiAgICAgICAgICAgICAgICAgICAgZnJvbTogYCR7YnJhY2tldC5mcm9tfWAsXG4gICAgICAgICAgICAgICAgICAgIHRvOiBgJHticmFja2V0LnRvID8/ICdBYm92ZSd9YCxcbiAgICAgICAgICAgICAgICAgICAgcmF0ZTogYnJhY2tldC5yYXRlLFxuICAgICAgICAgICAgICAgICAgICBhbW91bnQ6IGJyYWNrZXRUYXgsXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4geyB0YXgsIGJyZWFrZG93bnMgfTtcbiAgICB9XG59XG4iXX0=
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvY2FwaXRhbC1nYWlucy9jYW5hZGEvZG9tYWluL3R5cGVzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiIiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBCcmVha2Rvd24gfSBmcm9tIFwiLi4vLi4vZG9tYWluL3R5cGVzXCI7XG5cbmV4cG9ydCBpbnRlcmZhY2UgUnVsZXMge1xuICAgIGluY2x1c2lvblJhdGU6IG51bWJlcjtcbiAgICB0YXhCcmFja2V0czogVGF4QnJhY2tldFtdO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFRheEJyYWNrZXQge1xuICAgIGZyb206IG51bWJlcjtcbiAgICB0bzogbnVtYmVyIHwgbnVsbDtcbiAgICByYXRlOiBudW1iZXI7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgSW5wdXQge1xuICAgIGNhcGl0YWxHYWluOiBudW1iZXI7XG4gICAgdG90YWxUYXhhYmxlSW5jb21lOiBudW1iZXI7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgUmVzdWx0IHtcbiAgICB0YXhhYmxlR2FpbjogbnVtYmVyO1xuICAgIGNhcGl0YWxHYWluc1RheDogbnVtYmVyO1xuICAgIGVmZmVjdGl2ZVJhdGU6IG51bWJlcjtcbiAgICBicmVha2Rvd25zOiBCcmVha2Rvd25bXTtcbn1cbiJdfQ==
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvY2FwaXRhbC1nYWlucy9kb21haW4vdHlwZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IiIsInNvdXJjZXNDb250ZW50IjpbImV4cG9ydCBpbnRlcmZhY2UgQnJlYWtkb3duIHtcbiAgICBmcm9tOiBzdHJpbmc7XG4gICAgdG86IHN0cmluZztcbiAgICByYXRlOiBudW1iZXI7XG4gICAgYW1vdW50OiBudW1iZXI7XG59XG4iXX0=
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRnJhbmNlQ2FwaXRhbEdhaW5zU2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9jYXBpdGFsLWdhaW5zL2ZyYW5jZS9GcmFuY2VDYXBpdGFsR2FpbnNTZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiIiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBSZXN1bHQgfSBmcm9tIFwiLi9kb21haW4vdHlwZXNcIjtcblxuZXhwb3J0IGludGVyZmFjZSBGcmFuY2VDYXBpdGFsR2FpbnNTZXJ2aWNlIHtcbiAgICBjYWxjdWxhdGUoKTogUmVzdWx0O1xufVxuIl19
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FranceCapitalGainsServiceImpl = void 0;
4
+ class FranceCapitalGainsServiceImpl {
5
+ constructor(input, rules) {
6
+ this._input = input;
7
+ this._rules = rules;
8
+ }
9
+ calculate() {
10
+ const gain = this._input.capitalGain;
11
+ if (gain <= 0) {
12
+ return { incomeTax: 0, socialContributions: 0, totalTax: 0, effectiveRate: 0, breakdowns: [] };
13
+ }
14
+ const incomeTax = gain * this._rules.flatTaxRate;
15
+ const socialContributions = gain * this._rules.socialContributionsRate;
16
+ const totalTax = incomeTax + socialContributions;
17
+ const breakdowns = [
18
+ {
19
+ from: '0',
20
+ to: 'All',
21
+ rate: this._rules.flatTaxRate,
22
+ amount: incomeTax,
23
+ },
24
+ {
25
+ from: '0',
26
+ to: 'Social',
27
+ rate: this._rules.socialContributionsRate,
28
+ amount: socialContributions,
29
+ },
30
+ ];
31
+ return {
32
+ incomeTax,
33
+ socialContributions,
34
+ totalTax,
35
+ effectiveRate: (totalTax / gain) * 100,
36
+ breakdowns,
37
+ };
38
+ }
39
+ }
40
+ exports.FranceCapitalGainsServiceImpl = FranceCapitalGainsServiceImpl;
41
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRnJhbmNlQ2FwaXRhbEdhaW5zU2VydmljZUltcGwuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvY2FwaXRhbC1nYWlucy9mcmFuY2UvRnJhbmNlQ2FwaXRhbEdhaW5zU2VydmljZUltcGwudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBSUEsTUFBYSw2QkFBNkI7SUFJdEMsWUFBWSxLQUFZLEVBQUUsS0FBWTtRQUNsQyxJQUFJLENBQUMsTUFBTSxHQUFHLEtBQUssQ0FBQztRQUNwQixJQUFJLENBQUMsTUFBTSxHQUFHLEtBQUssQ0FBQztJQUN4QixDQUFDO0lBRUQsU0FBUztRQUNMLE1BQU0sSUFBSSxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsV0FBVyxDQUFDO1FBRXJDLElBQUksSUFBSSxJQUFJLENBQUMsRUFBRSxDQUFDO1lBQ1osT0FBTyxFQUFFLFNBQVMsRUFBRSxDQUFDLEVBQUUsbUJBQW1CLEVBQUUsQ0FBQyxFQUFFLFFBQVEsRUFBRSxDQUFDLEVBQUUsYUFBYSxFQUFFLENBQUMsRUFBRSxVQUFVLEVBQUUsRUFBRSxFQUFFLENBQUM7UUFDbkcsQ0FBQztRQUVELE1BQU0sU0FBUyxHQUFHLElBQUksR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLFdBQVcsQ0FBQztRQUNqRCxNQUFNLG1CQUFtQixHQUFHLElBQUksR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLHVCQUF1QixDQUFDO1FBQ3ZFLE1BQU0sUUFBUSxHQUFHLFNBQVMsR0FBRyxtQkFBbUIsQ0FBQztRQUVqRCxNQUFNLFVBQVUsR0FBZ0I7WUFDNUI7Z0JBQ0ksSUFBSSxFQUFFLEdBQUc7Z0JBQ1QsRUFBRSxFQUFFLEtBQUs7Z0JBQ1QsSUFBSSxFQUFFLElBQUksQ0FBQyxNQUFNLENBQUMsV0FBVztnQkFDN0IsTUFBTSxFQUFFLFNBQVM7YUFDcEI7WUFDRDtnQkFDSSxJQUFJLEVBQUUsR0FBRztnQkFDVCxFQUFFLEVBQUUsUUFBUTtnQkFDWixJQUFJLEVBQUUsSUFBSSxDQUFDLE1BQU0sQ0FBQyx1QkFBdUI7Z0JBQ3pDLE1BQU0sRUFBRSxtQkFBbUI7YUFDOUI7U0FDSixDQUFDO1FBRUYsT0FBTztZQUNILFNBQVM7WUFDVCxtQkFBbUI7WUFDbkIsUUFBUTtZQUNSLGFBQWEsRUFBRSxDQUFDLFFBQVEsR0FBRyxJQUFJLENBQUMsR0FBRyxHQUFHO1lBQ3RDLFVBQVU7U0FDYixDQUFDO0lBQ04sQ0FBQztDQUNKO0FBM0NELHNFQTJDQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEJyZWFrZG93biB9IGZyb20gXCIuLi9kb21haW4vdHlwZXNcIjtcbmltcG9ydCB7IEZyYW5jZUNhcGl0YWxHYWluc1NlcnZpY2UgfSBmcm9tIFwiLi9GcmFuY2VDYXBpdGFsR2FpbnNTZXJ2aWNlXCI7XG5pbXBvcnQgeyBJbnB1dCwgUmVzdWx0LCBSdWxlcyB9IGZyb20gXCIuL2RvbWFpbi90eXBlc1wiO1xuXG5leHBvcnQgY2xhc3MgRnJhbmNlQ2FwaXRhbEdhaW5zU2VydmljZUltcGwgaW1wbGVtZW50cyBGcmFuY2VDYXBpdGFsR2FpbnNTZXJ2aWNlIHtcbiAgICBwcml2YXRlIF9pbnB1dDogSW5wdXQ7XG4gICAgcHJpdmF0ZSBfcnVsZXM6IFJ1bGVzO1xuXG4gICAgY29uc3RydWN0b3IoaW5wdXQ6IElucHV0LCBydWxlczogUnVsZXMpIHtcbiAgICAgICAgdGhpcy5faW5wdXQgPSBpbnB1dDtcbiAgICAgICAgdGhpcy5fcnVsZXMgPSBydWxlcztcbiAgICB9XG5cbiAgICBjYWxjdWxhdGUoKTogUmVzdWx0IHtcbiAgICAgICAgY29uc3QgZ2FpbiA9IHRoaXMuX2lucHV0LmNhcGl0YWxHYWluO1xuXG4gICAgICAgIGlmIChnYWluIDw9IDApIHtcbiAgICAgICAgICAgIHJldHVybiB7IGluY29tZVRheDogMCwgc29jaWFsQ29udHJpYnV0aW9uczogMCwgdG90YWxUYXg6IDAsIGVmZmVjdGl2ZVJhdGU6IDAsIGJyZWFrZG93bnM6IFtdIH07XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBpbmNvbWVUYXggPSBnYWluICogdGhpcy5fcnVsZXMuZmxhdFRheFJhdGU7XG4gICAgICAgIGNvbnN0IHNvY2lhbENvbnRyaWJ1dGlvbnMgPSBnYWluICogdGhpcy5fcnVsZXMuc29jaWFsQ29udHJpYnV0aW9uc1JhdGU7XG4gICAgICAgIGNvbnN0IHRvdGFsVGF4ID0gaW5jb21lVGF4ICsgc29jaWFsQ29udHJpYnV0aW9ucztcblxuICAgICAgICBjb25zdCBicmVha2Rvd25zOiBCcmVha2Rvd25bXSA9IFtcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBmcm9tOiAnMCcsXG4gICAgICAgICAgICAgICAgdG86ICdBbGwnLFxuICAgICAgICAgICAgICAgIHJhdGU6IHRoaXMuX3J1bGVzLmZsYXRUYXhSYXRlLFxuICAgICAgICAgICAgICAgIGFtb3VudDogaW5jb21lVGF4LFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBmcm9tOiAnMCcsXG4gICAgICAgICAgICAgICAgdG86ICdTb2NpYWwnLFxuICAgICAgICAgICAgICAgIHJhdGU6IHRoaXMuX3J1bGVzLnNvY2lhbENvbnRyaWJ1dGlvbnNSYXRlLFxuICAgICAgICAgICAgICAgIGFtb3VudDogc29jaWFsQ29udHJpYnV0aW9ucyxcbiAgICAgICAgICAgIH0sXG4gICAgICAgIF07XG5cbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIGluY29tZVRheCxcbiAgICAgICAgICAgIHNvY2lhbENvbnRyaWJ1dGlvbnMsXG4gICAgICAgICAgICB0b3RhbFRheCxcbiAgICAgICAgICAgIGVmZmVjdGl2ZVJhdGU6ICh0b3RhbFRheCAvIGdhaW4pICogMTAwLFxuICAgICAgICAgICAgYnJlYWtkb3ducyxcbiAgICAgICAgfTtcbiAgICB9XG59XG4iXX0=
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvY2FwaXRhbC1nYWlucy9mcmFuY2UvZG9tYWluL3R5cGVzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiIiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBCcmVha2Rvd24gfSBmcm9tIFwiLi4vLi4vZG9tYWluL3R5cGVzXCI7XG5cbmV4cG9ydCBpbnRlcmZhY2UgUnVsZXMge1xuICAgIGZsYXRUYXhSYXRlOiBudW1iZXI7XG4gICAgc29jaWFsQ29udHJpYnV0aW9uc1JhdGU6IG51bWJlcjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBJbnB1dCB7XG4gICAgY2FwaXRhbEdhaW46IG51bWJlcjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBSZXN1bHQge1xuICAgIGluY29tZVRheDogbnVtYmVyO1xuICAgIHNvY2lhbENvbnRyaWJ1dGlvbnM6IG51bWJlcjtcbiAgICB0b3RhbFRheDogbnVtYmVyO1xuICAgIGVmZmVjdGl2ZVJhdGU6IG51bWJlcjtcbiAgICBicmVha2Rvd25zOiBCcmVha2Rvd25bXTtcbn1cbiJdfQ==
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiR2VybWFueUNhcGl0YWxHYWluc1NlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvY2FwaXRhbC1nYWlucy9nZXJtYW55L0dlcm1hbnlDYXBpdGFsR2FpbnNTZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiIiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBSZXN1bHQgfSBmcm9tIFwiLi9kb21haW4vdHlwZXNcIjtcblxuZXhwb3J0IGludGVyZmFjZSBHZXJtYW55Q2FwaXRhbEdhaW5zU2VydmljZSB7XG4gICAgY2FsY3VsYXRlKCk6IFJlc3VsdDtcbn1cbiJdfQ==
@@ -0,0 +1,65 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GermanyCapitalGainsServiceImpl = void 0;
4
+ class GermanyCapitalGainsServiceImpl {
5
+ constructor(input, rules) {
6
+ this._input = input;
7
+ this._rules = rules;
8
+ }
9
+ calculate() {
10
+ const gain = this._input.capitalGain;
11
+ if (gain <= 0) {
12
+ return {
13
+ taxableGain: 0,
14
+ capitalGainsTax: 0,
15
+ solidaritySurcharge: 0,
16
+ totalTax: 0,
17
+ effectiveRate: 0,
18
+ breakdowns: [],
19
+ };
20
+ }
21
+ const taxableGain = Math.max(0, gain - this._rules.annualExemption);
22
+ if (taxableGain <= 0) {
23
+ return {
24
+ taxableGain: 0,
25
+ capitalGainsTax: 0,
26
+ solidaritySurcharge: 0,
27
+ totalTax: 0,
28
+ effectiveRate: 0,
29
+ breakdowns: [{
30
+ from: '0',
31
+ to: `${this._rules.annualExemption}`,
32
+ rate: 0,
33
+ amount: 0,
34
+ }],
35
+ };
36
+ }
37
+ const capitalGainsTax = taxableGain * this._rules.flatTaxRate;
38
+ const solidaritySurcharge = capitalGainsTax * this._rules.solidaritySurchargeRate;
39
+ const totalTax = capitalGainsTax + solidaritySurcharge;
40
+ const breakdowns = [
41
+ {
42
+ from: '0',
43
+ to: 'All',
44
+ rate: this._rules.flatTaxRate,
45
+ amount: capitalGainsTax,
46
+ },
47
+ {
48
+ from: 'CGT',
49
+ to: 'Solidarity',
50
+ rate: this._rules.solidaritySurchargeRate,
51
+ amount: solidaritySurcharge,
52
+ },
53
+ ];
54
+ return {
55
+ taxableGain,
56
+ capitalGainsTax,
57
+ solidaritySurcharge,
58
+ totalTax,
59
+ effectiveRate: gain > 0 ? (totalTax / gain) * 100 : 0,
60
+ breakdowns,
61
+ };
62
+ }
63
+ }
64
+ exports.GermanyCapitalGainsServiceImpl = GermanyCapitalGainsServiceImpl;
65
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiR2VybWFueUNhcGl0YWxHYWluc1NlcnZpY2VJbXBsLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2NhcGl0YWwtZ2FpbnMvZ2VybWFueS9HZXJtYW55Q2FwaXRhbEdhaW5zU2VydmljZUltcGwudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBSUEsTUFBYSw4QkFBOEI7SUFJdkMsWUFBWSxLQUFZLEVBQUUsS0FBWTtRQUNsQyxJQUFJLENBQUMsTUFBTSxHQUFHLEtBQUssQ0FBQztRQUNwQixJQUFJLENBQUMsTUFBTSxHQUFHLEtBQUssQ0FBQztJQUN4QixDQUFDO0lBRUQsU0FBUztRQUNMLE1BQU0sSUFBSSxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsV0FBVyxDQUFDO1FBRXJDLElBQUksSUFBSSxJQUFJLENBQUMsRUFBRSxDQUFDO1lBQ1osT0FBTztnQkFDSCxXQUFXLEVBQUUsQ0FBQztnQkFDZCxlQUFlLEVBQUUsQ0FBQztnQkFDbEIsbUJBQW1CLEVBQUUsQ0FBQztnQkFDdEIsUUFBUSxFQUFFLENBQUM7Z0JBQ1gsYUFBYSxFQUFFLENBQUM7Z0JBQ2hCLFVBQVUsRUFBRSxFQUFFO2FBQ2pCLENBQUM7UUFDTixDQUFDO1FBRUQsTUFBTSxXQUFXLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsSUFBSSxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsZUFBZSxDQUFDLENBQUM7UUFFcEUsSUFBSSxXQUFXLElBQUksQ0FBQyxFQUFFLENBQUM7WUFDbkIsT0FBTztnQkFDSCxXQUFXLEVBQUUsQ0FBQztnQkFDZCxlQUFlLEVBQUUsQ0FBQztnQkFDbEIsbUJBQW1CLEVBQUUsQ0FBQztnQkFDdEIsUUFBUSxFQUFFLENBQUM7Z0JBQ1gsYUFBYSxFQUFFLENBQUM7Z0JBQ2hCLFVBQVUsRUFBRSxDQUFDO3dCQUNULElBQUksRUFBRSxHQUFHO3dCQUNULEVBQUUsRUFBRSxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsZUFBZSxFQUFFO3dCQUNwQyxJQUFJLEVBQUUsQ0FBQzt3QkFDUCxNQUFNLEVBQUUsQ0FBQztxQkFDWixDQUFDO2FBQ0wsQ0FBQztRQUNOLENBQUM7UUFFRCxNQUFNLGVBQWUsR0FBRyxXQUFXLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxXQUFXLENBQUM7UUFDOUQsTUFBTSxtQkFBbUIsR0FBRyxlQUFlLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyx1QkFBdUIsQ0FBQztRQUNsRixNQUFNLFFBQVEsR0FBRyxlQUFlLEdBQUcsbUJBQW1CLENBQUM7UUFFdkQsTUFBTSxVQUFVLEdBQWdCO1lBQzVCO2dCQUNJLElBQUksRUFBRSxHQUFHO2dCQUNULEVBQUUsRUFBRSxLQUFLO2dCQUNULElBQUksRUFBRSxJQUFJLENBQUMsTUFBTSxDQUFDLFdBQVc7Z0JBQzdCLE1BQU0sRUFBRSxlQUFlO2FBQzFCO1lBQ0Q7Z0JBQ0ksSUFBSSxFQUFFLEtBQUs7Z0JBQ1gsRUFBRSxFQUFFLFlBQVk7Z0JBQ2hCLElBQUksRUFBRSxJQUFJLENBQUMsTUFBTSxDQUFDLHVCQUF1QjtnQkFDekMsTUFBTSxFQUFFLG1CQUFtQjthQUM5QjtTQUNKLENBQUM7UUFFRixPQUFPO1lBQ0gsV0FBVztZQUNYLGVBQWU7WUFDZixtQkFBbUI7WUFDbkIsUUFBUTtZQUNSLGFBQWEsRUFBRSxJQUFJLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLFFBQVEsR0FBRyxJQUFJLENBQUMsR0FBRyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDckQsVUFBVTtTQUNiLENBQUM7SUFDTixDQUFDO0NBQ0o7QUFyRUQsd0VBcUVDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQnJlYWtkb3duIH0gZnJvbSBcIi4uL2RvbWFpbi90eXBlc1wiO1xuaW1wb3J0IHsgR2VybWFueUNhcGl0YWxHYWluc1NlcnZpY2UgfSBmcm9tIFwiLi9HZXJtYW55Q2FwaXRhbEdhaW5zU2VydmljZVwiO1xuaW1wb3J0IHsgSW5wdXQsIFJlc3VsdCwgUnVsZXMgfSBmcm9tIFwiLi9kb21haW4vdHlwZXNcIjtcblxuZXhwb3J0IGNsYXNzIEdlcm1hbnlDYXBpdGFsR2FpbnNTZXJ2aWNlSW1wbCBpbXBsZW1lbnRzIEdlcm1hbnlDYXBpdGFsR2FpbnNTZXJ2aWNlIHtcbiAgICBwcml2YXRlIF9pbnB1dDogSW5wdXQ7XG4gICAgcHJpdmF0ZSBfcnVsZXM6IFJ1bGVzO1xuXG4gICAgY29uc3RydWN0b3IoaW5wdXQ6IElucHV0LCBydWxlczogUnVsZXMpIHtcbiAgICAgICAgdGhpcy5faW5wdXQgPSBpbnB1dDtcbiAgICAgICAgdGhpcy5fcnVsZXMgPSBydWxlcztcbiAgICB9XG5cbiAgICBjYWxjdWxhdGUoKTogUmVzdWx0IHtcbiAgICAgICAgY29uc3QgZ2FpbiA9IHRoaXMuX2lucHV0LmNhcGl0YWxHYWluO1xuXG4gICAgICAgIGlmIChnYWluIDw9IDApIHtcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgdGF4YWJsZUdhaW46IDAsXG4gICAgICAgICAgICAgICAgY2FwaXRhbEdhaW5zVGF4OiAwLFxuICAgICAgICAgICAgICAgIHNvbGlkYXJpdHlTdXJjaGFyZ2U6IDAsXG4gICAgICAgICAgICAgICAgdG90YWxUYXg6IDAsXG4gICAgICAgICAgICAgICAgZWZmZWN0aXZlUmF0ZTogMCxcbiAgICAgICAgICAgICAgICBicmVha2Rvd25zOiBbXSxcbiAgICAgICAgICAgIH07XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCB0YXhhYmxlR2FpbiA9IE1hdGgubWF4KDAsIGdhaW4gLSB0aGlzLl9ydWxlcy5hbm51YWxFeGVtcHRpb24pO1xuXG4gICAgICAgIGlmICh0YXhhYmxlR2FpbiA8PSAwKSB7XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgIHRheGFibGVHYWluOiAwLFxuICAgICAgICAgICAgICAgIGNhcGl0YWxHYWluc1RheDogMCxcbiAgICAgICAgICAgICAgICBzb2xpZGFyaXR5U3VyY2hhcmdlOiAwLFxuICAgICAgICAgICAgICAgIHRvdGFsVGF4OiAwLFxuICAgICAgICAgICAgICAgIGVmZmVjdGl2ZVJhdGU6IDAsXG4gICAgICAgICAgICAgICAgYnJlYWtkb3duczogW3tcbiAgICAgICAgICAgICAgICAgICAgZnJvbTogJzAnLFxuICAgICAgICAgICAgICAgICAgICB0bzogYCR7dGhpcy5fcnVsZXMuYW5udWFsRXhlbXB0aW9ufWAsXG4gICAgICAgICAgICAgICAgICAgIHJhdGU6IDAsXG4gICAgICAgICAgICAgICAgICAgIGFtb3VudDogMCxcbiAgICAgICAgICAgICAgICB9XSxcbiAgICAgICAgICAgIH07XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBjYXBpdGFsR2FpbnNUYXggPSB0YXhhYmxlR2FpbiAqIHRoaXMuX3J1bGVzLmZsYXRUYXhSYXRlO1xuICAgICAgICBjb25zdCBzb2xpZGFyaXR5U3VyY2hhcmdlID0gY2FwaXRhbEdhaW5zVGF4ICogdGhpcy5fcnVsZXMuc29saWRhcml0eVN1cmNoYXJnZVJhdGU7XG4gICAgICAgIGNvbnN0IHRvdGFsVGF4ID0gY2FwaXRhbEdhaW5zVGF4ICsgc29saWRhcml0eVN1cmNoYXJnZTtcblxuICAgICAgICBjb25zdCBicmVha2Rvd25zOiBCcmVha2Rvd25bXSA9IFtcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBmcm9tOiAnMCcsXG4gICAgICAgICAgICAgICAgdG86ICdBbGwnLFxuICAgICAgICAgICAgICAgIHJhdGU6IHRoaXMuX3J1bGVzLmZsYXRUYXhSYXRlLFxuICAgICAgICAgICAgICAgIGFtb3VudDogY2FwaXRhbEdhaW5zVGF4LFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBmcm9tOiAnQ0dUJyxcbiAgICAgICAgICAgICAgICB0bzogJ1NvbGlkYXJpdHknLFxuICAgICAgICAgICAgICAgIHJhdGU6IHRoaXMuX3J1bGVzLnNvbGlkYXJpdHlTdXJjaGFyZ2VSYXRlLFxuICAgICAgICAgICAgICAgIGFtb3VudDogc29saWRhcml0eVN1cmNoYXJnZSxcbiAgICAgICAgICAgIH0sXG4gICAgICAgIF07XG5cbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHRheGFibGVHYWluLFxuICAgICAgICAgICAgY2FwaXRhbEdhaW5zVGF4LFxuICAgICAgICAgICAgc29saWRhcml0eVN1cmNoYXJnZSxcbiAgICAgICAgICAgIHRvdGFsVGF4LFxuICAgICAgICAgICAgZWZmZWN0aXZlUmF0ZTogZ2FpbiA+IDAgPyAodG90YWxUYXggLyBnYWluKSAqIDEwMCA6IDAsXG4gICAgICAgICAgICBicmVha2Rvd25zLFxuICAgICAgICB9O1xuICAgIH1cbn1cbiJdfQ==
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvY2FwaXRhbC1nYWlucy9nZXJtYW55L2RvbWFpbi90eXBlcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQnJlYWtkb3duIH0gZnJvbSBcIi4uLy4uL2RvbWFpbi90eXBlc1wiO1xuXG5leHBvcnQgaW50ZXJmYWNlIFJ1bGVzIHtcbiAgICBmbGF0VGF4UmF0ZTogbnVtYmVyO1xuICAgIHNvbGlkYXJpdHlTdXJjaGFyZ2VSYXRlOiBudW1iZXI7XG4gICAgYW5udWFsRXhlbXB0aW9uOiBudW1iZXI7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgSW5wdXQge1xuICAgIGNhcGl0YWxHYWluOiBudW1iZXI7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgUmVzdWx0IHtcbiAgICB0YXhhYmxlR2FpbjogbnVtYmVyO1xuICAgIGNhcGl0YWxHYWluc1RheDogbnVtYmVyO1xuICAgIHNvbGlkYXJpdHlTdXJjaGFyZ2U6IG51bWJlcjtcbiAgICB0b3RhbFRheDogbnVtYmVyO1xuICAgIGVmZmVjdGl2ZVJhdGU6IG51bWJlcjtcbiAgICBicmVha2Rvd25zOiBCcmVha2Rvd25bXTtcbn1cbiJdfQ==
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU291dGhBZnJpY2FDYXBpdGFsR2FpbnNTZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2NhcGl0YWwtZ2FpbnMvc291dGgtYWZyaWNhL1NvdXRoQWZyaWNhQ2FwaXRhbEdhaW5zU2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgUmVzdWx0IH0gZnJvbSBcIi4vZG9tYWluL3R5cGVzXCI7XG5cbmV4cG9ydCBpbnRlcmZhY2UgU291dGhBZnJpY2FDYXBpdGFsR2FpbnNTZXJ2aWNlIHtcbiAgICBjYWxjdWxhdGUoKTogUmVzdWx0O1xufVxuIl19
@@ -0,0 +1,69 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SouthAfricaCapitalGainsServiceImpl = void 0;
4
+ class SouthAfricaCapitalGainsServiceImpl {
5
+ constructor(input, rules) {
6
+ this._input = input;
7
+ this._rules = rules;
8
+ }
9
+ calculate() {
10
+ const gain = this._input.capitalGain;
11
+ if (gain <= 0) {
12
+ return { taxableGain: 0, capitalGainsTax: 0, effectiveRate: 0, breakdowns: [] };
13
+ }
14
+ const netGain = Math.max(0, gain - this._rules.annualExclusion);
15
+ const taxableGain = netGain * this._rules.inclusionRate;
16
+ if (taxableGain <= 0) {
17
+ return {
18
+ taxableGain: 0,
19
+ capitalGainsTax: 0,
20
+ effectiveRate: 0,
21
+ breakdowns: [{
22
+ from: '0',
23
+ to: `${this._rules.annualExclusion}`,
24
+ rate: 0,
25
+ amount: 0,
26
+ }],
27
+ };
28
+ }
29
+ const otherIncome = this._input.totalTaxableIncome - gain;
30
+ const { tax, breakdowns } = this.applyBrackets(taxableGain, otherIncome, this._rules.taxBrackets);
31
+ return {
32
+ taxableGain,
33
+ capitalGainsTax: tax,
34
+ effectiveRate: gain > 0 ? (tax / gain) * 100 : 0,
35
+ breakdowns,
36
+ };
37
+ }
38
+ applyBrackets(taxableGain, otherIncome, brackets) {
39
+ let tax = 0;
40
+ const breakdowns = [];
41
+ let remaining = taxableGain;
42
+ let incomeUsed = otherIncome;
43
+ for (const bracket of brackets) {
44
+ if (remaining <= 0)
45
+ break;
46
+ const upper = bracket.to ?? Infinity;
47
+ if (incomeUsed >= upper)
48
+ continue;
49
+ const bracketStart = Math.max(bracket.from, incomeUsed);
50
+ const bracketSpace = upper - bracketStart;
51
+ const taxable = Math.min(bracketSpace, remaining);
52
+ if (taxable > 0) {
53
+ const bracketTax = taxable * bracket.rate;
54
+ tax += bracketTax;
55
+ remaining -= taxable;
56
+ incomeUsed += taxable;
57
+ breakdowns.push({
58
+ from: `${bracket.from}`,
59
+ to: `${bracket.to ?? 'Above'}`,
60
+ rate: bracket.rate,
61
+ amount: bracketTax,
62
+ });
63
+ }
64
+ }
65
+ return { tax, breakdowns };
66
+ }
67
+ }
68
+ exports.SouthAfricaCapitalGainsServiceImpl = SouthAfricaCapitalGainsServiceImpl;
69
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU291dGhBZnJpY2FDYXBpdGFsR2FpbnNTZXJ2aWNlSW1wbC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9jYXBpdGFsLWdhaW5zL3NvdXRoLWFmcmljYS9Tb3V0aEFmcmljYUNhcGl0YWxHYWluc1NlcnZpY2VJbXBsLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUlBLE1BQWEsa0NBQWtDO0lBSTNDLFlBQVksS0FBWSxFQUFFLEtBQVk7UUFDbEMsSUFBSSxDQUFDLE1BQU0sR0FBRyxLQUFLLENBQUM7UUFDcEIsSUFBSSxDQUFDLE1BQU0sR0FBRyxLQUFLLENBQUM7SUFDeEIsQ0FBQztJQUVELFNBQVM7UUFDTCxNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLFdBQVcsQ0FBQztRQUVyQyxJQUFJLElBQUksSUFBSSxDQUFDLEVBQUUsQ0FBQztZQUNaLE9BQU8sRUFBRSxXQUFXLEVBQUUsQ0FBQyxFQUFFLGVBQWUsRUFBRSxDQUFDLEVBQUUsYUFBYSxFQUFFLENBQUMsRUFBRSxVQUFVLEVBQUUsRUFBRSxFQUFFLENBQUM7UUFDcEYsQ0FBQztRQUVELE1BQU0sT0FBTyxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLElBQUksR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLGVBQWUsQ0FBQyxDQUFDO1FBQ2hFLE1BQU0sV0FBVyxHQUFHLE9BQU8sR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLGFBQWEsQ0FBQztRQUV4RCxJQUFJLFdBQVcsSUFBSSxDQUFDLEVBQUUsQ0FBQztZQUNuQixPQUFPO2dCQUNILFdBQVcsRUFBRSxDQUFDO2dCQUNkLGVBQWUsRUFBRSxDQUFDO2dCQUNsQixhQUFhLEVBQUUsQ0FBQztnQkFDaEIsVUFBVSxFQUFFLENBQUM7d0JBQ1QsSUFBSSxFQUFFLEdBQUc7d0JBQ1QsRUFBRSxFQUFFLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxlQUFlLEVBQUU7d0JBQ3BDLElBQUksRUFBRSxDQUFDO3dCQUNQLE1BQU0sRUFBRSxDQUFDO3FCQUNaLENBQUM7YUFDTCxDQUFDO1FBQ04sQ0FBQztRQUVELE1BQU0sV0FBVyxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsa0JBQWtCLEdBQUcsSUFBSSxDQUFDO1FBQzFELE1BQU0sRUFBRSxHQUFHLEVBQUUsVUFBVSxFQUFFLEdBQUcsSUFBSSxDQUFDLGFBQWEsQ0FBQyxXQUFXLEVBQUUsV0FBVyxFQUFFLElBQUksQ0FBQyxNQUFNLENBQUMsV0FBVyxDQUFDLENBQUM7UUFFbEcsT0FBTztZQUNILFdBQVc7WUFDWCxlQUFlLEVBQUUsR0FBRztZQUNwQixhQUFhLEVBQUUsSUFBSSxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLEdBQUcsSUFBSSxDQUFDLEdBQUcsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQ2hELFVBQVU7U0FDYixDQUFDO0lBQ04sQ0FBQztJQUVPLGFBQWEsQ0FDakIsV0FBbUIsRUFDbkIsV0FBbUIsRUFDbkIsUUFBc0I7UUFFdEIsSUFBSSxHQUFHLEdBQUcsQ0FBQyxDQUFDO1FBQ1osTUFBTSxVQUFVLEdBQWdCLEVBQUUsQ0FBQztRQUNuQyxJQUFJLFNBQVMsR0FBRyxXQUFXLENBQUM7UUFDNUIsSUFBSSxVQUFVLEdBQUcsV0FBVyxDQUFDO1FBRTdCLEtBQUssTUFBTSxPQUFPLElBQUksUUFBUSxFQUFFLENBQUM7WUFDN0IsSUFBSSxTQUFTLElBQUksQ0FBQztnQkFBRSxNQUFNO1lBRTFCLE1BQU0sS0FBSyxHQUFHLE9BQU8sQ0FBQyxFQUFFLElBQUksUUFBUSxDQUFDO1lBRXJDLElBQUksVUFBVSxJQUFJLEtBQUs7Z0JBQUUsU0FBUztZQUVsQyxNQUFNLFlBQVksR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxJQUFJLEVBQUUsVUFBVSxDQUFDLENBQUM7WUFDeEQsTUFBTSxZQUFZLEdBQUcsS0FBSyxHQUFHLFlBQVksQ0FBQztZQUMxQyxNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLFlBQVksRUFBRSxTQUFTLENBQUMsQ0FBQztZQUVsRCxJQUFJLE9BQU8sR0FBRyxDQUFDLEVBQUUsQ0FBQztnQkFDZCxNQUFNLFVBQVUsR0FBRyxPQUFPLEdBQUcsT0FBTyxDQUFDLElBQUksQ0FBQztnQkFDMUMsR0FBRyxJQUFJLFVBQVUsQ0FBQztnQkFDbEIsU0FBUyxJQUFJLE9BQU8sQ0FBQztnQkFDckIsVUFBVSxJQUFJLE9BQU8sQ0FBQztnQkFFdEIsVUFBVSxDQUFDLElBQUksQ0FBQztvQkFDWixJQUFJLEVBQUUsR0FBRyxPQUFPLENBQUMsSUFBSSxFQUFFO29CQUN2QixFQUFFLEVBQUUsR0FBRyxPQUFPLENBQUMsRUFBRSxJQUFJLE9BQU8sRUFBRTtvQkFDOUIsSUFBSSxFQUFFLE9BQU8sQ0FBQyxJQUFJO29CQUNsQixNQUFNLEVBQUUsVUFBVTtpQkFDckIsQ0FBQyxDQUFDO1lBQ1AsQ0FBQztRQUNMLENBQUM7UUFFRCxPQUFPLEVBQUUsR0FBRyxFQUFFLFVBQVUsRUFBRSxDQUFDO0lBQy9CLENBQUM7Q0FDSjtBQWxGRCxnRkFrRkMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBCcmVha2Rvd24gfSBmcm9tIFwiLi4vZG9tYWluL3R5cGVzXCI7XG5pbXBvcnQgeyBTb3V0aEFmcmljYUNhcGl0YWxHYWluc1NlcnZpY2UgfSBmcm9tIFwiLi9Tb3V0aEFmcmljYUNhcGl0YWxHYWluc1NlcnZpY2VcIjtcbmltcG9ydCB7IElucHV0LCBSZXN1bHQsIFJ1bGVzLCBUYXhCcmFja2V0IH0gZnJvbSBcIi4vZG9tYWluL3R5cGVzXCI7XG5cbmV4cG9ydCBjbGFzcyBTb3V0aEFmcmljYUNhcGl0YWxHYWluc1NlcnZpY2VJbXBsIGltcGxlbWVudHMgU291dGhBZnJpY2FDYXBpdGFsR2FpbnNTZXJ2aWNlIHtcbiAgICBwcml2YXRlIF9pbnB1dDogSW5wdXQ7XG4gICAgcHJpdmF0ZSBfcnVsZXM6IFJ1bGVzO1xuXG4gICAgY29uc3RydWN0b3IoaW5wdXQ6IElucHV0LCBydWxlczogUnVsZXMpIHtcbiAgICAgICAgdGhpcy5faW5wdXQgPSBpbnB1dDtcbiAgICAgICAgdGhpcy5fcnVsZXMgPSBydWxlcztcbiAgICB9XG5cbiAgICBjYWxjdWxhdGUoKTogUmVzdWx0IHtcbiAgICAgICAgY29uc3QgZ2FpbiA9IHRoaXMuX2lucHV0LmNhcGl0YWxHYWluO1xuXG4gICAgICAgIGlmIChnYWluIDw9IDApIHtcbiAgICAgICAgICAgIHJldHVybiB7IHRheGFibGVHYWluOiAwLCBjYXBpdGFsR2FpbnNUYXg6IDAsIGVmZmVjdGl2ZVJhdGU6IDAsIGJyZWFrZG93bnM6IFtdIH07XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBuZXRHYWluID0gTWF0aC5tYXgoMCwgZ2FpbiAtIHRoaXMuX3J1bGVzLmFubnVhbEV4Y2x1c2lvbik7XG4gICAgICAgIGNvbnN0IHRheGFibGVHYWluID0gbmV0R2FpbiAqIHRoaXMuX3J1bGVzLmluY2x1c2lvblJhdGU7XG5cbiAgICAgICAgaWYgKHRheGFibGVHYWluIDw9IDApIHtcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgdGF4YWJsZUdhaW46IDAsXG4gICAgICAgICAgICAgICAgY2FwaXRhbEdhaW5zVGF4OiAwLFxuICAgICAgICAgICAgICAgIGVmZmVjdGl2ZVJhdGU6IDAsXG4gICAgICAgICAgICAgICAgYnJlYWtkb3duczogW3tcbiAgICAgICAgICAgICAgICAgICAgZnJvbTogJzAnLFxuICAgICAgICAgICAgICAgICAgICB0bzogYCR7dGhpcy5fcnVsZXMuYW5udWFsRXhjbHVzaW9ufWAsXG4gICAgICAgICAgICAgICAgICAgIHJhdGU6IDAsXG4gICAgICAgICAgICAgICAgICAgIGFtb3VudDogMCxcbiAgICAgICAgICAgICAgICB9XSxcbiAgICAgICAgICAgIH07XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBvdGhlckluY29tZSA9IHRoaXMuX2lucHV0LnRvdGFsVGF4YWJsZUluY29tZSAtIGdhaW47XG4gICAgICAgIGNvbnN0IHsgdGF4LCBicmVha2Rvd25zIH0gPSB0aGlzLmFwcGx5QnJhY2tldHModGF4YWJsZUdhaW4sIG90aGVySW5jb21lLCB0aGlzLl9ydWxlcy50YXhCcmFja2V0cyk7XG5cbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHRheGFibGVHYWluLFxuICAgICAgICAgICAgY2FwaXRhbEdhaW5zVGF4OiB0YXgsXG4gICAgICAgICAgICBlZmZlY3RpdmVSYXRlOiBnYWluID4gMCA/ICh0YXggLyBnYWluKSAqIDEwMCA6IDAsXG4gICAgICAgICAgICBicmVha2Rvd25zLFxuICAgICAgICB9O1xuICAgIH1cblxuICAgIHByaXZhdGUgYXBwbHlCcmFja2V0cyhcbiAgICAgICAgdGF4YWJsZUdhaW46IG51bWJlcixcbiAgICAgICAgb3RoZXJJbmNvbWU6IG51bWJlcixcbiAgICAgICAgYnJhY2tldHM6IFRheEJyYWNrZXRbXSxcbiAgICApOiB7IHRheDogbnVtYmVyOyBicmVha2Rvd25zOiBCcmVha2Rvd25bXSB9IHtcbiAgICAgICAgbGV0IHRheCA9IDA7XG4gICAgICAgIGNvbnN0IGJyZWFrZG93bnM6IEJyZWFrZG93bltdID0gW107XG4gICAgICAgIGxldCByZW1haW5pbmcgPSB0YXhhYmxlR2FpbjtcbiAgICAgICAgbGV0IGluY29tZVVzZWQgPSBvdGhlckluY29tZTtcblxuICAgICAgICBmb3IgKGNvbnN0IGJyYWNrZXQgb2YgYnJhY2tldHMpIHtcbiAgICAgICAgICAgIGlmIChyZW1haW5pbmcgPD0gMCkgYnJlYWs7XG5cbiAgICAgICAgICAgIGNvbnN0IHVwcGVyID0gYnJhY2tldC50byA/PyBJbmZpbml0eTtcblxuICAgICAgICAgICAgaWYgKGluY29tZVVzZWQgPj0gdXBwZXIpIGNvbnRpbnVlO1xuXG4gICAgICAgICAgICBjb25zdCBicmFja2V0U3RhcnQgPSBNYXRoLm1heChicmFja2V0LmZyb20sIGluY29tZVVzZWQpO1xuICAgICAgICAgICAgY29uc3QgYnJhY2tldFNwYWNlID0gdXBwZXIgLSBicmFja2V0U3RhcnQ7XG4gICAgICAgICAgICBjb25zdCB0YXhhYmxlID0gTWF0aC5taW4oYnJhY2tldFNwYWNlLCByZW1haW5pbmcpO1xuXG4gICAgICAgICAgICBpZiAodGF4YWJsZSA+IDApIHtcbiAgICAgICAgICAgICAgICBjb25zdCBicmFja2V0VGF4ID0gdGF4YWJsZSAqIGJyYWNrZXQucmF0ZTtcbiAgICAgICAgICAgICAgICB0YXggKz0gYnJhY2tldFRheDtcbiAgICAgICAgICAgICAgICByZW1haW5pbmcgLT0gdGF4YWJsZTtcbiAgICAgICAgICAgICAgICBpbmNvbWVVc2VkICs9IHRheGFibGU7XG5cbiAgICAgICAgICAgICAgICBicmVha2Rvd25zLnB1c2goe1xuICAgICAgICAgICAgICAgICAgICBmcm9tOiBgJHticmFja2V0LmZyb219YCxcbiAgICAgICAgICAgICAgICAgICAgdG86IGAke2JyYWNrZXQudG8gPz8gJ0Fib3ZlJ31gLFxuICAgICAgICAgICAgICAgICAgICByYXRlOiBicmFja2V0LnJhdGUsXG4gICAgICAgICAgICAgICAgICAgIGFtb3VudDogYnJhY2tldFRheCxcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB7IHRheCwgYnJlYWtkb3ducyB9O1xuICAgIH1cbn1cbiJdfQ==
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvY2FwaXRhbC1nYWlucy9zb3V0aC1hZnJpY2EvZG9tYWluL3R5cGVzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiIiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBCcmVha2Rvd24gfSBmcm9tIFwiLi4vLi4vZG9tYWluL3R5cGVzXCI7XG5cbmV4cG9ydCBpbnRlcmZhY2UgVGF4QnJhY2tldCB7XG4gICAgZnJvbTogbnVtYmVyO1xuICAgIHRvOiBudW1iZXIgfCBudWxsO1xuICAgIHJhdGU6IG51bWJlcjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBSdWxlcyB7XG4gICAgaW5jbHVzaW9uUmF0ZTogbnVtYmVyO1xuICAgIGFubnVhbEV4Y2x1c2lvbjogbnVtYmVyO1xuICAgIHRheEJyYWNrZXRzOiBUYXhCcmFja2V0W107XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgSW5wdXQge1xuICAgIGNhcGl0YWxHYWluOiBudW1iZXI7XG4gICAgdG90YWxUYXhhYmxlSW5jb21lOiBudW1iZXI7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgUmVzdWx0IHtcbiAgICB0YXhhYmxlR2FpbjogbnVtYmVyO1xuICAgIGNhcGl0YWxHYWluc1RheDogbnVtYmVyO1xuICAgIGVmZmVjdGl2ZVJhdGU6IG51bWJlcjtcbiAgICBicmVha2Rvd25zOiBCcmVha2Rvd25bXTtcbn1cbiJdfQ==
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiVUtDYXBpdGFsR2FpbnNTZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2NhcGl0YWwtZ2FpbnMvdWsvVUtDYXBpdGFsR2FpbnNTZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiIiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBSZXN1bHQgfSBmcm9tIFwiLi9kb21haW4vdHlwZXNcIjtcblxuZXhwb3J0IGludGVyZmFjZSBVS0NhcGl0YWxHYWluc1NlcnZpY2Uge1xuICAgIGNhbGN1bGF0ZSgpOiBSZXN1bHQ7XG59XG4iXX0=
@@ -0,0 +1,72 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.UKCapitalGainsServiceImpl = void 0;
4
+ class UKCapitalGainsServiceImpl {
5
+ constructor(input, rules) {
6
+ this._input = input;
7
+ this._rules = rules;
8
+ }
9
+ calculate() {
10
+ const gain = this._input.capitalGain;
11
+ if (gain <= 0) {
12
+ return { taxableGain: 0, capitalGainsTax: 0, effectiveRate: 0, breakdowns: [] };
13
+ }
14
+ const taxableGain = Math.max(0, gain - this._rules.annualExemption);
15
+ if (taxableGain <= 0) {
16
+ return {
17
+ taxableGain: 0,
18
+ capitalGainsTax: 0,
19
+ effectiveRate: 0,
20
+ breakdowns: [{
21
+ from: '0',
22
+ to: `${this._rules.annualExemption}`,
23
+ rate: 0,
24
+ amount: 0,
25
+ }],
26
+ };
27
+ }
28
+ const basicRateRemaining = Math.max(0, this._rules.basicRateLimit - this._input.totalTaxableIncome);
29
+ const breakdowns = [];
30
+ let tax = 0;
31
+ if (basicRateRemaining > 0) {
32
+ const basicRateGain = Math.min(taxableGain, basicRateRemaining);
33
+ const basicTax = basicRateGain * this._rules.basicRate;
34
+ tax += basicTax;
35
+ breakdowns.push({
36
+ from: '0',
37
+ to: `${basicRateRemaining}`,
38
+ rate: this._rules.basicRate,
39
+ amount: basicTax,
40
+ });
41
+ const higherRateGain = taxableGain - basicRateGain;
42
+ if (higherRateGain > 0) {
43
+ const higherTax = higherRateGain * this._rules.higherRate;
44
+ tax += higherTax;
45
+ breakdowns.push({
46
+ from: `${basicRateRemaining}`,
47
+ to: 'Above',
48
+ rate: this._rules.higherRate,
49
+ amount: higherTax,
50
+ });
51
+ }
52
+ }
53
+ else {
54
+ const higherTax = taxableGain * this._rules.higherRate;
55
+ tax += higherTax;
56
+ breakdowns.push({
57
+ from: '0',
58
+ to: 'Above',
59
+ rate: this._rules.higherRate,
60
+ amount: higherTax,
61
+ });
62
+ }
63
+ return {
64
+ taxableGain,
65
+ capitalGainsTax: tax,
66
+ effectiveRate: gain > 0 ? (tax / gain) * 100 : 0,
67
+ breakdowns,
68
+ };
69
+ }
70
+ }
71
+ exports.UKCapitalGainsServiceImpl = UKCapitalGainsServiceImpl;
72
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiVUtDYXBpdGFsR2FpbnNTZXJ2aWNlSW1wbC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9jYXBpdGFsLWdhaW5zL3VrL1VLQ2FwaXRhbEdhaW5zU2VydmljZUltcGwudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBSUEsTUFBYSx5QkFBeUI7SUFJbEMsWUFBWSxLQUFZLEVBQUUsS0FBWTtRQUNsQyxJQUFJLENBQUMsTUFBTSxHQUFHLEtBQUssQ0FBQztRQUNwQixJQUFJLENBQUMsTUFBTSxHQUFHLEtBQUssQ0FBQztJQUN4QixDQUFDO0lBRUQsU0FBUztRQUNMLE1BQU0sSUFBSSxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsV0FBVyxDQUFDO1FBRXJDLElBQUksSUFBSSxJQUFJLENBQUMsRUFBRSxDQUFDO1lBQ1osT0FBTyxFQUFFLFdBQVcsRUFBRSxDQUFDLEVBQUUsZUFBZSxFQUFFLENBQUMsRUFBRSxhQUFhLEVBQUUsQ0FBQyxFQUFFLFVBQVUsRUFBRSxFQUFFLEVBQUUsQ0FBQztRQUNwRixDQUFDO1FBRUQsTUFBTSxXQUFXLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsSUFBSSxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsZUFBZSxDQUFDLENBQUM7UUFFcEUsSUFBSSxXQUFXLElBQUksQ0FBQyxFQUFFLENBQUM7WUFDbkIsT0FBTztnQkFDSCxXQUFXLEVBQUUsQ0FBQztnQkFDZCxlQUFlLEVBQUUsQ0FBQztnQkFDbEIsYUFBYSxFQUFFLENBQUM7Z0JBQ2hCLFVBQVUsRUFBRSxDQUFDO3dCQUNULElBQUksRUFBRSxHQUFHO3dCQUNULEVBQUUsRUFBRSxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsZUFBZSxFQUFFO3dCQUNwQyxJQUFJLEVBQUUsQ0FBQzt3QkFDUCxNQUFNLEVBQUUsQ0FBQztxQkFDWixDQUFDO2FBQ0wsQ0FBQztRQUNOLENBQUM7UUFFRCxNQUFNLGtCQUFrQixHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLElBQUksQ0FBQyxNQUFNLENBQUMsY0FBYyxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsa0JBQWtCLENBQUMsQ0FBQztRQUNwRyxNQUFNLFVBQVUsR0FBZ0IsRUFBRSxDQUFDO1FBQ25DLElBQUksR0FBRyxHQUFHLENBQUMsQ0FBQztRQUVaLElBQUksa0JBQWtCLEdBQUcsQ0FBQyxFQUFFLENBQUM7WUFDekIsTUFBTSxhQUFhLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxXQUFXLEVBQUUsa0JBQWtCLENBQUMsQ0FBQztZQUNoRSxNQUFNLFFBQVEsR0FBRyxhQUFhLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxTQUFTLENBQUM7WUFDdkQsR0FBRyxJQUFJLFFBQVEsQ0FBQztZQUVoQixVQUFVLENBQUMsSUFBSSxDQUFDO2dCQUNaLElBQUksRUFBRSxHQUFHO2dCQUNULEVBQUUsRUFBRSxHQUFHLGtCQUFrQixFQUFFO2dCQUMzQixJQUFJLEVBQUUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxTQUFTO2dCQUMzQixNQUFNLEVBQUUsUUFBUTthQUNuQixDQUFDLENBQUM7WUFFSCxNQUFNLGNBQWMsR0FBRyxXQUFXLEdBQUcsYUFBYSxDQUFDO1lBQ25ELElBQUksY0FBYyxHQUFHLENBQUMsRUFBRSxDQUFDO2dCQUNyQixNQUFNLFNBQVMsR0FBRyxjQUFjLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxVQUFVLENBQUM7Z0JBQzFELEdBQUcsSUFBSSxTQUFTLENBQUM7Z0JBRWpCLFVBQVUsQ0FBQyxJQUFJLENBQUM7b0JBQ1osSUFBSSxFQUFFLEdBQUcsa0JBQWtCLEVBQUU7b0JBQzdCLEVBQUUsRUFBRSxPQUFPO29CQUNYLElBQUksRUFBRSxJQUFJLENBQUMsTUFBTSxDQUFDLFVBQVU7b0JBQzVCLE1BQU0sRUFBRSxTQUFTO2lCQUNwQixDQUFDLENBQUM7WUFDUCxDQUFDO1FBQ0wsQ0FBQzthQUFNLENBQUM7WUFDSixNQUFNLFNBQVMsR0FBRyxXQUFXLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxVQUFVLENBQUM7WUFDdkQsR0FBRyxJQUFJLFNBQVMsQ0FBQztZQUVqQixVQUFVLENBQUMsSUFBSSxDQUFDO2dCQUNaLElBQUksRUFBRSxHQUFHO2dCQUNULEVBQUUsRUFBRSxPQUFPO2dCQUNYLElBQUksRUFBRSxJQUFJLENBQUMsTUFBTSxDQUFDLFVBQVU7Z0JBQzVCLE1BQU0sRUFBRSxTQUFTO2FBQ3BCLENBQUMsQ0FBQztRQUNQLENBQUM7UUFFRCxPQUFPO1lBQ0gsV0FBVztZQUNYLGVBQWUsRUFBRSxHQUFHO1lBQ3BCLGFBQWEsRUFBRSxJQUFJLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsR0FBRyxJQUFJLENBQUMsR0FBRyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDaEQsVUFBVTtTQUNiLENBQUM7SUFDTixDQUFDO0NBQ0o7QUEvRUQsOERBK0VDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQnJlYWtkb3duIH0gZnJvbSBcIi4uL2RvbWFpbi90eXBlc1wiO1xuaW1wb3J0IHsgVUtDYXBpdGFsR2FpbnNTZXJ2aWNlIH0gZnJvbSBcIi4vVUtDYXBpdGFsR2FpbnNTZXJ2aWNlXCI7XG5pbXBvcnQgeyBJbnB1dCwgUmVzdWx0LCBSdWxlcyB9IGZyb20gXCIuL2RvbWFpbi90eXBlc1wiO1xuXG5leHBvcnQgY2xhc3MgVUtDYXBpdGFsR2FpbnNTZXJ2aWNlSW1wbCBpbXBsZW1lbnRzIFVLQ2FwaXRhbEdhaW5zU2VydmljZSB7XG4gICAgcHJpdmF0ZSBfaW5wdXQ6IElucHV0O1xuICAgIHByaXZhdGUgX3J1bGVzOiBSdWxlcztcblxuICAgIGNvbnN0cnVjdG9yKGlucHV0OiBJbnB1dCwgcnVsZXM6IFJ1bGVzKSB7XG4gICAgICAgIHRoaXMuX2lucHV0ID0gaW5wdXQ7XG4gICAgICAgIHRoaXMuX3J1bGVzID0gcnVsZXM7XG4gICAgfVxuXG4gICAgY2FsY3VsYXRlKCk6IFJlc3VsdCB7XG4gICAgICAgIGNvbnN0IGdhaW4gPSB0aGlzLl9pbnB1dC5jYXBpdGFsR2FpbjtcblxuICAgICAgICBpZiAoZ2FpbiA8PSAwKSB7XG4gICAgICAgICAgICByZXR1cm4geyB0YXhhYmxlR2FpbjogMCwgY2FwaXRhbEdhaW5zVGF4OiAwLCBlZmZlY3RpdmVSYXRlOiAwLCBicmVha2Rvd25zOiBbXSB9O1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgdGF4YWJsZUdhaW4gPSBNYXRoLm1heCgwLCBnYWluIC0gdGhpcy5fcnVsZXMuYW5udWFsRXhlbXB0aW9uKTtcblxuICAgICAgICBpZiAodGF4YWJsZUdhaW4gPD0gMCkge1xuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICB0YXhhYmxlR2FpbjogMCxcbiAgICAgICAgICAgICAgICBjYXBpdGFsR2FpbnNUYXg6IDAsXG4gICAgICAgICAgICAgICAgZWZmZWN0aXZlUmF0ZTogMCxcbiAgICAgICAgICAgICAgICBicmVha2Rvd25zOiBbe1xuICAgICAgICAgICAgICAgICAgICBmcm9tOiAnMCcsXG4gICAgICAgICAgICAgICAgICAgIHRvOiBgJHt0aGlzLl9ydWxlcy5hbm51YWxFeGVtcHRpb259YCxcbiAgICAgICAgICAgICAgICAgICAgcmF0ZTogMCxcbiAgICAgICAgICAgICAgICAgICAgYW1vdW50OiAwLFxuICAgICAgICAgICAgICAgIH1dLFxuICAgICAgICAgICAgfTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGJhc2ljUmF0ZVJlbWFpbmluZyA9IE1hdGgubWF4KDAsIHRoaXMuX3J1bGVzLmJhc2ljUmF0ZUxpbWl0IC0gdGhpcy5faW5wdXQudG90YWxUYXhhYmxlSW5jb21lKTtcbiAgICAgICAgY29uc3QgYnJlYWtkb3duczogQnJlYWtkb3duW10gPSBbXTtcbiAgICAgICAgbGV0IHRheCA9IDA7XG5cbiAgICAgICAgaWYgKGJhc2ljUmF0ZVJlbWFpbmluZyA+IDApIHtcbiAgICAgICAgICAgIGNvbnN0IGJhc2ljUmF0ZUdhaW4gPSBNYXRoLm1pbih0YXhhYmxlR2FpbiwgYmFzaWNSYXRlUmVtYWluaW5nKTtcbiAgICAgICAgICAgIGNvbnN0IGJhc2ljVGF4ID0gYmFzaWNSYXRlR2FpbiAqIHRoaXMuX3J1bGVzLmJhc2ljUmF0ZTtcbiAgICAgICAgICAgIHRheCArPSBiYXNpY1RheDtcblxuICAgICAgICAgICAgYnJlYWtkb3ducy5wdXNoKHtcbiAgICAgICAgICAgICAgICBmcm9tOiAnMCcsXG4gICAgICAgICAgICAgICAgdG86IGAke2Jhc2ljUmF0ZVJlbWFpbmluZ31gLFxuICAgICAgICAgICAgICAgIHJhdGU6IHRoaXMuX3J1bGVzLmJhc2ljUmF0ZSxcbiAgICAgICAgICAgICAgICBhbW91bnQ6IGJhc2ljVGF4LFxuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIGNvbnN0IGhpZ2hlclJhdGVHYWluID0gdGF4YWJsZUdhaW4gLSBiYXNpY1JhdGVHYWluO1xuICAgICAgICAgICAgaWYgKGhpZ2hlclJhdGVHYWluID4gMCkge1xuICAgICAgICAgICAgICAgIGNvbnN0IGhpZ2hlclRheCA9IGhpZ2hlclJhdGVHYWluICogdGhpcy5fcnVsZXMuaGlnaGVyUmF0ZTtcbiAgICAgICAgICAgICAgICB0YXggKz0gaGlnaGVyVGF4O1xuXG4gICAgICAgICAgICAgICAgYnJlYWtkb3ducy5wdXNoKHtcbiAgICAgICAgICAgICAgICAgICAgZnJvbTogYCR7YmFzaWNSYXRlUmVtYWluaW5nfWAsXG4gICAgICAgICAgICAgICAgICAgIHRvOiAnQWJvdmUnLFxuICAgICAgICAgICAgICAgICAgICByYXRlOiB0aGlzLl9ydWxlcy5oaWdoZXJSYXRlLFxuICAgICAgICAgICAgICAgICAgICBhbW91bnQ6IGhpZ2hlclRheCxcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGNvbnN0IGhpZ2hlclRheCA9IHRheGFibGVHYWluICogdGhpcy5fcnVsZXMuaGlnaGVyUmF0ZTtcbiAgICAgICAgICAgIHRheCArPSBoaWdoZXJUYXg7XG5cbiAgICAgICAgICAgIGJyZWFrZG93bnMucHVzaCh7XG4gICAgICAgICAgICAgICAgZnJvbTogJzAnLFxuICAgICAgICAgICAgICAgIHRvOiAnQWJvdmUnLFxuICAgICAgICAgICAgICAgIHJhdGU6IHRoaXMuX3J1bGVzLmhpZ2hlclJhdGUsXG4gICAgICAgICAgICAgICAgYW1vdW50OiBoaWdoZXJUYXgsXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICB0YXhhYmxlR2FpbixcbiAgICAgICAgICAgIGNhcGl0YWxHYWluc1RheDogdGF4LFxuICAgICAgICAgICAgZWZmZWN0aXZlUmF0ZTogZ2FpbiA+IDAgPyAodGF4IC8gZ2FpbikgKiAxMDAgOiAwLFxuICAgICAgICAgICAgYnJlYWtkb3ducyxcbiAgICAgICAgfTtcbiAgICB9XG59XG4iXX0=
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvY2FwaXRhbC1nYWlucy91ay9kb21haW4vdHlwZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEJyZWFrZG93biB9IGZyb20gXCIuLi8uLi9kb21haW4vdHlwZXNcIjtcblxuZXhwb3J0IGludGVyZmFjZSBSdWxlcyB7XG4gICAgYW5udWFsRXhlbXB0aW9uOiBudW1iZXI7XG4gICAgYmFzaWNSYXRlOiBudW1iZXI7XG4gICAgaGlnaGVyUmF0ZTogbnVtYmVyO1xuICAgIGJhc2ljUmF0ZUxpbWl0OiBudW1iZXI7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgSW5wdXQge1xuICAgIGNhcGl0YWxHYWluOiBudW1iZXI7XG4gICAgdG90YWxUYXhhYmxlSW5jb21lOiBudW1iZXI7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgUmVzdWx0IHtcbiAgICB0YXhhYmxlR2FpbjogbnVtYmVyO1xuICAgIGNhcGl0YWxHYWluc1RheDogbnVtYmVyO1xuICAgIGVmZmVjdGl2ZVJhdGU6IG51bWJlcjtcbiAgICBicmVha2Rvd25zOiBCcmVha2Rvd25bXTtcbn1cbiJdfQ==
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiVVNBQ2FwaXRhbEdhaW5zU2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9jYXBpdGFsLWdhaW5zL3VzYS9VU0FDYXBpdGFsR2FpbnNTZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiIiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBSZXN1bHQgfSBmcm9tIFwiLi9kb21haW4vdHlwZXNcIjtcblxuZXhwb3J0IGludGVyZmFjZSBVU0FDYXBpdGFsR2FpbnNTZXJ2aWNlIHtcbiAgICBjYWxjdWxhdGUoKTogUmVzdWx0O1xufVxuIl19
@@ -0,0 +1,67 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.USACapitalGainsServiceImpl = void 0;
4
+ class USACapitalGainsServiceImpl {
5
+ constructor(input, rules) {
6
+ this._input = input;
7
+ this._rules = rules;
8
+ }
9
+ calculate() {
10
+ const gain = this._input.capitalGain;
11
+ if (gain <= 0) {
12
+ return { capitalGainsTax: 0, netInvestmentIncomeTax: 0, totalTax: 0, effectiveRate: 0, breakdowns: [] };
13
+ }
14
+ const isLongTerm = this._input.holdingPeriodMonths > 12;
15
+ const brackets = isLongTerm ? this._rules.longTermBrackets : this._rules.shortTermBrackets;
16
+ const { tax, breakdowns } = this.applyBrackets(gain, this._input.totalTaxableIncome, brackets);
17
+ let niit = 0;
18
+ if (this._input.totalTaxableIncome > this._rules.netInvestmentIncomeTax.threshold) {
19
+ niit = gain * this._rules.netInvestmentIncomeTax.rate;
20
+ breakdowns.push({
21
+ from: 'NIIT',
22
+ to: 'All Gain',
23
+ rate: this._rules.netInvestmentIncomeTax.rate,
24
+ amount: niit,
25
+ });
26
+ }
27
+ const totalTax = tax + niit;
28
+ return {
29
+ capitalGainsTax: tax,
30
+ netInvestmentIncomeTax: niit,
31
+ totalTax,
32
+ effectiveRate: gain > 0 ? (totalTax / gain) * 100 : 0,
33
+ breakdowns,
34
+ };
35
+ }
36
+ applyBrackets(gain, totalIncome, brackets) {
37
+ let tax = 0;
38
+ const breakdowns = [];
39
+ let remaining = gain;
40
+ let incomeUsed = totalIncome - gain;
41
+ for (const bracket of brackets) {
42
+ if (remaining <= 0)
43
+ break;
44
+ const upper = bracket.to ?? Infinity;
45
+ if (incomeUsed >= upper)
46
+ continue;
47
+ const bracketStart = Math.max(bracket.from, incomeUsed);
48
+ const bracketSpace = upper - bracketStart;
49
+ const taxable = Math.min(bracketSpace, remaining);
50
+ if (taxable > 0) {
51
+ const bracketTax = taxable * bracket.rate;
52
+ tax += bracketTax;
53
+ remaining -= taxable;
54
+ incomeUsed += taxable;
55
+ breakdowns.push({
56
+ from: `${bracket.from}`,
57
+ to: `${bracket.to ?? 'Above'}`,
58
+ rate: bracket.rate,
59
+ amount: bracketTax,
60
+ });
61
+ }
62
+ }
63
+ return { tax, breakdowns };
64
+ }
65
+ }
66
+ exports.USACapitalGainsServiceImpl = USACapitalGainsServiceImpl;
67
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiVVNBQ2FwaXRhbEdhaW5zU2VydmljZUltcGwuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvY2FwaXRhbC1nYWlucy91c2EvVVNBQ2FwaXRhbEdhaW5zU2VydmljZUltcGwudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBSUEsTUFBYSwwQkFBMEI7SUFJbkMsWUFBWSxLQUFZLEVBQUUsS0FBWTtRQUNsQyxJQUFJLENBQUMsTUFBTSxHQUFHLEtBQUssQ0FBQztRQUNwQixJQUFJLENBQUMsTUFBTSxHQUFHLEtBQUssQ0FBQztJQUN4QixDQUFDO0lBRUQsU0FBUztRQUNMLE1BQU0sSUFBSSxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsV0FBVyxDQUFDO1FBRXJDLElBQUksSUFBSSxJQUFJLENBQUMsRUFBRSxDQUFDO1lBQ1osT0FBTyxFQUFFLGVBQWUsRUFBRSxDQUFDLEVBQUUsc0JBQXNCLEVBQUUsQ0FBQyxFQUFFLFFBQVEsRUFBRSxDQUFDLEVBQUUsYUFBYSxFQUFFLENBQUMsRUFBRSxVQUFVLEVBQUUsRUFBRSxFQUFFLENBQUM7UUFDNUcsQ0FBQztRQUVELE1BQU0sVUFBVSxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsbUJBQW1CLEdBQUcsRUFBRSxDQUFDO1FBQ3hELE1BQU0sUUFBUSxHQUFHLFVBQVUsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxpQkFBaUIsQ0FBQztRQUUzRixNQUFNLEVBQUUsR0FBRyxFQUFFLFVBQVUsRUFBRSxHQUFHLElBQUksQ0FBQyxhQUFhLENBQUMsSUFBSSxFQUFFLElBQUksQ0FBQyxNQUFNLENBQUMsa0JBQWtCLEVBQUUsUUFBUSxDQUFDLENBQUM7UUFFL0YsSUFBSSxJQUFJLEdBQUcsQ0FBQyxDQUFDO1FBQ2IsSUFBSSxJQUFJLENBQUMsTUFBTSxDQUFDLGtCQUFrQixHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsc0JBQXNCLENBQUMsU0FBUyxFQUFFLENBQUM7WUFDaEYsSUFBSSxHQUFHLElBQUksR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLHNCQUFzQixDQUFDLElBQUksQ0FBQztZQUN0RCxVQUFVLENBQUMsSUFBSSxDQUFDO2dCQUNaLElBQUksRUFBRSxNQUFNO2dCQUNaLEVBQUUsRUFBRSxVQUFVO2dCQUNkLElBQUksRUFBRSxJQUFJLENBQUMsTUFBTSxDQUFDLHNCQUFzQixDQUFDLElBQUk7Z0JBQzdDLE1BQU0sRUFBRSxJQUFJO2FBQ2YsQ0FBQyxDQUFDO1FBQ1AsQ0FBQztRQUVELE1BQU0sUUFBUSxHQUFHLEdBQUcsR0FBRyxJQUFJLENBQUM7UUFFNUIsT0FBTztZQUNILGVBQWUsRUFBRSxHQUFHO1lBQ3BCLHNCQUFzQixFQUFFLElBQUk7WUFDNUIsUUFBUTtZQUNSLGFBQWEsRUFBRSxJQUFJLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLFFBQVEsR0FBRyxJQUFJLENBQUMsR0FBRyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDckQsVUFBVTtTQUNiLENBQUM7SUFDTixDQUFDO0lBRU8sYUFBYSxDQUNqQixJQUFZLEVBQ1osV0FBbUIsRUFDbkIsUUFBMkI7UUFFM0IsSUFBSSxHQUFHLEdBQUcsQ0FBQyxDQUFDO1FBQ1osTUFBTSxVQUFVLEdBQWdCLEVBQUUsQ0FBQztRQUNuQyxJQUFJLFNBQVMsR0FBRyxJQUFJLENBQUM7UUFDckIsSUFBSSxVQUFVLEdBQUcsV0FBVyxHQUFHLElBQUksQ0FBQztRQUVwQyxLQUFLLE1BQU0sT0FBTyxJQUFJLFFBQVEsRUFBRSxDQUFDO1lBQzdCLElBQUksU0FBUyxJQUFJLENBQUM7Z0JBQUUsTUFBTTtZQUUxQixNQUFNLEtBQUssR0FBRyxPQUFPLENBQUMsRUFBRSxJQUFJLFFBQVEsQ0FBQztZQUVyQyxJQUFJLFVBQVUsSUFBSSxLQUFLO2dCQUFFLFNBQVM7WUFFbEMsTUFBTSxZQUFZLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsSUFBSSxFQUFFLFVBQVUsQ0FBQyxDQUFDO1lBQ3hELE1BQU0sWUFBWSxHQUFHLEtBQUssR0FBRyxZQUFZLENBQUM7WUFDMUMsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxZQUFZLEVBQUUsU0FBUyxDQUFDLENBQUM7WUFFbEQsSUFBSSxPQUFPLEdBQUcsQ0FBQyxFQUFFLENBQUM7Z0JBQ2QsTUFBTSxVQUFVLEdBQUcsT0FBTyxHQUFHLE9BQU8sQ0FBQyxJQUFJLENBQUM7Z0JBQzFDLEdBQUcsSUFBSSxVQUFVLENBQUM7Z0JBQ2xCLFNBQVMsSUFBSSxPQUFPLENBQUM7Z0JBQ3JCLFVBQVUsSUFBSSxPQUFPLENBQUM7Z0JBRXRCLFVBQVUsQ0FBQyxJQUFJLENBQUM7b0JBQ1osSUFBSSxFQUFFLEdBQUcsT0FBTyxDQUFDLElBQUksRUFBRTtvQkFDdkIsRUFBRSxFQUFFLEdBQUcsT0FBTyxDQUFDLEVBQUUsSUFBSSxPQUFPLEVBQUU7b0JBQzlCLElBQUksRUFBRSxPQUFPLENBQUMsSUFBSTtvQkFDbEIsTUFBTSxFQUFFLFVBQVU7aUJBQ3JCLENBQUMsQ0FBQztZQUNQLENBQUM7UUFDTCxDQUFDO1FBRUQsT0FBTyxFQUFFLEdBQUcsRUFBRSxVQUFVLEVBQUUsQ0FBQztJQUMvQixDQUFDO0NBQ0o7QUFqRkQsZ0VBaUZDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQnJlYWtkb3duIH0gZnJvbSBcIi4uL2RvbWFpbi90eXBlc1wiO1xuaW1wb3J0IHsgVVNBQ2FwaXRhbEdhaW5zU2VydmljZSB9IGZyb20gXCIuL1VTQUNhcGl0YWxHYWluc1NlcnZpY2VcIjtcbmltcG9ydCB7IElucHV0LCBMb25nVGVybUJyYWNrZXQsIFJlc3VsdCwgUnVsZXMgfSBmcm9tIFwiLi9kb21haW4vdHlwZXNcIjtcblxuZXhwb3J0IGNsYXNzIFVTQUNhcGl0YWxHYWluc1NlcnZpY2VJbXBsIGltcGxlbWVudHMgVVNBQ2FwaXRhbEdhaW5zU2VydmljZSB7XG4gICAgcHJpdmF0ZSBfaW5wdXQ6IElucHV0O1xuICAgIHByaXZhdGUgX3J1bGVzOiBSdWxlcztcblxuICAgIGNvbnN0cnVjdG9yKGlucHV0OiBJbnB1dCwgcnVsZXM6IFJ1bGVzKSB7XG4gICAgICAgIHRoaXMuX2lucHV0ID0gaW5wdXQ7XG4gICAgICAgIHRoaXMuX3J1bGVzID0gcnVsZXM7XG4gICAgfVxuXG4gICAgY2FsY3VsYXRlKCk6IFJlc3VsdCB7XG4gICAgICAgIGNvbnN0IGdhaW4gPSB0aGlzLl9pbnB1dC5jYXBpdGFsR2FpbjtcblxuICAgICAgICBpZiAoZ2FpbiA8PSAwKSB7XG4gICAgICAgICAgICByZXR1cm4geyBjYXBpdGFsR2FpbnNUYXg6IDAsIG5ldEludmVzdG1lbnRJbmNvbWVUYXg6IDAsIHRvdGFsVGF4OiAwLCBlZmZlY3RpdmVSYXRlOiAwLCBicmVha2Rvd25zOiBbXSB9O1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgaXNMb25nVGVybSA9IHRoaXMuX2lucHV0LmhvbGRpbmdQZXJpb2RNb250aHMgPiAxMjtcbiAgICAgICAgY29uc3QgYnJhY2tldHMgPSBpc0xvbmdUZXJtID8gdGhpcy5fcnVsZXMubG9uZ1Rlcm1CcmFja2V0cyA6IHRoaXMuX3J1bGVzLnNob3J0VGVybUJyYWNrZXRzO1xuXG4gICAgICAgIGNvbnN0IHsgdGF4LCBicmVha2Rvd25zIH0gPSB0aGlzLmFwcGx5QnJhY2tldHMoZ2FpbiwgdGhpcy5faW5wdXQudG90YWxUYXhhYmxlSW5jb21lLCBicmFja2V0cyk7XG5cbiAgICAgICAgbGV0IG5paXQgPSAwO1xuICAgICAgICBpZiAodGhpcy5faW5wdXQudG90YWxUYXhhYmxlSW5jb21lID4gdGhpcy5fcnVsZXMubmV0SW52ZXN0bWVudEluY29tZVRheC50aHJlc2hvbGQpIHtcbiAgICAgICAgICAgIG5paXQgPSBnYWluICogdGhpcy5fcnVsZXMubmV0SW52ZXN0bWVudEluY29tZVRheC5yYXRlO1xuICAgICAgICAgICAgYnJlYWtkb3ducy5wdXNoKHtcbiAgICAgICAgICAgICAgICBmcm9tOiAnTklJVCcsXG4gICAgICAgICAgICAgICAgdG86ICdBbGwgR2FpbicsXG4gICAgICAgICAgICAgICAgcmF0ZTogdGhpcy5fcnVsZXMubmV0SW52ZXN0bWVudEluY29tZVRheC5yYXRlLFxuICAgICAgICAgICAgICAgIGFtb3VudDogbmlpdCxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgdG90YWxUYXggPSB0YXggKyBuaWl0O1xuXG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBjYXBpdGFsR2FpbnNUYXg6IHRheCxcbiAgICAgICAgICAgIG5ldEludmVzdG1lbnRJbmNvbWVUYXg6IG5paXQsXG4gICAgICAgICAgICB0b3RhbFRheCxcbiAgICAgICAgICAgIGVmZmVjdGl2ZVJhdGU6IGdhaW4gPiAwID8gKHRvdGFsVGF4IC8gZ2FpbikgKiAxMDAgOiAwLFxuICAgICAgICAgICAgYnJlYWtkb3ducyxcbiAgICAgICAgfTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGFwcGx5QnJhY2tldHMoXG4gICAgICAgIGdhaW46IG51bWJlcixcbiAgICAgICAgdG90YWxJbmNvbWU6IG51bWJlcixcbiAgICAgICAgYnJhY2tldHM6IExvbmdUZXJtQnJhY2tldFtdLFxuICAgICk6IHsgdGF4OiBudW1iZXI7IGJyZWFrZG93bnM6IEJyZWFrZG93bltdIH0ge1xuICAgICAgICBsZXQgdGF4ID0gMDtcbiAgICAgICAgY29uc3QgYnJlYWtkb3duczogQnJlYWtkb3duW10gPSBbXTtcbiAgICAgICAgbGV0IHJlbWFpbmluZyA9IGdhaW47XG4gICAgICAgIGxldCBpbmNvbWVVc2VkID0gdG90YWxJbmNvbWUgLSBnYWluO1xuXG4gICAgICAgIGZvciAoY29uc3QgYnJhY2tldCBvZiBicmFja2V0cykge1xuICAgICAgICAgICAgaWYgKHJlbWFpbmluZyA8PSAwKSBicmVhaztcblxuICAgICAgICAgICAgY29uc3QgdXBwZXIgPSBicmFja2V0LnRvID8/IEluZmluaXR5O1xuXG4gICAgICAgICAgICBpZiAoaW5jb21lVXNlZCA+PSB1cHBlcikgY29udGludWU7XG5cbiAgICAgICAgICAgIGNvbnN0IGJyYWNrZXRTdGFydCA9IE1hdGgubWF4KGJyYWNrZXQuZnJvbSwgaW5jb21lVXNlZCk7XG4gICAgICAgICAgICBjb25zdCBicmFja2V0U3BhY2UgPSB1cHBlciAtIGJyYWNrZXRTdGFydDtcbiAgICAgICAgICAgIGNvbnN0IHRheGFibGUgPSBNYXRoLm1pbihicmFja2V0U3BhY2UsIHJlbWFpbmluZyk7XG5cbiAgICAgICAgICAgIGlmICh0YXhhYmxlID4gMCkge1xuICAgICAgICAgICAgICAgIGNvbnN0IGJyYWNrZXRUYXggPSB0YXhhYmxlICogYnJhY2tldC5yYXRlO1xuICAgICAgICAgICAgICAgIHRheCArPSBicmFja2V0VGF4O1xuICAgICAgICAgICAgICAgIHJlbWFpbmluZyAtPSB0YXhhYmxlO1xuICAgICAgICAgICAgICAgIGluY29tZVVzZWQgKz0gdGF4YWJsZTtcblxuICAgICAgICAgICAgICAgIGJyZWFrZG93bnMucHVzaCh7XG4gICAgICAgICAgICAgICAgICAgIGZyb206IGAke2JyYWNrZXQuZnJvbX1gLFxuICAgICAgICAgICAgICAgICAgICB0bzogYCR7YnJhY2tldC50byA/PyAnQWJvdmUnfWAsXG4gICAgICAgICAgICAgICAgICAgIHJhdGU6IGJyYWNrZXQucmF0ZSxcbiAgICAgICAgICAgICAgICAgICAgYW1vdW50OiBicmFja2V0VGF4LFxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHsgdGF4LCBicmVha2Rvd25zIH07XG4gICAgfVxufVxuIl19
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvY2FwaXRhbC1nYWlucy91c2EvZG9tYWluL3R5cGVzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiIiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBCcmVha2Rvd24gfSBmcm9tIFwiLi4vLi4vZG9tYWluL3R5cGVzXCI7XG5cbmV4cG9ydCBpbnRlcmZhY2UgTG9uZ1Rlcm1CcmFja2V0IHtcbiAgICBmcm9tOiBudW1iZXI7XG4gICAgdG86IG51bWJlciB8IG51bGw7XG4gICAgcmF0ZTogbnVtYmVyO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFJ1bGVzIHtcbiAgICBsb25nVGVybUJyYWNrZXRzOiBMb25nVGVybUJyYWNrZXRbXTtcbiAgICBzaG9ydFRlcm1CcmFja2V0czogTG9uZ1Rlcm1CcmFja2V0W107XG4gICAgbmV0SW52ZXN0bWVudEluY29tZVRheDogeyByYXRlOiBudW1iZXI7IHRocmVzaG9sZDogbnVtYmVyIH07XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgSW5wdXQge1xuICAgIGNhcGl0YWxHYWluOiBudW1iZXI7XG4gICAgdG90YWxUYXhhYmxlSW5jb21lOiBudW1iZXI7XG4gICAgaG9sZGluZ1BlcmlvZE1vbnRoczogbnVtYmVyO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFJlc3VsdCB7XG4gICAgY2FwaXRhbEdhaW5zVGF4OiBudW1iZXI7XG4gICAgbmV0SW52ZXN0bWVudEluY29tZVRheDogbnVtYmVyO1xuICAgIHRvdGFsVGF4OiBudW1iZXI7XG4gICAgZWZmZWN0aXZlUmF0ZTogbnVtYmVyO1xuICAgIGJyZWFrZG93bnM6IEJyZWFrZG93bltdO1xufVxuIl19
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiR2VybWFueUNvcnBvcmF0ZVRheFNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvY29ycG9yYXRlL2dlcm1hbnkvR2VybWFueUNvcnBvcmF0ZVRheFNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IFJlc3VsdCB9IGZyb20gXCIuL2RvbWFpbi90eXBlc1wiO1xuXG5leHBvcnQgaW50ZXJmYWNlIEdlcm1hbnlDb3Jwb3JhdGVUYXhTZXJ2aWNlIHtcbiAgICBjYWxjdWxhdGUoKTogUmVzdWx0O1xufVxuIl19