@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,374 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import {
3
+ validateChargeForMatching,
4
+ validateChargeIsUnmatched,
5
+ isChargeMatched,
6
+ hasOnlyTransactions,
7
+ hasOnlyDocuments,
8
+ } from '../helpers/charge-validator.helper.js';
9
+ import { createMockTransaction, createMockDocument } from './test-helpers.js';
10
+
11
+ describe('Charge Validator', () => {
12
+ describe('validateChargeForMatching', () => {
13
+ it('should pass for charge with transactions', () => {
14
+ const charge = {
15
+ id: 'charge-1',
16
+ owner_id: 'user-1',
17
+ transactions: [createMockTransaction({ charge_id: 'charge-1' })],
18
+ documents: [],
19
+ };
20
+
21
+ expect(() => validateChargeForMatching(charge)).not.toThrow();
22
+ });
23
+
24
+ it('should pass for charge with documents', () => {
25
+ const charge = {
26
+ id: 'charge-1',
27
+ owner_id: 'user-1',
28
+ transactions: [],
29
+ documents: [createMockDocument({ charge_id: 'charge-1', type: 'INVOICE' })],
30
+ };
31
+
32
+ expect(() => validateChargeForMatching(charge)).not.toThrow();
33
+ });
34
+
35
+ it('should pass for charge with both transactions and documents', () => {
36
+ const charge = {
37
+ id: 'charge-1',
38
+ owner_id: 'user-1',
39
+ transactions: [createMockTransaction({ charge_id: 'charge-1' })],
40
+ documents: [createMockDocument({ charge_id: 'charge-1', type: 'INVOICE' })],
41
+ };
42
+
43
+ expect(() => validateChargeForMatching(charge)).not.toThrow();
44
+ });
45
+
46
+ it('should throw if charge is null', () => {
47
+ expect(() => validateChargeForMatching(null as any)).toThrow('Charge is required');
48
+ });
49
+
50
+ it('should throw if charge is undefined', () => {
51
+ expect(() => validateChargeForMatching(undefined as any)).toThrow('Charge is required');
52
+ });
53
+
54
+ it('should throw if charge has no ID', () => {
55
+ const charge = {
56
+ id: '',
57
+ owner_id: 'user-1',
58
+ transactions: [createMockTransaction()],
59
+ documents: [],
60
+ };
61
+
62
+ expect(() => validateChargeForMatching(charge)).toThrow('Charge must have an ID');
63
+ });
64
+
65
+ it('should throw if charge has no owner_id', () => {
66
+ const charge = {
67
+ id: 'charge-1',
68
+ owner_id: null,
69
+ transactions: [createMockTransaction({ charge_id: 'charge-1' })],
70
+ documents: [],
71
+ };
72
+
73
+ expect(() => validateChargeForMatching(charge)).toThrow('must have an owner_id');
74
+ });
75
+
76
+ it('should throw if charge has no transactions and no documents', () => {
77
+ const charge = {
78
+ id: 'charge-1',
79
+ owner_id: 'user-1',
80
+ transactions: [],
81
+ documents: [],
82
+ };
83
+
84
+ expect(() => validateChargeForMatching(charge)).toThrow(
85
+ 'has no transactions or documents',
86
+ );
87
+ });
88
+
89
+ it('should throw if charge has undefined transactions and documents', () => {
90
+ const charge = {
91
+ id: 'charge-1',
92
+ owner_id: 'user-1',
93
+ transactions: undefined,
94
+ documents: undefined,
95
+ };
96
+
97
+ expect(() => validateChargeForMatching(charge)).toThrow(
98
+ 'has no transactions or documents',
99
+ );
100
+ });
101
+ });
102
+
103
+ describe('isChargeMatched', () => {
104
+ it('should return true for charge with transactions and accounting documents', () => {
105
+ const charge = {
106
+ id: 'charge-1',
107
+ owner_id: 'user-1',
108
+ transactions: [createMockTransaction({ charge_id: 'charge-1' })],
109
+ documents: [createMockDocument({ charge_id: 'charge-1', type: 'INVOICE' })],
110
+ };
111
+
112
+ expect(isChargeMatched(charge)).toBe(true);
113
+ });
114
+
115
+ it('should return true for charge with CREDIT_INVOICE', () => {
116
+ const charge = {
117
+ id: 'charge-1',
118
+ owner_id: 'user-1',
119
+ transactions: [createMockTransaction({ charge_id: 'charge-1' })],
120
+ documents: [createMockDocument({ charge_id: 'charge-1', type: 'CREDIT_INVOICE' })],
121
+ };
122
+
123
+ expect(isChargeMatched(charge)).toBe(true);
124
+ });
125
+
126
+ it('should return true for charge with RECEIPT', () => {
127
+ const charge = {
128
+ id: 'charge-1',
129
+ owner_id: 'user-1',
130
+ transactions: [createMockTransaction({ charge_id: 'charge-1' })],
131
+ documents: [createMockDocument({ charge_id: 'charge-1', type: 'RECEIPT' })],
132
+ };
133
+
134
+ expect(isChargeMatched(charge)).toBe(true);
135
+ });
136
+
137
+ it('should return true for charge with INVOICE_RECEIPT', () => {
138
+ const charge = {
139
+ id: 'charge-1',
140
+ owner_id: 'user-1',
141
+ transactions: [createMockTransaction({ charge_id: 'charge-1' })],
142
+ documents: [createMockDocument({ charge_id: 'charge-1', type: 'INVOICE_RECEIPT' })],
143
+ };
144
+
145
+ expect(isChargeMatched(charge)).toBe(true);
146
+ });
147
+
148
+ it('should return false for charge with only transactions', () => {
149
+ const charge = {
150
+ id: 'charge-1',
151
+ owner_id: 'user-1',
152
+ transactions: [createMockTransaction({ charge_id: 'charge-1' })],
153
+ documents: [],
154
+ };
155
+
156
+ expect(isChargeMatched(charge)).toBe(false);
157
+ });
158
+
159
+ it('should return false for charge with only documents', () => {
160
+ const charge = {
161
+ id: 'charge-1',
162
+ owner_id: 'user-1',
163
+ transactions: [],
164
+ documents: [createMockDocument({ charge_id: 'charge-1', type: 'INVOICE' })],
165
+ };
166
+
167
+ expect(isChargeMatched(charge)).toBe(false);
168
+ });
169
+
170
+ it('should return false for charge with transactions and PROFORMA (non-accounting doc)', () => {
171
+ const charge = {
172
+ id: 'charge-1',
173
+ owner_id: 'user-1',
174
+ transactions: [createMockTransaction({ charge_id: 'charge-1' })],
175
+ documents: [createMockDocument({ charge_id: 'charge-1', type: 'PROFORMA' })],
176
+ };
177
+
178
+ expect(isChargeMatched(charge)).toBe(false);
179
+ });
180
+
181
+ it('should return false for charge with transactions and OTHER (non-accounting doc)', () => {
182
+ const charge = {
183
+ id: 'charge-1',
184
+ owner_id: 'user-1',
185
+ transactions: [createMockTransaction({ charge_id: 'charge-1' })],
186
+ documents: [createMockDocument({ charge_id: 'charge-1', type: 'OTHER' })],
187
+ };
188
+
189
+ expect(isChargeMatched(charge)).toBe(false);
190
+ });
191
+
192
+ it('should return false for charge with transactions and UNPROCESSED (non-accounting doc)', () => {
193
+ const charge = {
194
+ id: 'charge-1',
195
+ owner_id: 'user-1',
196
+ transactions: [createMockTransaction({ charge_id: 'charge-1' })],
197
+ documents: [createMockDocument({ charge_id: 'charge-1', type: 'UNPROCESSED' })],
198
+ };
199
+
200
+ expect(isChargeMatched(charge)).toBe(false);
201
+ });
202
+ });
203
+
204
+ describe('hasOnlyTransactions', () => {
205
+ it('should return true for charge with only transactions', () => {
206
+ const charge = {
207
+ id: 'charge-1',
208
+ owner_id: 'user-1',
209
+ transactions: [createMockTransaction({ charge_id: 'charge-1' })],
210
+ documents: [],
211
+ };
212
+
213
+ expect(hasOnlyTransactions(charge)).toBe(true);
214
+ });
215
+
216
+ it('should return true for charge with transactions and non-accounting documents', () => {
217
+ const charge = {
218
+ id: 'charge-1',
219
+ owner_id: 'user-1',
220
+ transactions: [createMockTransaction({ charge_id: 'charge-1' })],
221
+ documents: [createMockDocument({ charge_id: 'charge-1', type: 'PROFORMA' })],
222
+ };
223
+
224
+ expect(hasOnlyTransactions(charge)).toBe(true);
225
+ });
226
+
227
+ it('should return false for charge with transactions and accounting documents', () => {
228
+ const charge = {
229
+ id: 'charge-1',
230
+ owner_id: 'user-1',
231
+ transactions: [createMockTransaction({ charge_id: 'charge-1' })],
232
+ documents: [createMockDocument({ charge_id: 'charge-1', type: 'INVOICE' })],
233
+ };
234
+
235
+ expect(hasOnlyTransactions(charge)).toBe(false);
236
+ });
237
+
238
+ it('should return false for charge with only documents', () => {
239
+ const charge = {
240
+ id: 'charge-1',
241
+ owner_id: 'user-1',
242
+ transactions: [],
243
+ documents: [createMockDocument({ charge_id: 'charge-1', type: 'INVOICE' })],
244
+ };
245
+
246
+ expect(hasOnlyTransactions(charge)).toBe(false);
247
+ });
248
+
249
+ it('should return false for charge with no data', () => {
250
+ const charge = {
251
+ id: 'charge-1',
252
+ owner_id: 'user-1',
253
+ transactions: [],
254
+ documents: [],
255
+ };
256
+
257
+ expect(hasOnlyTransactions(charge)).toBe(false);
258
+ });
259
+ });
260
+
261
+ describe('hasOnlyDocuments', () => {
262
+ it('should return true for charge with only accounting documents', () => {
263
+ const charge = {
264
+ id: 'charge-1',
265
+ owner_id: 'user-1',
266
+ transactions: [],
267
+ documents: [createMockDocument({ charge_id: 'charge-1', type: 'INVOICE' })],
268
+ };
269
+
270
+ expect(hasOnlyDocuments(charge)).toBe(true);
271
+ });
272
+
273
+ it('should return true for charge with CREDIT_INVOICE', () => {
274
+ const charge = {
275
+ id: 'charge-1',
276
+ owner_id: 'user-1',
277
+ transactions: [],
278
+ documents: [createMockDocument({ charge_id: 'charge-1', type: 'CREDIT_INVOICE' })],
279
+ };
280
+
281
+ expect(hasOnlyDocuments(charge)).toBe(true);
282
+ });
283
+
284
+ it('should return false for charge with only non-accounting documents', () => {
285
+ const charge = {
286
+ id: 'charge-1',
287
+ owner_id: 'user-1',
288
+ transactions: [],
289
+ documents: [createMockDocument({ charge_id: 'charge-1', type: 'PROFORMA' })],
290
+ };
291
+
292
+ expect(hasOnlyDocuments(charge)).toBe(false);
293
+ });
294
+
295
+ it('should return false for charge with transactions and documents', () => {
296
+ const charge = {
297
+ id: 'charge-1',
298
+ owner_id: 'user-1',
299
+ transactions: [createMockTransaction({ charge_id: 'charge-1' })],
300
+ documents: [createMockDocument({ charge_id: 'charge-1', type: 'INVOICE' })],
301
+ };
302
+
303
+ expect(hasOnlyDocuments(charge)).toBe(false);
304
+ });
305
+
306
+ it('should return false for charge with only transactions', () => {
307
+ const charge = {
308
+ id: 'charge-1',
309
+ owner_id: 'user-1',
310
+ transactions: [createMockTransaction({ charge_id: 'charge-1' })],
311
+ documents: [],
312
+ };
313
+
314
+ expect(hasOnlyDocuments(charge)).toBe(false);
315
+ });
316
+
317
+ it('should return false for charge with no data', () => {
318
+ const charge = {
319
+ id: 'charge-1',
320
+ owner_id: 'user-1',
321
+ transactions: [],
322
+ documents: [],
323
+ };
324
+
325
+ expect(hasOnlyDocuments(charge)).toBe(false);
326
+ });
327
+ });
328
+
329
+ describe('validateChargeIsUnmatched', () => {
330
+ it('should pass for charge with only transactions', () => {
331
+ const charge = {
332
+ id: 'charge-1',
333
+ owner_id: 'user-1',
334
+ transactions: [createMockTransaction({ charge_id: 'charge-1' })],
335
+ documents: [],
336
+ };
337
+
338
+ expect(() => validateChargeIsUnmatched(charge)).not.toThrow();
339
+ });
340
+
341
+ it('should pass for charge with only documents', () => {
342
+ const charge = {
343
+ id: 'charge-1',
344
+ owner_id: 'user-1',
345
+ transactions: [],
346
+ documents: [createMockDocument({ charge_id: 'charge-1', type: 'INVOICE' })],
347
+ };
348
+
349
+ expect(() => validateChargeIsUnmatched(charge)).not.toThrow();
350
+ });
351
+
352
+ it('should throw for charge with both transactions and accounting documents', () => {
353
+ const charge = {
354
+ id: 'charge-1',
355
+ owner_id: 'user-1',
356
+ transactions: [createMockTransaction({ charge_id: 'charge-1' })],
357
+ documents: [createMockDocument({ charge_id: 'charge-1', type: 'INVOICE' })],
358
+ };
359
+
360
+ expect(() => validateChargeIsUnmatched(charge)).toThrow('is already matched');
361
+ });
362
+
363
+ it('should propagate validation errors', () => {
364
+ const charge = {
365
+ id: 'charge-1',
366
+ owner_id: null,
367
+ transactions: [createMockTransaction({ charge_id: 'charge-1' })],
368
+ documents: [],
369
+ };
370
+
371
+ expect(() => validateChargeIsUnmatched(charge)).toThrow('must have an owner_id');
372
+ });
373
+ });
374
+ });
@@ -0,0 +1,164 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { calculateCurrencyConfidence } from '../helpers/currency-confidence.helper.js';
3
+
4
+ describe('calculateCurrencyConfidence', () => {
5
+ describe('same currency', () => {
6
+ it('should return 1.0 for identical USD', () => {
7
+ expect(calculateCurrencyConfidence('USD', 'USD')).toBe(1.0);
8
+ });
9
+
10
+ it('should return 1.0 for identical EUR', () => {
11
+ expect(calculateCurrencyConfidence('EUR', 'EUR')).toBe(1.0);
12
+ });
13
+
14
+ it('should return 1.0 for identical ILS', () => {
15
+ expect(calculateCurrencyConfidence('ILS', 'ILS')).toBe(1.0);
16
+ });
17
+
18
+ it('should return 1.0 for identical GBP', () => {
19
+ expect(calculateCurrencyConfidence('GBP', 'GBP')).toBe(1.0);
20
+ });
21
+
22
+ it('should return 1.0 for identical USDC', () => {
23
+ expect(calculateCurrencyConfidence('USDC', 'USDC')).toBe(1.0);
24
+ });
25
+
26
+ it('should return 1.0 for identical GRT', () => {
27
+ expect(calculateCurrencyConfidence('GRT', 'GRT')).toBe(1.0);
28
+ });
29
+
30
+ it('should return 1.0 for identical ETH', () => {
31
+ expect(calculateCurrencyConfidence('ETH', 'ETH')).toBe(1.0);
32
+ });
33
+ });
34
+
35
+ describe('different currencies', () => {
36
+ it('should return 0.0 for USD vs EUR', () => {
37
+ expect(calculateCurrencyConfidence('USD', 'EUR')).toBe(0.0);
38
+ });
39
+
40
+ it('should return 0.0 for ILS vs USD', () => {
41
+ expect(calculateCurrencyConfidence('ILS', 'USD')).toBe(0.0);
42
+ });
43
+
44
+ it('should return 0.0 for EUR vs GBP', () => {
45
+ expect(calculateCurrencyConfidence('EUR', 'GBP')).toBe(0.0);
46
+ });
47
+
48
+ it('should return 0.0 for GRT vs ETH', () => {
49
+ expect(calculateCurrencyConfidence('GRT', 'ETH')).toBe(0.0);
50
+ });
51
+
52
+ it('should return 0.0 for USDC vs USD', () => {
53
+ expect(calculateCurrencyConfidence('USDC', 'USD')).toBe(0.0);
54
+ });
55
+ });
56
+
57
+ describe('case sensitivity', () => {
58
+ it('should be case-insensitive for uppercase vs lowercase', () => {
59
+ expect(calculateCurrencyConfidence('USD', 'usd')).toBe(1.0);
60
+ });
61
+
62
+ it('should be case-insensitive for lowercase vs uppercase', () => {
63
+ expect(calculateCurrencyConfidence('eur', 'EUR')).toBe(1.0);
64
+ });
65
+
66
+ it('should be case-insensitive for mixed case', () => {
67
+ expect(calculateCurrencyConfidence('Usd', 'UsD')).toBe(1.0);
68
+ });
69
+
70
+ it('should be case-insensitive for ILS variations', () => {
71
+ expect(calculateCurrencyConfidence('ILS', 'ils')).toBe(1.0);
72
+ expect(calculateCurrencyConfidence('ils', 'ILS')).toBe(1.0);
73
+ });
74
+ });
75
+
76
+ describe('edge cases with null and undefined', () => {
77
+ it('should return 0.2 when transaction currency is null', () => {
78
+ expect(calculateCurrencyConfidence(null, 'USD')).toBe(0.2);
79
+ });
80
+
81
+ it('should return 0.2 when document currency is null', () => {
82
+ expect(calculateCurrencyConfidence('USD', null)).toBe(0.2);
83
+ });
84
+
85
+ it('should return 0.2 when both currencies are null', () => {
86
+ expect(calculateCurrencyConfidence(null, null)).toBe(0.2);
87
+ });
88
+
89
+ it('should return 0.2 when transaction currency is undefined', () => {
90
+ expect(calculateCurrencyConfidence(undefined, 'USD')).toBe(0.2);
91
+ });
92
+
93
+ it('should return 0.2 when document currency is undefined', () => {
94
+ expect(calculateCurrencyConfidence('USD', undefined)).toBe(0.2);
95
+ });
96
+
97
+ it('should return 0.2 when both currencies are undefined', () => {
98
+ expect(calculateCurrencyConfidence(undefined, undefined)).toBe(0.2);
99
+ });
100
+
101
+ it('should return 0.2 when transaction is null and document is undefined', () => {
102
+ expect(calculateCurrencyConfidence(null, undefined)).toBe(0.2);
103
+ });
104
+
105
+ it('should return 0.2 when transaction is undefined and document is null', () => {
106
+ expect(calculateCurrencyConfidence(undefined, null)).toBe(0.2);
107
+ });
108
+ });
109
+
110
+ describe('edge cases with empty strings', () => {
111
+ it('should return 0.2 when transaction currency is empty string', () => {
112
+ expect(calculateCurrencyConfidence('', 'USD')).toBe(0.2);
113
+ });
114
+
115
+ it('should return 0.2 when document currency is empty string', () => {
116
+ expect(calculateCurrencyConfidence('USD', '')).toBe(0.2);
117
+ });
118
+
119
+ it('should return 0.2 when both currencies are empty strings', () => {
120
+ expect(calculateCurrencyConfidence('', '')).toBe(0.2);
121
+ });
122
+ });
123
+
124
+ describe('symmetry', () => {
125
+ it('should return same result regardless of parameter order for same currencies', () => {
126
+ expect(calculateCurrencyConfidence('USD', 'EUR')).toBe(
127
+ calculateCurrencyConfidence('EUR', 'USD'),
128
+ );
129
+ });
130
+
131
+ it('should return same result regardless of parameter order for matching currencies', () => {
132
+ expect(calculateCurrencyConfidence('USD', 'USD')).toBe(
133
+ calculateCurrencyConfidence('USD', 'USD'),
134
+ );
135
+ });
136
+ });
137
+
138
+ describe('return value validation', () => {
139
+ it('should return exactly 1.0, 0.2, or 0.0 (no other values)', () => {
140
+ const result1 = calculateCurrencyConfidence('USD', 'USD');
141
+ const result2 = calculateCurrencyConfidence('USD', 'EUR');
142
+ const result3 = calculateCurrencyConfidence(null, 'USD');
143
+
144
+ expect([1.0, 0.2, 0.0]).toContain(result1);
145
+ expect([1.0, 0.2, 0.0]).toContain(result2);
146
+ expect([1.0, 0.2, 0.0]).toContain(result3);
147
+ });
148
+
149
+ it('should return numbers with correct precision', () => {
150
+ const match = calculateCurrencyConfidence('USD', 'USD');
151
+ const mismatch = calculateCurrencyConfidence('USD', 'EUR');
152
+ const missing = calculateCurrencyConfidence(null, 'USD');
153
+
154
+ expect(match).toBe(1.0);
155
+ expect(mismatch).toBe(0.0);
156
+ expect(missing).toBe(0.2);
157
+
158
+ // Verify exact values
159
+ expect(match === 1.0).toBe(true);
160
+ expect(mismatch === 0.0).toBe(true);
161
+ expect(missing === 0.2).toBe(true);
162
+ });
163
+ });
164
+ });