@develit-services/bank 0.0.2
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.
- package/dist/@types/index.d.mts +444 -0
- package/dist/@types/index.d.ts +444 -0
- package/dist/@types/index.mjs +9 -0
- package/dist/database/schema/index.d.mts +4 -0
- package/dist/database/schema/index.d.ts +4 -0
- package/dist/database/schema/index.mjs +4 -0
- package/dist/export/worker.d.mts +240 -0
- package/dist/export/worker.d.ts +240 -0
- package/dist/export/worker.mjs +1214 -0
- package/dist/export/wrangler.d.mts +59 -0
- package/dist/export/wrangler.d.ts +59 -0
- package/dist/export/wrangler.mjs +129 -0
- package/dist/shared/bank.BeH-ZCJJ.mjs +67 -0
- package/dist/shared/bank.CBNQZ5Pd.d.mts +785 -0
- package/dist/shared/bank.CBNQZ5Pd.d.ts +785 -0
- package/dist/shared/bank.D-DeJSGN.d.ts +3127 -0
- package/dist/shared/bank.DdbWdNgy.d.mts +3127 -0
- package/dist/shared/bank.DxGqqFhD.d.mts +36 -0
- package/dist/shared/bank.DxGqqFhD.d.ts +36 -0
- package/dist/shared/bank._EHVypLw.mjs +3751 -0
- package/package.json +59 -0
|
@@ -0,0 +1,1214 @@
|
|
|
1
|
+
import { uuidv4, useResult, createInternalError, develitWorker, first, RPCResponse, action } from '@develit-io/backend-sdk';
|
|
2
|
+
import { C as CURRENCY_CODES, P as PAYMENT_TYPES, t as tables, F as FinbricksConnector, M as MockConnector, a as MockCobsConnector, E as ErsteConnector, g as getPaymentDirection } from '../shared/bank._EHVypLw.mjs';
|
|
3
|
+
import { WorkerEntrypoint } from 'cloudflare:workers';
|
|
4
|
+
import { drizzle } from 'drizzle-orm/d1';
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
import { eq, and, inArray, desc, sql } from 'drizzle-orm';
|
|
7
|
+
import superjson from 'superjson';
|
|
8
|
+
import '../shared/bank.BeH-ZCJJ.mjs';
|
|
9
|
+
import 'drizzle-orm/sqlite-core';
|
|
10
|
+
import 'drizzle-orm/relations';
|
|
11
|
+
import 'date-fns';
|
|
12
|
+
import 'jose';
|
|
13
|
+
|
|
14
|
+
const sendPaymentInputSchema = z.object({
|
|
15
|
+
refId: z.string(),
|
|
16
|
+
amount: z.number().positive(),
|
|
17
|
+
paymentType: z.enum(PAYMENT_TYPES),
|
|
18
|
+
currency: z.enum(CURRENCY_CODES),
|
|
19
|
+
vs: z.string().nullable().optional(),
|
|
20
|
+
ss: z.string().nullable().optional(),
|
|
21
|
+
ks: z.string().nullable().optional(),
|
|
22
|
+
message: z.string().nullable().optional(),
|
|
23
|
+
creditorHolderName: z.string(),
|
|
24
|
+
creditorAccountNumberWithBankCode: z.string(),
|
|
25
|
+
creditorIban: z.string(),
|
|
26
|
+
debtorHolderName: z.string(),
|
|
27
|
+
debtorAccountNumberWithBankCode: z.string(),
|
|
28
|
+
debtorIban: z.string()
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
const saveErsteCodeInputSchema = z.object({
|
|
32
|
+
code: z.string()
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
const simulateDepositInputSchema = z.object({
|
|
36
|
+
amount: z.number(),
|
|
37
|
+
currency: z.enum(CURRENCY_CODES),
|
|
38
|
+
bankingVs: z.string().max(10),
|
|
39
|
+
message: z.string(),
|
|
40
|
+
creditorIban: z.string().max(34),
|
|
41
|
+
creditorHolderName: z.string(),
|
|
42
|
+
debtorIban: z.string().max(34),
|
|
43
|
+
debtorHolderName: z.string()
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
const setLastSyncAtInputSchema = z.object({
|
|
47
|
+
iban: z.string(),
|
|
48
|
+
lastSyncedAt: z.coerce.date()
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
const initiateConnectorInputSchema = z.object({
|
|
52
|
+
connectorKey: z.string()
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
const getBatchesInputSchema = z.object({
|
|
56
|
+
limit: z.number().positive().optional().default(100),
|
|
57
|
+
offset: z.number().min(0).optional().default(0)
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
const monthAgo = new Date(
|
|
61
|
+
Date.now() - 30 * 24 * 60 * 60 * 1e3
|
|
62
|
+
// 30 days ago
|
|
63
|
+
);
|
|
64
|
+
const stagingAccounts = [
|
|
65
|
+
{
|
|
66
|
+
connectorKey: "MOCK_COBS",
|
|
67
|
+
id: "staging-czk",
|
|
68
|
+
identification: {
|
|
69
|
+
number: "1234567890",
|
|
70
|
+
bankCode: "5051",
|
|
71
|
+
iban: "CZ0350510000000000000449",
|
|
72
|
+
holderName: "Devizov\xE1 Burza a.s."
|
|
73
|
+
},
|
|
74
|
+
fallbackLastSync: monthAgo,
|
|
75
|
+
currency: "CZK",
|
|
76
|
+
production: false
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
connectorKey: "MOCK_COBS",
|
|
80
|
+
id: "staging-eur",
|
|
81
|
+
identification: {
|
|
82
|
+
number: "2345678901",
|
|
83
|
+
bankCode: "5051",
|
|
84
|
+
iban: "CZ0750510000000000000668",
|
|
85
|
+
holderName: "Devizov\xE1 Burza a.s."
|
|
86
|
+
},
|
|
87
|
+
fallbackLastSync: monthAgo,
|
|
88
|
+
currency: "EUR",
|
|
89
|
+
production: false
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
connectorKey: "FIO",
|
|
93
|
+
id: "kleinpetr-test",
|
|
94
|
+
identification: {
|
|
95
|
+
number: "2502130437",
|
|
96
|
+
bankCode: "2010",
|
|
97
|
+
iban: "CZ8520100000002502130437",
|
|
98
|
+
holderName: "Petr Klein"
|
|
99
|
+
},
|
|
100
|
+
fallbackLastSync: monthAgo,
|
|
101
|
+
currency: "CZK",
|
|
102
|
+
production: true
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
connectorKey: "MOCK",
|
|
106
|
+
id: "id-test",
|
|
107
|
+
identification: {
|
|
108
|
+
number: "777777777",
|
|
109
|
+
bankCode: "0800",
|
|
110
|
+
iban: "PL0000000000002444430437",
|
|
111
|
+
holderName: "Test Test"
|
|
112
|
+
},
|
|
113
|
+
fallbackLastSync: monthAgo,
|
|
114
|
+
currency: "PLN",
|
|
115
|
+
production: false
|
|
116
|
+
}
|
|
117
|
+
// {
|
|
118
|
+
// connectorKey: 'MOCK_COBS',
|
|
119
|
+
// id: 'staging-usd',
|
|
120
|
+
// identification: {
|
|
121
|
+
// iban: 'CZ3456789012345678901234',
|
|
122
|
+
// accountNumberWithBankCode: '3456789012/3456',
|
|
123
|
+
// },
|
|
124
|
+
// currency: 'USD',
|
|
125
|
+
// bankCode: '0800',
|
|
126
|
+
// accountNumber: '3456789012',
|
|
127
|
+
// production: false,
|
|
128
|
+
// },
|
|
129
|
+
];
|
|
130
|
+
const productionAccounts = [
|
|
131
|
+
// Banka CREDITAS (2250)
|
|
132
|
+
{
|
|
133
|
+
connectorKey: "CREDITAS",
|
|
134
|
+
id: "2250-CZK",
|
|
135
|
+
identification: {
|
|
136
|
+
number: "100602391",
|
|
137
|
+
bankCode: "2250",
|
|
138
|
+
iban: "CZ5122500000000100602391",
|
|
139
|
+
holderName: "Devizov\xE1 Burza a.s."
|
|
140
|
+
},
|
|
141
|
+
fallbackLastSync: monthAgo,
|
|
142
|
+
currency: "CZK",
|
|
143
|
+
production: true
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
connectorKey: "CREDITAS",
|
|
147
|
+
id: "2250-EUR",
|
|
148
|
+
identification: {
|
|
149
|
+
number: "100602404",
|
|
150
|
+
bankCode: "2250",
|
|
151
|
+
iban: "CZ8822500000000100602404",
|
|
152
|
+
holderName: "Devizov\xE1 Burza a.s."
|
|
153
|
+
},
|
|
154
|
+
fallbackLastSync: monthAgo,
|
|
155
|
+
currency: "EUR",
|
|
156
|
+
production: true
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
connectorKey: "CREDITAS",
|
|
160
|
+
id: "2250-USD",
|
|
161
|
+
identification: {
|
|
162
|
+
number: "100602412",
|
|
163
|
+
bankCode: "2250",
|
|
164
|
+
iban: "CZ6622500000000100602412",
|
|
165
|
+
holderName: "Devizov\xE1 Burza a.s."
|
|
166
|
+
},
|
|
167
|
+
fallbackLastSync: monthAgo,
|
|
168
|
+
currency: "USD",
|
|
169
|
+
production: true
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
connectorKey: "CREDITAS",
|
|
173
|
+
id: "2250-GBP",
|
|
174
|
+
identification: {
|
|
175
|
+
number: "100602420",
|
|
176
|
+
bankCode: "2250",
|
|
177
|
+
iban: "CZ4422500000000100602420",
|
|
178
|
+
holderName: "Devizov\xE1 Burza a.s."
|
|
179
|
+
},
|
|
180
|
+
fallbackLastSync: monthAgo,
|
|
181
|
+
currency: "GBP",
|
|
182
|
+
production: true
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
connectorKey: "CREDITAS",
|
|
186
|
+
id: "2250-CHF",
|
|
187
|
+
identification: {
|
|
188
|
+
number: "100602439",
|
|
189
|
+
bankCode: "2250",
|
|
190
|
+
iban: "CZ1622500000000100602439",
|
|
191
|
+
holderName: "Devizov\xE1 Burza a.s."
|
|
192
|
+
},
|
|
193
|
+
fallbackLastSync: monthAgo,
|
|
194
|
+
currency: "CHF",
|
|
195
|
+
production: true
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
connectorKey: "CREDITAS",
|
|
199
|
+
id: "2250-PLN",
|
|
200
|
+
identification: {
|
|
201
|
+
number: "100602447",
|
|
202
|
+
bankCode: "2250",
|
|
203
|
+
iban: "CZ9122500000000100602447",
|
|
204
|
+
holderName: "Devizov\xE1 Burza a.s."
|
|
205
|
+
},
|
|
206
|
+
fallbackLastSync: monthAgo,
|
|
207
|
+
currency: "PLN",
|
|
208
|
+
production: true
|
|
209
|
+
},
|
|
210
|
+
// Fio banka (2010)
|
|
211
|
+
{
|
|
212
|
+
connectorKey: "FINBRICKS",
|
|
213
|
+
id: "2010-CZK",
|
|
214
|
+
identification: {
|
|
215
|
+
number: "2500845869",
|
|
216
|
+
bankCode: "2010",
|
|
217
|
+
iban: "CZ0420100000002500845869",
|
|
218
|
+
holderName: "Devizov\xE1 Burza a.s."
|
|
219
|
+
},
|
|
220
|
+
fallbackLastSync: monthAgo,
|
|
221
|
+
currency: "CZK",
|
|
222
|
+
production: true
|
|
223
|
+
},
|
|
224
|
+
{
|
|
225
|
+
connectorKey: "FINBRICKS",
|
|
226
|
+
id: "2010-EUR",
|
|
227
|
+
identification: {
|
|
228
|
+
number: "2600884128",
|
|
229
|
+
bankCode: "2010",
|
|
230
|
+
iban: "CZ0820100000002600884128",
|
|
231
|
+
holderName: "Devizov\xE1 Burza a.s."
|
|
232
|
+
},
|
|
233
|
+
fallbackLastSync: monthAgo,
|
|
234
|
+
currency: "EUR",
|
|
235
|
+
production: true
|
|
236
|
+
},
|
|
237
|
+
{
|
|
238
|
+
connectorKey: "FINBRICKS",
|
|
239
|
+
id: "2010-USD",
|
|
240
|
+
identification: {
|
|
241
|
+
number: "2700884133",
|
|
242
|
+
bankCode: "2010",
|
|
243
|
+
iban: "CZ1420100000002700884133",
|
|
244
|
+
holderName: "Devizov\xE1 Burza a.s."
|
|
245
|
+
},
|
|
246
|
+
fallbackLastSync: monthAgo,
|
|
247
|
+
currency: "USD",
|
|
248
|
+
production: true
|
|
249
|
+
},
|
|
250
|
+
{
|
|
251
|
+
connectorKey: "FINBRICKS",
|
|
252
|
+
id: "2010-CHF",
|
|
253
|
+
identification: {
|
|
254
|
+
number: "2401098351",
|
|
255
|
+
bankCode: "2010",
|
|
256
|
+
iban: "CZ0920100000002401098351",
|
|
257
|
+
holderName: "Devizov\xE1 Burza a.s."
|
|
258
|
+
},
|
|
259
|
+
fallbackLastSync: monthAgo,
|
|
260
|
+
currency: "CHF",
|
|
261
|
+
production: true
|
|
262
|
+
},
|
|
263
|
+
{
|
|
264
|
+
connectorKey: "FINBRICKS",
|
|
265
|
+
id: "2010-GBP",
|
|
266
|
+
identification: {
|
|
267
|
+
number: "2400884131",
|
|
268
|
+
bankCode: "2010",
|
|
269
|
+
iban: "CZ3320100000002400884131",
|
|
270
|
+
holderName: "Devizov\xE1 Burza a.s."
|
|
271
|
+
},
|
|
272
|
+
fallbackLastSync: monthAgo,
|
|
273
|
+
currency: "GBP",
|
|
274
|
+
production: true
|
|
275
|
+
},
|
|
276
|
+
{
|
|
277
|
+
connectorKey: "FINBRICKS",
|
|
278
|
+
id: "2010-PLN",
|
|
279
|
+
identification: {
|
|
280
|
+
number: "2701098353",
|
|
281
|
+
bankCode: "2010",
|
|
282
|
+
iban: "CZ8720100000002701098353",
|
|
283
|
+
holderName: "Devizov\xE1 Burza a.s."
|
|
284
|
+
},
|
|
285
|
+
fallbackLastSync: monthAgo,
|
|
286
|
+
currency: "PLN",
|
|
287
|
+
production: true
|
|
288
|
+
},
|
|
289
|
+
{
|
|
290
|
+
connectorKey: "FINBRICKS",
|
|
291
|
+
id: "2010-CAD",
|
|
292
|
+
identification: {
|
|
293
|
+
number: "2701478102",
|
|
294
|
+
bankCode: "2010",
|
|
295
|
+
iban: "CZ5520100000002701478102",
|
|
296
|
+
holderName: "Devizov\xE1 Burza a.s."
|
|
297
|
+
},
|
|
298
|
+
fallbackLastSync: monthAgo,
|
|
299
|
+
currency: "CAD",
|
|
300
|
+
production: true
|
|
301
|
+
},
|
|
302
|
+
// Komerční banka (0100)
|
|
303
|
+
{
|
|
304
|
+
connectorKey: "FINBRICKS",
|
|
305
|
+
id: "0100-CZK",
|
|
306
|
+
identification: {
|
|
307
|
+
number: "115-1483630297",
|
|
308
|
+
bankCode: "0100",
|
|
309
|
+
iban: "CZ5901000001151483630297",
|
|
310
|
+
holderName: "Devizov\xE1 Burza a.s."
|
|
311
|
+
},
|
|
312
|
+
fallbackLastSync: monthAgo,
|
|
313
|
+
currency: "CZK",
|
|
314
|
+
production: true
|
|
315
|
+
},
|
|
316
|
+
{
|
|
317
|
+
connectorKey: "FINBRICKS",
|
|
318
|
+
id: "0100-EUR",
|
|
319
|
+
identification: {
|
|
320
|
+
number: "115-1484940297",
|
|
321
|
+
bankCode: "0100",
|
|
322
|
+
iban: "CZ4201000001151484940297",
|
|
323
|
+
holderName: "Devizov\xE1 Burza a.s."
|
|
324
|
+
},
|
|
325
|
+
fallbackLastSync: monthAgo,
|
|
326
|
+
currency: "EUR",
|
|
327
|
+
production: true
|
|
328
|
+
},
|
|
329
|
+
{
|
|
330
|
+
connectorKey: "FINBRICKS",
|
|
331
|
+
id: "0100-USD",
|
|
332
|
+
identification: {
|
|
333
|
+
number: "115-1483960237",
|
|
334
|
+
bankCode: "0100",
|
|
335
|
+
iban: "CZ6201000001151483960237",
|
|
336
|
+
holderName: "Devizov\xE1 Burza a.s."
|
|
337
|
+
},
|
|
338
|
+
fallbackLastSync: monthAgo,
|
|
339
|
+
currency: "USD",
|
|
340
|
+
production: true
|
|
341
|
+
},
|
|
342
|
+
{
|
|
343
|
+
connectorKey: "FINBRICKS",
|
|
344
|
+
id: "0100-PLN",
|
|
345
|
+
identification: {
|
|
346
|
+
number: "115-6674290267",
|
|
347
|
+
bankCode: "0100",
|
|
348
|
+
iban: "CZ3501000001156674290267",
|
|
349
|
+
holderName: "Devizov\xE1 Burza a.s."
|
|
350
|
+
},
|
|
351
|
+
fallbackLastSync: monthAgo,
|
|
352
|
+
currency: "PLN",
|
|
353
|
+
production: true
|
|
354
|
+
},
|
|
355
|
+
{
|
|
356
|
+
connectorKey: "FINBRICKS",
|
|
357
|
+
id: "0100-SEK",
|
|
358
|
+
identification: {
|
|
359
|
+
number: "115-9578110207",
|
|
360
|
+
bankCode: "0100",
|
|
361
|
+
iban: "CZ2401000001159578110207",
|
|
362
|
+
holderName: "Devizov\xE1 Burza a.s."
|
|
363
|
+
},
|
|
364
|
+
fallbackLastSync: monthAgo,
|
|
365
|
+
currency: "SEK",
|
|
366
|
+
production: true
|
|
367
|
+
},
|
|
368
|
+
// Česká spořitelna (0800)
|
|
369
|
+
{
|
|
370
|
+
connectorKey: "ERSTE",
|
|
371
|
+
id: "0800-CZK",
|
|
372
|
+
identification: {
|
|
373
|
+
number: "4413926379",
|
|
374
|
+
bankCode: "0800",
|
|
375
|
+
iban: "CZ7908000000004413926379",
|
|
376
|
+
holderName: "Devizov\xE1 Burza a.s."
|
|
377
|
+
},
|
|
378
|
+
fallbackLastSync: monthAgo,
|
|
379
|
+
currency: "CZK",
|
|
380
|
+
production: true
|
|
381
|
+
},
|
|
382
|
+
{
|
|
383
|
+
connectorKey: "ERSTE",
|
|
384
|
+
id: "0800-EUR",
|
|
385
|
+
identification: {
|
|
386
|
+
number: "1966646293",
|
|
387
|
+
bankCode: "0800",
|
|
388
|
+
iban: "CZ2308000000001966646293",
|
|
389
|
+
holderName: "Devizov\xE1 Burza a.s."
|
|
390
|
+
},
|
|
391
|
+
fallbackLastSync: monthAgo,
|
|
392
|
+
currency: "EUR",
|
|
393
|
+
production: true
|
|
394
|
+
},
|
|
395
|
+
{
|
|
396
|
+
connectorKey: "ERSTE",
|
|
397
|
+
id: "0800-USD",
|
|
398
|
+
identification: {
|
|
399
|
+
number: "1978982243",
|
|
400
|
+
bankCode: "0800",
|
|
401
|
+
iban: "CZ1908000000001978982243",
|
|
402
|
+
holderName: "Devizov\xE1 Burza a.s."
|
|
403
|
+
},
|
|
404
|
+
fallbackLastSync: monthAgo,
|
|
405
|
+
currency: "USD",
|
|
406
|
+
production: true
|
|
407
|
+
},
|
|
408
|
+
{
|
|
409
|
+
connectorKey: "ERSTE",
|
|
410
|
+
id: "0800-HUF",
|
|
411
|
+
identification: {
|
|
412
|
+
number: "13461252",
|
|
413
|
+
bankCode: "0800",
|
|
414
|
+
iban: "CZ1908000000000013461252",
|
|
415
|
+
holderName: "Devizov\xE1 Burza a.s."
|
|
416
|
+
},
|
|
417
|
+
fallbackLastSync: monthAgo,
|
|
418
|
+
currency: "HUF",
|
|
419
|
+
production: true
|
|
420
|
+
},
|
|
421
|
+
// MONETA Money Bank (0600)
|
|
422
|
+
{
|
|
423
|
+
connectorKey: "FINBRICKS",
|
|
424
|
+
id: "0600-CZK",
|
|
425
|
+
identification: {
|
|
426
|
+
number: "224252186",
|
|
427
|
+
bankCode: "0600",
|
|
428
|
+
iban: "CZ5906000000000224252186",
|
|
429
|
+
holderName: "Devizov\xE1 Burza a.s."
|
|
430
|
+
},
|
|
431
|
+
fallbackLastSync: monthAgo,
|
|
432
|
+
currency: "CZK",
|
|
433
|
+
production: true
|
|
434
|
+
},
|
|
435
|
+
{
|
|
436
|
+
connectorKey: "FINBRICKS",
|
|
437
|
+
id: "0600-EUR",
|
|
438
|
+
identification: {
|
|
439
|
+
number: "224252231",
|
|
440
|
+
bankCode: "0600",
|
|
441
|
+
iban: "CZ0806000000000224252231",
|
|
442
|
+
holderName: "Devizov\xE1 Burza a.s."
|
|
443
|
+
},
|
|
444
|
+
fallbackLastSync: monthAgo,
|
|
445
|
+
currency: "EUR",
|
|
446
|
+
production: true
|
|
447
|
+
},
|
|
448
|
+
{
|
|
449
|
+
connectorKey: "FINBRICKS",
|
|
450
|
+
id: "0600-USD",
|
|
451
|
+
identification: {
|
|
452
|
+
number: "224252290",
|
|
453
|
+
bankCode: "0600",
|
|
454
|
+
iban: "CZ6406000000000224252290",
|
|
455
|
+
holderName: "Devizov\xE1 Burza a.s."
|
|
456
|
+
},
|
|
457
|
+
fallbackLastSync: monthAgo,
|
|
458
|
+
currency: "USD",
|
|
459
|
+
production: true
|
|
460
|
+
},
|
|
461
|
+
// NEY spořitelní družstvo (2260)
|
|
462
|
+
{
|
|
463
|
+
connectorKey: "FINBRICKS",
|
|
464
|
+
id: "2260-CZK",
|
|
465
|
+
identification: {
|
|
466
|
+
number: "1702700014",
|
|
467
|
+
bankCode: "2260",
|
|
468
|
+
iban: "CZ7422600000001702700014",
|
|
469
|
+
holderName: "Devizov\xE1 Burza a.s."
|
|
470
|
+
},
|
|
471
|
+
fallbackLastSync: monthAgo,
|
|
472
|
+
currency: "CZK",
|
|
473
|
+
production: true
|
|
474
|
+
}
|
|
475
|
+
];
|
|
476
|
+
|
|
477
|
+
const createPaymentCommand = (db, { payment }) => {
|
|
478
|
+
return {
|
|
479
|
+
command: db.insert(tables.payment).values(payment).returning()
|
|
480
|
+
};
|
|
481
|
+
};
|
|
482
|
+
|
|
483
|
+
const updatePaymentCommand = (db, { payment }) => {
|
|
484
|
+
return {
|
|
485
|
+
command: db.update(tables.payment).set(payment).where(eq(tables.payment.id, payment.id)).returning()
|
|
486
|
+
};
|
|
487
|
+
};
|
|
488
|
+
|
|
489
|
+
const upsertBatchCommand = (db, { batch }) => {
|
|
490
|
+
const id = batch.id || uuidv4();
|
|
491
|
+
const command = db.insert(tables.batch).values({
|
|
492
|
+
...batch,
|
|
493
|
+
id
|
|
494
|
+
}).onConflictDoUpdate({
|
|
495
|
+
target: tables.batch.id,
|
|
496
|
+
set: {
|
|
497
|
+
...batch
|
|
498
|
+
}
|
|
499
|
+
}).returning();
|
|
500
|
+
return {
|
|
501
|
+
id,
|
|
502
|
+
command
|
|
503
|
+
};
|
|
504
|
+
};
|
|
505
|
+
|
|
506
|
+
const getPaymentByRefIdQuery = async (db, { refId }) => {
|
|
507
|
+
const payment = await db.select().from(tables.payment).where(eq(tables.payment.refId, refId)).limit(1).get();
|
|
508
|
+
return payment;
|
|
509
|
+
};
|
|
510
|
+
|
|
511
|
+
const getOpenBatchByAccountIdQuery = async (db, { accountId }) => {
|
|
512
|
+
const batch = await db.select().from(tables.batch).where(
|
|
513
|
+
and(
|
|
514
|
+
eq(tables.batch.accountId, accountId),
|
|
515
|
+
eq(tables.batch.status, "OPEN")
|
|
516
|
+
)
|
|
517
|
+
).limit(1).get();
|
|
518
|
+
return batch;
|
|
519
|
+
};
|
|
520
|
+
|
|
521
|
+
const getAllOpenBatchesQuery = async (db) => {
|
|
522
|
+
return await db.select().from(tables.batch).where(eq(tables.batch.status, "OPEN"));
|
|
523
|
+
};
|
|
524
|
+
|
|
525
|
+
const getPaymentsByBankRefIdsQuery = async (db, { ids }) => {
|
|
526
|
+
return await db.select().from(tables.payment).where(inArray(tables.payment.bankRefId, ids));
|
|
527
|
+
};
|
|
528
|
+
|
|
529
|
+
class CreditasConnector extends FinbricksConnector {
|
|
530
|
+
constructor(config) {
|
|
531
|
+
super("CREDITAS", config);
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
class FioConnector extends FinbricksConnector {
|
|
536
|
+
constructor(config) {
|
|
537
|
+
super("FIO", config);
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
const initiateConnector = (bank, env) => {
|
|
542
|
+
switch (bank) {
|
|
543
|
+
case "ERSTE":
|
|
544
|
+
return new ErsteConnector({
|
|
545
|
+
API_KEY: env.ERSTE_API_KEY,
|
|
546
|
+
CLIENT_ID: env.ERSTE_CLIENT_ID,
|
|
547
|
+
CLIENT_SECRET: env.ERSTE_CLIENT_SECRET,
|
|
548
|
+
REDIRECT_URI: env.ERSTE_REDIRECT_URI,
|
|
549
|
+
AUTH_URI: env.ERSTE_AUTH_URI,
|
|
550
|
+
PAYMENTS_URI: env.ERSTE_PAYMENTS_URI,
|
|
551
|
+
ACCOUNTS_URI: env.ERSTE_ACCOUNTS_URI
|
|
552
|
+
});
|
|
553
|
+
case "CREDITAS":
|
|
554
|
+
return new CreditasConnector({
|
|
555
|
+
BASE_URI: env.FINBRICKS_BASE_URI,
|
|
556
|
+
MERCHANT_ID: env.FINBRICKS_MERCHANT_ID,
|
|
557
|
+
PRIVATE_KEY_PEM: env.FINBRICKS_PRIVATE_KEY_PEM
|
|
558
|
+
});
|
|
559
|
+
case "MOCK_COBS":
|
|
560
|
+
return new MockCobsConnector({
|
|
561
|
+
BASE_URI: env.FINBRICKS_BASE_URI,
|
|
562
|
+
MERCHANT_ID: env.FINBRICKS_MERCHANT_ID,
|
|
563
|
+
PRIVATE_KEY_PEM: env.FINBRICKS_PRIVATE_KEY_PEM
|
|
564
|
+
});
|
|
565
|
+
case "FIO":
|
|
566
|
+
return new FioConnector({
|
|
567
|
+
BASE_URI: env.FINBRICKS_BASE_URI,
|
|
568
|
+
MERCHANT_ID: env.FINBRICKS_MERCHANT_ID,
|
|
569
|
+
PRIVATE_KEY_PEM: env.FINBRICKS_PRIVATE_KEY_PEM
|
|
570
|
+
});
|
|
571
|
+
default:
|
|
572
|
+
return new MockConnector();
|
|
573
|
+
}
|
|
574
|
+
};
|
|
575
|
+
|
|
576
|
+
const useSync = (kv) => {
|
|
577
|
+
const getLastSync = async ({
|
|
578
|
+
account
|
|
579
|
+
}) => {
|
|
580
|
+
const [rawSync, rawSyncError] = await useResult(
|
|
581
|
+
kv.get(`sync-log:${account.identification.iban}:${account.currency}`)
|
|
582
|
+
);
|
|
583
|
+
if (rawSyncError) throw createInternalError(rawSyncError);
|
|
584
|
+
if (!rawSync) return null;
|
|
585
|
+
return superjson.parse(rawSync);
|
|
586
|
+
};
|
|
587
|
+
const setLastSync = async ({
|
|
588
|
+
account,
|
|
589
|
+
log
|
|
590
|
+
}) => {
|
|
591
|
+
const [_, error] = await useResult(
|
|
592
|
+
kv.put(
|
|
593
|
+
`sync-log:${account.identification.iban}:${account.currency}`,
|
|
594
|
+
superjson.stringify(log)
|
|
595
|
+
)
|
|
596
|
+
);
|
|
597
|
+
if (error) throw error;
|
|
598
|
+
};
|
|
599
|
+
return {
|
|
600
|
+
getLastSync,
|
|
601
|
+
setLastSync
|
|
602
|
+
};
|
|
603
|
+
};
|
|
604
|
+
|
|
605
|
+
const seperateSupportedPayments = (mappedPayments, accounts) => {
|
|
606
|
+
const ibans = new Set(accounts.map((acc) => acc.identification.iban));
|
|
607
|
+
const currencies = new Set(accounts.map((acc) => acc.currency));
|
|
608
|
+
const [supportedPayments, unsupportedPayments] = mappedPayments.reduce(
|
|
609
|
+
([valid, invalid], payment) => {
|
|
610
|
+
const isValid = ibans.has(payment.debtorIban ?? "") && currencies.has(payment.currency);
|
|
611
|
+
if (isValid) {
|
|
612
|
+
valid.push(payment);
|
|
613
|
+
} else {
|
|
614
|
+
invalid.push(payment);
|
|
615
|
+
}
|
|
616
|
+
return [valid, invalid];
|
|
617
|
+
},
|
|
618
|
+
[[], []]
|
|
619
|
+
);
|
|
620
|
+
return {
|
|
621
|
+
supportedPayments,
|
|
622
|
+
unsupportedPayments
|
|
623
|
+
};
|
|
624
|
+
};
|
|
625
|
+
|
|
626
|
+
var __defProp = Object.defineProperty;
|
|
627
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
628
|
+
var __decorateClass = (decorators, target, key, kind) => {
|
|
629
|
+
var result = __getOwnPropDesc(target, key) ;
|
|
630
|
+
for (var i = decorators.length - 1, decorator; i >= 0; i--)
|
|
631
|
+
if (decorator = decorators[i])
|
|
632
|
+
result = (decorator(target, key, result) ) || result;
|
|
633
|
+
if (result) __defProp(target, key, result);
|
|
634
|
+
return result;
|
|
635
|
+
};
|
|
636
|
+
class BankServiceBase extends develitWorker(WorkerEntrypoint) {
|
|
637
|
+
constructor(ctx, env) {
|
|
638
|
+
super(ctx, env);
|
|
639
|
+
this.name = "bank-service";
|
|
640
|
+
this.db = drizzle(this.env.BANK_D1, { schema: tables });
|
|
641
|
+
}
|
|
642
|
+
get accounts() {
|
|
643
|
+
return this.env.ENVIRONMENT === "production" ? productionAccounts : stagingAccounts;
|
|
644
|
+
}
|
|
645
|
+
accountFetchInterval(connectorKey) {
|
|
646
|
+
switch (connectorKey) {
|
|
647
|
+
case "ERSTE":
|
|
648
|
+
return ErsteConnector.FETCH_INTERVAL;
|
|
649
|
+
case "FINBRICKS":
|
|
650
|
+
return FinbricksConnector.FETCH_INTERVAL;
|
|
651
|
+
case "MOCK":
|
|
652
|
+
return MockConnector.FETCH_INTERVAL;
|
|
653
|
+
default:
|
|
654
|
+
return 0;
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
async syncAccounts() {
|
|
658
|
+
return this.handleAction(null, {}, async () => {
|
|
659
|
+
const accountsToSync = [];
|
|
660
|
+
const { getLastSync } = useSync(this.env.BANK_KV);
|
|
661
|
+
for (const account of this.accounts.filter(
|
|
662
|
+
(acc) => !!!acc.connectorKey.includes("MOCK")
|
|
663
|
+
)) {
|
|
664
|
+
let lastSync = await getLastSync({ account });
|
|
665
|
+
if (!lastSync) {
|
|
666
|
+
await this.setLastSyncAt({
|
|
667
|
+
iban: account.identification.iban,
|
|
668
|
+
lastSyncedAt: account.fallbackLastSync
|
|
669
|
+
});
|
|
670
|
+
lastSync = await getLastSync({ account });
|
|
671
|
+
if (!lastSync) continue;
|
|
672
|
+
}
|
|
673
|
+
const accountFetchInterval = this.accountFetchInterval(
|
|
674
|
+
account.connectorKey
|
|
675
|
+
);
|
|
676
|
+
const now = Date.now();
|
|
677
|
+
const lastSyncTime = lastSync.lastSyncedAt.getTime();
|
|
678
|
+
const intervalMs = accountFetchInterval * 1e3;
|
|
679
|
+
const shouldFetch = now - lastSyncTime >= intervalMs;
|
|
680
|
+
if (!shouldFetch) continue;
|
|
681
|
+
accountsToSync.push({
|
|
682
|
+
...account,
|
|
683
|
+
lastSyncAt: lastSync
|
|
684
|
+
});
|
|
685
|
+
}
|
|
686
|
+
console.log("ACCS TO SYNC", accountsToSync.length);
|
|
687
|
+
if (accountsToSync.length <= 0) return;
|
|
688
|
+
await this.saveOrUpdatePayments(accountsToSync);
|
|
689
|
+
});
|
|
690
|
+
}
|
|
691
|
+
async scheduled(controller) {
|
|
692
|
+
if (controller.cron === this.env.CRON_BATCHES_PROCESSING) {
|
|
693
|
+
console.log("Scheduled CRON batches processing");
|
|
694
|
+
const openBatches = await getAllOpenBatchesQuery(this.db);
|
|
695
|
+
if (!openBatches.length) return;
|
|
696
|
+
for (const batch of openBatches) {
|
|
697
|
+
const connectorKey = this.accounts.find(
|
|
698
|
+
(acc) => acc.id === batch.accountId
|
|
699
|
+
)?.connectorKey;
|
|
700
|
+
if (!connectorKey) {
|
|
701
|
+
this.logError({
|
|
702
|
+
message: "Failed to find connector key",
|
|
703
|
+
batch,
|
|
704
|
+
connectorKey
|
|
705
|
+
});
|
|
706
|
+
continue;
|
|
707
|
+
}
|
|
708
|
+
await this.processBatch({
|
|
709
|
+
batch,
|
|
710
|
+
connectorKey
|
|
711
|
+
});
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
if (controller.cron === this.env.CRON_PAYMENTS_PROCESSING) {
|
|
715
|
+
console.log("Scheduled CRON payments processing");
|
|
716
|
+
await this.syncAccounts();
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
// @action('initiate-bank-connector')
|
|
720
|
+
async initiateBankConnector(input) {
|
|
721
|
+
return this.handleAction(
|
|
722
|
+
{ data: input, schema: initiateConnectorInputSchema },
|
|
723
|
+
{ successMessage: "Bank connector initiated successfully" },
|
|
724
|
+
async ({ connectorKey }) => {
|
|
725
|
+
this.bankConnector = initiateConnector(
|
|
726
|
+
connectorKey,
|
|
727
|
+
this.env
|
|
728
|
+
);
|
|
729
|
+
await this.env.BANK_KV.put(
|
|
730
|
+
`${connectorKey}:token`,
|
|
731
|
+
"d32a83cf-d352-41f3-96d7-4d2961336ddc"
|
|
732
|
+
//hard-coded finbricks clientId (valid til 03/26)
|
|
733
|
+
);
|
|
734
|
+
const token = await this.env.BANK_KV.get(`${connectorKey}:token`);
|
|
735
|
+
if (!token) throw createInternalError("Provider not authorized");
|
|
736
|
+
await this.bankConnector.authenticate({
|
|
737
|
+
token
|
|
738
|
+
});
|
|
739
|
+
}
|
|
740
|
+
);
|
|
741
|
+
}
|
|
742
|
+
async addPaymentsToBatch({
|
|
743
|
+
paymentsToBatch
|
|
744
|
+
}) {
|
|
745
|
+
return this.handleAction(null, {}, async () => {
|
|
746
|
+
this.logInput({ paymentsToBatch });
|
|
747
|
+
const mappedPayments = paymentsToBatch.map(
|
|
748
|
+
(payment) => ({
|
|
749
|
+
id: uuidv4(),
|
|
750
|
+
refId: payment.refId,
|
|
751
|
+
amount: payment.amount,
|
|
752
|
+
direction: "OUTGOING",
|
|
753
|
+
paymentType: payment.paymentType,
|
|
754
|
+
currency: payment.currency,
|
|
755
|
+
status: "CREATED",
|
|
756
|
+
initiatedAt: /* @__PURE__ */ new Date(),
|
|
757
|
+
processedAt: null,
|
|
758
|
+
vs: payment.vs || null,
|
|
759
|
+
ss: payment.ss || null,
|
|
760
|
+
ks: payment.ks || null,
|
|
761
|
+
message: payment.message || null,
|
|
762
|
+
creditorHolderName: payment.creditorHolderName,
|
|
763
|
+
creditorAccountNumberWithBankCode: payment.creditorAccountNumberWithBankCode,
|
|
764
|
+
creditorIban: payment.creditorIban,
|
|
765
|
+
debtorHolderName: payment.debtorHolderName,
|
|
766
|
+
debtorAccountNumberWithBankCode: payment.debtorAccountNumberWithBankCode,
|
|
767
|
+
debtorIban: payment.debtorIban
|
|
768
|
+
})
|
|
769
|
+
);
|
|
770
|
+
const { supportedPayments, unsupportedPayments } = seperateSupportedPayments(mappedPayments, this.accounts);
|
|
771
|
+
if (unsupportedPayments.length > 0) {
|
|
772
|
+
this.logError({ unsupportedPayments });
|
|
773
|
+
await this.pushToQueue(
|
|
774
|
+
this.env.QUEUE_BUS_QUEUE,
|
|
775
|
+
unsupportedPayments.map((unsupported) => ({
|
|
776
|
+
eventType: "BANK_PAYMENT",
|
|
777
|
+
bankPayment: {
|
|
778
|
+
...unsupported,
|
|
779
|
+
status: "FAILED",
|
|
780
|
+
statusReason: "UNSUPPORTED_ACCOUNT",
|
|
781
|
+
paymentType: unsupported.paymentType,
|
|
782
|
+
creditorAccountNumberWithBankCode: unsupported.creditorAccountNumberWithBankCode,
|
|
783
|
+
creditorIban: unsupported.creditorIban,
|
|
784
|
+
creditorHolderName: unsupported.creditorHolderName,
|
|
785
|
+
debtorAccountNumberWithBankCode: unsupported.debtorAccountNumberWithBankCode,
|
|
786
|
+
debtorIban: unsupported.debtorIban,
|
|
787
|
+
debtorHolderName: unsupported.debtorHolderName
|
|
788
|
+
},
|
|
789
|
+
metadata: {
|
|
790
|
+
correlationId: uuidv4(),
|
|
791
|
+
timestamp: (/* @__PURE__ */ new Date()).toDateString()
|
|
792
|
+
}
|
|
793
|
+
}))
|
|
794
|
+
);
|
|
795
|
+
}
|
|
796
|
+
for (const acc of this.accounts) {
|
|
797
|
+
const newPayments = supportedPayments.filter(
|
|
798
|
+
(payment) => payment.debtorIban === acc.identification.iban && payment.currency === acc.currency
|
|
799
|
+
);
|
|
800
|
+
if (newPayments.length === 0) {
|
|
801
|
+
continue;
|
|
802
|
+
}
|
|
803
|
+
this.log({
|
|
804
|
+
message: `\u{1F4B0} Processing ${newPayments.length} payments for account ${acc.id} (${acc.identification.iban}, ${acc.currency})`
|
|
805
|
+
});
|
|
806
|
+
const existingBatch = await getOpenBatchByAccountIdQuery(this.db, {
|
|
807
|
+
accountId: acc.id
|
|
808
|
+
});
|
|
809
|
+
if (existingBatch) {
|
|
810
|
+
this.log({
|
|
811
|
+
message: `\u{1F504} Found existing OPEN batch for account ${acc.id}, merging ${existingBatch.payments.length} existing + ${newPayments.length} new payments`
|
|
812
|
+
});
|
|
813
|
+
} else {
|
|
814
|
+
this.log({
|
|
815
|
+
message: `\u2728 Creating new batch for account ${acc.id} with ${newPayments.length} payments`
|
|
816
|
+
});
|
|
817
|
+
}
|
|
818
|
+
const { command } = upsertBatchCommand(this.db, {
|
|
819
|
+
batch: existingBatch ? {
|
|
820
|
+
...existingBatch,
|
|
821
|
+
payments: [...existingBatch.payments, ...newPayments]
|
|
822
|
+
} : {
|
|
823
|
+
id: uuidv4(),
|
|
824
|
+
authorizationUrls: [],
|
|
825
|
+
accountId: acc.id,
|
|
826
|
+
payments: newPayments,
|
|
827
|
+
status: "OPEN"
|
|
828
|
+
}
|
|
829
|
+
});
|
|
830
|
+
const upsertedBatch = await command.execute();
|
|
831
|
+
this.log({
|
|
832
|
+
message: `\u2705 Batch upserted successfully for account ${acc.id}`
|
|
833
|
+
});
|
|
834
|
+
return upsertedBatch;
|
|
835
|
+
}
|
|
836
|
+
});
|
|
837
|
+
}
|
|
838
|
+
async processBatch({
|
|
839
|
+
batch,
|
|
840
|
+
connectorKey
|
|
841
|
+
}) {
|
|
842
|
+
return this.handleAction(null, {}, async () => {
|
|
843
|
+
this.logInput({ batch, connectorKey });
|
|
844
|
+
await upsertBatchCommand(this.db, {
|
|
845
|
+
batch: {
|
|
846
|
+
...batch,
|
|
847
|
+
status: "PROCESSING"
|
|
848
|
+
}
|
|
849
|
+
}).command.execute();
|
|
850
|
+
await this.initiateBankConnector({ connectorKey });
|
|
851
|
+
if (!this.bankConnector) {
|
|
852
|
+
throw createInternalError(null, {
|
|
853
|
+
message: `\u274C Failed to initialize ${connectorKey} bank connector`
|
|
854
|
+
});
|
|
855
|
+
}
|
|
856
|
+
this.log({
|
|
857
|
+
message: `\u2705 Bank connector initialized successfully for account ${connectorKey}`
|
|
858
|
+
});
|
|
859
|
+
const preparedBatch = {
|
|
860
|
+
retriedPayments: [],
|
|
861
|
+
newlyPreparedPayments: [],
|
|
862
|
+
failedPayments: []
|
|
863
|
+
};
|
|
864
|
+
for (const payment of batch.payments) {
|
|
865
|
+
const existingPayment = await getPaymentByRefIdQuery(this.db, {
|
|
866
|
+
refId: payment.refId
|
|
867
|
+
});
|
|
868
|
+
if (existingPayment) {
|
|
869
|
+
preparedBatch.retriedPayments.push({
|
|
870
|
+
...existingPayment,
|
|
871
|
+
status: "PREPARED"
|
|
872
|
+
});
|
|
873
|
+
this.log({
|
|
874
|
+
message: `\u2705 Payment ${existingPayment.id} already exists`
|
|
875
|
+
});
|
|
876
|
+
continue;
|
|
877
|
+
}
|
|
878
|
+
const newlyPreparedPayment = await this.bankConnector.preparePayment(payment);
|
|
879
|
+
if (!newlyPreparedPayment) {
|
|
880
|
+
preparedBatch.failedPayments.push({ ...payment, status: "FAILED" });
|
|
881
|
+
continue;
|
|
882
|
+
}
|
|
883
|
+
preparedBatch.newlyPreparedPayments.push(newlyPreparedPayment);
|
|
884
|
+
}
|
|
885
|
+
await Promise.all([
|
|
886
|
+
[
|
|
887
|
+
...preparedBatch.failedPayments,
|
|
888
|
+
...preparedBatch.newlyPreparedPayments
|
|
889
|
+
].map(
|
|
890
|
+
(p) => createPaymentCommand(this.db, { payment: p }).command.execute()
|
|
891
|
+
)
|
|
892
|
+
]);
|
|
893
|
+
const { authorizationUrls, payments, metadata } = await this.bankConnector.initiateBatchFromPayments({
|
|
894
|
+
payments: [
|
|
895
|
+
...preparedBatch.newlyPreparedPayments,
|
|
896
|
+
...preparedBatch.retriedPayments
|
|
897
|
+
]
|
|
898
|
+
});
|
|
899
|
+
if (!authorizationUrls) {
|
|
900
|
+
this.logError({ message: "Failed to retrieve signing URI" });
|
|
901
|
+
return;
|
|
902
|
+
}
|
|
903
|
+
const { command: upsertBatch } = upsertBatchCommand(this.db, {
|
|
904
|
+
batch: {
|
|
905
|
+
...batch,
|
|
906
|
+
payments,
|
|
907
|
+
metadata,
|
|
908
|
+
status: "READY_TO_SIGN",
|
|
909
|
+
authorizationUrls,
|
|
910
|
+
batchPaymentInitiatedAt: /* @__PURE__ */ new Date()
|
|
911
|
+
}
|
|
912
|
+
});
|
|
913
|
+
const updatePayments = payments.map(
|
|
914
|
+
(payment) => updatePaymentCommand(this.db, {
|
|
915
|
+
payment: { ...payment, status: "INITIALIZED" }
|
|
916
|
+
}).command
|
|
917
|
+
);
|
|
918
|
+
await this.db.batch([upsertBatch, ...updatePayments]);
|
|
919
|
+
this.log({
|
|
920
|
+
message: "Authorization Urls for batch to create",
|
|
921
|
+
authorizationUrl: authorizationUrls[0]
|
|
922
|
+
});
|
|
923
|
+
await this.pushToQueue(this.env.NOTIFICATIONS_QUEUE, {
|
|
924
|
+
type: "email",
|
|
925
|
+
payload: {
|
|
926
|
+
email: {
|
|
927
|
+
to: ["petr@develit.io"],
|
|
928
|
+
subject: "Payment Authorization",
|
|
929
|
+
text: authorizationUrls[0] || "No Authorization Url"
|
|
930
|
+
}
|
|
931
|
+
},
|
|
932
|
+
metadata: {
|
|
933
|
+
initiator: {
|
|
934
|
+
service: this.name
|
|
935
|
+
}
|
|
936
|
+
}
|
|
937
|
+
});
|
|
938
|
+
this.logOutput({ message: "Batch successfully processed" });
|
|
939
|
+
});
|
|
940
|
+
}
|
|
941
|
+
async queue(b) {
|
|
942
|
+
await this.handleAction(
|
|
943
|
+
null,
|
|
944
|
+
{ successMessage: "Queue handler executed successfully" },
|
|
945
|
+
async () => {
|
|
946
|
+
this.logQueuePull(b);
|
|
947
|
+
const queueHandlerResponse = await this.addPaymentsToBatch({
|
|
948
|
+
paymentsToBatch: b.messages.map(({ body }) => body)
|
|
949
|
+
});
|
|
950
|
+
this.logOutput(queueHandlerResponse);
|
|
951
|
+
}
|
|
952
|
+
);
|
|
953
|
+
}
|
|
954
|
+
async getErsteCodeURI() {
|
|
955
|
+
return this.handleAction(
|
|
956
|
+
null,
|
|
957
|
+
{ successMessage: "Erste URI code obtained." },
|
|
958
|
+
async () => {
|
|
959
|
+
this.bankConnector = initiateConnector("ERSTE", this.env);
|
|
960
|
+
const uri = this.bankConnector instanceof ErsteConnector ? this.bankConnector.adminCodeCreationURI : "nothing";
|
|
961
|
+
return { uri };
|
|
962
|
+
}
|
|
963
|
+
);
|
|
964
|
+
}
|
|
965
|
+
async saveErsteCode(input) {
|
|
966
|
+
return this.handleAction(
|
|
967
|
+
{ data: input, schema: saveErsteCodeInputSchema },
|
|
968
|
+
{ successMessage: "Erste code saved." },
|
|
969
|
+
async ({ code }) => {
|
|
970
|
+
this.bankConnector = initiateConnector("ERSTE", this.env);
|
|
971
|
+
const token = await this.bankConnector.authenticate({
|
|
972
|
+
token: code
|
|
973
|
+
});
|
|
974
|
+
await this.env.BANK_KV.put("ERSTE:refreshToken", token);
|
|
975
|
+
}
|
|
976
|
+
);
|
|
977
|
+
}
|
|
978
|
+
async saveOrUpdatePayments(accounts) {
|
|
979
|
+
const { setLastSync } = useSync(this.env.BANK_KV);
|
|
980
|
+
return this.handleAction(null, {}, async () => {
|
|
981
|
+
const allFetchedPayments = [];
|
|
982
|
+
const connectorKeys = new Set(
|
|
983
|
+
accounts.map(({ connectorKey }) => connectorKey)
|
|
984
|
+
);
|
|
985
|
+
for (const connectorKey of connectorKeys) {
|
|
986
|
+
await this.initiateBankConnector({ connectorKey });
|
|
987
|
+
for (const account of accounts.filter(
|
|
988
|
+
(acc) => acc.connectorKey === connectorKey
|
|
989
|
+
)) {
|
|
990
|
+
const { lastSyncAt } = account;
|
|
991
|
+
const payments = await this.bankConnector.getAllAccountPayments({
|
|
992
|
+
db: this.db,
|
|
993
|
+
env: this.env.ENVIRONMENT,
|
|
994
|
+
account,
|
|
995
|
+
lastSync: lastSyncAt
|
|
996
|
+
});
|
|
997
|
+
if (!payments || payments.length === 0) continue;
|
|
998
|
+
this.log(payments);
|
|
999
|
+
payments.forEach((payment) => {
|
|
1000
|
+
payment.direction = getPaymentDirection(
|
|
1001
|
+
payment,
|
|
1002
|
+
account.identification.iban
|
|
1003
|
+
);
|
|
1004
|
+
});
|
|
1005
|
+
allFetchedPayments.push(...payments);
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
1008
|
+
if (allFetchedPayments.length < 1) return;
|
|
1009
|
+
const bankRefIds = allFetchedPayments.map((payment) => payment.bankRefId).filter(Boolean);
|
|
1010
|
+
const alreadyExistingPayments = await getPaymentsByBankRefIdsQuery(
|
|
1011
|
+
this.db,
|
|
1012
|
+
{ ids: bankRefIds }
|
|
1013
|
+
);
|
|
1014
|
+
const paymentsCommands = allFetchedPayments.map((payment) => {
|
|
1015
|
+
const isAlreadyExisting = alreadyExistingPayments.some(
|
|
1016
|
+
(existingPayment) => existingPayment.bankRefId === payment.bankRefId
|
|
1017
|
+
);
|
|
1018
|
+
if (isAlreadyExisting)
|
|
1019
|
+
return updatePaymentCommand(this.db, { payment }).command;
|
|
1020
|
+
return createPaymentCommand(this.db, { payment }).command;
|
|
1021
|
+
});
|
|
1022
|
+
await this.db.batch([paymentsCommands[0], ...paymentsCommands.slice(1)]);
|
|
1023
|
+
console.log("FETCHEDPAYMANETS TO SYNC", allFetchedPayments.length);
|
|
1024
|
+
for (const account of accounts) {
|
|
1025
|
+
const paymentsForAccount = allFetchedPayments.filter(
|
|
1026
|
+
(payment) => (payment.direction === "OUTGOING" ? payment.debtorIban : payment.creditorIban) === account.identification.iban
|
|
1027
|
+
);
|
|
1028
|
+
let lastSyncPayment;
|
|
1029
|
+
lastSyncPayment = paymentsForAccount.filter(({ status }) => status !== "COMPLETED").sort(
|
|
1030
|
+
(a, b) => (a.createdAt?.getTime() || 0) - (b.createdAt?.getTime() || 0)
|
|
1031
|
+
)[0];
|
|
1032
|
+
if (!lastSyncPayment) {
|
|
1033
|
+
lastSyncPayment = paymentsForAccount.sort(
|
|
1034
|
+
(a, b) => (b.createdAt?.getTime() || 0) - (a.createdAt?.getTime() || 0)
|
|
1035
|
+
)[0];
|
|
1036
|
+
}
|
|
1037
|
+
if (lastSyncPayment.createdAt) {
|
|
1038
|
+
await setLastSync({
|
|
1039
|
+
account,
|
|
1040
|
+
log: {
|
|
1041
|
+
lastSyncedAt: lastSyncPayment.createdAt
|
|
1042
|
+
}
|
|
1043
|
+
});
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1046
|
+
await this.pushToQueue(
|
|
1047
|
+
this.env.QUEUE_BUS_QUEUE,
|
|
1048
|
+
allFetchedPayments.map((payment) => ({
|
|
1049
|
+
eventType: "BANK_PAYMENT",
|
|
1050
|
+
bankPayment: payment,
|
|
1051
|
+
metadata: {
|
|
1052
|
+
correlationId: uuidv4(),
|
|
1053
|
+
timestamp: (/* @__PURE__ */ new Date()).toDateString()
|
|
1054
|
+
}
|
|
1055
|
+
}))
|
|
1056
|
+
);
|
|
1057
|
+
});
|
|
1058
|
+
}
|
|
1059
|
+
async simulateDeposit(input) {
|
|
1060
|
+
return this.handleAction(
|
|
1061
|
+
{ data: input, schema: simulateDepositInputSchema },
|
|
1062
|
+
{ successMessage: "Deposit saved." },
|
|
1063
|
+
async ({
|
|
1064
|
+
amount,
|
|
1065
|
+
currency,
|
|
1066
|
+
bankingVs,
|
|
1067
|
+
message,
|
|
1068
|
+
creditorIban,
|
|
1069
|
+
creditorHolderName,
|
|
1070
|
+
debtorIban,
|
|
1071
|
+
debtorHolderName
|
|
1072
|
+
}) => {
|
|
1073
|
+
const payment = {
|
|
1074
|
+
id: uuidv4(),
|
|
1075
|
+
amount,
|
|
1076
|
+
direction: "INCOMING",
|
|
1077
|
+
paymentType: "DOMESTIC",
|
|
1078
|
+
currency,
|
|
1079
|
+
status: "COMPLETED",
|
|
1080
|
+
batchId: uuidv4(),
|
|
1081
|
+
initiatedAt: /* @__PURE__ */ new Date(),
|
|
1082
|
+
processedAt: /* @__PURE__ */ new Date(),
|
|
1083
|
+
vs: bankingVs,
|
|
1084
|
+
message,
|
|
1085
|
+
creditorIban,
|
|
1086
|
+
creditorHolderName,
|
|
1087
|
+
debtorIban,
|
|
1088
|
+
debtorHolderName
|
|
1089
|
+
};
|
|
1090
|
+
const { command } = createPaymentCommand(this.db, { payment });
|
|
1091
|
+
const createdPayment = await command.execute().then(first);
|
|
1092
|
+
this.logQueuePush({ payment, isPaymentExecuted: true });
|
|
1093
|
+
await this.pushToQueue(this.env.QUEUE_BUS_QUEUE, {
|
|
1094
|
+
eventType: "BANK_PAYMENT",
|
|
1095
|
+
bankPayment: createdPayment,
|
|
1096
|
+
metadata: {
|
|
1097
|
+
correlationId: createdPayment.id,
|
|
1098
|
+
timestamp: (/* @__PURE__ */ new Date()).toDateString()
|
|
1099
|
+
}
|
|
1100
|
+
});
|
|
1101
|
+
return createdPayment;
|
|
1102
|
+
}
|
|
1103
|
+
);
|
|
1104
|
+
}
|
|
1105
|
+
async setLastSyncAt(input) {
|
|
1106
|
+
return this.handleAction(
|
|
1107
|
+
{ data: input, schema: setLastSyncAtInputSchema },
|
|
1108
|
+
{ successMessage: "Last sync set." },
|
|
1109
|
+
async ({ iban, lastSyncedAt }) => {
|
|
1110
|
+
const { setLastSync } = useSync(this.env.BANK_KV);
|
|
1111
|
+
const configAccount = this.accounts.find(
|
|
1112
|
+
(acc) => acc.identification.iban === iban
|
|
1113
|
+
);
|
|
1114
|
+
if (!configAccount) {
|
|
1115
|
+
throw createInternalError(null, {
|
|
1116
|
+
status: 404,
|
|
1117
|
+
message: "Account for this organization does not exist."
|
|
1118
|
+
});
|
|
1119
|
+
}
|
|
1120
|
+
await setLastSync({
|
|
1121
|
+
log: {
|
|
1122
|
+
lastSyncedAt
|
|
1123
|
+
},
|
|
1124
|
+
account: configAccount
|
|
1125
|
+
});
|
|
1126
|
+
return {};
|
|
1127
|
+
}
|
|
1128
|
+
);
|
|
1129
|
+
}
|
|
1130
|
+
async sendPayment(input) {
|
|
1131
|
+
return this.handleAction(
|
|
1132
|
+
{ data: input, schema: sendPaymentInputSchema },
|
|
1133
|
+
{ successMessage: "Payment queued successfully" },
|
|
1134
|
+
async (data) => {
|
|
1135
|
+
await this.pushToQueue(
|
|
1136
|
+
this.env.PAYMENTS_READY_TO_BATCH_QUEUE,
|
|
1137
|
+
data
|
|
1138
|
+
);
|
|
1139
|
+
}
|
|
1140
|
+
);
|
|
1141
|
+
}
|
|
1142
|
+
async getBankAccounts() {
|
|
1143
|
+
return RPCResponse.ok("Bank accounts retrieved successfully", {
|
|
1144
|
+
data: this.accounts
|
|
1145
|
+
});
|
|
1146
|
+
}
|
|
1147
|
+
async getBatches(input) {
|
|
1148
|
+
return this.handleAction(
|
|
1149
|
+
{ data: input, schema: getBatchesInputSchema },
|
|
1150
|
+
{ successMessage: "Batches retrieved successfully" },
|
|
1151
|
+
async ({ limit = 100, offset = 0 }) => {
|
|
1152
|
+
const [batchesResult, countResult] = await Promise.all([
|
|
1153
|
+
this.db.select().from(tables.batch).limit(limit).offset(offset).orderBy(desc(tables.batch.createdAt)),
|
|
1154
|
+
this.db.select({ count: sql`count(*)`.as("count") }).from(tables.batch)
|
|
1155
|
+
]);
|
|
1156
|
+
const totalCount = Number(countResult[0]?.count) || 0;
|
|
1157
|
+
return {
|
|
1158
|
+
batches: batchesResult,
|
|
1159
|
+
totalCount
|
|
1160
|
+
};
|
|
1161
|
+
}
|
|
1162
|
+
);
|
|
1163
|
+
}
|
|
1164
|
+
}
|
|
1165
|
+
__decorateClass([
|
|
1166
|
+
action("synchronize-accounts")
|
|
1167
|
+
], BankServiceBase.prototype, "syncAccounts");
|
|
1168
|
+
__decorateClass([
|
|
1169
|
+
action("scheduled")
|
|
1170
|
+
], BankServiceBase.prototype, "scheduled");
|
|
1171
|
+
__decorateClass([
|
|
1172
|
+
action("add-payments-to-batch")
|
|
1173
|
+
], BankServiceBase.prototype, "addPaymentsToBatch");
|
|
1174
|
+
__decorateClass([
|
|
1175
|
+
action("process-batch")
|
|
1176
|
+
], BankServiceBase.prototype, "processBatch");
|
|
1177
|
+
__decorateClass([
|
|
1178
|
+
action("queue-handler")
|
|
1179
|
+
], BankServiceBase.prototype, "queue");
|
|
1180
|
+
__decorateClass([
|
|
1181
|
+
action("get-erste-code-uri")
|
|
1182
|
+
], BankServiceBase.prototype, "getErsteCodeURI");
|
|
1183
|
+
__decorateClass([
|
|
1184
|
+
action("save-erste-code")
|
|
1185
|
+
], BankServiceBase.prototype, "saveErsteCode");
|
|
1186
|
+
__decorateClass([
|
|
1187
|
+
action("save-or-update-payments")
|
|
1188
|
+
], BankServiceBase.prototype, "saveOrUpdatePayments");
|
|
1189
|
+
__decorateClass([
|
|
1190
|
+
action("simulate-deposit")
|
|
1191
|
+
], BankServiceBase.prototype, "simulateDeposit");
|
|
1192
|
+
__decorateClass([
|
|
1193
|
+
action("set-last-sync-at")
|
|
1194
|
+
], BankServiceBase.prototype, "setLastSyncAt");
|
|
1195
|
+
__decorateClass([
|
|
1196
|
+
action("send-payment")
|
|
1197
|
+
], BankServiceBase.prototype, "sendPayment");
|
|
1198
|
+
__decorateClass([
|
|
1199
|
+
action("get-bank-accounts")
|
|
1200
|
+
], BankServiceBase.prototype, "getBankAccounts");
|
|
1201
|
+
__decorateClass([
|
|
1202
|
+
action("getBatches")
|
|
1203
|
+
], BankServiceBase.prototype, "getBatches");
|
|
1204
|
+
function defineBankService() {
|
|
1205
|
+
return class BankService extends BankServiceBase {
|
|
1206
|
+
constructor(ctx, env) {
|
|
1207
|
+
super(ctx, env);
|
|
1208
|
+
}
|
|
1209
|
+
};
|
|
1210
|
+
}
|
|
1211
|
+
|
|
1212
|
+
const BankService = defineBankService();
|
|
1213
|
+
|
|
1214
|
+
export { BankService as default, defineBankService };
|