@accounter/server 0.0.8-alpha-20251102200443-d7162b8ce1dfc629b8b454df17dcec9ed005a052 → 0.0.8-alpha-20251103003648-f6467c8cb9c739ec4439c260bccc7325f6a761ae

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 (185) hide show
  1. package/CHANGELOG.md +47 -7
  2. package/dist/green-invoice-graphql/src/mesh-artifacts/index.d.ts +7 -7
  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/green-invoice/helpers/contract-to-draft.helper.js +1 -1
  128. package/dist/server/src/modules/green-invoice/helpers/contract-to-draft.helper.js.map +1 -1
  129. package/dist/server/src/modules/green-invoice/helpers/green-invoice.helper.d.ts +1 -1
  130. package/dist/server/src/modules/green-invoice/helpers/green-invoice.helper.js +1 -1
  131. package/dist/server/src/modules/green-invoice/helpers/green-invoice.helper.js.map +1 -1
  132. package/dist/server/src/modules-app.js +2 -0
  133. package/dist/server/src/modules-app.js.map +1 -1
  134. package/dist/server/src/shared/types/index.d.ts +1 -1
  135. package/package.json +4 -4
  136. package/src/__generated__/types.ts +87 -0
  137. package/src/modules/charges-matcher/README.md +279 -0
  138. package/src/modules/charges-matcher/__generated__/types.ts +71 -0
  139. package/src/modules/charges-matcher/__tests__/amount-confidence.test.ts +260 -0
  140. package/src/modules/charges-matcher/__tests__/auto-match-integration.test.ts +714 -0
  141. package/src/modules/charges-matcher/__tests__/auto-match.test.ts +621 -0
  142. package/src/modules/charges-matcher/__tests__/business-confidence.test.ts +177 -0
  143. package/src/modules/charges-matcher/__tests__/candidate-filter.test.ts +238 -0
  144. package/src/modules/charges-matcher/__tests__/charge-validator.test.ts +374 -0
  145. package/src/modules/charges-matcher/__tests__/currency-confidence.test.ts +164 -0
  146. package/src/modules/charges-matcher/__tests__/date-confidence.test.ts +291 -0
  147. package/src/modules/charges-matcher/__tests__/document-aggregator.test.ts +614 -0
  148. package/src/modules/charges-matcher/__tests__/document-amount.test.ts +352 -0
  149. package/src/modules/charges-matcher/__tests__/document-business.test.ts +192 -0
  150. package/src/modules/charges-matcher/__tests__/match-scorer.test.ts +659 -0
  151. package/src/modules/charges-matcher/__tests__/overall-confidence.test.ts +502 -0
  152. package/src/modules/charges-matcher/__tests__/single-match-integration.test.ts +556 -0
  153. package/src/modules/charges-matcher/__tests__/single-match.test.ts +608 -0
  154. package/src/modules/charges-matcher/__tests__/test-helpers.ts +174 -0
  155. package/src/modules/charges-matcher/__tests__/test-infrastructure.spec.ts +177 -0
  156. package/src/modules/charges-matcher/__tests__/transaction-aggregator.test.ts +547 -0
  157. package/src/modules/charges-matcher/documentation/README.md +331 -0
  158. package/src/modules/charges-matcher/documentation/SPEC.md +1503 -0
  159. package/src/modules/charges-matcher/documentation/TODO.md +799 -0
  160. package/src/modules/charges-matcher/helpers/amount-confidence.helper.ts +88 -0
  161. package/src/modules/charges-matcher/helpers/business-confidence.helper.ts +23 -0
  162. package/src/modules/charges-matcher/helpers/candidate-filter.helper.ts +56 -0
  163. package/src/modules/charges-matcher/helpers/charge-validator.helper.ts +100 -0
  164. package/src/modules/charges-matcher/helpers/currency-confidence.helper.ts +22 -0
  165. package/src/modules/charges-matcher/helpers/date-confidence.helper.ts +41 -0
  166. package/src/modules/charges-matcher/helpers/document-amount.helper.ts +77 -0
  167. package/src/modules/charges-matcher/helpers/document-business.helper.ts +54 -0
  168. package/src/modules/charges-matcher/helpers/overall-confidence.helper.ts +90 -0
  169. package/src/modules/charges-matcher/index.ts +17 -0
  170. package/src/modules/charges-matcher/providers/auto-match.provider.ts +176 -0
  171. package/src/modules/charges-matcher/providers/charges-matcher.provider.ts +322 -0
  172. package/src/modules/charges-matcher/providers/document-aggregator.ts +211 -0
  173. package/src/modules/charges-matcher/providers/match-scorer.provider.ts +154 -0
  174. package/src/modules/charges-matcher/providers/single-match.provider.ts +252 -0
  175. package/src/modules/charges-matcher/providers/transaction-aggregator.ts +131 -0
  176. package/src/modules/charges-matcher/resolvers/auto-match-charges.resolver.ts +23 -0
  177. package/src/modules/charges-matcher/resolvers/find-charge-matches.resolver.ts +25 -0
  178. package/src/modules/charges-matcher/resolvers/index.ts +12 -0
  179. package/src/modules/charges-matcher/typeDefs/charges-matcher.graphql.ts +47 -0
  180. package/src/modules/charges-matcher/types.ts +200 -0
  181. package/src/modules/documents/resolvers/document-suggestions.resolver.ts +2 -2
  182. package/src/modules/green-invoice/helpers/contract-to-draft.helper.ts +1 -1
  183. package/src/modules/green-invoice/helpers/green-invoice.helper.ts +1 -1
  184. package/src/modules-app.ts +2 -0
  185. package/src/shared/types/index.ts +1 -1
@@ -0,0 +1,659 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import type { AggregatedTransaction, DocumentCharge, TransactionCharge } from '../types.js';
3
+ import {
4
+ scoreMatch,
5
+ selectTransactionDate,
6
+ } from '../providers/match-scorer.provider.js';
7
+ import { createMockTransaction, createMockDocument } from './test-helpers.js';
8
+
9
+ // Test user ID
10
+ const USER_ID = 'user-123';
11
+ const BUSINESS_ID = 'business-abc';
12
+
13
+ describe('Match Scorer', () => {
14
+ describe('selectTransactionDate', () => {
15
+ const transaction: AggregatedTransaction = {
16
+ amount: 100,
17
+ currency: 'USD' as const,
18
+ businessId: BUSINESS_ID,
19
+ date: new Date('2024-01-15'), // event_date
20
+ debitDate: new Date('2024-01-20'), // debit_date
21
+ description: 'Test',
22
+ };
23
+
24
+ it('should use event_date for INVOICE', () => {
25
+ const result = selectTransactionDate(transaction, 'INVOICE');
26
+ expect(result).toEqual(new Date('2024-01-15'));
27
+ });
28
+
29
+ it('should use event_date for CREDIT_INVOICE', () => {
30
+ const result = selectTransactionDate(transaction, 'CREDIT_INVOICE');
31
+ expect(result).toEqual(new Date('2024-01-15'));
32
+ });
33
+
34
+ it('should use event_date for RECEIPT', () => {
35
+ const result = selectTransactionDate(transaction, 'RECEIPT');
36
+ expect(result).toEqual(new Date('2024-01-15'));
37
+ });
38
+
39
+ it('should use event_date for INVOICE_RECEIPT', () => {
40
+ const result = selectTransactionDate(transaction, 'INVOICE_RECEIPT');
41
+ expect(result).toEqual(new Date('2024-01-15'));
42
+ });
43
+
44
+ it('should use event_date for RECEIPT when debitDate is null', () => {
45
+ const txWithoutDebitDate = { ...transaction, debitDate: null };
46
+ const result = selectTransactionDate(txWithoutDebitDate, 'RECEIPT');
47
+ expect(result).toEqual(new Date('2024-01-15'));
48
+ });
49
+
50
+ it('should use event_date for OTHER', () => {
51
+ const result = selectTransactionDate(transaction, 'OTHER');
52
+ expect(result).toEqual(new Date('2024-01-15'));
53
+ });
54
+
55
+ it('should use event_date for PROFORMA', () => {
56
+ const result = selectTransactionDate(transaction, 'PROFORMA');
57
+ expect(result).toEqual(new Date('2024-01-15'));
58
+ });
59
+
60
+ it('should use event_date for UNPROCESSED', () => {
61
+ const result = selectTransactionDate(transaction, 'UNPROCESSED');
62
+ expect(result).toEqual(new Date('2024-01-15'));
63
+ });
64
+ });
65
+
66
+ describe('scoreMatch', () => {
67
+ describe('Perfect Matches', () => {
68
+ it('should score perfect match close to 1.0', () => {
69
+ const txCharge: TransactionCharge = {
70
+ chargeId: 'charge-tx-1',
71
+ transactions: [
72
+ createMockTransaction({
73
+ amount: '100.00',
74
+ currency: 'USD',
75
+ event_date: new Date('2024-01-15'),
76
+ business_id: BUSINESS_ID,
77
+ }),
78
+ ],
79
+ };
80
+
81
+ const docCharge: DocumentCharge = {
82
+ chargeId: 'charge-doc-1',
83
+ documents: [
84
+ createMockDocument({
85
+ total_amount: 100,
86
+ currency_code: 'USD',
87
+ date: new Date('2024-01-15'),
88
+ creditor_id: BUSINESS_ID,
89
+ debtor_id: USER_ID,
90
+ type: 'INVOICE',
91
+ }),
92
+ ],
93
+ };
94
+
95
+ const result = scoreMatch(txCharge, docCharge, USER_ID);
96
+
97
+ expect(result.chargeId).toBe('charge-doc-1');
98
+ expect(result.confidenceScore).toBeGreaterThan(0.95);
99
+ expect(result.components.amount).toBe(1.0);
100
+ expect(result.components.currency).toBe(1.0);
101
+ expect(result.components.business).toBe(1.0);
102
+ expect(result.components.date).toBe(1.0);
103
+ });
104
+
105
+ it('should handle receipt matching with event_date', () => {
106
+ const txCharge: TransactionCharge = {
107
+ chargeId: 'charge-tx-2',
108
+ transactions: [
109
+ createMockTransaction({
110
+ amount: "200.00",
111
+ event_date: new Date('2024-01-10'),
112
+ debit_date: new Date('2024-01-15'),
113
+ debit_timestamp: null,
114
+ }),
115
+ ],
116
+ };
117
+
118
+ const docCharge: DocumentCharge = {
119
+ chargeId: 'charge-doc-2',
120
+ documents: [
121
+ createMockDocument({
122
+ total_amount: 200,
123
+ date: new Date('2024-01-15'),
124
+ type: 'RECEIPT',
125
+ }),
126
+ ],
127
+ };
128
+
129
+ const result = scoreMatch(txCharge, docCharge, USER_ID);
130
+
131
+ expect(result.confidenceScore).toBeGreaterThan(0.80);
132
+ expect(result.components.date).toBeCloseTo(0.83, 1);
133
+ });
134
+ });
135
+
136
+ describe('Partial Matches', () => {
137
+ it('should handle amount mismatch', () => {
138
+ const txCharge: TransactionCharge = {
139
+ chargeId: 'charge-tx-3',
140
+ transactions: [createMockTransaction({ amount: "100.00" })],
141
+ };
142
+
143
+ const docCharge: DocumentCharge = {
144
+ chargeId: 'charge-doc-3',
145
+ documents: [createMockDocument({ total_amount: 110 })], // 10% difference
146
+ };
147
+
148
+ const result = scoreMatch(txCharge, docCharge, USER_ID);
149
+
150
+ expect(result.components.amount).toBeLessThan(1.0);
151
+ expect(result.components.amount).toBeGreaterThan(0.0);
152
+ expect(result.confidenceScore).toBeLessThan(0.95);
153
+ });
154
+
155
+ it('should handle currency mismatch', () => {
156
+ const txCharge: TransactionCharge = {
157
+ chargeId: 'charge-tx-4',
158
+ transactions: [createMockTransaction({ currency: 'USD' })],
159
+ };
160
+
161
+ const docCharge: DocumentCharge = {
162
+ chargeId: 'charge-doc-4',
163
+ documents: [createMockDocument({ currency_code: 'EUR' })],
164
+ };
165
+
166
+ const result = scoreMatch(txCharge, docCharge, USER_ID);
167
+
168
+ expect(result.components.currency).toBe(0.0); // Different currencies = 0.0
169
+ // Overall confidence can still be decent if other factors match
170
+ expect(result.confidenceScore).toBeLessThan(1.0);
171
+ });
172
+
173
+ it('should handle business mismatch', () => {
174
+ const txCharge: TransactionCharge = {
175
+ chargeId: 'charge-tx-5',
176
+ transactions: [createMockTransaction({ business_id: 'business-1' })],
177
+ };
178
+
179
+ const docCharge: DocumentCharge = {
180
+ chargeId: 'charge-doc-5',
181
+ documents: [
182
+ createMockDocument({
183
+ creditor_id: 'business-2',
184
+ debtor_id: USER_ID,
185
+ }),
186
+ ],
187
+ };
188
+
189
+ const result = scoreMatch(txCharge, docCharge, USER_ID);
190
+
191
+ expect(result.components.business).toBe(0.2);
192
+ });
193
+
194
+ it('should handle date difference', () => {
195
+ const txCharge: TransactionCharge = {
196
+ chargeId: 'charge-tx-6',
197
+ transactions: [
198
+ createMockTransaction({
199
+ event_date: new Date('2024-01-01'),
200
+ }),
201
+ ],
202
+ };
203
+
204
+ const docCharge: DocumentCharge = {
205
+ chargeId: 'charge-doc-6',
206
+ documents: [
207
+ createMockDocument({
208
+ date: new Date('2024-01-16'), // 15 days difference
209
+ }),
210
+ ],
211
+ };
212
+
213
+ const result = scoreMatch(txCharge, docCharge, USER_ID);
214
+
215
+ expect(result.components.date).toBe(0.5); // 15/30 = 0.5
216
+ });
217
+ });
218
+
219
+ describe('Date Type Selection', () => {
220
+ it('should use event_date for INVOICE matching', () => {
221
+ const txCharge: TransactionCharge = {
222
+ chargeId: 'charge-tx-7',
223
+ transactions: [
224
+ createMockTransaction({
225
+ event_date: new Date('2024-01-15'),
226
+ debit_date: new Date('2024-01-20'), // Different date
227
+ }),
228
+ ],
229
+ };
230
+
231
+ const docCharge: DocumentCharge = {
232
+ chargeId: 'charge-doc-7',
233
+ documents: [
234
+ createMockDocument({
235
+ date: new Date('2024-01-15'), // Matches event_date
236
+ type: 'INVOICE',
237
+ }),
238
+ ],
239
+ };
240
+
241
+ const result = scoreMatch(txCharge, docCharge, USER_ID);
242
+
243
+ expect(result.components.date).toBe(1.0); // Should match event_date
244
+ });
245
+
246
+ it('should use event_date for RECEIPT matching', () => {
247
+ const txCharge: TransactionCharge = {
248
+ chargeId: 'charge-tx-8',
249
+ transactions: [
250
+ createMockTransaction({
251
+ event_date: new Date('2024-01-10'),
252
+ debit_date: new Date('2024-01-15'),
253
+ debit_timestamp: null,
254
+ }),
255
+ ],
256
+ };
257
+
258
+ const docCharge: DocumentCharge = {
259
+ chargeId: 'charge-doc-8',
260
+ documents: [
261
+ createMockDocument({
262
+ date: new Date('2024-01-15'), // Matches debit_date
263
+ type: 'RECEIPT',
264
+ }),
265
+ ],
266
+ };
267
+
268
+ const result = scoreMatch(txCharge, docCharge, USER_ID);
269
+
270
+ expect(result.components.date).toBeCloseTo(0.83, 1);
271
+ });
272
+
273
+ it('should fall back to event_date for RECEIPT when debit_date is null', () => {
274
+ const txCharge: TransactionCharge = {
275
+ chargeId: 'charge-tx-9',
276
+ transactions: [
277
+ createMockTransaction({
278
+ event_date: new Date('2024-01-15'),
279
+ debit_date: null,
280
+ debit_timestamp: null,
281
+ }),
282
+ ],
283
+ };
284
+
285
+ const docCharge: DocumentCharge = {
286
+ chargeId: 'charge-doc-9',
287
+ documents: [
288
+ createMockDocument({
289
+ date: new Date('2024-01-15'),
290
+ type: 'RECEIPT',
291
+ }),
292
+ ],
293
+ };
294
+
295
+ const result = scoreMatch(txCharge, docCharge, USER_ID);
296
+
297
+ expect(result.components.date).toBe(1.0);
298
+ });
299
+ });
300
+
301
+ describe('Flexible Document Types (PROFORMA/OTHER/UNPROCESSED)', () => {
302
+ it('should use event_date for PROFORMA and use better score', () => {
303
+ const txCharge: TransactionCharge = {
304
+ chargeId: 'charge-tx-10',
305
+ transactions: [
306
+ createMockTransaction({
307
+ event_date: new Date('2024-01-01'), // Far from document date
308
+ debit_date: new Date('2024-01-15'), // Matches document date
309
+ debit_timestamp: null,
310
+ }),
311
+ ],
312
+ };
313
+
314
+ const docCharge: DocumentCharge = {
315
+ chargeId: 'charge-doc-10',
316
+ documents: [
317
+ createMockDocument({
318
+ date: new Date('2024-01-15'),
319
+ type: 'PROFORMA',
320
+ }),
321
+ ],
322
+ };
323
+
324
+ const result = scoreMatch(txCharge, docCharge, USER_ID);
325
+
326
+ // Should use event_date (2024-01-01) vs latest doc date (2024-01-15) = 14 days
327
+ // Date confidence: 1.0 - 14/30 = 0.53
328
+ expect(result.components.date).toBeCloseTo(0.53, 1);
329
+ });
330
+
331
+ it('should handle OTHER type with both dates', () => {
332
+ const txCharge: TransactionCharge = {
333
+ chargeId: 'charge-tx-11',
334
+ transactions: [
335
+ createMockTransaction({
336
+ event_date: new Date('2024-01-10'),
337
+ debit_date: new Date('2024-01-25'), // Far from document
338
+ }),
339
+ ],
340
+ };
341
+
342
+ const docCharge: DocumentCharge = {
343
+ chargeId: 'charge-doc-11',
344
+ documents: [
345
+ createMockDocument({
346
+ date: new Date('2024-01-10'), // Matches event_date
347
+ type: 'OTHER',
348
+ }),
349
+ ],
350
+ };
351
+
352
+ const result = scoreMatch(txCharge, docCharge, USER_ID);
353
+
354
+ // Should use event_date since it matches better
355
+ expect(result.components.date).toBe(1.0);
356
+ });
357
+
358
+ it('should handle UNPROCESSED type', () => {
359
+ const txCharge: TransactionCharge = {
360
+ chargeId: 'charge-tx-12',
361
+ transactions: [
362
+ createMockTransaction({
363
+ event_date: new Date('2024-01-15'),
364
+ debit_date: new Date('2024-01-15'),
365
+ debit_timestamp: null,
366
+ }),
367
+ ],
368
+ };
369
+
370
+ const docCharge: DocumentCharge = {
371
+ chargeId: 'charge-doc-12',
372
+ documents: [
373
+ createMockDocument({
374
+ date: new Date('2024-01-15'),
375
+ type: 'UNPROCESSED',
376
+ }),
377
+ ],
378
+ };
379
+
380
+ const result = scoreMatch(txCharge, docCharge, USER_ID);
381
+
382
+ expect(result.components.date).toBe(1.0);
383
+ });
384
+
385
+ it('should handle flexible type without debit_date', () => {
386
+ const txCharge: TransactionCharge = {
387
+ chargeId: 'charge-tx-13',
388
+ transactions: [
389
+ createMockTransaction({
390
+ event_date: new Date('2024-01-15'),
391
+ debit_date: null,
392
+ debit_timestamp: null,
393
+ }),
394
+ ],
395
+ };
396
+
397
+ const docCharge: DocumentCharge = {
398
+ chargeId: 'charge-doc-13',
399
+ documents: [
400
+ createMockDocument({
401
+ date: new Date('2024-01-15'),
402
+ type: 'OTHER',
403
+ }),
404
+ ],
405
+ };
406
+
407
+ const result = scoreMatch(txCharge, docCharge, USER_ID);
408
+
409
+ // Should only use event_date
410
+ expect(result.components.date).toBe(1.0);
411
+ });
412
+ });
413
+
414
+ describe('Amount Variations', () => {
415
+ it('should handle small amount differences', () => {
416
+ const txCharge: TransactionCharge = {
417
+ chargeId: 'charge-tx-14',
418
+ transactions: [createMockTransaction({ amount: "100.00" })],
419
+ };
420
+
421
+ const docCharge: DocumentCharge = {
422
+ chargeId: 'charge-doc-14',
423
+ documents: [createMockDocument({ total_amount: 100.5 })], // 0.5 difference
424
+ };
425
+
426
+ const result = scoreMatch(txCharge, docCharge, USER_ID);
427
+
428
+ expect(result.components.amount).toBeGreaterThanOrEqual(0.9); // Within 1 unit = exactly 0.9
429
+ });
430
+
431
+ it('should handle large amount differences', () => {
432
+ const txCharge: TransactionCharge = {
433
+ chargeId: 'charge-tx-15',
434
+ transactions: [createMockTransaction({ amount: "100.00" })],
435
+ };
436
+
437
+ const docCharge: DocumentCharge = {
438
+ chargeId: 'charge-doc-15',
439
+ documents: [createMockDocument({ total_amount: 150 })], // 50% difference
440
+ };
441
+
442
+ const result = scoreMatch(txCharge, docCharge, USER_ID);
443
+
444
+ expect(result.components.amount).toBe(0.0);
445
+ });
446
+ });
447
+
448
+ describe('Integration Tests', () => {
449
+ it('should handle multiple transactions and documents', () => {
450
+ const txCharge: TransactionCharge = {
451
+ chargeId: 'charge-tx-16',
452
+ transactions: [
453
+ createMockTransaction({ amount: "50.00", source_description: 'Part 1' }),
454
+ createMockTransaction({ amount: "50.00", source_description: 'Part 2' }),
455
+ ],
456
+ };
457
+
458
+ const docCharge: DocumentCharge = {
459
+ chargeId: 'charge-doc-16',
460
+ documents: [
461
+ createMockDocument({ total_amount: 100, serial_number: 'INV-001' }),
462
+ ],
463
+ };
464
+
465
+ const result = scoreMatch(txCharge, docCharge, USER_ID);
466
+
467
+ expect(result.components.amount).toBe(1.0); // 50 + 50 = 100
468
+ expect(result.confidenceScore).toBeGreaterThan(0.95);
469
+ });
470
+
471
+ it('should handle credit invoice (negative amounts)', () => {
472
+ const txCharge: TransactionCharge = {
473
+ chargeId: 'charge-tx-17',
474
+ transactions: [createMockTransaction({ amount: "-100.00" })],
475
+ };
476
+
477
+ const docCharge: DocumentCharge = {
478
+ chargeId: 'charge-doc-17',
479
+ documents: [
480
+ createMockDocument({
481
+ total_amount: 100,
482
+ type: 'CREDIT_INVOICE',
483
+ creditor_id: USER_ID, // Business is debtor
484
+ debtor_id: BUSINESS_ID,
485
+ }),
486
+ ],
487
+ };
488
+
489
+ const result = scoreMatch(txCharge, docCharge, USER_ID);
490
+
491
+ expect(result.components.amount).toBe(1.0);
492
+ });
493
+
494
+ it('should handle real-world scenario with slight variations', () => {
495
+ const txCharge: TransactionCharge = {
496
+ chargeId: 'charge-tx-18',
497
+ transactions: [
498
+ createMockTransaction({
499
+ amount: "1234.56",
500
+ currency: 'USD',
501
+ event_date: new Date('2024-03-15'),
502
+ debit_date: new Date('2024-03-17'),
503
+ business_id: 'vendor-xyz',
504
+ }),
505
+ ],
506
+ };
507
+
508
+ const docCharge: DocumentCharge = {
509
+ chargeId: 'charge-doc-18',
510
+ documents: [
511
+ createMockDocument({
512
+ total_amount: 1234.5,
513
+ currency_code: 'USD',
514
+ date: new Date('2024-03-16'), // 1 day difference from tx event_date
515
+ creditor_id: 'vendor-xyz',
516
+ debtor_id: USER_ID,
517
+ type: 'INVOICE',
518
+ }),
519
+ ],
520
+ };
521
+
522
+ const result = scoreMatch(txCharge, docCharge, USER_ID);
523
+
524
+ expect(result.components.amount).toBeGreaterThanOrEqual(0.9); // Within 1 unit = 0.9
525
+ expect(result.components.currency).toBe(1.0);
526
+ expect(result.components.business).toBe(1.0);
527
+ expect(result.components.date).toBeGreaterThan(0.95); // 1 day = 0.97
528
+ expect(result.confidenceScore).toBeGreaterThanOrEqual(0.9);
529
+ });
530
+ });
531
+
532
+ describe('Error Propagation', () => {
533
+ it('should throw error for mixed currencies in transactions', () => {
534
+ const txCharge: TransactionCharge = {
535
+ chargeId: 'charge-tx-19',
536
+ transactions: [
537
+ createMockTransaction({ currency: 'USD' }),
538
+ createMockTransaction({ currency: 'EUR' }),
539
+ ],
540
+ };
541
+
542
+ const docCharge: DocumentCharge = {
543
+ chargeId: 'charge-doc-19',
544
+ documents: [createMockDocument()],
545
+ };
546
+
547
+ expect(() => scoreMatch(txCharge, docCharge, USER_ID)).toThrow(/multiple currencies/);
548
+ });
549
+
550
+ it('should throw error for mixed currencies in documents', () => {
551
+ const txCharge: TransactionCharge = {
552
+ chargeId: 'charge-tx-20',
553
+ transactions: [createMockTransaction()],
554
+ };
555
+
556
+ const docCharge: DocumentCharge = {
557
+ chargeId: 'charge-doc-20',
558
+ documents: [
559
+ createMockDocument({ currency_code: 'USD' }),
560
+ createMockDocument({ currency_code: 'EUR' }),
561
+ ],
562
+ };
563
+
564
+ expect(() => scoreMatch(txCharge, docCharge, USER_ID)).toThrow(/multiple currencies/);
565
+ });
566
+
567
+ it('should throw error for multiple business IDs in transactions', () => {
568
+ const txCharge: TransactionCharge = {
569
+ chargeId: 'charge-tx-21',
570
+ transactions: [
571
+ createMockTransaction({ business_id: 'business-1' }),
572
+ createMockTransaction({ business_id: 'business-2' }),
573
+ ],
574
+ };
575
+
576
+ const docCharge: DocumentCharge = {
577
+ chargeId: 'charge-doc-21',
578
+ documents: [createMockDocument()],
579
+ };
580
+
581
+ expect(() => scoreMatch(txCharge, docCharge, USER_ID)).toThrow(/multiple business/);
582
+ });
583
+
584
+ it('should throw error for invalid document business extraction', () => {
585
+ const txCharge: TransactionCharge = {
586
+ chargeId: 'charge-tx-22',
587
+ transactions: [createMockTransaction()],
588
+ };
589
+
590
+ const docCharge: DocumentCharge = {
591
+ chargeId: 'charge-doc-22',
592
+ documents: [
593
+ createMockDocument({
594
+ creditor_id: 'other-user',
595
+ debtor_id: 'another-user',
596
+ }),
597
+ ],
598
+ };
599
+
600
+ expect(() => scoreMatch(txCharge, docCharge, USER_ID)).toThrow();
601
+ });
602
+ });
603
+
604
+ describe('Edge Cases', () => {
605
+ it('should handle null business IDs', () => {
606
+ const txCharge: TransactionCharge = {
607
+ chargeId: 'charge-tx-23',
608
+ transactions: [createMockTransaction({ business_id: null })],
609
+ };
610
+
611
+ const docCharge: DocumentCharge = {
612
+ chargeId: 'charge-doc-23',
613
+ documents: [
614
+ createMockDocument({
615
+ creditor_id: USER_ID,
616
+ debtor_id: null,
617
+ }),
618
+ ],
619
+ };
620
+
621
+ const result = scoreMatch(txCharge, docCharge, USER_ID);
622
+
623
+ expect(result.components.business).toBe(0.5);
624
+ });
625
+
626
+ it('should handle zero amounts', () => {
627
+ const txCharge: TransactionCharge = {
628
+ chargeId: 'charge-tx-24',
629
+ transactions: [createMockTransaction({ amount: '0.00' })],
630
+ };
631
+
632
+ const docCharge: DocumentCharge = {
633
+ chargeId: 'charge-doc-24',
634
+ documents: [createMockDocument({ total_amount: 0 })],
635
+ };
636
+
637
+ const result = scoreMatch(txCharge, docCharge, USER_ID);
638
+
639
+ expect(result.components.amount).toBe(1.0);
640
+ });
641
+
642
+ it('should handle very large amounts', () => {
643
+ const txCharge: TransactionCharge = {
644
+ chargeId: 'charge-tx-25',
645
+ transactions: [createMockTransaction({ amount: '1000000.00' })],
646
+ };
647
+
648
+ const docCharge: DocumentCharge = {
649
+ chargeId: 'charge-doc-25',
650
+ documents: [createMockDocument({ total_amount: 1000000 })],
651
+ };
652
+
653
+ const result = scoreMatch(txCharge, docCharge, USER_ID);
654
+
655
+ expect(result.components.amount).toBe(1.0);
656
+ });
657
+ });
658
+ });
659
+ });