@accounter/server 0.0.8-alpha-20251102200443-d7162b8ce1dfc629b8b454df17dcec9ed005a052 → 0.0.8-alpha-20251102213150-c9d936f545d5351df0dc5326c2623266f1ad1f46

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 (178) hide show
  1. package/CHANGELOG.md +47 -7
  2. package/dist/green-invoice-graphql/src/mesh-artifacts/index.d.ts +1 -1
  3. package/dist/server/src/__generated__/types.d.ts +77 -0
  4. package/dist/server/src/__generated__/types.js.map +1 -1
  5. package/dist/server/src/modules/charges-matcher/__generated__/types.d.ts +68 -0
  6. package/dist/server/src/modules/charges-matcher/__generated__/types.js +7 -0
  7. package/dist/server/src/modules/charges-matcher/__generated__/types.js.map +1 -0
  8. package/dist/server/src/modules/charges-matcher/__tests__/amount-confidence.test.d.ts +1 -0
  9. package/dist/server/src/modules/charges-matcher/__tests__/amount-confidence.test.js +218 -0
  10. package/dist/server/src/modules/charges-matcher/__tests__/amount-confidence.test.js.map +1 -0
  11. package/dist/server/src/modules/charges-matcher/__tests__/auto-match-integration.test.d.ts +1 -0
  12. package/dist/server/src/modules/charges-matcher/__tests__/auto-match-integration.test.js +645 -0
  13. package/dist/server/src/modules/charges-matcher/__tests__/auto-match-integration.test.js.map +1 -0
  14. package/dist/server/src/modules/charges-matcher/__tests__/auto-match.test.d.ts +1 -0
  15. package/dist/server/src/modules/charges-matcher/__tests__/auto-match.test.js +530 -0
  16. package/dist/server/src/modules/charges-matcher/__tests__/auto-match.test.js.map +1 -0
  17. package/dist/server/src/modules/charges-matcher/__tests__/business-confidence.test.d.ts +1 -0
  18. package/dist/server/src/modules/charges-matcher/__tests__/business-confidence.test.js +143 -0
  19. package/dist/server/src/modules/charges-matcher/__tests__/business-confidence.test.js.map +1 -0
  20. package/dist/server/src/modules/charges-matcher/__tests__/candidate-filter.test.d.ts +1 -0
  21. package/dist/server/src/modules/charges-matcher/__tests__/candidate-filter.test.js +186 -0
  22. package/dist/server/src/modules/charges-matcher/__tests__/candidate-filter.test.js.map +1 -0
  23. package/dist/server/src/modules/charges-matcher/__tests__/charge-validator.test.d.ts +1 -0
  24. package/dist/server/src/modules/charges-matcher/__tests__/charge-validator.test.js +301 -0
  25. package/dist/server/src/modules/charges-matcher/__tests__/charge-validator.test.js.map +1 -0
  26. package/dist/server/src/modules/charges-matcher/__tests__/currency-confidence.test.d.ts +1 -0
  27. package/dist/server/src/modules/charges-matcher/__tests__/currency-confidence.test.js +127 -0
  28. package/dist/server/src/modules/charges-matcher/__tests__/currency-confidence.test.js.map +1 -0
  29. package/dist/server/src/modules/charges-matcher/__tests__/date-confidence.test.d.ts +1 -0
  30. package/dist/server/src/modules/charges-matcher/__tests__/date-confidence.test.js +246 -0
  31. package/dist/server/src/modules/charges-matcher/__tests__/date-confidence.test.js.map +1 -0
  32. package/dist/server/src/modules/charges-matcher/__tests__/document-aggregator.test.d.ts +1 -0
  33. package/dist/server/src/modules/charges-matcher/__tests__/document-aggregator.test.js +475 -0
  34. package/dist/server/src/modules/charges-matcher/__tests__/document-aggregator.test.js.map +1 -0
  35. package/dist/server/src/modules/charges-matcher/__tests__/document-amount.test.d.ts +1 -0
  36. package/dist/server/src/modules/charges-matcher/__tests__/document-amount.test.js +287 -0
  37. package/dist/server/src/modules/charges-matcher/__tests__/document-amount.test.js.map +1 -0
  38. package/dist/server/src/modules/charges-matcher/__tests__/document-business.test.d.ts +1 -0
  39. package/dist/server/src/modules/charges-matcher/__tests__/document-business.test.js +151 -0
  40. package/dist/server/src/modules/charges-matcher/__tests__/document-business.test.js.map +1 -0
  41. package/dist/server/src/modules/charges-matcher/__tests__/match-scorer.test.d.ts +1 -0
  42. package/dist/server/src/modules/charges-matcher/__tests__/match-scorer.test.js +550 -0
  43. package/dist/server/src/modules/charges-matcher/__tests__/match-scorer.test.js.map +1 -0
  44. package/dist/server/src/modules/charges-matcher/__tests__/overall-confidence.test.d.ts +1 -0
  45. package/dist/server/src/modules/charges-matcher/__tests__/overall-confidence.test.js +410 -0
  46. package/dist/server/src/modules/charges-matcher/__tests__/overall-confidence.test.js.map +1 -0
  47. package/dist/server/src/modules/charges-matcher/__tests__/single-match-integration.test.d.ts +1 -0
  48. package/dist/server/src/modules/charges-matcher/__tests__/single-match-integration.test.js +504 -0
  49. package/dist/server/src/modules/charges-matcher/__tests__/single-match-integration.test.js.map +1 -0
  50. package/dist/server/src/modules/charges-matcher/__tests__/single-match.test.d.ts +1 -0
  51. package/dist/server/src/modules/charges-matcher/__tests__/single-match.test.js +483 -0
  52. package/dist/server/src/modules/charges-matcher/__tests__/single-match.test.js.map +1 -0
  53. package/dist/server/src/modules/charges-matcher/__tests__/test-helpers.d.ts +46 -0
  54. package/dist/server/src/modules/charges-matcher/__tests__/test-helpers.js +143 -0
  55. package/dist/server/src/modules/charges-matcher/__tests__/test-helpers.js.map +1 -0
  56. package/dist/server/src/modules/charges-matcher/__tests__/test-infrastructure.spec.d.ts +1 -0
  57. package/dist/server/src/modules/charges-matcher/__tests__/test-infrastructure.spec.js +137 -0
  58. package/dist/server/src/modules/charges-matcher/__tests__/test-infrastructure.spec.js.map +1 -0
  59. package/dist/server/src/modules/charges-matcher/__tests__/transaction-aggregator.test.d.ts +1 -0
  60. package/dist/server/src/modules/charges-matcher/__tests__/transaction-aggregator.test.js +415 -0
  61. package/dist/server/src/modules/charges-matcher/__tests__/transaction-aggregator.test.js.map +1 -0
  62. package/dist/server/src/modules/charges-matcher/helpers/amount-confidence.helper.d.ts +7 -0
  63. package/dist/server/src/modules/charges-matcher/helpers/amount-confidence.helper.js +70 -0
  64. package/dist/server/src/modules/charges-matcher/helpers/amount-confidence.helper.js.map +1 -0
  65. package/dist/server/src/modules/charges-matcher/helpers/business-confidence.helper.d.ts +7 -0
  66. package/dist/server/src/modules/charges-matcher/helpers/business-confidence.helper.js +19 -0
  67. package/dist/server/src/modules/charges-matcher/helpers/business-confidence.helper.js.map +1 -0
  68. package/dist/server/src/modules/charges-matcher/helpers/candidate-filter.helper.d.ts +24 -0
  69. package/dist/server/src/modules/charges-matcher/helpers/candidate-filter.helper.js +45 -0
  70. package/dist/server/src/modules/charges-matcher/helpers/candidate-filter.helper.js.map +1 -0
  71. package/dist/server/src/modules/charges-matcher/helpers/charge-validator.helper.d.ts +33 -0
  72. package/dist/server/src/modules/charges-matcher/helpers/charge-validator.helper.js +65 -0
  73. package/dist/server/src/modules/charges-matcher/helpers/charge-validator.helper.js.map +1 -0
  74. package/dist/server/src/modules/charges-matcher/helpers/currency-confidence.helper.d.ts +7 -0
  75. package/dist/server/src/modules/charges-matcher/helpers/currency-confidence.helper.js +18 -0
  76. package/dist/server/src/modules/charges-matcher/helpers/currency-confidence.helper.js.map +1 -0
  77. package/dist/server/src/modules/charges-matcher/helpers/date-confidence.helper.d.ts +7 -0
  78. package/dist/server/src/modules/charges-matcher/helpers/date-confidence.helper.js +35 -0
  79. package/dist/server/src/modules/charges-matcher/helpers/date-confidence.helper.js.map +1 -0
  80. package/dist/server/src/modules/charges-matcher/helpers/document-amount.helper.d.ts +49 -0
  81. package/dist/server/src/modules/charges-matcher/helpers/document-amount.helper.js +58 -0
  82. package/dist/server/src/modules/charges-matcher/helpers/document-amount.helper.js.map +1 -0
  83. package/dist/server/src/modules/charges-matcher/helpers/document-business.helper.d.ts +13 -0
  84. package/dist/server/src/modules/charges-matcher/helpers/document-business.helper.js +37 -0
  85. package/dist/server/src/modules/charges-matcher/helpers/document-business.helper.js.map +1 -0
  86. package/dist/server/src/modules/charges-matcher/helpers/overall-confidence.helper.d.ts +42 -0
  87. package/dist/server/src/modules/charges-matcher/helpers/overall-confidence.helper.js +77 -0
  88. package/dist/server/src/modules/charges-matcher/helpers/overall-confidence.helper.js.map +1 -0
  89. package/dist/server/src/modules/charges-matcher/index.d.ts +3 -0
  90. package/dist/server/src/modules/charges-matcher/index.js +15 -0
  91. package/dist/server/src/modules/charges-matcher/index.js.map +1 -0
  92. package/dist/server/src/modules/charges-matcher/providers/auto-match.provider.d.ts +48 -0
  93. package/dist/server/src/modules/charges-matcher/providers/auto-match.provider.js +133 -0
  94. package/dist/server/src/modules/charges-matcher/providers/auto-match.provider.js.map +1 -0
  95. package/dist/server/src/modules/charges-matcher/providers/charges-matcher.provider.d.ts +38 -0
  96. package/dist/server/src/modules/charges-matcher/providers/charges-matcher.provider.js +248 -0
  97. package/dist/server/src/modules/charges-matcher/providers/charges-matcher.provider.js.map +1 -0
  98. package/dist/server/src/modules/charges-matcher/providers/document-aggregator.d.ts +61 -0
  99. package/dist/server/src/modules/charges-matcher/providers/document-aggregator.js +153 -0
  100. package/dist/server/src/modules/charges-matcher/providers/document-aggregator.js.map +1 -0
  101. package/dist/server/src/modules/charges-matcher/providers/match-scorer.provider.d.ts +25 -0
  102. package/dist/server/src/modules/charges-matcher/providers/match-scorer.provider.js +114 -0
  103. package/dist/server/src/modules/charges-matcher/providers/match-scorer.provider.js.map +1 -0
  104. package/dist/server/src/modules/charges-matcher/providers/single-match.provider.d.ts +39 -0
  105. package/dist/server/src/modules/charges-matcher/providers/single-match.provider.js +189 -0
  106. package/dist/server/src/modules/charges-matcher/providers/single-match.provider.js.map +1 -0
  107. package/dist/server/src/modules/charges-matcher/providers/transaction-aggregator.d.ts +54 -0
  108. package/dist/server/src/modules/charges-matcher/providers/transaction-aggregator.js +93 -0
  109. package/dist/server/src/modules/charges-matcher/providers/transaction-aggregator.js.map +1 -0
  110. package/dist/server/src/modules/charges-matcher/resolvers/auto-match-charges.resolver.d.ts +2 -0
  111. package/dist/server/src/modules/charges-matcher/resolvers/auto-match-charges.resolver.js +22 -0
  112. package/dist/server/src/modules/charges-matcher/resolvers/auto-match-charges.resolver.js.map +1 -0
  113. package/dist/server/src/modules/charges-matcher/resolvers/find-charge-matches.resolver.d.ts +2 -0
  114. package/dist/server/src/modules/charges-matcher/resolvers/find-charge-matches.resolver.js +24 -0
  115. package/dist/server/src/modules/charges-matcher/resolvers/find-charge-matches.resolver.js.map +1 -0
  116. package/dist/server/src/modules/charges-matcher/resolvers/index.d.ts +2 -0
  117. package/dist/server/src/modules/charges-matcher/resolvers/index.js +11 -0
  118. package/dist/server/src/modules/charges-matcher/resolvers/index.js.map +1 -0
  119. package/dist/server/src/modules/charges-matcher/typeDefs/charges-matcher.graphql.d.ts +2 -0
  120. package/dist/server/src/modules/charges-matcher/typeDefs/charges-matcher.graphql.js +47 -0
  121. package/dist/server/src/modules/charges-matcher/typeDefs/charges-matcher.graphql.js.map +1 -0
  122. package/dist/server/src/modules/charges-matcher/types.d.ts +179 -0
  123. package/dist/server/src/modules/charges-matcher/types.js +14 -0
  124. package/dist/server/src/modules/charges-matcher/types.js.map +1 -0
  125. package/dist/server/src/modules/documents/resolvers/document-suggestions.resolver.js +2 -2
  126. package/dist/server/src/modules/documents/resolvers/document-suggestions.resolver.js.map +1 -1
  127. package/dist/server/src/modules-app.js +2 -0
  128. package/dist/server/src/modules-app.js.map +1 -1
  129. package/dist/server/src/shared/types/index.d.ts +1 -1
  130. package/package.json +4 -4
  131. package/src/__generated__/types.ts +87 -0
  132. package/src/modules/charges-matcher/README.md +279 -0
  133. package/src/modules/charges-matcher/__generated__/types.ts +71 -0
  134. package/src/modules/charges-matcher/__tests__/amount-confidence.test.ts +260 -0
  135. package/src/modules/charges-matcher/__tests__/auto-match-integration.test.ts +714 -0
  136. package/src/modules/charges-matcher/__tests__/auto-match.test.ts +621 -0
  137. package/src/modules/charges-matcher/__tests__/business-confidence.test.ts +177 -0
  138. package/src/modules/charges-matcher/__tests__/candidate-filter.test.ts +238 -0
  139. package/src/modules/charges-matcher/__tests__/charge-validator.test.ts +374 -0
  140. package/src/modules/charges-matcher/__tests__/currency-confidence.test.ts +164 -0
  141. package/src/modules/charges-matcher/__tests__/date-confidence.test.ts +291 -0
  142. package/src/modules/charges-matcher/__tests__/document-aggregator.test.ts +614 -0
  143. package/src/modules/charges-matcher/__tests__/document-amount.test.ts +352 -0
  144. package/src/modules/charges-matcher/__tests__/document-business.test.ts +192 -0
  145. package/src/modules/charges-matcher/__tests__/match-scorer.test.ts +659 -0
  146. package/src/modules/charges-matcher/__tests__/overall-confidence.test.ts +502 -0
  147. package/src/modules/charges-matcher/__tests__/single-match-integration.test.ts +556 -0
  148. package/src/modules/charges-matcher/__tests__/single-match.test.ts +608 -0
  149. package/src/modules/charges-matcher/__tests__/test-helpers.ts +174 -0
  150. package/src/modules/charges-matcher/__tests__/test-infrastructure.spec.ts +177 -0
  151. package/src/modules/charges-matcher/__tests__/transaction-aggregator.test.ts +547 -0
  152. package/src/modules/charges-matcher/documentation/README.md +331 -0
  153. package/src/modules/charges-matcher/documentation/SPEC.md +1503 -0
  154. package/src/modules/charges-matcher/documentation/TODO.md +799 -0
  155. package/src/modules/charges-matcher/helpers/amount-confidence.helper.ts +88 -0
  156. package/src/modules/charges-matcher/helpers/business-confidence.helper.ts +23 -0
  157. package/src/modules/charges-matcher/helpers/candidate-filter.helper.ts +56 -0
  158. package/src/modules/charges-matcher/helpers/charge-validator.helper.ts +100 -0
  159. package/src/modules/charges-matcher/helpers/currency-confidence.helper.ts +22 -0
  160. package/src/modules/charges-matcher/helpers/date-confidence.helper.ts +41 -0
  161. package/src/modules/charges-matcher/helpers/document-amount.helper.ts +77 -0
  162. package/src/modules/charges-matcher/helpers/document-business.helper.ts +54 -0
  163. package/src/modules/charges-matcher/helpers/overall-confidence.helper.ts +90 -0
  164. package/src/modules/charges-matcher/index.ts +17 -0
  165. package/src/modules/charges-matcher/providers/auto-match.provider.ts +176 -0
  166. package/src/modules/charges-matcher/providers/charges-matcher.provider.ts +322 -0
  167. package/src/modules/charges-matcher/providers/document-aggregator.ts +211 -0
  168. package/src/modules/charges-matcher/providers/match-scorer.provider.ts +154 -0
  169. package/src/modules/charges-matcher/providers/single-match.provider.ts +252 -0
  170. package/src/modules/charges-matcher/providers/transaction-aggregator.ts +131 -0
  171. package/src/modules/charges-matcher/resolvers/auto-match-charges.resolver.ts +23 -0
  172. package/src/modules/charges-matcher/resolvers/find-charge-matches.resolver.ts +25 -0
  173. package/src/modules/charges-matcher/resolvers/index.ts +12 -0
  174. package/src/modules/charges-matcher/typeDefs/charges-matcher.graphql.ts +47 -0
  175. package/src/modules/charges-matcher/types.ts +200 -0
  176. package/src/modules/documents/resolvers/document-suggestions.resolver.ts +2 -2
  177. package/src/modules-app.ts +2 -0
  178. package/src/shared/types/index.ts +1 -1
@@ -0,0 +1,502 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import {
3
+ calculateOverallConfidence,
4
+ type ConfidenceComponents,
5
+ } from '../helpers/overall-confidence.helper.js';
6
+
7
+ describe('Overall Confidence Calculator', () => {
8
+ describe('Perfect Matches', () => {
9
+ it('should return 1.0 when all components are 1.0', () => {
10
+ const components: ConfidenceComponents = {
11
+ amount: 1.0,
12
+ currency: 1.0,
13
+ business: 1.0,
14
+ date: 1.0,
15
+ };
16
+
17
+ expect(calculateOverallConfidence(components)).toBe(1.0);
18
+ });
19
+
20
+ it('should return 1.0 when all components are exactly 1.0', () => {
21
+ const result = calculateOverallConfidence({
22
+ amount: 1.0,
23
+ currency: 1.0,
24
+ business: 1.0,
25
+ date: 1.0,
26
+ });
27
+
28
+ expect(result).toBe(1.0);
29
+ expect(typeof result).toBe('number');
30
+ });
31
+ });
32
+
33
+ describe('Zero Matches', () => {
34
+ it('should return 0.0 when all components are 0.0', () => {
35
+ const components: ConfidenceComponents = {
36
+ amount: 0.0,
37
+ currency: 0.0,
38
+ business: 0.0,
39
+ date: 0.0,
40
+ };
41
+
42
+ expect(calculateOverallConfidence(components)).toBe(0.0);
43
+ });
44
+ });
45
+
46
+ describe('Weighted Formula Verification', () => {
47
+ it('should correctly apply amount weight (0.4)', () => {
48
+ // Only amount is 1.0, others are 0.0
49
+ const result = calculateOverallConfidence({
50
+ amount: 1.0,
51
+ currency: 0.0,
52
+ business: 0.0,
53
+ date: 0.0,
54
+ });
55
+
56
+ expect(result).toBe(0.4);
57
+ });
58
+
59
+ it('should correctly apply currency weight (0.2)', () => {
60
+ // Only currency is 1.0, others are 0.0
61
+ const result = calculateOverallConfidence({
62
+ amount: 0.0,
63
+ currency: 1.0,
64
+ business: 0.0,
65
+ date: 0.0,
66
+ });
67
+
68
+ expect(result).toBe(0.2);
69
+ });
70
+
71
+ it('should correctly apply business weight (0.3)', () => {
72
+ // Only business is 1.0, others are 0.0
73
+ const result = calculateOverallConfidence({
74
+ amount: 0.0,
75
+ currency: 0.0,
76
+ business: 1.0,
77
+ date: 0.0,
78
+ });
79
+
80
+ expect(result).toBe(0.3);
81
+ });
82
+
83
+ it('should correctly apply date weight (0.1)', () => {
84
+ // Only date is 1.0, others are 0.0
85
+ const result = calculateOverallConfidence({
86
+ amount: 0.0,
87
+ currency: 0.0,
88
+ business: 0.0,
89
+ date: 1.0,
90
+ });
91
+
92
+ expect(result).toBe(0.1);
93
+ });
94
+
95
+ it('should verify weights sum to 1.0', () => {
96
+ // When all components are 1.0, result should be 1.0
97
+ // This verifies: 0.4 + 0.2 + 0.3 + 0.1 = 1.0
98
+ const result = calculateOverallConfidence({
99
+ amount: 1.0,
100
+ currency: 1.0,
101
+ business: 1.0,
102
+ date: 1.0,
103
+ });
104
+
105
+ expect(result).toBe(1.0);
106
+ });
107
+ });
108
+
109
+ describe('Mixed Confidence Scenarios', () => {
110
+ it('should handle typical good match (all high)', () => {
111
+ const result = calculateOverallConfidence({
112
+ amount: 0.9,
113
+ currency: 1.0,
114
+ business: 1.0,
115
+ date: 1.0,
116
+ });
117
+
118
+ // (0.9 × 0.4) + (1.0 × 0.2) + (1.0 × 0.3) + (1.0 × 0.1) = 0.96
119
+ expect(result).toBe(0.96);
120
+ });
121
+
122
+ it('should handle partial match (mixed scores)', () => {
123
+ const result = calculateOverallConfidence({
124
+ amount: 0.9,
125
+ currency: 1.0,
126
+ business: 0.5,
127
+ date: 0.8,
128
+ });
129
+
130
+ // (0.9 × 0.4) + (1.0 × 0.2) + (0.5 × 0.3) + (0.8 × 0.1)
131
+ // = 0.36 + 0.2 + 0.15 + 0.08 = 0.79
132
+ expect(result).toBe(0.79);
133
+ });
134
+
135
+ it('should handle uncertain business with good other factors', () => {
136
+ const result = calculateOverallConfidence({
137
+ amount: 1.0,
138
+ currency: 1.0,
139
+ business: 0.5,
140
+ date: 1.0,
141
+ });
142
+
143
+ // (1.0 × 0.4) + (1.0 × 0.2) + (0.5 × 0.3) + (1.0 × 0.1)
144
+ // = 0.4 + 0.2 + 0.15 + 0.1 = 0.85
145
+ expect(result).toBe(0.85);
146
+ });
147
+
148
+ it('should handle missing currency with good match otherwise', () => {
149
+ const result = calculateOverallConfidence({
150
+ amount: 1.0,
151
+ currency: 0.2, // Missing currency penalty
152
+ business: 1.0,
153
+ date: 1.0,
154
+ });
155
+
156
+ // (1.0 × 0.4) + (0.2 × 0.2) + (1.0 × 0.3) + (1.0 × 0.1)
157
+ // = 0.4 + 0.04 + 0.3 + 0.1 = 0.84
158
+ expect(result).toBe(0.84);
159
+ });
160
+
161
+ it('should handle business mismatch with good amount/currency', () => {
162
+ const result = calculateOverallConfidence({
163
+ amount: 1.0,
164
+ currency: 1.0,
165
+ business: 0.2, // Mismatch
166
+ date: 1.0,
167
+ });
168
+
169
+ // (1.0 × 0.4) + (1.0 × 0.2) + (0.2 × 0.3) + (1.0 × 0.1)
170
+ // = 0.4 + 0.2 + 0.06 + 0.1 = 0.76
171
+ expect(result).toBe(0.76);
172
+ });
173
+
174
+ it('should handle old date with perfect other factors', () => {
175
+ const result = calculateOverallConfidence({
176
+ amount: 1.0,
177
+ currency: 1.0,
178
+ business: 1.0,
179
+ date: 0.0, // 30+ days apart
180
+ });
181
+
182
+ // (1.0 × 0.4) + (1.0 × 0.2) + (1.0 × 0.3) + (0.0 × 0.1)
183
+ // = 0.4 + 0.2 + 0.3 + 0.0 = 0.9
184
+ expect(result).toBe(0.9);
185
+ });
186
+ });
187
+
188
+ describe('Auto-Match Threshold Scenarios', () => {
189
+ it('should identify clear auto-match candidate (≥0.95)', () => {
190
+ const result = calculateOverallConfidence({
191
+ amount: 1.0,
192
+ currency: 1.0,
193
+ business: 1.0,
194
+ date: 0.5,
195
+ });
196
+
197
+ // (1.0 × 0.4) + (1.0 × 0.2) + (1.0 × 0.3) + (0.5 × 0.1)
198
+ // = 0.4 + 0.2 + 0.3 + 0.05 = 0.95
199
+ expect(result).toBe(0.95);
200
+ expect(result).toBeGreaterThanOrEqual(0.95);
201
+ });
202
+
203
+ it('should identify borderline case (just below threshold)', () => {
204
+ const result = calculateOverallConfidence({
205
+ amount: 0.9,
206
+ currency: 1.0,
207
+ business: 1.0,
208
+ date: 0.9,
209
+ });
210
+
211
+ // (0.9 × 0.4) + (1.0 × 0.2) + (1.0 × 0.3) + (0.9 × 0.1)
212
+ // = 0.36 + 0.2 + 0.3 + 0.09 = 0.95
213
+ expect(result).toBe(0.95);
214
+ });
215
+
216
+ it('should identify case just above threshold', () => {
217
+ const result = calculateOverallConfidence({
218
+ amount: 1.0,
219
+ currency: 1.0,
220
+ business: 1.0,
221
+ date: 0.6,
222
+ });
223
+
224
+ // (1.0 × 0.4) + (1.0 × 0.2) + (1.0 × 0.3) + (0.6 × 0.1)
225
+ // = 0.4 + 0.2 + 0.3 + 0.06 = 0.96
226
+ expect(result).toBe(0.96);
227
+ expect(result).toBeGreaterThan(0.95);
228
+ });
229
+ });
230
+
231
+ describe('Decimal Precision', () => {
232
+ it('should round to 2 decimal places', () => {
233
+ const result = calculateOverallConfidence({
234
+ amount: 0.333,
235
+ currency: 0.667,
236
+ business: 0.555,
237
+ date: 0.444,
238
+ });
239
+
240
+ // (0.333 × 0.4) + (0.667 × 0.2) + (0.555 × 0.3) + (0.444 × 0.1)
241
+ // = 0.1332 + 0.1334 + 0.1665 + 0.0444 = 0.4775
242
+ expect(result).toBe(0.48);
243
+ });
244
+
245
+ it('should handle rounding edge case (0.445 rounds to 0.45)', () => {
246
+ const result = calculateOverallConfidence({
247
+ amount: 0.5,
248
+ currency: 0.5,
249
+ business: 0.5,
250
+ date: 0.0,
251
+ });
252
+
253
+ // (0.5 × 0.4) + (0.5 × 0.2) + (0.5 × 0.3) + (0.0 × 0.1)
254
+ // = 0.2 + 0.1 + 0.15 + 0.0 = 0.45
255
+ expect(result).toBe(0.45);
256
+ });
257
+
258
+ it('should handle precise calculation without floating point errors', () => {
259
+ const result = calculateOverallConfidence({
260
+ amount: 0.1,
261
+ currency: 0.2,
262
+ business: 0.3,
263
+ date: 0.4,
264
+ });
265
+
266
+ // (0.1 × 0.4) + (0.2 × 0.2) + (0.3 × 0.3) + (0.4 × 0.1)
267
+ // = 0.04 + 0.04 + 0.09 + 0.04 = 0.21
268
+ expect(result).toBe(0.21);
269
+ });
270
+ });
271
+
272
+ describe('Edge Cases', () => {
273
+ it('should handle all components at 0.5', () => {
274
+ const result = calculateOverallConfidence({
275
+ amount: 0.5,
276
+ currency: 0.5,
277
+ business: 0.5,
278
+ date: 0.5,
279
+ });
280
+
281
+ // (0.5 × 0.4) + (0.5 × 0.2) + (0.5 × 0.3) + (0.5 × 0.1)
282
+ // = 0.2 + 0.1 + 0.15 + 0.05 = 0.5
283
+ expect(result).toBe(0.5);
284
+ });
285
+
286
+ it('should handle very small non-zero values', () => {
287
+ const result = calculateOverallConfidence({
288
+ amount: 0.01,
289
+ currency: 0.01,
290
+ business: 0.01,
291
+ date: 0.01,
292
+ });
293
+
294
+ // (0.01 × 0.4) + (0.01 × 0.2) + (0.01 × 0.3) + (0.01 × 0.1)
295
+ // = 0.004 + 0.002 + 0.003 + 0.001 = 0.01
296
+ expect(result).toBe(0.01);
297
+ });
298
+
299
+ it('should handle values very close to 1.0', () => {
300
+ const result = calculateOverallConfidence({
301
+ amount: 0.99,
302
+ currency: 0.99,
303
+ business: 0.99,
304
+ date: 0.99,
305
+ });
306
+
307
+ // (0.99 × 0.4) + (0.99 × 0.2) + (0.99 × 0.3) + (0.99 × 0.1)
308
+ // = 0.396 + 0.198 + 0.297 + 0.099 = 0.99
309
+ expect(result).toBe(0.99);
310
+ });
311
+ });
312
+
313
+ describe('Validation - Missing Components', () => {
314
+ it('should throw error when amount is null', () => {
315
+ expect(() =>
316
+ calculateOverallConfidence({
317
+ amount: null as any,
318
+ currency: 1.0,
319
+ business: 1.0,
320
+ date: 1.0,
321
+ }),
322
+ ).toThrow('Amount confidence is required');
323
+ });
324
+
325
+ it('should throw error when currency is null', () => {
326
+ expect(() =>
327
+ calculateOverallConfidence({
328
+ amount: 1.0,
329
+ currency: null as any,
330
+ business: 1.0,
331
+ date: 1.0,
332
+ }),
333
+ ).toThrow('Currency confidence is required');
334
+ });
335
+
336
+ it('should throw error when business is null', () => {
337
+ expect(() =>
338
+ calculateOverallConfidence({
339
+ amount: 1.0,
340
+ currency: 1.0,
341
+ business: null as any,
342
+ date: 1.0,
343
+ }),
344
+ ).toThrow('Business confidence is required');
345
+ });
346
+
347
+ it('should throw error when date is null', () => {
348
+ expect(() =>
349
+ calculateOverallConfidence({
350
+ amount: 1.0,
351
+ currency: 1.0,
352
+ business: 1.0,
353
+ date: null as any,
354
+ }),
355
+ ).toThrow('Date confidence is required');
356
+ });
357
+
358
+ it('should throw error when amount is undefined', () => {
359
+ expect(() =>
360
+ calculateOverallConfidence({
361
+ amount: undefined as any,
362
+ currency: 1.0,
363
+ business: 1.0,
364
+ date: 1.0,
365
+ }),
366
+ ).toThrow('Amount confidence is required');
367
+ });
368
+
369
+ it('should throw error when multiple components are null', () => {
370
+ expect(() =>
371
+ calculateOverallConfidence({
372
+ amount: null as any,
373
+ currency: null as any,
374
+ business: 1.0,
375
+ date: 1.0,
376
+ }),
377
+ ).toThrow('Amount confidence is required');
378
+ });
379
+ });
380
+
381
+ describe('Validation - Out of Range', () => {
382
+ it('should throw error when amount is negative', () => {
383
+ expect(() =>
384
+ calculateOverallConfidence({
385
+ amount: -0.1,
386
+ currency: 1.0,
387
+ business: 1.0,
388
+ date: 1.0,
389
+ }),
390
+ ).toThrow('Amount confidence must be between 0.0 and 1.0');
391
+ });
392
+
393
+ it('should throw error when amount exceeds 1.0', () => {
394
+ expect(() =>
395
+ calculateOverallConfidence({
396
+ amount: 1.1,
397
+ currency: 1.0,
398
+ business: 1.0,
399
+ date: 1.0,
400
+ }),
401
+ ).toThrow('Amount confidence must be between 0.0 and 1.0');
402
+ });
403
+
404
+ it('should throw error when currency is negative', () => {
405
+ expect(() =>
406
+ calculateOverallConfidence({
407
+ amount: 1.0,
408
+ currency: -0.5,
409
+ business: 1.0,
410
+ date: 1.0,
411
+ }),
412
+ ).toThrow('Currency confidence must be between 0.0 and 1.0');
413
+ });
414
+
415
+ it('should throw error when business exceeds 1.0', () => {
416
+ expect(() =>
417
+ calculateOverallConfidence({
418
+ amount: 1.0,
419
+ currency: 1.0,
420
+ business: 2.0,
421
+ date: 1.0,
422
+ }),
423
+ ).toThrow('Business confidence must be between 0.0 and 1.0');
424
+ });
425
+
426
+ it('should throw error when date is negative', () => {
427
+ expect(() =>
428
+ calculateOverallConfidence({
429
+ amount: 1.0,
430
+ currency: 1.0,
431
+ business: 1.0,
432
+ date: -1.0,
433
+ }),
434
+ ).toThrow('Date confidence must be between 0.0 and 1.0');
435
+ });
436
+
437
+ it('should throw error with correct component name', () => {
438
+ expect(() =>
439
+ calculateOverallConfidence({
440
+ amount: 1.0,
441
+ currency: 1.0,
442
+ business: 5.0,
443
+ date: 1.0,
444
+ }),
445
+ ).toThrow(/Business confidence/);
446
+ });
447
+ });
448
+
449
+ describe('Real-World Scenarios', () => {
450
+ it('should handle typical invoice match', () => {
451
+ // Exact amount, currency, business match, 2 days apart
452
+ const result = calculateOverallConfidence({
453
+ amount: 1.0,
454
+ currency: 1.0,
455
+ business: 1.0,
456
+ date: 0.93, // ~2 days difference
457
+ });
458
+
459
+ // (1.0 × 0.4) + (1.0 × 0.2) + (1.0 × 0.3) + (0.93 × 0.1) = 0.993
460
+ expect(result).toBe(0.99);
461
+ });
462
+
463
+ it('should handle receipt with missing business', () => {
464
+ // Good amount/currency, no business ID, same day
465
+ const result = calculateOverallConfidence({
466
+ amount: 1.0,
467
+ currency: 1.0,
468
+ business: 0.5, // Unknown business
469
+ date: 1.0,
470
+ });
471
+
472
+ // (1.0 × 0.4) + (1.0 × 0.2) + (0.5 × 0.3) + (1.0 × 0.1) = 0.85
473
+ expect(result).toBe(0.85);
474
+ });
475
+
476
+ it('should handle cross-currency near match', () => {
477
+ // Good amount, no currency match, good business/date
478
+ const result = calculateOverallConfidence({
479
+ amount: 0.9,
480
+ currency: 0.0, // Different currency
481
+ business: 1.0,
482
+ date: 1.0,
483
+ });
484
+
485
+ // (0.9 × 0.4) + (0.0 × 0.2) + (1.0 × 0.3) + (1.0 × 0.1) = 0.76
486
+ expect(result).toBe(0.76);
487
+ });
488
+
489
+ it('should handle delayed receipt (15 days)', () => {
490
+ // Perfect match except date
491
+ const result = calculateOverallConfidence({
492
+ amount: 1.0,
493
+ currency: 1.0,
494
+ business: 1.0,
495
+ date: 0.5, // 15 days difference
496
+ });
497
+
498
+ // (1.0 × 0.4) + (1.0 × 0.2) + (1.0 × 0.3) + (0.5 × 0.1) = 0.95
499
+ expect(result).toBe(0.95);
500
+ });
501
+ });
502
+ });