@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,415 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { aggregateTransactions, } from '../providers/transaction-aggregator.js';
3
+ describe('Transaction Aggregator', () => {
4
+ // Helper to create test transactions
5
+ const createTransaction = (overrides = {}) => ({
6
+ id: 'txn-' + Math.random().toString(36).substr(2, 9),
7
+ charge_id: 'charge-123',
8
+ amount: "100",
9
+ currency: 'USD',
10
+ business_id: null,
11
+ event_date: new Date('2024-01-15'),
12
+ debit_date: null,
13
+ source_description: 'Test transaction',
14
+ is_fee: false,
15
+ debit_timestamp: null,
16
+ ...overrides,
17
+ });
18
+ describe('Single Transaction', () => {
19
+ it('should return single transaction as-is', () => {
20
+ const transaction = createTransaction({
21
+ amount: "150.5",
22
+ currency: 'USD',
23
+ business_id: 'business-1',
24
+ event_date: new Date('2024-01-15'),
25
+ source_description: 'Payment from client',
26
+ });
27
+ const result = aggregateTransactions([transaction]);
28
+ expect(result).toEqual({
29
+ amount: 150.5,
30
+ currency: 'USD',
31
+ businessId: 'business-1',
32
+ date: new Date('2024-01-15'),
33
+ debitDate: null,
34
+ description: 'Payment from client',
35
+ });
36
+ });
37
+ it('should handle transaction with null business_id', () => {
38
+ const transaction = createTransaction({
39
+ amount: "200",
40
+ business_id: null,
41
+ });
42
+ const result = aggregateTransactions([transaction]);
43
+ expect(result.businessId).toBeNull();
44
+ });
45
+ it('should handle transaction with null description', () => {
46
+ const transaction = createTransaction({
47
+ source_description: null,
48
+ });
49
+ const result = aggregateTransactions([transaction]);
50
+ expect(result.description).toBe('');
51
+ });
52
+ it('should handle transaction with empty description', () => {
53
+ const transaction = createTransaction({
54
+ source_description: ' ',
55
+ });
56
+ const result = aggregateTransactions([transaction]);
57
+ expect(result.description).toBe('');
58
+ });
59
+ });
60
+ describe('Multiple Transactions - Same Currency', () => {
61
+ it('should sum amounts correctly', () => {
62
+ const transactions = [
63
+ createTransaction({ amount: "100", currency: 'USD' }),
64
+ createTransaction({ amount: "200", currency: 'USD' }),
65
+ createTransaction({ amount: "50.5", currency: 'USD' }),
66
+ ];
67
+ const result = aggregateTransactions(transactions);
68
+ expect(result.amount).toBe(350.5);
69
+ expect(result.currency).toBe('USD');
70
+ });
71
+ it('should handle negative amounts (debits)', () => {
72
+ const transactions = [
73
+ createTransaction({ amount: "-100", currency: 'ILS' }),
74
+ createTransaction({ amount: "-50", currency: 'ILS' }),
75
+ ];
76
+ const result = aggregateTransactions(transactions);
77
+ expect(result.amount).toBe(-150);
78
+ expect(result.currency).toBe('ILS');
79
+ });
80
+ it('should handle mixed positive and negative amounts', () => {
81
+ const transactions = [
82
+ createTransaction({ amount: "100", currency: 'EUR' }),
83
+ createTransaction({ amount: "-30", currency: 'EUR' }),
84
+ createTransaction({ amount: "50", currency: 'EUR' }),
85
+ ];
86
+ const result = aggregateTransactions(transactions);
87
+ expect(result.amount).toBe(120);
88
+ });
89
+ });
90
+ describe('Fee Transactions', () => {
91
+ it('should exclude transactions where is_fee is true', () => {
92
+ const transactions = [
93
+ createTransaction({ amount: "100", currency: 'USD', is_fee: false }),
94
+ createTransaction({ amount: "5", currency: 'USD', is_fee: true }), // Fee - should be excluded
95
+ createTransaction({ amount: "200", currency: 'USD', is_fee: false }),
96
+ ];
97
+ const result = aggregateTransactions(transactions);
98
+ expect(result.amount).toBe(300); // 100 + 200, fee excluded
99
+ });
100
+ it('should exclude transactions where is_fee is null but treated as false', () => {
101
+ const transactions = [
102
+ createTransaction({ amount: "100", currency: 'USD', is_fee: null }),
103
+ createTransaction({ amount: "50", currency: 'USD', is_fee: false }),
104
+ ];
105
+ const result = aggregateTransactions(transactions);
106
+ expect(result.amount).toBe(150); // Both included (null treated as false)
107
+ });
108
+ it('should throw error when all transactions are fees', () => {
109
+ const transactions = [
110
+ createTransaction({ amount: "5", is_fee: true }),
111
+ createTransaction({ amount: "3", is_fee: true }),
112
+ ];
113
+ expect(() => aggregateTransactions(transactions)).toThrow('Cannot aggregate transactions: all transactions are marked as fees');
114
+ });
115
+ it('should not include fee descriptions in concatenation', () => {
116
+ const transactions = [
117
+ createTransaction({
118
+ amount: "100",
119
+ source_description: 'Main transaction',
120
+ is_fee: false,
121
+ }),
122
+ createTransaction({ amount: "5", source_description: 'Bank fee', is_fee: true }),
123
+ ];
124
+ const result = aggregateTransactions(transactions);
125
+ expect(result.description).toBe('Main transaction');
126
+ });
127
+ });
128
+ describe('Currency Validation', () => {
129
+ it('should throw error with multiple currencies', () => {
130
+ const transactions = [
131
+ createTransaction({ amount: "100", currency: 'USD' }),
132
+ createTransaction({ amount: "200", currency: 'EUR' }),
133
+ ];
134
+ expect(() => aggregateTransactions(transactions)).toThrow('Cannot aggregate transactions: multiple currencies found (USD, EUR)');
135
+ });
136
+ it('should throw error with three different currencies', () => {
137
+ const transactions = [
138
+ createTransaction({ amount: "100", currency: 'USD' }),
139
+ createTransaction({ amount: "200", currency: 'EUR' }),
140
+ createTransaction({ amount: "300", currency: 'GBP' }),
141
+ ];
142
+ expect(() => aggregateTransactions(transactions)).toThrow(/multiple currencies found/);
143
+ });
144
+ it('should not throw error when all have same currency', () => {
145
+ const transactions = [
146
+ createTransaction({ amount: "100", currency: 'ILS' }),
147
+ createTransaction({ amount: "200", currency: 'ILS' }),
148
+ createTransaction({ amount: "300", currency: 'ILS' }),
149
+ ];
150
+ expect(() => aggregateTransactions(transactions)).not.toThrow();
151
+ });
152
+ it('should ignore currency of fee transactions in validation', () => {
153
+ const transactions = [
154
+ createTransaction({ amount: "100", currency: 'USD', is_fee: false }),
155
+ createTransaction({ amount: "5", currency: 'EUR', is_fee: true }), // Different currency but is fee
156
+ createTransaction({ amount: "200", currency: 'USD', is_fee: false }),
157
+ ];
158
+ const result = aggregateTransactions(transactions);
159
+ expect(result.currency).toBe('USD');
160
+ expect(result.amount).toBe(300);
161
+ });
162
+ });
163
+ describe('Business ID Validation', () => {
164
+ it('should throw error with multiple different business IDs', () => {
165
+ const transactions = [
166
+ createTransaction({ amount: "100", business_id: 'business-1' }),
167
+ createTransaction({ amount: "200", business_id: 'business-2' }),
168
+ ];
169
+ expect(() => aggregateTransactions(transactions)).toThrow('Cannot aggregate transactions: multiple business IDs found (business-1, business-2)');
170
+ });
171
+ it('should throw error with three different business IDs', () => {
172
+ const transactions = [
173
+ createTransaction({ amount: "100", business_id: 'business-1' }),
174
+ createTransaction({ amount: "200", business_id: 'business-2' }),
175
+ createTransaction({ amount: "300", business_id: 'business-3' }),
176
+ ];
177
+ expect(() => aggregateTransactions(transactions)).toThrow(/multiple business IDs found/);
178
+ });
179
+ it('should return null when all business IDs are null', () => {
180
+ const transactions = [
181
+ createTransaction({ amount: "100", business_id: null }),
182
+ createTransaction({ amount: "200", business_id: null }),
183
+ createTransaction({ amount: "300", business_id: null }),
184
+ ];
185
+ const result = aggregateTransactions(transactions);
186
+ expect(result.businessId).toBeNull();
187
+ });
188
+ it('should return single non-null business ID', () => {
189
+ const transactions = [
190
+ createTransaction({ amount: "100", business_id: 'business-1' }),
191
+ createTransaction({ amount: "200", business_id: null }),
192
+ createTransaction({ amount: "300", business_id: null }),
193
+ ];
194
+ const result = aggregateTransactions(transactions);
195
+ expect(result.businessId).toBe('business-1');
196
+ });
197
+ it('should handle multiple nulls and one business ID', () => {
198
+ const transactions = [
199
+ createTransaction({ amount: "100", business_id: null }),
200
+ createTransaction({ amount: "200", business_id: 'business-xyz' }),
201
+ createTransaction({ amount: "300", business_id: null }),
202
+ ];
203
+ const result = aggregateTransactions(transactions);
204
+ expect(result.businessId).toBe('business-xyz');
205
+ });
206
+ it('should not throw when all have same business ID', () => {
207
+ const transactions = [
208
+ createTransaction({ amount: "100", business_id: 'business-1' }),
209
+ createTransaction({ amount: "200", business_id: 'business-1' }),
210
+ createTransaction({ amount: "300", business_id: 'business-1' }),
211
+ ];
212
+ const result = aggregateTransactions(transactions);
213
+ expect(result.businessId).toBe('business-1');
214
+ });
215
+ it('should ignore business ID of fee transactions in validation', () => {
216
+ const transactions = [
217
+ createTransaction({ amount: "100", business_id: 'business-1', is_fee: false }),
218
+ createTransaction({ amount: "5", business_id: 'business-2', is_fee: true }), // Different business but is fee
219
+ createTransaction({ amount: "200", business_id: 'business-1', is_fee: false }),
220
+ ];
221
+ const result = aggregateTransactions(transactions);
222
+ expect(result.businessId).toBe('business-1');
223
+ });
224
+ });
225
+ describe('Date Selection', () => {
226
+ it('should select earliest event_date', () => {
227
+ const transactions = [
228
+ createTransaction({ event_date: new Date('2024-03-15') }),
229
+ createTransaction({ event_date: new Date('2024-01-10') }), // Earliest
230
+ createTransaction({ event_date: new Date('2024-02-20') }),
231
+ ];
232
+ const result = aggregateTransactions(transactions);
233
+ expect(result.date).toEqual(new Date('2024-01-10'));
234
+ });
235
+ it('should select earliest from same month', () => {
236
+ const transactions = [
237
+ createTransaction({ event_date: new Date('2024-01-20') }),
238
+ createTransaction({ event_date: new Date('2024-01-15') }), // Earliest
239
+ createTransaction({ event_date: new Date('2024-01-25') }),
240
+ ];
241
+ const result = aggregateTransactions(transactions);
242
+ expect(result.date).toEqual(new Date('2024-01-15'));
243
+ });
244
+ it('should handle dates spanning years', () => {
245
+ const transactions = [
246
+ createTransaction({ event_date: new Date('2024-01-15') }),
247
+ createTransaction({ event_date: new Date('2023-12-31') }), // Earliest (previous year)
248
+ createTransaction({ event_date: new Date('2024-02-01') }),
249
+ ];
250
+ const result = aggregateTransactions(transactions);
251
+ expect(result.date).toEqual(new Date('2023-12-31'));
252
+ });
253
+ it('should handle same date for all transactions', () => {
254
+ const transactions = [
255
+ createTransaction({ event_date: new Date('2024-01-15') }),
256
+ createTransaction({ event_date: new Date('2024-01-15') }),
257
+ ];
258
+ const result = aggregateTransactions(transactions);
259
+ expect(result.date).toEqual(new Date('2024-01-15'));
260
+ });
261
+ });
262
+ describe('Description Concatenation', () => {
263
+ it('should concatenate descriptions with line breaks', () => {
264
+ const transactions = [
265
+ createTransaction({ source_description: 'First transaction' }),
266
+ createTransaction({ source_description: 'Second transaction' }),
267
+ createTransaction({ source_description: 'Third transaction' }),
268
+ ];
269
+ const result = aggregateTransactions(transactions);
270
+ expect(result.description).toBe('First transaction\nSecond transaction\nThird transaction');
271
+ });
272
+ it('should filter out null descriptions', () => {
273
+ const transactions = [
274
+ createTransaction({ source_description: 'First' }),
275
+ createTransaction({ source_description: null }),
276
+ createTransaction({ source_description: 'Third' }),
277
+ ];
278
+ const result = aggregateTransactions(transactions);
279
+ expect(result.description).toBe('First\nThird');
280
+ });
281
+ it('should filter out empty string descriptions', () => {
282
+ const transactions = [
283
+ createTransaction({ source_description: 'First' }),
284
+ createTransaction({ source_description: ' ' }),
285
+ createTransaction({ source_description: 'Third' }),
286
+ ];
287
+ const result = aggregateTransactions(transactions);
288
+ expect(result.description).toBe('First\nThird');
289
+ });
290
+ it('should return empty string when all descriptions are null', () => {
291
+ const transactions = [
292
+ createTransaction({ source_description: null }),
293
+ createTransaction({ source_description: null }),
294
+ ];
295
+ const result = aggregateTransactions(transactions);
296
+ expect(result.description).toBe('');
297
+ });
298
+ it('should preserve order of descriptions', () => {
299
+ const transactions = [
300
+ createTransaction({ source_description: 'Alpha' }),
301
+ createTransaction({ source_description: 'Beta' }),
302
+ createTransaction({ source_description: 'Gamma' }),
303
+ ];
304
+ const result = aggregateTransactions(transactions);
305
+ expect(result.description).toBe('Alpha\nBeta\nGamma');
306
+ });
307
+ it('should handle special characters in descriptions', () => {
308
+ const transactions = [
309
+ createTransaction({ source_description: 'Payment: $100 USD' }),
310
+ createTransaction({ source_description: 'Ref #12345 (invoice)' }),
311
+ ];
312
+ const result = aggregateTransactions(transactions);
313
+ expect(result.description).toBe('Payment: $100 USD\nRef #12345 (invoice)');
314
+ });
315
+ });
316
+ describe('Input Validation', () => {
317
+ it('should throw error for empty array', () => {
318
+ expect(() => aggregateTransactions([])).toThrow('Cannot aggregate transactions: array is empty');
319
+ });
320
+ it('should throw error for null input', () => {
321
+ expect(() => aggregateTransactions(null)).toThrow('Cannot aggregate transactions: array is empty');
322
+ });
323
+ it('should throw error for undefined input', () => {
324
+ expect(() => aggregateTransactions(undefined)).toThrow('Cannot aggregate transactions: array is empty');
325
+ });
326
+ });
327
+ describe('Complex Scenarios', () => {
328
+ it('should handle real-world scenario with fees, nulls, and mixed data', () => {
329
+ const transactions = [
330
+ createTransaction({
331
+ amount: "1000",
332
+ currency: 'USD',
333
+ business_id: 'client-abc',
334
+ event_date: new Date('2024-01-15'),
335
+ source_description: 'Invoice #123 payment',
336
+ is_fee: false,
337
+ }),
338
+ createTransaction({
339
+ amount: "2.5",
340
+ currency: 'USD',
341
+ business_id: 'bank-xyz',
342
+ event_date: new Date('2024-01-15'),
343
+ source_description: 'Wire transfer fee',
344
+ is_fee: true, // Should be excluded
345
+ }),
346
+ createTransaction({
347
+ amount: "500",
348
+ currency: 'USD',
349
+ business_id: 'client-abc',
350
+ event_date: new Date('2024-01-10'), // Earlier date
351
+ source_description: 'Partial payment',
352
+ is_fee: false,
353
+ }),
354
+ createTransaction({
355
+ amount: "200",
356
+ currency: 'USD',
357
+ business_id: null, // Null business
358
+ event_date: new Date('2024-01-20'),
359
+ source_description: null, // Null description
360
+ is_fee: false,
361
+ }),
362
+ ];
363
+ const result = aggregateTransactions(transactions);
364
+ expect(result.amount).toBe(1700); // 1000 + 500 + 200 (fee excluded)
365
+ expect(result.currency).toBe('USD');
366
+ expect(result.businessId).toBe('client-abc'); // One non-null, one null
367
+ expect(result.date).toEqual(new Date('2024-01-10')); // Earliest
368
+ expect(result.description).toBe('Invoice #123 payment\nPartial payment'); // Fee desc excluded, null excluded
369
+ });
370
+ it('should handle cryptocurrency transactions', () => {
371
+ const transactions = [
372
+ createTransaction({ amount: "0.5", currency: 'ETH' }),
373
+ createTransaction({ amount: "0.3", currency: 'ETH' }),
374
+ ];
375
+ const result = aggregateTransactions(transactions);
376
+ expect(result.amount).toBe(0.8);
377
+ expect(result.currency).toBe('ETH');
378
+ });
379
+ it('should handle large number of transactions', () => {
380
+ const transactions = Array.from({ length: 100 }, (_, i) => createTransaction({
381
+ amount: "10",
382
+ currency: 'USD',
383
+ event_date: new Date(`2024-01-${(i % 28) + 1}`),
384
+ }));
385
+ const result = aggregateTransactions(transactions);
386
+ expect(result.amount).toBe(1000); // 100 × 10
387
+ expect(result.currency).toBe('USD');
388
+ });
389
+ });
390
+ describe('Error Messages', () => {
391
+ it('should provide descriptive error for mixed currencies', () => {
392
+ const transactions = [
393
+ createTransaction({ currency: 'USD' }),
394
+ createTransaction({ currency: 'EUR' }),
395
+ createTransaction({ currency: 'GBP' }),
396
+ ];
397
+ expect(() => aggregateTransactions(transactions)).toThrow(/multiple currencies found \(USD, EUR, GBP\)/);
398
+ });
399
+ it('should provide descriptive error for multiple business IDs', () => {
400
+ const transactions = [
401
+ createTransaction({ business_id: 'business-a' }),
402
+ createTransaction({ business_id: 'business-b' }),
403
+ ];
404
+ expect(() => aggregateTransactions(transactions)).toThrow(/multiple business IDs found \(business-a, business-b\)/);
405
+ });
406
+ it('should provide descriptive error for all fees', () => {
407
+ const transactions = [createTransaction({ is_fee: true })];
408
+ expect(() => aggregateTransactions(transactions)).toThrow('all transactions are marked as fees');
409
+ });
410
+ it('should provide descriptive error for empty array', () => {
411
+ expect(() => aggregateTransactions([])).toThrow('array is empty');
412
+ });
413
+ });
414
+ });
415
+ //# sourceMappingURL=transaction-aggregator.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transaction-aggregator.test.js","sourceRoot":"","sources":["../../../../../../src/modules/charges-matcher/__tests__/transaction-aggregator.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Calculate confidence score based on amount similarity
3
+ * @param transactionAmount - The transaction amount (signed number)
4
+ * @param documentAmount - The normalized document amount (signed number)
5
+ * @returns Confidence score between 0.0 and 1.0
6
+ */
7
+ export declare function calculateAmountConfidence(transactionAmount: number, documentAmount: number): number;
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Calculate the absolute difference between two numbers as a percentage of the smaller absolute value
3
+ * @param amount1 - First amount
4
+ * @param amount2 - Second amount
5
+ * @returns Percentage difference (0-100+)
6
+ */
7
+ function calculatePercentageDiff(amount1, amount2) {
8
+ const abs1 = Math.abs(amount1);
9
+ const abs2 = Math.abs(amount2);
10
+ const smallerAmount = Math.min(abs1, abs2);
11
+ // Handle zero amounts - if one is zero, we can't calculate percentage
12
+ // In this case, treat any difference > 1 as beyond 20%
13
+ if (smallerAmount === 0) {
14
+ return 100; // Return a high percentage to indicate no match
15
+ }
16
+ const diff = Math.abs(abs1 - abs2);
17
+ return (diff / smallerAmount) * 100;
18
+ }
19
+ /**
20
+ * Calculate confidence score based on amount similarity
21
+ * @param transactionAmount - The transaction amount (signed number)
22
+ * @param documentAmount - The normalized document amount (signed number)
23
+ * @returns Confidence score between 0.0 and 1.0
24
+ */
25
+ export function calculateAmountConfidence(transactionAmount, documentAmount) {
26
+ // Calculate absolute difference
27
+ const absoluteDiff = Math.abs(Math.abs(transactionAmount) - Math.abs(documentAmount));
28
+ // Exact match (0% difference): 1.0
29
+ if (absoluteDiff === 0) {
30
+ return 1.0;
31
+ }
32
+ // Within 1 currency unit: 0.9
33
+ if (absoluteDiff <= 1) {
34
+ return 0.9;
35
+ }
36
+ // Calculate percentage difference for amounts beyond 1 unit
37
+ const percentageDiff = calculatePercentageDiff(transactionAmount, documentAmount);
38
+ // 20%+ difference: 0.0
39
+ if (percentageDiff >= 20) {
40
+ return 0.0;
41
+ }
42
+ // Between 1 unit and 20% difference: Linear degradation from 0.7 to 0.0
43
+ // We need to determine which threshold is reached first:
44
+ // - The absolute difference exceeds 1 unit (already true at this point)
45
+ // - The percentage difference reaches 20%
46
+ // Linear interpolation from 0.7 (at percentage start) to 0.0 (at 20%)
47
+ // We need to find where we are in the range
48
+ // Calculate what percentage corresponds to 1 unit difference
49
+ const abs1 = Math.abs(transactionAmount);
50
+ const abs2 = Math.abs(documentAmount);
51
+ const smallerAmount = Math.min(abs1, abs2);
52
+ const oneUnitPercentage = (1 / smallerAmount) * 100;
53
+ // If we're still within the percentage range that corresponds to 1 unit,
54
+ // this shouldn't happen since we already checked absoluteDiff <= 1 above
55
+ // But just in case of floating point issues
56
+ if (percentageDiff <= oneUnitPercentage) {
57
+ return 0.9;
58
+ }
59
+ // Linear degradation from 0.7 to 0.0 over the range [oneUnitPercentage, 20%]
60
+ const rangeStart = oneUnitPercentage;
61
+ const rangeEnd = 20;
62
+ const rangeSpan = rangeEnd - rangeStart;
63
+ // How far are we into this range? (0.0 = at start, 1.0 = at end)
64
+ const position = (percentageDiff - rangeStart) / rangeSpan;
65
+ // Linear degradation from 0.7 to 0.0
66
+ const confidence = 0.7 * (1 - position);
67
+ // Round to 2 decimal places
68
+ return Math.round(confidence * 100) / 100;
69
+ }
70
+ //# sourceMappingURL=amount-confidence.helper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"amount-confidence.helper.js","sourceRoot":"","sources":["../../../../../../src/modules/charges-matcher/helpers/amount-confidence.helper.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,SAAS,uBAAuB,CAAC,OAAe,EAAE,OAAe;IAC/D,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAC/B,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAC/B,MAAM,aAAa,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAE3C,sEAAsE;IACtE,uDAAuD;IACvD,IAAI,aAAa,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO,GAAG,CAAC,CAAC,gDAAgD;IAC9D,CAAC;IAED,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC;IACnC,OAAO,CAAC,IAAI,GAAG,aAAa,CAAC,GAAG,GAAG,CAAC;AACtC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,yBAAyB,CACvC,iBAAyB,EACzB,cAAsB;IAEtB,gCAAgC;IAChC,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,iBAAiB,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC;IAEtF,mCAAmC;IACnC,IAAI,YAAY,KAAK,CAAC,EAAE,CAAC;QACvB,OAAO,GAAG,CAAC;IACb,CAAC;IAED,8BAA8B;IAC9B,IAAI,YAAY,IAAI,CAAC,EAAE,CAAC;QACtB,OAAO,GAAG,CAAC;IACb,CAAC;IAED,4DAA4D;IAC5D,MAAM,cAAc,GAAG,uBAAuB,CAAC,iBAAiB,EAAE,cAAc,CAAC,CAAC;IAElF,uBAAuB;IACvB,IAAI,cAAc,IAAI,EAAE,EAAE,CAAC;QACzB,OAAO,GAAG,CAAC;IACb,CAAC;IAED,wEAAwE;IACxE,yDAAyD;IACzD,wEAAwE;IACxE,0CAA0C;IAE1C,sEAAsE;IACtE,4CAA4C;IAE5C,6DAA6D;IAC7D,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;IACzC,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IACtC,MAAM,aAAa,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAE3C,MAAM,iBAAiB,GAAG,CAAC,CAAC,GAAG,aAAa,CAAC,GAAG,GAAG,CAAC;IAEpD,yEAAyE;IACzE,yEAAyE;IACzE,4CAA4C;IAC5C,IAAI,cAAc,IAAI,iBAAiB,EAAE,CAAC;QACxC,OAAO,GAAG,CAAC;IACb,CAAC;IAED,6EAA6E;IAC7E,MAAM,UAAU,GAAG,iBAAiB,CAAC;IACrC,MAAM,QAAQ,GAAG,EAAE,CAAC;IACpB,MAAM,SAAS,GAAG,QAAQ,GAAG,UAAU,CAAC;IAExC,iEAAiE;IACjE,MAAM,QAAQ,GAAG,CAAC,cAAc,GAAG,UAAU,CAAC,GAAG,SAAS,CAAC;IAE3D,qCAAqC;IACrC,MAAM,UAAU,GAAG,GAAG,GAAG,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC;IAExC,4BAA4B;IAC5B,OAAO,IAAI,CAAC,KAAK,CAAC,UAAU,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC;AAC5C,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Calculate confidence score based on business ID match
3
+ * @param transactionBusinessId - Business ID from transaction (can be null)
4
+ * @param documentBusinessId - Business ID from document (can be null)
5
+ * @returns Confidence score: 1.0 (exact match), 0.5 (one or both null), 0.2 (mismatch)
6
+ */
7
+ export declare function calculateBusinessConfidence(transactionBusinessId: string | null, documentBusinessId: string | null): number;
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Calculate confidence score based on business ID match
3
+ * @param transactionBusinessId - Business ID from transaction (can be null)
4
+ * @param documentBusinessId - Business ID from document (can be null)
5
+ * @returns Confidence score: 1.0 (exact match), 0.5 (one or both null), 0.2 (mismatch)
6
+ */
7
+ export function calculateBusinessConfidence(transactionBusinessId, documentBusinessId) {
8
+ // If either or both are null, return 0.5
9
+ if (transactionBusinessId === null || documentBusinessId === null) {
10
+ return 0.5;
11
+ }
12
+ // Both are non-null, check if they match
13
+ if (transactionBusinessId === documentBusinessId) {
14
+ return 1.0;
15
+ }
16
+ // Both are non-null but don't match
17
+ return 0.2;
18
+ }
19
+ //# sourceMappingURL=business-confidence.helper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"business-confidence.helper.js","sourceRoot":"","sources":["../../../../../../src/modules/charges-matcher/helpers/business-confidence.helper.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,UAAU,2BAA2B,CACzC,qBAAoC,EACpC,kBAAiC;IAEjC,yCAAyC;IACzC,IAAI,qBAAqB,KAAK,IAAI,IAAI,kBAAkB,KAAK,IAAI,EAAE,CAAC;QAClE,OAAO,GAAG,CAAC;IACb,CAAC;IAED,yCAAyC;IACzC,IAAI,qBAAqB,KAAK,kBAAkB,EAAE,CAAC;QACjD,OAAO,GAAG,CAAC;IACb,CAAC;IAED,oCAAoC;IACpC,OAAO,GAAG,CAAC;AACb,CAAC"}
@@ -0,0 +1,24 @@
1
+ import type { Document, Transaction } from '../types.js';
2
+ /**
3
+ * Filter transactions that should be excluded from matching
4
+ * Excludes transactions marked as fees (is_fee = true)
5
+ * @param transaction - Transaction to check
6
+ * @returns true if transaction should be included in matching
7
+ */
8
+ export declare function isValidTransactionForMatching(transaction: Transaction): boolean;
9
+ /**
10
+ * Filter documents that should be excluded from matching
11
+ * Excludes documents with null mandatory fields (total_amount or currency_code)
12
+ * @param document - Document to check
13
+ * @returns true if document should be included in matching
14
+ */
15
+ export declare function isValidDocumentForMatching(document: Document): boolean;
16
+ /**
17
+ * Check if a date falls within the matching window
18
+ * Window is calculated as ±windowMonths from the reference date
19
+ * @param candidateDate - Date to check
20
+ * @param referenceDate - Center point of the window
21
+ * @param windowMonths - Number of months before/after (default 12)
22
+ * @returns true if within window
23
+ */
24
+ export declare function isWithinDateWindow(candidateDate: Date, referenceDate: Date, windowMonths?: number): boolean;
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Filter transactions that should be excluded from matching
3
+ * Excludes transactions marked as fees (is_fee = true)
4
+ * @param transaction - Transaction to check
5
+ * @returns true if transaction should be included in matching
6
+ */
7
+ export function isValidTransactionForMatching(transaction) {
8
+ // Exclude fee transactions
9
+ return !transaction.is_fee;
10
+ }
11
+ /**
12
+ * Filter documents that should be excluded from matching
13
+ * Excludes documents with null mandatory fields (total_amount or currency_code)
14
+ * @param document - Document to check
15
+ * @returns true if document should be included in matching
16
+ */
17
+ export function isValidDocumentForMatching(document) {
18
+ // Document must have total_amount (can be zero, but not null)
19
+ if (document.total_amount === null || document.total_amount === undefined) {
20
+ return false;
21
+ }
22
+ // Document must have currency_code
23
+ if (!document.currency_code) {
24
+ return false;
25
+ }
26
+ return true;
27
+ }
28
+ /**
29
+ * Check if a date falls within the matching window
30
+ * Window is calculated as ±windowMonths from the reference date
31
+ * @param candidateDate - Date to check
32
+ * @param referenceDate - Center point of the window
33
+ * @param windowMonths - Number of months before/after (default 12)
34
+ * @returns true if within window
35
+ */
36
+ export function isWithinDateWindow(candidateDate, referenceDate, windowMonths = 12) {
37
+ // Calculate the date range
38
+ const minDate = new Date(referenceDate);
39
+ minDate.setMonth(minDate.getMonth() - windowMonths);
40
+ const maxDate = new Date(referenceDate);
41
+ maxDate.setMonth(maxDate.getMonth() + windowMonths);
42
+ // Check if candidate is within range (inclusive)
43
+ return candidateDate >= minDate && candidateDate <= maxDate;
44
+ }
45
+ //# sourceMappingURL=candidate-filter.helper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"candidate-filter.helper.js","sourceRoot":"","sources":["../../../../../../src/modules/charges-matcher/helpers/candidate-filter.helper.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,MAAM,UAAU,6BAA6B,CAAC,WAAwB;IACpE,2BAA2B;IAC3B,OAAO,CAAC,WAAW,CAAC,MAAM,CAAC;AAC7B,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,0BAA0B,CAAC,QAAkB;IAC3D,8DAA8D;IAC9D,IAAI,QAAQ,CAAC,YAAY,KAAK,IAAI,IAAI,QAAQ,CAAC,YAAY,KAAK,SAAS,EAAE,CAAC;QAC1E,OAAO,KAAK,CAAC;IACf,CAAC;IAED,mCAAmC;IACnC,IAAI,CAAC,QAAQ,CAAC,aAAa,EAAE,CAAC;QAC5B,OAAO,KAAK,CAAC;IACf,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,kBAAkB,CAChC,aAAmB,EACnB,aAAmB,EACnB,eAAuB,EAAE;IAEzB,2BAA2B;IAC3B,MAAM,OAAO,GAAG,IAAI,IAAI,CAAC,aAAa,CAAC,CAAC;IACxC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,EAAE,GAAG,YAAY,CAAC,CAAC;IAEpD,MAAM,OAAO,GAAG,IAAI,IAAI,CAAC,aAAa,CAAC,CAAC;IACxC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,EAAE,GAAG,YAAY,CAAC,CAAC;IAEpD,iDAAiD;IACjD,OAAO,aAAa,IAAI,OAAO,IAAI,aAAa,IAAI,OAAO,CAAC;AAC9D,CAAC"}