@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.
Files changed (98) hide show
  1. package/dist/capital-gains/australia/AustraliaCapitalGainsService.js +3 -0
  2. package/dist/capital-gains/australia/AustraliaCapitalGainsServiceImpl.js +67 -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 +66 -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 +51 -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 +68 -0
  13. package/dist/capital-gains/germany/domain/types.js +3 -0
  14. package/dist/capital-gains/index.js +25 -0
  15. package/dist/capital-gains/south-africa/SouthAfricaCapitalGainsService.js +3 -0
  16. package/dist/capital-gains/south-africa/SouthAfricaCapitalGainsServiceImpl.js +83 -0
  17. package/dist/capital-gains/south-africa/domain/types.js +3 -0
  18. package/dist/capital-gains/uk/UKCapitalGainsService.js +3 -0
  19. package/dist/capital-gains/uk/UKCapitalGainsServiceImpl.js +86 -0
  20. package/dist/capital-gains/uk/domain/types.js +3 -0
  21. package/dist/capital-gains/usa/USACapitalGainsService.js +3 -0
  22. package/dist/capital-gains/usa/USACapitalGainsServiceImpl.js +77 -0
  23. package/dist/capital-gains/usa/domain/types.js +3 -0
  24. package/dist/corporate/index.js +18 -0
  25. package/dist/income-tax/index.js +24 -0
  26. package/dist/index.js +18 -51
  27. package/dist/mortgage/france/FranceMortgageService.js +1 -1
  28. package/dist/mortgage/france/FranceMortgageServiceImpl.js +1 -1
  29. package/dist/mortgage/index.js +25 -0
  30. package/dist/shared/domain/types.js +2 -1
  31. package/dist/types/capital-gains/australia/AustraliaCapitalGainsService.d.ts +4 -0
  32. package/dist/types/capital-gains/australia/AustraliaCapitalGainsServiceImpl.d.ts +10 -0
  33. package/dist/types/capital-gains/australia/domain/types.d.ts +15 -0
  34. package/dist/types/capital-gains/canada/CanadaCapitalGainsService.d.ts +4 -0
  35. package/dist/types/capital-gains/canada/CanadaCapitalGainsServiceImpl.d.ts +10 -0
  36. package/dist/types/capital-gains/canada/domain/types.d.ts +13 -0
  37. package/dist/types/capital-gains/domain/types.d.ts +15 -0
  38. package/dist/types/capital-gains/france/FranceCapitalGainsService.d.ts +4 -0
  39. package/dist/types/capital-gains/france/FranceCapitalGainsServiceImpl.d.ts +9 -0
  40. package/dist/types/capital-gains/france/domain/types.d.ts +7 -0
  41. package/dist/types/capital-gains/germany/GermanyCapitalGainsService.d.ts +4 -0
  42. package/dist/types/capital-gains/germany/GermanyCapitalGainsServiceImpl.d.ts +9 -0
  43. package/dist/types/capital-gains/germany/domain/types.d.ts +8 -0
  44. package/dist/types/capital-gains/index.d.ts +15 -0
  45. package/dist/types/capital-gains/south-africa/SouthAfricaCapitalGainsService.d.ts +4 -0
  46. package/dist/types/capital-gains/south-africa/SouthAfricaCapitalGainsServiceImpl.d.ts +10 -0
  47. package/dist/types/capital-gains/south-africa/domain/types.d.ts +14 -0
  48. package/dist/types/capital-gains/uk/UKCapitalGainsService.d.ts +4 -0
  49. package/dist/types/capital-gains/uk/UKCapitalGainsServiceImpl.d.ts +9 -0
  50. package/dist/types/capital-gains/uk/domain/types.d.ts +10 -0
  51. package/dist/types/capital-gains/usa/USACapitalGainsService.d.ts +4 -0
  52. package/dist/types/capital-gains/usa/USACapitalGainsServiceImpl.d.ts +10 -0
  53. package/dist/types/capital-gains/usa/domain/types.d.ts +26 -0
  54. package/dist/types/corporate/index.d.ts +15 -0
  55. package/dist/types/income-tax/index.d.ts +15 -0
  56. package/dist/types/index.d.ts +4 -42
  57. package/dist/types/mortgage/france/FranceMortgageService.d.ts +1 -1
  58. package/dist/types/mortgage/france/FranceMortgageServiceImpl.d.ts +1 -1
  59. package/dist/types/mortgage/index.d.ts +15 -0
  60. package/dist/types/shared/domain/types.d.ts +2 -1
  61. package/package.json +1 -1
  62. package/src/capital-gains/australia/AustraliaCapitalGainsService.ts +5 -0
  63. package/src/capital-gains/australia/AustraliaCapitalGainsServiceImpl.ts +84 -0
  64. package/src/capital-gains/australia/domain/types.ts +17 -0
  65. package/src/capital-gains/canada/CanadaCapitalGainsService.ts +5 -0
  66. package/src/capital-gains/canada/CanadaCapitalGainsServiceImpl.ts +82 -0
  67. package/src/capital-gains/canada/domain/types.ts +15 -0
  68. package/src/capital-gains/domain/types.ts +15 -0
  69. package/src/capital-gains/france/FranceCapitalGainsService.ts +5 -0
  70. package/src/capital-gains/france/FranceCapitalGainsServiceImpl.ts +58 -0
  71. package/src/capital-gains/france/domain/types.ts +8 -0
  72. package/src/capital-gains/germany/GermanyCapitalGainsService.ts +5 -0
  73. package/src/capital-gains/germany/GermanyCapitalGainsServiceImpl.ts +77 -0
  74. package/src/capital-gains/germany/domain/types.ts +10 -0
  75. package/src/capital-gains/index.ts +72 -0
  76. package/src/capital-gains/south-africa/SouthAfricaCapitalGainsService.ts +5 -0
  77. package/src/capital-gains/south-africa/SouthAfricaCapitalGainsServiceImpl.ts +101 -0
  78. package/src/capital-gains/south-africa/domain/types.ts +16 -0
  79. package/src/capital-gains/uk/UKCapitalGainsService.ts +5 -0
  80. package/src/capital-gains/uk/UKCapitalGainsServiceImpl.ts +98 -0
  81. package/src/capital-gains/uk/domain/types.ts +11 -0
  82. package/src/capital-gains/usa/USACapitalGainsService.ts +5 -0
  83. package/src/capital-gains/usa/USACapitalGainsServiceImpl.ts +96 -0
  84. package/src/capital-gains/usa/domain/types.ts +27 -0
  85. package/src/corporate/index.ts +79 -0
  86. package/src/income-tax/index.ts +72 -0
  87. package/src/index.ts +6 -146
  88. package/src/mortgage/france/FranceMortgageService.ts +1 -1
  89. package/src/mortgage/france/FranceMortgageServiceImpl.ts +1 -1
  90. package/src/mortgage/index.ts +87 -0
  91. package/src/shared/domain/types.ts +1 -0
  92. package/test/australia-capital-gains.test.ts +80 -0
  93. package/test/canada-capital-gains.test.ts +71 -0
  94. package/test/france-capital-gains.test.ts +66 -0
  95. package/test/germany-capital-gains.test.ts +85 -0
  96. package/test/south-africa-capital-gains.test.ts +84 -0
  97. package/test/uk-capital-gains.test.ts +79 -0
  98. package/test/usa-capital-gains.test.ts +88 -0
@@ -0,0 +1,79 @@
1
+ import { UKCapitalGainsServiceImpl } from '../src/capital-gains/uk/UKCapitalGainsServiceImpl';
2
+ import { Input, Rules } from '../src/capital-gains/uk/domain/types';
3
+
4
+ // UK 2024-25 CGT rules (non-residential assets)
5
+ const ukCapitalGainsRules: Rules = {
6
+ annualExemption: 3000,
7
+ basicRate: 0.10,
8
+ higherRate: 0.20,
9
+ basicRateLimit: 37700,
10
+ };
11
+
12
+ describe('UKCapitalGainsServiceImpl', () => {
13
+ it('applies annual exemption', () => {
14
+ const input: Input = { capitalGain: 2000, totalTaxableIncome: 20000 };
15
+ const service = new UKCapitalGainsServiceImpl(input, ukCapitalGainsRules);
16
+ const result = service.calculate();
17
+
18
+ expect(result.taxableGain).toBe(0);
19
+ expect(result.capitalGainTax).toBe(0);
20
+ });
21
+
22
+ it('applies basic rate for basic-rate taxpayer', () => {
23
+ const input: Input = { capitalGain: 13000, totalTaxableIncome: 20000 };
24
+ const service = new UKCapitalGainsServiceImpl(input, ukCapitalGainsRules);
25
+ const result = service.calculate();
26
+
27
+ // Taxable gain = 13000 - 3000 = 10000
28
+ // Basic rate remaining = 37700 - 20000 = 17700 (enough for all)
29
+ expect(result.taxableGain).toBe(10000);
30
+ expect(result.capitalGainTax).toBe(10000 * 0.10);
31
+ });
32
+
33
+ it('applies higher rate for higher-rate taxpayer', () => {
34
+ const input: Input = { capitalGain: 53000, totalTaxableIncome: 50000 };
35
+ const service = new UKCapitalGainsServiceImpl(input, ukCapitalGainsRules);
36
+ const result = service.calculate();
37
+
38
+ // Taxable gain = 53000 - 3000 = 50000, all at higher rate (income > basic rate limit)
39
+ expect(result.taxableGain).toBe(50000);
40
+ expect(result.capitalGainTax).toBe(50000 * 0.20);
41
+ });
42
+
43
+ it('splits between basic and higher rate', () => {
44
+ const input: Input = { capitalGain: 23000, totalTaxableIncome: 30000 };
45
+ const service = new UKCapitalGainsServiceImpl(input, ukCapitalGainsRules);
46
+ const result = service.calculate();
47
+
48
+ // Taxable gain = 23000 - 3000 = 20000
49
+ // Basic rate remaining = 37700 - 30000 = 7700
50
+ // 7700 at 10% = 770, 12300 at 20% = 2460
51
+ expect(result.taxableGain).toBe(20000);
52
+ expect(result.capitalGainTax).toBe(7700 * 0.10 + 12300 * 0.20);
53
+ });
54
+
55
+ it('returns zero for zero gain', () => {
56
+ const input: Input = { capitalGain: 0, totalTaxableIncome: 50000 };
57
+ const service = new UKCapitalGainsServiceImpl(input, ukCapitalGainsRules);
58
+ const result = service.calculate();
59
+
60
+ expect(result.capitalGainTax).toBe(0);
61
+ expect(result.breakdowns).toHaveLength(0);
62
+ });
63
+
64
+ it('returns zero for negative gain', () => {
65
+ const input: Input = { capitalGain: -5000, totalTaxableIncome: 50000 };
66
+ const service = new UKCapitalGainsServiceImpl(input, ukCapitalGainsRules);
67
+ const result = service.calculate();
68
+
69
+ expect(result.capitalGainTax).toBe(0);
70
+ });
71
+
72
+ it('calculates effective rate based on full gain', () => {
73
+ const input: Input = { capitalGain: 53000, totalTaxableIncome: 50000 };
74
+ const service = new UKCapitalGainsServiceImpl(input, ukCapitalGainsRules);
75
+ const result = service.calculate();
76
+
77
+ expect(result.effectiveRate).toBe((result.capitalGainTax / 53000) * 100);
78
+ });
79
+ });
@@ -0,0 +1,88 @@
1
+ import { USACapitalGainsServiceImpl } from '../src/capital-gains/usa/USACapitalGainsServiceImpl';
2
+ import { Input, Rules } from '../src/capital-gains/usa/domain/types';
3
+
4
+ // USA 2024 long-term capital gains brackets (single filer)
5
+ const usaCapitalGainsRules: Rules = {
6
+ longTermBrackets: [
7
+ { from: 0, to: 47025, rate: 0.00 },
8
+ { from: 47025, to: 518900, rate: 0.15 },
9
+ { from: 518900, to: null, rate: 0.20 },
10
+ ],
11
+ shortTermBrackets: [
12
+ { from: 0, to: 11600, rate: 0.10 },
13
+ { from: 11600, to: 47150, rate: 0.12 },
14
+ { from: 47150, to: 100525, rate: 0.22 },
15
+ { from: 100525, to: 191950, rate: 0.24 },
16
+ { from: 191950, to: 243725, rate: 0.32 },
17
+ { from: 243725, to: 609350, rate: 0.35 },
18
+ { from: 609350, to: null, rate: 0.37 },
19
+ ],
20
+ netInvestmentIncomeTax: { rate: 0.038, threshold: 200000 },
21
+ };
22
+
23
+ describe('USACapitalGainsServiceImpl', () => {
24
+ it('applies 0% long-term rate for low income', () => {
25
+ const input: Input = { capitalGain: 30000, totalTaxableIncome: 30000, holdingPeriodMonths: 24 };
26
+ const service = new USACapitalGainsServiceImpl(input, usaCapitalGainsRules);
27
+ const result = service.calculate();
28
+
29
+ expect(result.capitalGainTax).toBe(0);
30
+ expect(result.netInvestmentIncomeTax).toBe(0);
31
+ expect(result.totalTax).toBe(0);
32
+ });
33
+
34
+ it('applies 15% long-term rate for mid income', () => {
35
+ const input: Input = { capitalGain: 50000, totalTaxableIncome: 100000, holdingPeriodMonths: 13 };
36
+ const service = new USACapitalGainsServiceImpl(input, usaCapitalGainsRules);
37
+ const result = service.calculate();
38
+
39
+ // Other income = 50000, gain falls in 50000-100000 range, all at 15%
40
+ expect(result.capitalGainTax).toBe(50000 * 0.15);
41
+ expect(result.netInvestmentIncomeTax).toBe(0);
42
+ });
43
+
44
+ it('applies NIIT for high-income earners', () => {
45
+ const input: Input = { capitalGain: 100000, totalTaxableIncome: 300000, holdingPeriodMonths: 24 };
46
+ const service = new USACapitalGainsServiceImpl(input, usaCapitalGainsRules);
47
+ const result = service.calculate();
48
+
49
+ expect(result.netInvestmentIncomeTax).toBe(100000 * 0.038);
50
+ expect(result.totalTax).toBe(result.capitalGainTax + result.netInvestmentIncomeTax);
51
+ });
52
+
53
+ it('applies short-term rates for gains held <= 12 months', () => {
54
+ const input: Input = { capitalGain: 50000, totalTaxableIncome: 50000, holdingPeriodMonths: 6 };
55
+ const service = new USACapitalGainsServiceImpl(input, usaCapitalGainsRules);
56
+ const result = service.calculate();
57
+
58
+ // Short-term gain taxed as ordinary income from 0-50000
59
+ expect(result.capitalGainTax).toBeGreaterThan(0);
60
+ expect(result.breakdowns.length).toBeGreaterThan(0);
61
+ });
62
+
63
+ it('returns zero for zero gain', () => {
64
+ const input: Input = { capitalGain: 0, totalTaxableIncome: 50000, holdingPeriodMonths: 24 };
65
+ const service = new USACapitalGainsServiceImpl(input, usaCapitalGainsRules);
66
+ const result = service.calculate();
67
+
68
+ expect(result.totalTax).toBe(0);
69
+ expect(result.effectiveRate).toBe(0);
70
+ expect(result.breakdowns).toHaveLength(0);
71
+ });
72
+
73
+ it('returns zero for negative gain', () => {
74
+ const input: Input = { capitalGain: -5000, totalTaxableIncome: 50000, holdingPeriodMonths: 24 };
75
+ const service = new USACapitalGainsServiceImpl(input, usaCapitalGainsRules);
76
+ const result = service.calculate();
77
+
78
+ expect(result.totalTax).toBe(0);
79
+ });
80
+
81
+ it('calculates effective rate correctly', () => {
82
+ const input: Input = { capitalGain: 100000, totalTaxableIncome: 100000, holdingPeriodMonths: 24 };
83
+ const service = new USACapitalGainsServiceImpl(input, usaCapitalGainsRules);
84
+ const result = service.calculate();
85
+
86
+ expect(result.effectiveRate).toBe((result.totalTax / 100000) * 100);
87
+ });
88
+ });