@dalmore/api-contracts 1.0.3 → 1.0.6

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 (186) hide show
  1. package/README.md +34 -60
  2. package/index.mjs +1001 -18638
  3. package/package.json +5 -53
  4. package/src/common/types/address.spec.ts +203 -0
  5. package/src/common/types/batch-jobs.types.ts +1 -0
  6. package/src/common/types/common.types.spec.ts +336 -0
  7. package/src/common/types/files.types.spec.ts +154 -0
  8. package/src/common/types/issuer-payment-method.types.spec.ts +612 -0
  9. package/src/common/types/offering.types.spec.ts +91 -0
  10. package/src/common/types/phone.spec.ts +76 -0
  11. package/src/common/types/queue.types.ts +1 -0
  12. package/src/common/types/reminder-config.types.ts +40 -0
  13. package/src/common/types/site-link.types.spec.ts +134 -0
  14. package/src/common/types/trade.types.ts +2 -4
  15. package/clients/index.mjs +0 -10970
  16. package/compliance/index.mjs +0 -20016
  17. package/compliance-apikey/index.mjs +0 -9795
  18. package/helpers/index.mjs +0 -146
  19. package/investors/index.mjs +0 -12844
  20. package/issuers/index.mjs +0 -16168
  21. package/secondaries/index.mjs +0 -10282
  22. package/src/common/helpers/index.ts +0 -205
  23. package/src/contracts/compliance/account-contacts/index.ts +0 -82
  24. package/src/contracts/compliance/account-managers/index.ts +0 -142
  25. package/src/contracts/compliance/accounts/index.ts +0 -187
  26. package/src/contracts/compliance/activities/index.ts +0 -55
  27. package/src/contracts/compliance/aic/index.ts +0 -60
  28. package/src/contracts/compliance/api-keys/index.ts +0 -91
  29. package/src/contracts/compliance/assets/index.ts +0 -122
  30. package/src/contracts/compliance/auth/index.ts +0 -134
  31. package/src/contracts/compliance/batch-jobs/index.ts +0 -62
  32. package/src/contracts/compliance/bonus-tiers/index.ts +0 -55
  33. package/src/contracts/compliance/checklist/index.ts +0 -87
  34. package/src/contracts/compliance/checklist-items/index.ts +0 -86
  35. package/src/contracts/compliance/covered-persons/index.ts +0 -97
  36. package/src/contracts/compliance/dashboard/index.ts +0 -111
  37. package/src/contracts/compliance/data-records/index.ts +0 -116
  38. package/src/contracts/compliance/data-rooms/index.ts +0 -113
  39. package/src/contracts/compliance/default-theme-configs/index.ts +0 -95
  40. package/src/contracts/compliance/disbursement/index.ts +0 -165
  41. package/src/contracts/compliance/disbursement-approval-users/index.ts +0 -84
  42. package/src/contracts/compliance/disbursement-transactions/index.ts +0 -37
  43. package/src/contracts/compliance/domain-filters/index.ts +0 -117
  44. package/src/contracts/compliance/email-themes/index.ts +0 -284
  45. package/src/contracts/compliance/escrow-accounts/index.ts +0 -85
  46. package/src/contracts/compliance/exchange-api-keys/index.ts +0 -129
  47. package/src/contracts/compliance/exchange-imports/index.ts +0 -137
  48. package/src/contracts/compliance/files/index.ts +0 -267
  49. package/src/contracts/compliance/files-public/index.ts +0 -188
  50. package/src/contracts/compliance/health/index.ts +0 -26
  51. package/src/contracts/compliance/index.ts +0 -147
  52. package/src/contracts/compliance/individuals/index.ts +0 -57
  53. package/src/contracts/compliance/investor-accounts/index.ts +0 -141
  54. package/src/contracts/compliance/invites/index.ts +0 -137
  55. package/src/contracts/compliance/issuer-bank-accounts/index.ts +0 -81
  56. package/src/contracts/compliance/issuer-payment-methods/index.ts +0 -81
  57. package/src/contracts/compliance/issuers/index.ts +0 -97
  58. package/src/contracts/compliance/job-items/index.ts +0 -58
  59. package/src/contracts/compliance/jobs/index.ts +0 -59
  60. package/src/contracts/compliance/kyb/index.ts +0 -54
  61. package/src/contracts/compliance/kyc/index.ts +0 -77
  62. package/src/contracts/compliance/legal-entities/index.ts +0 -57
  63. package/src/contracts/compliance/login-histories/index.ts +0 -37
  64. package/src/contracts/compliance/notes/index.ts +0 -69
  65. package/src/contracts/compliance/notion-databases/index.ts +0 -107
  66. package/src/contracts/compliance/notion-pages/index.ts +0 -105
  67. package/src/contracts/compliance/offering-reports/index.ts +0 -149
  68. package/src/contracts/compliance/offerings/index.ts +0 -233
  69. package/src/contracts/compliance/pages/index.ts +0 -178
  70. package/src/contracts/compliance/payment-methods/index.ts +0 -57
  71. package/src/contracts/compliance/rejection-reasons/index.ts +0 -32
  72. package/src/contracts/compliance/review/index.ts +0 -169
  73. package/src/contracts/compliance/roles/index.ts +0 -34
  74. package/src/contracts/compliance/secondary-customers/index.ts +0 -77
  75. package/src/contracts/compliance/secondary-orders/index.ts +0 -60
  76. package/src/contracts/compliance/secondary-trades/index.ts +0 -100
  77. package/src/contracts/compliance/secure-requests/index.ts +0 -54
  78. package/src/contracts/compliance/signer/index.ts +0 -369
  79. package/src/contracts/compliance/site-links/index.ts +0 -128
  80. package/src/contracts/compliance/site-settings/index.ts +0 -669
  81. package/src/contracts/compliance/sites/index.ts +0 -56
  82. package/src/contracts/compliance/state-machine/index.ts +0 -94
  83. package/src/contracts/compliance/tasks/index.ts +0 -91
  84. package/src/contracts/compliance/third-parties/index.ts +0 -52
  85. package/src/contracts/compliance/trade-line-items/index.ts +0 -59
  86. package/src/contracts/compliance/trades/index.ts +0 -230
  87. package/src/contracts/compliance/transactions/index.ts +0 -161
  88. package/src/contracts/compliance/user-manuals/index.ts +0 -271
  89. package/src/contracts/compliance/user-settings/index.ts +0 -189
  90. package/src/contracts/compliance/users/index.ts +0 -200
  91. package/src/contracts/compliance/webhooks/index.ts +0 -41
  92. package/src/contracts/compliance-apikey/accounts/index.ts +0 -58
  93. package/src/contracts/compliance-apikey/index.ts +0 -14
  94. package/src/contracts/index.ts +0 -6
  95. package/src/contracts/investors/account-contacts/index.ts +0 -58
  96. package/src/contracts/investors/aic/index.ts +0 -59
  97. package/src/contracts/investors/assets/index.ts +0 -61
  98. package/src/contracts/investors/auth/index.ts +0 -116
  99. package/src/contracts/investors/bonus-tiers/index.ts +0 -37
  100. package/src/contracts/investors/cart/index.ts +0 -75
  101. package/src/contracts/investors/contact-us/index.ts +0 -48
  102. package/src/contracts/investors/data-records/index.ts +0 -113
  103. package/src/contracts/investors/data-rooms/index.ts +0 -96
  104. package/src/contracts/investors/files/index.ts +0 -167
  105. package/src/contracts/investors/files-public/index.ts +0 -185
  106. package/src/contracts/investors/index.ts +0 -72
  107. package/src/contracts/investors/individuals/index.ts +0 -99
  108. package/src/contracts/investors/investor-accounts/index.ts +0 -110
  109. package/src/contracts/investors/issuer-payment-methods/index.ts +0 -36
  110. package/src/contracts/investors/issuers/index.ts +0 -30
  111. package/src/contracts/investors/legal-entities/index.ts +0 -93
  112. package/src/contracts/investors/notes/index.ts +0 -69
  113. package/src/contracts/investors/offerings/index.ts +0 -93
  114. package/src/contracts/investors/pages/index.ts +0 -88
  115. package/src/contracts/investors/payment-methods/index.ts +0 -149
  116. package/src/contracts/investors/portfolios/index.ts +0 -53
  117. package/src/contracts/investors/sites/index.ts +0 -96
  118. package/src/contracts/investors/tasks/index.ts +0 -111
  119. package/src/contracts/investors/trade-line-items/index.ts +0 -75
  120. package/src/contracts/investors/trades/index.ts +0 -114
  121. package/src/contracts/investors/transactions/index.ts +0 -37
  122. package/src/contracts/investors/trusted-contacts/index.ts +0 -93
  123. package/src/contracts/investors/user-manuals/index.ts +0 -62
  124. package/src/contracts/investors/user-settings/index.ts +0 -170
  125. package/src/contracts/investors/users/index.ts +0 -45
  126. package/src/contracts/investors/webhooks/index.ts +0 -30
  127. package/src/contracts/issuers/account-contacts/index.ts +0 -76
  128. package/src/contracts/issuers/account-integrations/index.ts +0 -97
  129. package/src/contracts/issuers/accounts/index.ts +0 -97
  130. package/src/contracts/issuers/activities/index.ts +0 -54
  131. package/src/contracts/issuers/aic/index.ts +0 -39
  132. package/src/contracts/issuers/api-key-logs/index.ts +0 -53
  133. package/src/contracts/issuers/api-keys/index.ts +0 -93
  134. package/src/contracts/issuers/assets/index.ts +0 -122
  135. package/src/contracts/issuers/auth/index.ts +0 -152
  136. package/src/contracts/issuers/bonus-tiers/index.ts +0 -55
  137. package/src/contracts/issuers/contact-us/index.ts +0 -48
  138. package/src/contracts/issuers/covered-persons/index.ts +0 -136
  139. package/src/contracts/issuers/dashboard/index.ts +0 -72
  140. package/src/contracts/issuers/data-records/index.ts +0 -257
  141. package/src/contracts/issuers/data-rooms/index.ts +0 -134
  142. package/src/contracts/issuers/disbursement-approval-users/index.ts +0 -82
  143. package/src/contracts/issuers/disbursement-transactions/index.ts +0 -53
  144. package/src/contracts/issuers/disbursements/index.ts +0 -153
  145. package/src/contracts/issuers/email-themes/index.ts +0 -242
  146. package/src/contracts/issuers/escrow-accounts/index.ts +0 -81
  147. package/src/contracts/issuers/exchange-api-keys/index.ts +0 -144
  148. package/src/contracts/issuers/files/index.ts +0 -166
  149. package/src/contracts/issuers/files-public/index.ts +0 -166
  150. package/src/contracts/issuers/health/index.ts +0 -24
  151. package/src/contracts/issuers/index.ts +0 -112
  152. package/src/contracts/issuers/investor-accounts/index.ts +0 -148
  153. package/src/contracts/issuers/invites/index.ts +0 -129
  154. package/src/contracts/issuers/issuer/index.ts +0 -94
  155. package/src/contracts/issuers/issuer-bank-accounts/index.ts +0 -81
  156. package/src/contracts/issuers/issuer-payment-methods/index.ts +0 -136
  157. package/src/contracts/issuers/kyc/index.ts +0 -38
  158. package/src/contracts/issuers/login-histories/index.ts +0 -51
  159. package/src/contracts/issuers/notes/index.ts +0 -69
  160. package/src/contracts/issuers/offerings/index.ts +0 -206
  161. package/src/contracts/issuers/pages/index.ts +0 -138
  162. package/src/contracts/issuers/payment-methods/index.ts +0 -61
  163. package/src/contracts/issuers/portfolios/index.ts +0 -36
  164. package/src/contracts/issuers/rejection-reasons/index.ts +0 -32
  165. package/src/contracts/issuers/review/index.ts +0 -63
  166. package/src/contracts/issuers/secondary-customers/index.ts +0 -55
  167. package/src/contracts/issuers/secondary-orders/index.ts +0 -57
  168. package/src/contracts/issuers/secondary-trades/index.ts +0 -57
  169. package/src/contracts/issuers/secure-requests/index.ts +0 -34
  170. package/src/contracts/issuers/site-links/index.ts +0 -116
  171. package/src/contracts/issuers/site-settings/index.ts +0 -585
  172. package/src/contracts/issuers/sites/index.ts +0 -32
  173. package/src/contracts/issuers/tasks/index.ts +0 -111
  174. package/src/contracts/issuers/trades/index.ts +0 -132
  175. package/src/contracts/issuers/transactions/index.ts +0 -158
  176. package/src/contracts/issuers/user-manuals/index.ts +0 -62
  177. package/src/contracts/issuers/user-settings/index.ts +0 -170
  178. package/src/contracts/issuers/users/index.ts +0 -126
  179. package/src/contracts/secondaries/accounts/index.ts +0 -58
  180. package/src/contracts/secondaries/index.ts +0 -23
  181. package/src/contracts/secondaries/secondary-customers/index.ts +0 -55
  182. package/src/contracts/secondaries/secondary-issuers/index.ts +0 -94
  183. package/src/contracts/secondaries/secondary-orders/index.ts +0 -56
  184. package/src/contracts/secondaries/secondary-securities/index.ts +0 -95
  185. package/src/contracts/secondaries/secondary-trades/index.ts +0 -56
  186. package/types/index.mjs +0 -10320
@@ -0,0 +1,612 @@
1
+ import { PaymentMethodType } from './payment-methods.types';
2
+ import {
3
+ PatchIssuerPaymentMethodZod,
4
+ PaymentMethodConfig,
5
+ createDefaultIssuerPaymentMethods,
6
+ stripeConfigSchema,
7
+ wireConfigSchema,
8
+ checkConfigSchema,
9
+ retirementConfigSchema,
10
+ } from './issuer-payment-method.types';
11
+ import { StateCode } from './states.types';
12
+ import { CountryCode } from './countries.types';
13
+ import { typeid } from 'typeid-js';
14
+ import {
15
+ getRandomName,
16
+ getRandomCompanyName,
17
+ getRandomAddress,
18
+ getRandomCity,
19
+ getRandomState,
20
+ getRandomZip,
21
+ getRandomNumber,
22
+ getRandomStripeAccountId,
23
+ } from '../../tests/factory/random.factory';
24
+
25
+ describe('PatchIssuerPaymentMethodZod Schema', () => {
26
+ it('should validate CREDIT_CARD payment method', () => {
27
+ const input = {
28
+ paymentMethodType: PaymentMethodType.CREDIT_CARD,
29
+ config: {
30
+ stripeAccountId: getRandomStripeAccountId(),
31
+ },
32
+ };
33
+
34
+ const result = PatchIssuerPaymentMethodZod.safeParse(input);
35
+ expect(result.success).toBe(true);
36
+ });
37
+
38
+ it('should validate WIRE payment method', () => {
39
+ const input = {
40
+ paymentMethodType: PaymentMethodType.WIRE,
41
+ config: {
42
+ usAccountHolderName: getRandomName(),
43
+ usBankName: `${getRandomName()} Bank`,
44
+ usRoutingNumber: getRandomNumber(100000000, 999999999, 0)
45
+ .toString()
46
+ .padStart(9, '0'),
47
+ usAccountNumber: getRandomNumber(
48
+ 10000000,
49
+ Number.MAX_SAFE_INTEGER,
50
+ 0,
51
+ ).toString(),
52
+ reference: null,
53
+ swiftId: null,
54
+ },
55
+ };
56
+
57
+ const result = PatchIssuerPaymentMethodZod.safeParse(input);
58
+ expect(result.success).toBe(true);
59
+ });
60
+
61
+ it('should validate CHECK payment method', () => {
62
+ const input = {
63
+ paymentMethodType: PaymentMethodType.CHECK,
64
+ config: {
65
+ companyName: getRandomCompanyName(),
66
+ address: getRandomAddress(),
67
+ address2: `Suite ${getRandomNumber(1, 999, 0)}`,
68
+ city: getRandomCity(),
69
+ state: StateCode[getRandomState() as keyof typeof StateCode],
70
+ zip: getRandomZip(),
71
+ country: CountryCode['US'],
72
+ },
73
+ };
74
+
75
+ const result = PatchIssuerPaymentMethodZod.safeParse(input);
76
+ expect(result.success).toBe(true);
77
+ });
78
+
79
+ it('should reject mismatched payment method type and config', () => {
80
+ const input = {
81
+ paymentMethodType: PaymentMethodType.CREDIT_CARD,
82
+ config: {
83
+ usAccountHolderName: getRandomName(),
84
+ usBankName: `${getRandomName()} Bank`,
85
+ usRoutingNumber: getRandomNumber(100000000, 999999999, 0)
86
+ .toString()
87
+ .padStart(9, '0'),
88
+ usAccountNumber: getRandomNumber(
89
+ 10000000,
90
+ Number.MAX_SAFE_INTEGER,
91
+ 0,
92
+ ).toString(),
93
+ },
94
+ };
95
+
96
+ const result = PatchIssuerPaymentMethodZod.safeParse(input);
97
+ expect(result.success).toBe(false);
98
+ });
99
+
100
+ it('should reject invalid Stripe account id', () => {
101
+ const input = {
102
+ paymentMethodType: PaymentMethodType.CREDIT_CARD,
103
+ config: {
104
+ stripeAccountId: 123,
105
+ },
106
+ };
107
+
108
+ const result = PatchIssuerPaymentMethodZod.safeParse(input);
109
+ expect(result.success).toBe(false);
110
+ });
111
+
112
+ it('should reject missing required fields', () => {
113
+ const input = {
114
+ paymentMethodType: PaymentMethodType.WIRE,
115
+ config: {
116
+ usAccountHolderName: getRandomName(),
117
+ // missing other required fields
118
+ },
119
+ };
120
+
121
+ const result = PatchIssuerPaymentMethodZod.safeParse(input);
122
+ expect(result.success).toBe(false);
123
+ });
124
+ });
125
+
126
+ describe('Issuer Payment Method Schema Consistency', () => {
127
+ describe('PatchIssuerPaymentMethodZod and PaymentMethodConfig consistency', () => {
128
+ it('should use the same stripeConfigSchema for CREDIT_CARD in both schemas', () => {
129
+ const stripeAccountId = getRandomStripeAccountId();
130
+ const patchInput = {
131
+ paymentMethodType: PaymentMethodType.CREDIT_CARD,
132
+ config: {
133
+ stripeAccountId,
134
+ },
135
+ };
136
+
137
+ const configInput = {
138
+ paymentMethodType: PaymentMethodType.CREDIT_CARD,
139
+ config: {
140
+ stripeAccountId,
141
+ },
142
+ };
143
+
144
+ const patchResult = PatchIssuerPaymentMethodZod.safeParse(patchInput);
145
+ const configResult = PaymentMethodConfig.safeParse(configInput);
146
+
147
+ expect(patchResult.success).toBe(true);
148
+ expect(configResult.success).toBe(true);
149
+ });
150
+
151
+ it('should use the same stripeConfigSchema for ACH in both schemas', () => {
152
+ const stripeAccountId = getRandomStripeAccountId();
153
+ const patchInput = {
154
+ paymentMethodType: PaymentMethodType.ACH,
155
+ config: {
156
+ stripeAccountId,
157
+ },
158
+ };
159
+
160
+ const configInput = {
161
+ paymentMethodType: PaymentMethodType.ACH,
162
+ config: {
163
+ stripeAccountId,
164
+ },
165
+ };
166
+
167
+ const patchResult = PatchIssuerPaymentMethodZod.safeParse(patchInput);
168
+ const configResult = PaymentMethodConfig.safeParse(configInput);
169
+
170
+ expect(patchResult.success).toBe(true);
171
+ expect(configResult.success).toBe(true);
172
+ });
173
+
174
+ it('should use the same wireConfigSchema for WIRE in both schemas', () => {
175
+ // Generate a valid swiftId (8-11 characters)
176
+ const bankCode = getRandomName()
177
+ .substring(0, 4)
178
+ .toUpperCase()
179
+ .padEnd(4, 'A');
180
+ const swiftId = `${bankCode}US33XXX`.substring(0, 11); // Ensure 8-11 chars
181
+
182
+ const wireConfig = {
183
+ usAccountHolderName: getRandomName(),
184
+ usBankName: `${getRandomName()} Bank`,
185
+ usRoutingNumber: getRandomNumber(100000000, 999999999, 0)
186
+ .toString()
187
+ .padStart(9, '0'),
188
+ usAccountNumber: getRandomNumber(
189
+ 10000000,
190
+ Number.MAX_SAFE_INTEGER,
191
+ 0,
192
+ ).toString(),
193
+ reference: `REF${getRandomNumber(100, 999, 0)}`,
194
+ swiftId:
195
+ swiftId.length >= 8 ? swiftId : `${bankCode}US33XXX`.substring(0, 11),
196
+ };
197
+
198
+ const patchInput = {
199
+ paymentMethodType: PaymentMethodType.WIRE,
200
+ config: wireConfig,
201
+ };
202
+
203
+ const configInput = {
204
+ paymentMethodType: PaymentMethodType.WIRE,
205
+ config: wireConfig,
206
+ };
207
+
208
+ const patchResult = PatchIssuerPaymentMethodZod.safeParse(patchInput);
209
+ const configResult = PaymentMethodConfig.safeParse(configInput);
210
+
211
+ expect(patchResult.success).toBe(true);
212
+ expect(configResult.success).toBe(true);
213
+ });
214
+
215
+ it('should use the same checkConfigSchema for CHECK in both schemas', () => {
216
+ const checkConfig = {
217
+ companyName: getRandomCompanyName(),
218
+ address: getRandomAddress(),
219
+ address2: `Suite ${getRandomNumber(1, 999, 0)}`,
220
+ city: getRandomCity(),
221
+ state: StateCode[getRandomState() as keyof typeof StateCode],
222
+ zip: getRandomZip(),
223
+ country: CountryCode['US'],
224
+ reference: `REF${getRandomNumber(100, 999, 0)}`,
225
+ };
226
+
227
+ const patchInput = {
228
+ paymentMethodType: PaymentMethodType.CHECK,
229
+ config: checkConfig,
230
+ };
231
+
232
+ const configInput = {
233
+ paymentMethodType: PaymentMethodType.CHECK,
234
+ config: checkConfig,
235
+ };
236
+
237
+ const patchResult = PatchIssuerPaymentMethodZod.safeParse(patchInput);
238
+ const configResult = PaymentMethodConfig.safeParse(configInput);
239
+
240
+ expect(patchResult.success).toBe(true);
241
+ expect(configResult.success).toBe(true);
242
+ });
243
+
244
+ it('should use the same retirementConfigSchema for RETIREMENT in both schemas', () => {
245
+ const retirementConfig = {
246
+ custodianInstruction: `Custodian instruction for ${getRandomCompanyName()}`,
247
+ custodianDocument: null,
248
+ };
249
+
250
+ const patchInput = {
251
+ paymentMethodType: PaymentMethodType.RETIREMENT,
252
+ config: retirementConfig,
253
+ };
254
+
255
+ const configInput = {
256
+ paymentMethodType: PaymentMethodType.RETIREMENT,
257
+ config: retirementConfig,
258
+ };
259
+
260
+ const patchResult = PatchIssuerPaymentMethodZod.safeParse(patchInput);
261
+ const configResult = PaymentMethodConfig.safeParse(configInput);
262
+
263
+ expect(patchResult.success).toBe(true);
264
+ expect(configResult.success).toBe(true);
265
+ });
266
+
267
+ it('should reject the same invalid configs in both schemas', () => {
268
+ const invalidWireConfig = {
269
+ usAccountHolderName: getRandomName(),
270
+ // Missing required fields
271
+ };
272
+
273
+ const patchInput = {
274
+ paymentMethodType: PaymentMethodType.WIRE,
275
+ config: invalidWireConfig,
276
+ };
277
+
278
+ const configInput = {
279
+ paymentMethodType: PaymentMethodType.WIRE,
280
+ config: invalidWireConfig,
281
+ };
282
+
283
+ const patchResult = PatchIssuerPaymentMethodZod.safeParse(patchInput);
284
+ const configResult = PaymentMethodConfig.safeParse(configInput);
285
+
286
+ expect(patchResult.success).toBe(false);
287
+ expect(configResult.success).toBe(false);
288
+ });
289
+ });
290
+
291
+ describe('Payment method type coverage', () => {
292
+ it('should cover all payment method types in PatchIssuerPaymentMethodZod', () => {
293
+ const paymentMethodTypes = Object.values(PaymentMethodType);
294
+ const coveredTypes = new Set<string>();
295
+
296
+ // Test each payment method type
297
+ paymentMethodTypes.forEach((type) => {
298
+ let config: any;
299
+ switch (type) {
300
+ case PaymentMethodType.CREDIT_CARD:
301
+ case PaymentMethodType.ACH:
302
+ case PaymentMethodType.BANK_ACCOUNT:
303
+ config = { stripeAccountId: getRandomStripeAccountId() };
304
+ break;
305
+ case PaymentMethodType.WIRE:
306
+ config = {
307
+ usAccountHolderName: getRandomName(),
308
+ usBankName: `${getRandomName()} Bank`,
309
+ usRoutingNumber: getRandomNumber(100000000, 999999999, 0)
310
+ .toString()
311
+ .padStart(9, '0'),
312
+ usAccountNumber: getRandomNumber(
313
+ 10000000,
314
+ Number.MAX_SAFE_INTEGER,
315
+ 0,
316
+ ).toString(),
317
+ };
318
+ break;
319
+ case PaymentMethodType.CHECK:
320
+ config = {
321
+ companyName: getRandomCompanyName(),
322
+ address: getRandomAddress(),
323
+ city: getRandomCity(),
324
+ state: StateCode[getRandomState() as keyof typeof StateCode],
325
+ zip: getRandomZip(),
326
+ country: CountryCode['US'],
327
+ };
328
+ break;
329
+ case PaymentMethodType.RETIREMENT:
330
+ config = {
331
+ custodianInstruction: `Custodian instruction for ${getRandomCompanyName()}`,
332
+ };
333
+ break;
334
+ }
335
+
336
+ const result = PatchIssuerPaymentMethodZod.safeParse({
337
+ paymentMethodType: type,
338
+ config,
339
+ });
340
+
341
+ if (result.success) {
342
+ coveredTypes.add(type);
343
+ }
344
+ });
345
+
346
+ // BANK_ACCOUNT is in PatchIssuerPaymentMethodZod but not in PaymentMethodConfig
347
+ // This is expected behavior, so we check that all types that should be covered are covered
348
+ expect(coveredTypes.has(PaymentMethodType.CREDIT_CARD)).toBe(true);
349
+ expect(coveredTypes.has(PaymentMethodType.ACH)).toBe(true);
350
+ expect(coveredTypes.has(PaymentMethodType.BANK_ACCOUNT)).toBe(true);
351
+ expect(coveredTypes.has(PaymentMethodType.WIRE)).toBe(true);
352
+ expect(coveredTypes.has(PaymentMethodType.CHECK)).toBe(true);
353
+ expect(coveredTypes.has(PaymentMethodType.RETIREMENT)).toBe(true);
354
+ });
355
+
356
+ it('should cover all payment method types in PaymentMethodConfig', () => {
357
+ const paymentMethodTypes = Object.values(PaymentMethodType);
358
+ const coveredTypes = new Set<string>();
359
+
360
+ // Test each payment method type
361
+ paymentMethodTypes.forEach((type) => {
362
+ let config: any;
363
+ switch (type) {
364
+ case PaymentMethodType.CREDIT_CARD:
365
+ case PaymentMethodType.ACH:
366
+ config = { stripeAccountId: getRandomStripeAccountId() };
367
+ break;
368
+ case PaymentMethodType.WIRE:
369
+ config = {
370
+ usAccountHolderName: getRandomName(),
371
+ usBankName: `${getRandomName()} Bank`,
372
+ usRoutingNumber: getRandomNumber(100000000, 999999999, 0)
373
+ .toString()
374
+ .padStart(9, '0'),
375
+ usAccountNumber: getRandomNumber(
376
+ 10000000,
377
+ Number.MAX_SAFE_INTEGER,
378
+ 0,
379
+ ).toString(),
380
+ };
381
+ break;
382
+ case PaymentMethodType.CHECK:
383
+ config = {
384
+ companyName: getRandomCompanyName(),
385
+ address: getRandomAddress(),
386
+ city: getRandomCity(),
387
+ state: StateCode[getRandomState() as keyof typeof StateCode],
388
+ zip: getRandomZip(),
389
+ country: CountryCode['US'],
390
+ };
391
+ break;
392
+ case PaymentMethodType.RETIREMENT:
393
+ config = {
394
+ custodianInstruction: `Custodian instruction for ${getRandomCompanyName()}`,
395
+ };
396
+ break;
397
+ case PaymentMethodType.BANK_ACCOUNT:
398
+ // BANK_ACCOUNT is not in PaymentMethodConfig, skip it
399
+ return;
400
+ }
401
+
402
+ const result = PaymentMethodConfig.safeParse({
403
+ paymentMethodType: type,
404
+ config,
405
+ });
406
+
407
+ if (result.success) {
408
+ coveredTypes.add(type);
409
+ }
410
+ });
411
+
412
+ // PaymentMethodConfig doesn't include BANK_ACCOUNT, which is expected
413
+ expect(coveredTypes.has(PaymentMethodType.CREDIT_CARD)).toBe(true);
414
+ expect(coveredTypes.has(PaymentMethodType.ACH)).toBe(true);
415
+ expect(coveredTypes.has(PaymentMethodType.WIRE)).toBe(true);
416
+ expect(coveredTypes.has(PaymentMethodType.CHECK)).toBe(true);
417
+ expect(coveredTypes.has(PaymentMethodType.RETIREMENT)).toBe(true);
418
+ });
419
+ });
420
+
421
+ describe('createDefaultIssuerPaymentMethods schema consistency', () => {
422
+ it('should create payment methods with valid configs that match their schemas', () => {
423
+ const issuerId = typeid('issuer').toString();
424
+ const defaultMethods = createDefaultIssuerPaymentMethods(issuerId);
425
+
426
+ defaultMethods.forEach((method) => {
427
+ let configSchema: any;
428
+ switch (method.paymentMethodType) {
429
+ case PaymentMethodType.CREDIT_CARD:
430
+ case PaymentMethodType.ACH:
431
+ case PaymentMethodType.BANK_ACCOUNT:
432
+ configSchema = stripeConfigSchema;
433
+ break;
434
+ case PaymentMethodType.WIRE:
435
+ configSchema = wireConfigSchema;
436
+ break;
437
+ case PaymentMethodType.CHECK:
438
+ configSchema = checkConfigSchema;
439
+ break;
440
+ case PaymentMethodType.RETIREMENT:
441
+ configSchema = retirementConfigSchema;
442
+ break;
443
+ default:
444
+ throw new Error(
445
+ `Unknown payment method type: ${method.paymentMethodType}`,
446
+ );
447
+ }
448
+
449
+ // Parse the config string back to object
450
+ const configObj =
451
+ typeof method.config === 'string'
452
+ ? JSON.parse(method.config)
453
+ : method.config;
454
+
455
+ // Validate the config against its schema
456
+ const result = configSchema.safeParse(configObj);
457
+ expect(result.success).toBe(true);
458
+ });
459
+ });
460
+
461
+ it('should create all expected payment method types', () => {
462
+ const issuerId = typeid('issuer').toString();
463
+ const defaultMethods = createDefaultIssuerPaymentMethods(issuerId);
464
+
465
+ const createdTypes = defaultMethods.map((m) => m.paymentMethodType);
466
+ const expectedTypes = [
467
+ PaymentMethodType.CREDIT_CARD,
468
+ PaymentMethodType.ACH,
469
+ PaymentMethodType.BANK_ACCOUNT,
470
+ PaymentMethodType.WIRE,
471
+ PaymentMethodType.CHECK,
472
+ PaymentMethodType.RETIREMENT,
473
+ ];
474
+
475
+ expectedTypes.forEach((expectedType) => {
476
+ expect(createdTypes).toContain(expectedType);
477
+ });
478
+
479
+ expect(defaultMethods.length).toBe(expectedTypes.length);
480
+ });
481
+
482
+ it('should create payment methods that can be validated by PatchIssuerPaymentMethodZod', () => {
483
+ const issuerId = typeid('issuer').toString();
484
+ const defaultMethods = createDefaultIssuerPaymentMethods(issuerId);
485
+
486
+ defaultMethods.forEach((method) => {
487
+ const configObj =
488
+ typeof method.config === 'string'
489
+ ? JSON.parse(method.config)
490
+ : method.config;
491
+
492
+ const input = {
493
+ paymentMethodType: method.paymentMethodType,
494
+ config: configObj,
495
+ };
496
+
497
+ const result = PatchIssuerPaymentMethodZod.safeParse(input);
498
+
499
+ // BANK_ACCOUNT might not be in PaymentMethodConfig but should be in PatchIssuerPaymentMethodZod
500
+ expect(result.success).toBe(true);
501
+ });
502
+ });
503
+ });
504
+
505
+ describe('Config schema field consistency', () => {
506
+ it('should have consistent field definitions in wireConfigSchema', () => {
507
+ // Generate a valid swiftId (8-11 characters, alphanumeric)
508
+ // SWIFT IDs are typically 8 or 11 characters: 4 letters (bank code) + 2 letters (country) + 2 chars (location) + optional 3 chars (branch)
509
+ const bankCode = getRandomName()
510
+ .substring(0, 4)
511
+ .toUpperCase()
512
+ .padEnd(4, 'A');
513
+ const countryCode = 'US';
514
+ const locationCode = '33';
515
+ const branchCode = 'XXX'; // Optional 3-character branch code
516
+ const swiftId =
517
+ `${bankCode}${countryCode}${locationCode}${branchCode}`.substring(
518
+ 0,
519
+ 11,
520
+ ); // Ensure max 11 chars
521
+
522
+ const validConfig = {
523
+ usAccountHolderName: getRandomName(),
524
+ usBankName: `${getRandomName()} Bank`,
525
+ usRoutingNumber: getRandomNumber(100000000, 999999999, 0)
526
+ .toString()
527
+ .padStart(9, '0'),
528
+ usAccountNumber: getRandomNumber(
529
+ 10000000,
530
+ Number.MAX_SAFE_INTEGER,
531
+ 0,
532
+ ).toString(),
533
+ reference: `REF${getRandomNumber(100, 999, 0)}`,
534
+ swiftId:
535
+ swiftId.length >= 8
536
+ ? swiftId
537
+ : `${bankCode}${countryCode}${locationCode}XXX`.substring(0, 11),
538
+ };
539
+
540
+ const result = wireConfigSchema.safeParse(validConfig);
541
+ expect(result.success).toBe(true);
542
+
543
+ // Verify all expected fields are present
544
+ if (result.success) {
545
+ expect(result.data).toHaveProperty('usAccountHolderName');
546
+ expect(result.data).toHaveProperty('usBankName');
547
+ expect(result.data).toHaveProperty('usRoutingNumber');
548
+ expect(result.data).toHaveProperty('usAccountNumber');
549
+ expect(result.data).toHaveProperty('reference');
550
+ expect(result.data).toHaveProperty('swiftId');
551
+ }
552
+ });
553
+
554
+ it('should have consistent field definitions in checkConfigSchema', () => {
555
+ const validConfig = {
556
+ companyName: getRandomCompanyName(),
557
+ address: getRandomAddress(),
558
+ address2: `Suite ${getRandomNumber(1, 999, 0)}`,
559
+ city: getRandomCity(),
560
+ state: StateCode[getRandomState() as keyof typeof StateCode],
561
+ zip: getRandomZip(),
562
+ country: CountryCode['US'],
563
+ reference: `REF${getRandomNumber(100, 999, 0)}`,
564
+ };
565
+
566
+ const result = checkConfigSchema.safeParse(validConfig);
567
+ expect(result.success).toBe(true);
568
+
569
+ // Verify all expected fields are present
570
+ if (result.success) {
571
+ expect(result.data).toHaveProperty('companyName');
572
+ expect(result.data).toHaveProperty('address');
573
+ expect(result.data).toHaveProperty('address2');
574
+ expect(result.data).toHaveProperty('city');
575
+ expect(result.data).toHaveProperty('state');
576
+ expect(result.data).toHaveProperty('zip');
577
+ expect(result.data).toHaveProperty('country');
578
+ expect(result.data).toHaveProperty('reference');
579
+ }
580
+ });
581
+
582
+ it('should have consistent field definitions in retirementConfigSchema', () => {
583
+ const validConfig = {
584
+ custodianInstruction: `Custodian instruction for ${getRandomCompanyName()}`,
585
+ custodianDocument: null,
586
+ };
587
+
588
+ const result = retirementConfigSchema.safeParse(validConfig);
589
+ expect(result.success).toBe(true);
590
+
591
+ // Verify all expected fields are present
592
+ if (result.success) {
593
+ expect(result.data).toHaveProperty('custodianInstruction');
594
+ expect(result.data).toHaveProperty('custodianDocument');
595
+ }
596
+ });
597
+
598
+ it('should have consistent field definitions in stripeConfigSchema', () => {
599
+ const validConfig = {
600
+ stripeAccountId: getRandomStripeAccountId(),
601
+ };
602
+
603
+ const result = stripeConfigSchema.safeParse(validConfig);
604
+ expect(result.success).toBe(true);
605
+
606
+ // Verify all expected fields are present
607
+ if (result.success) {
608
+ expect(result.data).toHaveProperty('stripeAccountId');
609
+ }
610
+ });
611
+ });
612
+ });
@@ -0,0 +1,91 @@
1
+ import { z } from 'zod';
2
+ import { OfferingSettings, OfferingFeeType } from './offering.types';
3
+
4
+ describe('OfferingSettings Schema', () => {
5
+ it('should pass with all null or undefined values', () => {
6
+ const data = {
7
+ settingsBrokerageFeeValue: null,
8
+ settingsBrokerageFeeType: null,
9
+ settingsCardFeeValue: null,
10
+ settingsCardFeeType: null,
11
+ settingsDisbursementFeeValue: null,
12
+ settingsDisbursementFeeType: null,
13
+ settingsRefundPoolFeeValue: null,
14
+ settingsRefundPoolFeeType: null,
15
+ serviceCharges: null,
16
+ serviceChargesType: null,
17
+ };
18
+ expect(() => OfferingSettings.parse(data)).not.toThrow();
19
+ });
20
+
21
+ it('should pass with valid non-null pair values', () => {
22
+ const data = {
23
+ settingsBrokerageFeeValue: 50,
24
+ settingsBrokerageFeeType: OfferingFeeType.PERCENTAGE,
25
+ settingsCardFeeValue: 25,
26
+ settingsCardFeeType: OfferingFeeType.PERCENTAGE,
27
+ settingsDisbursementFeeValue: 30,
28
+ settingsDisbursementFeeType: OfferingFeeType.PERCENTAGE,
29
+ settingsRefundPoolFeeValue: 40,
30
+ settingsRefundPoolFeeType: OfferingFeeType.PERCENTAGE,
31
+ };
32
+ expect(() => OfferingSettings.parse(data)).not.toThrow();
33
+ });
34
+
35
+ it('should fail if one of a pair is null and the other is not', () => {
36
+ const data = {
37
+ settingsBrokerageFeeValue: 10,
38
+ settingsBrokerageFeeType: null,
39
+ settingsCardFeeValue: null,
40
+ settingsCardFeeType: OfferingFeeType.PERCENTAGE,
41
+ settingsDisbursementFeeValue: 15,
42
+ settingsDisbursementFeeType: null,
43
+ settingsRefundPoolFeeValue: null,
44
+ settingsRefundPoolFeeType: OfferingFeeType.PERCENTAGE,
45
+ };
46
+ expect(() => OfferingSettings.parse(data)).toThrow(
47
+ 'settingsBrokerageFeeType and settingsBrokerageFeeValue must both be either null or not-null',
48
+ );
49
+ expect(() => OfferingSettings.parse(data)).toThrow(
50
+ 'settingsCardFeeType and settingsCardFeeValue must both be either null or not-null',
51
+ );
52
+ });
53
+
54
+ it('should fail if percentage fee values exceed 100', () => {
55
+ const data = {
56
+ settingsBrokerageFeeValue: 101,
57
+ settingsBrokerageFeeType: OfferingFeeType.PERCENTAGE,
58
+ settingsCardFeeValue: 50,
59
+ settingsCardFeeType: OfferingFeeType.PERCENTAGE,
60
+ settingsDisbursementFeeValue: 200,
61
+ settingsDisbursementFeeType: OfferingFeeType.PERCENTAGE,
62
+ settingsRefundPoolFeeValue: 150,
63
+ settingsRefundPoolFeeType: OfferingFeeType.PERCENTAGE,
64
+ };
65
+ expect(() => OfferingSettings.parse(data)).toThrow(
66
+ 'settingsBrokerageFeeValue must be less than or equal to 100',
67
+ );
68
+ expect(() => OfferingSettings.parse(data)).toThrow(
69
+ 'settingsDisbursementFeeValue must be less than 100',
70
+ );
71
+ expect(() => OfferingSettings.parse(data)).toThrow(
72
+ 'settingsRefundPoolFeeValue must be less than or equal to 100',
73
+ );
74
+ });
75
+
76
+ it('should fail if required values are missing', () => {
77
+ const data = {
78
+ settingsBrokerageFeeValue: undefined,
79
+ settingsBrokerageFeeType: OfferingFeeType.PERCENTAGE,
80
+ };
81
+ expect(() => OfferingSettings.parse(data)).toThrow(z.ZodError);
82
+ });
83
+
84
+ it('should fail if invalid types are provided', () => {
85
+ const data = {
86
+ settingsBrokerageFeeValue: 'invalid', // should be a number
87
+ settingsBrokerageFeeType: OfferingFeeType.PERCENTAGE,
88
+ };
89
+ expect(() => OfferingSettings.parse(data)).toThrow(z.ZodError);
90
+ });
91
+ });