@develit-services/bank 0.8.6 → 0.8.7
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/database/schema.cjs +1 -1
- package/dist/database/schema.d.cts +1 -1
- package/dist/database/schema.d.mts +1 -1
- package/dist/database/schema.d.ts +1 -1
- package/dist/database/schema.mjs +1 -1
- package/dist/export/worker.cjs +583 -146
- package/dist/export/worker.d.cts +251 -39
- package/dist/export/worker.d.mts +251 -39
- package/dist/export/worker.d.ts +251 -39
- package/dist/export/worker.mjs +584 -147
- package/dist/export/workflows.cjs +132 -16
- package/dist/export/workflows.mjs +133 -17
- package/dist/shared/{bank.C-T1FQxg.cjs → bank.62VzK9Aj.cjs} +1 -1
- package/dist/shared/{bank.SQ4Mmr8u.cjs → bank.BS7fFjGA.cjs} +34 -4
- package/dist/shared/{bank.B6U8sUZn.d.mts → bank.BYRq3yJf.d.ts} +17 -7
- package/dist/shared/{bank.C4VOdIx1.mjs → bank.C0UN6luZ.mjs} +34 -4
- package/dist/shared/{bank.DDHrdFgy.mjs → bank.CA5ytXxp.mjs} +1 -1
- package/dist/shared/{bank.BoMDujsl.d.ts → bank.CO89tR9U.d.cts} +17 -7
- package/dist/shared/{bank.BliD3oCT.d.ts → bank.Cns5ss41.d.cts} +47 -10
- package/dist/shared/{bank.BliD3oCT.d.cts → bank.Cns5ss41.d.mts} +47 -10
- package/dist/shared/{bank.BliD3oCT.d.mts → bank.Cns5ss41.d.ts} +47 -10
- package/dist/shared/{bank.lbzMqyr3.d.cts → bank.CreoSb2d.d.mts} +17 -7
- package/dist/shared/{bank.DRrBrAdI.mjs → bank.D1jqaHaF.mjs} +91 -31
- package/dist/shared/{bank.Cpy9PULF.mjs → bank.DEmzZGZW.mjs} +31 -5
- package/dist/shared/{bank.BOnP9p9Y.cjs → bank.Dm8GHThw.cjs} +31 -5
- package/dist/shared/{bank.CQURey1E.cjs → bank.DwyCCyd0.cjs} +90 -31
- package/dist/types.cjs +3 -4
- package/dist/types.d.cts +8 -16
- package/dist/types.d.mts +8 -16
- package/dist/types.d.ts +8 -16
- package/dist/types.mjs +3 -3
- package/package.json +2 -2
package/dist/export/worker.mjs
CHANGED
|
@@ -1,27 +1,27 @@
|
|
|
1
1
|
import { uuidv4, first, buildMultiFilterConditions as buildMultiFilterConditions$1, bankAccountMetadataSchema, workflowInstanceStatusSchema, develitWorker, createInternalError, action, service } from '@develit-io/backend-sdk';
|
|
2
|
-
import { t as tables, h as encrypt, d as createCredentialsResolver, u as upsertBatchCommand, a as getPaymentRequestsByBatchIdQuery, e as updatePaymentRequestStatusCommand, g as getBatchByIdQuery, i as importAesKey, f as createPaymentCommand, b as getAccountByIdQuery } from '../shared/bank.
|
|
2
|
+
import { t as tables, h as encrypt, d as createCredentialsResolver, u as upsertBatchCommand, a as getPaymentRequestsByBatchIdQuery, e as updatePaymentRequestStatusCommand, g as getBatchByIdQuery, i as importAesKey, f as createPaymentCommand, b as getAccountByIdQuery } from '../shared/bank.DEmzZGZW.mjs';
|
|
3
3
|
import { WorkerEntrypoint } from 'cloudflare:workers';
|
|
4
4
|
import { drizzle } from 'drizzle-orm/d1';
|
|
5
|
-
import {
|
|
5
|
+
import { j as initiateConnector, m as mapFinbricksTransactionStatus, g as toIncomingPayment, d as assignAccount, t as toBatchedPayment, a as FinbricksClient, F as FINBRICKS_ENDPOINTS, h as toPaymentRequestInsert } from '../shared/bank.D1jqaHaF.mjs';
|
|
6
6
|
import 'jose';
|
|
7
7
|
import { z } from 'zod';
|
|
8
|
-
import { I as INSTRUCTION_PRIORITIES, C as CHARGE_BEARERS, e as PAYMENT_TYPES, a as CONNECTOR_KEYS, B as BATCH_STATUSES, d as PAYMENT_STATUSES, P as PAYMENT_DIRECTIONS, i as accountInsertSchema } from '../shared/bank.
|
|
8
|
+
import { I as INSTRUCTION_PRIORITIES, C as CHARGE_BEARERS, e as PAYMENT_TYPES, a as CONNECTOR_KEYS, B as BATCH_STATUSES, d as PAYMENT_STATUSES, P as PAYMENT_DIRECTIONS, i as accountInsertSchema } from '../shared/bank.C0UN6luZ.mjs';
|
|
9
9
|
import { CURRENCY_CODES } from '@develit-io/general-codes';
|
|
10
10
|
import 'date-fns';
|
|
11
|
-
import { eq, sql, and, inArray, asc, desc, gte, lte } from 'drizzle-orm';
|
|
11
|
+
import { eq, sql, and, inArray, like, asc, desc, gte, lte, isNull, or, isNotNull } from 'drizzle-orm';
|
|
12
|
+
import { unionAll } from 'drizzle-orm/sqlite-core';
|
|
12
13
|
import 'node:crypto';
|
|
13
|
-
import '../shared/bank.
|
|
14
|
+
import '../shared/bank.CA5ytXxp.mjs';
|
|
14
15
|
import 'drizzle-orm/relations';
|
|
15
|
-
import 'drizzle-orm/sqlite-core';
|
|
16
16
|
import 'drizzle-zod';
|
|
17
17
|
|
|
18
18
|
const upsertAccountCommand = (db, { account }) => {
|
|
19
19
|
const id = account.id || uuidv4();
|
|
20
|
+
const { id: _id, ...accountWithoutId } = account;
|
|
20
21
|
const command = db.insert(tables.account).values({ ...account, id }).onConflictDoUpdate({
|
|
21
22
|
target: tables.account.iban,
|
|
22
|
-
set:
|
|
23
|
-
|
|
24
|
-
}
|
|
23
|
+
set: accountWithoutId
|
|
24
|
+
// preserve existing id on re-auth
|
|
25
25
|
}).returning();
|
|
26
26
|
return {
|
|
27
27
|
id,
|
|
@@ -139,16 +139,25 @@ const getAllAccountsQuery = async (db, filters) => {
|
|
|
139
139
|
filters?.filterBankRefIds
|
|
140
140
|
)
|
|
141
141
|
);
|
|
142
|
-
const
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
}
|
|
151
|
-
|
|
142
|
+
const page = filters?.page ?? 1;
|
|
143
|
+
const limit = filters?.limit ?? 20;
|
|
144
|
+
const offset = (page - 1) * limit;
|
|
145
|
+
const [accountsWithExpiration, countResult] = await Promise.all([
|
|
146
|
+
db.select().from(tables.account).leftJoin(
|
|
147
|
+
tables.accountCredentials,
|
|
148
|
+
eq(tables.accountCredentials.accountId, tables.account.id)
|
|
149
|
+
).where(whereConditions).limit(limit).offset(offset),
|
|
150
|
+
db.select({ count: sql`count(*)` }).from(tables.account).where(whereConditions)
|
|
151
|
+
]);
|
|
152
|
+
return {
|
|
153
|
+
accounts: accountsWithExpiration.map(
|
|
154
|
+
({ account, account_credentials }) => ({
|
|
155
|
+
...account,
|
|
156
|
+
expiresAt: account_credentials?.expiresAt
|
|
157
|
+
})
|
|
158
|
+
),
|
|
159
|
+
totalCount: countResult[0]?.count ?? 0
|
|
160
|
+
};
|
|
152
161
|
};
|
|
153
162
|
|
|
154
163
|
const getAllPendingBatchesQuery = (db) => {
|
|
@@ -189,7 +198,17 @@ const getPaymentsWithPaginationQuery = async (db, {
|
|
|
189
198
|
filterPaymentDateFrom,
|
|
190
199
|
filterPaymentDateTo,
|
|
191
200
|
filterPaymentStatus,
|
|
192
|
-
|
|
201
|
+
filterPaymentDirection,
|
|
202
|
+
filterPaymentType,
|
|
203
|
+
filterPaymentMinAmount,
|
|
204
|
+
filterPaymentMaxAmount,
|
|
205
|
+
filterPaymentVariableSymbol,
|
|
206
|
+
filterPaymentSpecificSymbol,
|
|
207
|
+
filterPaymentConstantSymbol,
|
|
208
|
+
filterPaymentMessage,
|
|
209
|
+
filterPaymentCreditorIban,
|
|
210
|
+
filterPaymentDebtorIban,
|
|
211
|
+
filterPaymentBatchId
|
|
193
212
|
}) => {
|
|
194
213
|
const whereConditions = and(
|
|
195
214
|
buildMultiFilterConditions(
|
|
@@ -206,9 +225,22 @@ const getPaymentsWithPaginationQuery = async (db, {
|
|
|
206
225
|
buildMultiFilterConditions(tables.payment.status, filterPaymentStatus),
|
|
207
226
|
buildMultiFilterConditions(
|
|
208
227
|
tables.payment.direction,
|
|
209
|
-
|
|
228
|
+
filterPaymentDirection
|
|
229
|
+
),
|
|
230
|
+
buildMultiFilterConditions(tables.payment.id, ids),
|
|
231
|
+
buildMultiFilterConditions(tables.payment.paymentType, filterPaymentType),
|
|
232
|
+
buildRangeFilterConditions(
|
|
233
|
+
tables.payment.amount,
|
|
234
|
+
filterPaymentMinAmount,
|
|
235
|
+
filterPaymentMaxAmount
|
|
210
236
|
),
|
|
211
|
-
|
|
237
|
+
filterPaymentVariableSymbol !== void 0 ? eq(tables.payment.vs, filterPaymentVariableSymbol) : void 0,
|
|
238
|
+
filterPaymentSpecificSymbol !== void 0 ? eq(tables.payment.ss, filterPaymentSpecificSymbol) : void 0,
|
|
239
|
+
filterPaymentConstantSymbol !== void 0 ? eq(tables.payment.ks, filterPaymentConstantSymbol) : void 0,
|
|
240
|
+
filterPaymentMessage !== void 0 ? like(tables.payment.message, `%${filterPaymentMessage}%`) : void 0,
|
|
241
|
+
filterPaymentCreditorIban !== void 0 ? eq(tables.payment.creditorIban, filterPaymentCreditorIban) : void 0,
|
|
242
|
+
filterPaymentDebtorIban !== void 0 ? eq(tables.payment.debtorIban, filterPaymentDebtorIban) : void 0,
|
|
243
|
+
filterPaymentBatchId !== void 0 ? eq(tables.payment.batchId, filterPaymentBatchId) : void 0
|
|
212
244
|
);
|
|
213
245
|
const sortColumn = resolveColumn(tables.payment, sort.column);
|
|
214
246
|
const [{ totalCount }] = await db.select({
|
|
@@ -268,28 +300,261 @@ const getOttQuery = async (db, { ott }) => {
|
|
|
268
300
|
};
|
|
269
301
|
|
|
270
302
|
const getPaymentRequestByIdQuery = async (db, { paymentId }) => {
|
|
271
|
-
const
|
|
272
|
-
|
|
303
|
+
const prResults = await db.select().from(tables.paymentRequest).where(
|
|
304
|
+
and(
|
|
305
|
+
eq(tables.paymentRequest.id, paymentId),
|
|
306
|
+
isNull(tables.paymentRequest.deletedAt)
|
|
307
|
+
)
|
|
308
|
+
).limit(1);
|
|
309
|
+
if (prResults[0]) return prResults[0];
|
|
310
|
+
const paymentResults = await db.select().from(tables.payment).where(
|
|
311
|
+
or(
|
|
312
|
+
eq(tables.payment.paymentRequestId, paymentId),
|
|
313
|
+
and(
|
|
314
|
+
isNull(tables.payment.paymentRequestId),
|
|
315
|
+
eq(tables.payment.id, paymentId)
|
|
316
|
+
)
|
|
317
|
+
)
|
|
318
|
+
).limit(1);
|
|
319
|
+
if (!paymentResults[0]) return null;
|
|
320
|
+
const p = paymentResults[0];
|
|
321
|
+
return {
|
|
322
|
+
...p,
|
|
323
|
+
id: p.paymentRequestId ?? p.id,
|
|
324
|
+
authorizationUrl: null,
|
|
325
|
+
sendAsSinglePayment: null,
|
|
326
|
+
direction: p.direction ?? "OUTGOING"
|
|
327
|
+
};
|
|
273
328
|
};
|
|
274
329
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
330
|
+
function isCompletedOnly(filterStatus) {
|
|
331
|
+
if (!filterStatus) return false;
|
|
332
|
+
const statuses = Array.isArray(filterStatus) ? filterStatus : [filterStatus];
|
|
333
|
+
return statuses.length > 0 && statuses.every((s) => s === "COMPLETED");
|
|
334
|
+
}
|
|
335
|
+
function mapPaymentToPaymentRequest(p) {
|
|
336
|
+
return {
|
|
337
|
+
id: p.id,
|
|
338
|
+
createdAt: p.createdAt,
|
|
339
|
+
createdBy: p.createdBy,
|
|
340
|
+
updatedAt: p.updatedAt,
|
|
341
|
+
updatedBy: p.updatedBy,
|
|
342
|
+
deletedAt: p.deletedAt,
|
|
343
|
+
deletedBy: p.deletedBy,
|
|
344
|
+
batchId: p.batchId,
|
|
345
|
+
accountId: p.accountId,
|
|
346
|
+
correlationId: p.correlationId,
|
|
347
|
+
refId: p.refId,
|
|
348
|
+
bankRefId: p.bankRefId,
|
|
349
|
+
connectorKey: p.connectorKey,
|
|
350
|
+
amount: p.amount,
|
|
351
|
+
paymentType: p.paymentType,
|
|
352
|
+
currency: p.currency,
|
|
353
|
+
status: p.status,
|
|
354
|
+
statusReason: p.statusReason,
|
|
355
|
+
initiatedAt: p.initiatedAt,
|
|
356
|
+
processedAt: p.processedAt,
|
|
357
|
+
vs: p.vs,
|
|
358
|
+
ss: p.ss,
|
|
359
|
+
ks: p.ks,
|
|
360
|
+
message: p.message,
|
|
361
|
+
chargeBearer: p.chargeBearer,
|
|
362
|
+
instructionPriority: p.instructionPriority,
|
|
363
|
+
creditor: p.creditor,
|
|
364
|
+
creditorIban: p.creditorIban,
|
|
365
|
+
debtor: p.debtor,
|
|
366
|
+
debtorIban: p.debtorIban,
|
|
367
|
+
authorizationUrl: null,
|
|
368
|
+
sendAsSinglePayment: null
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
const getUnionColumns = () => ({
|
|
372
|
+
id: tables.paymentRequest.id,
|
|
373
|
+
createdAt: tables.paymentRequest.createdAt,
|
|
374
|
+
createdBy: tables.paymentRequest.createdBy,
|
|
375
|
+
updatedAt: tables.paymentRequest.updatedAt,
|
|
376
|
+
updatedBy: tables.paymentRequest.updatedBy,
|
|
377
|
+
deletedAt: tables.paymentRequest.deletedAt,
|
|
378
|
+
deletedBy: tables.paymentRequest.deletedBy,
|
|
379
|
+
batchId: tables.paymentRequest.batchId,
|
|
380
|
+
accountId: tables.paymentRequest.accountId,
|
|
381
|
+
correlationId: tables.paymentRequest.correlationId,
|
|
382
|
+
refId: tables.paymentRequest.refId,
|
|
383
|
+
bankRefId: tables.paymentRequest.bankRefId,
|
|
384
|
+
connectorKey: tables.paymentRequest.connectorKey,
|
|
385
|
+
amount: tables.paymentRequest.amount,
|
|
386
|
+
paymentType: tables.paymentRequest.paymentType,
|
|
387
|
+
currency: tables.paymentRequest.currency,
|
|
388
|
+
status: tables.paymentRequest.status,
|
|
389
|
+
statusReason: tables.paymentRequest.statusReason,
|
|
390
|
+
authorizationUrl: tables.paymentRequest.authorizationUrl,
|
|
391
|
+
initiatedAt: tables.paymentRequest.initiatedAt,
|
|
392
|
+
processedAt: tables.paymentRequest.processedAt,
|
|
393
|
+
vs: tables.paymentRequest.vs,
|
|
394
|
+
ss: tables.paymentRequest.ss,
|
|
395
|
+
ks: tables.paymentRequest.ks,
|
|
396
|
+
message: tables.paymentRequest.message,
|
|
397
|
+
chargeBearer: tables.paymentRequest.chargeBearer,
|
|
398
|
+
instructionPriority: tables.paymentRequest.instructionPriority,
|
|
399
|
+
creditor: tables.paymentRequest.creditor,
|
|
400
|
+
creditorIban: tables.paymentRequest.creditorIban,
|
|
401
|
+
debtor: tables.paymentRequest.debtor,
|
|
402
|
+
debtorIban: tables.paymentRequest.debtorIban,
|
|
403
|
+
sendAsSinglePayment: tables.paymentRequest.sendAsSinglePayment,
|
|
404
|
+
// payment_request je vždy OUTGOING — typ musí být kompatibilní s payment.direction
|
|
405
|
+
direction: sql`'OUTGOING'`.as("direction")
|
|
406
|
+
});
|
|
407
|
+
const getPaymentUnionColumns = () => ({
|
|
408
|
+
id: sql`COALESCE(${tables.payment.paymentRequestId}, ${tables.payment.id})`.as(
|
|
409
|
+
"id"
|
|
410
|
+
),
|
|
411
|
+
createdAt: tables.payment.createdAt,
|
|
412
|
+
createdBy: tables.payment.createdBy,
|
|
413
|
+
updatedAt: tables.payment.updatedAt,
|
|
414
|
+
updatedBy: tables.payment.updatedBy,
|
|
415
|
+
deletedAt: tables.payment.deletedAt,
|
|
416
|
+
deletedBy: tables.payment.deletedBy,
|
|
417
|
+
batchId: tables.payment.batchId,
|
|
418
|
+
accountId: tables.payment.accountId,
|
|
419
|
+
correlationId: tables.payment.correlationId,
|
|
420
|
+
refId: tables.payment.refId,
|
|
421
|
+
bankRefId: tables.payment.bankRefId,
|
|
422
|
+
connectorKey: tables.payment.connectorKey,
|
|
423
|
+
amount: tables.payment.amount,
|
|
424
|
+
paymentType: tables.payment.paymentType,
|
|
425
|
+
currency: tables.payment.currency,
|
|
426
|
+
status: tables.payment.status,
|
|
427
|
+
statusReason: tables.payment.statusReason,
|
|
428
|
+
authorizationUrl: sql`NULL`.as("authorization_url"),
|
|
429
|
+
initiatedAt: tables.payment.initiatedAt,
|
|
430
|
+
processedAt: tables.payment.processedAt,
|
|
431
|
+
vs: tables.payment.vs,
|
|
432
|
+
ss: tables.payment.ss,
|
|
433
|
+
ks: tables.payment.ks,
|
|
434
|
+
message: tables.payment.message,
|
|
435
|
+
chargeBearer: tables.payment.chargeBearer,
|
|
436
|
+
instructionPriority: tables.payment.instructionPriority,
|
|
437
|
+
creditor: tables.payment.creditor,
|
|
438
|
+
creditorIban: tables.payment.creditorIban,
|
|
439
|
+
debtor: tables.payment.debtor,
|
|
440
|
+
debtorIban: tables.payment.debtorIban,
|
|
441
|
+
sendAsSinglePayment: sql`NULL`.as("send_as_single_payment"),
|
|
442
|
+
direction: tables.payment.direction
|
|
443
|
+
});
|
|
444
|
+
const getPaymentRequestsWithPaginationQuery = async (db, {
|
|
445
|
+
limit,
|
|
446
|
+
page,
|
|
447
|
+
sort,
|
|
448
|
+
filterAccountId,
|
|
449
|
+
filterStatus,
|
|
450
|
+
filterPaymentType,
|
|
451
|
+
filterCurrency,
|
|
452
|
+
filterMinAmount,
|
|
453
|
+
filterMaxAmount,
|
|
454
|
+
filterBatchId,
|
|
455
|
+
filterCreditorIban,
|
|
456
|
+
filterDebtorIban,
|
|
457
|
+
filterDateFrom,
|
|
458
|
+
filterDateTo,
|
|
459
|
+
filterVariableSymbol,
|
|
460
|
+
filterSpecificSymbol,
|
|
461
|
+
filterConstantSymbol,
|
|
462
|
+
filterMessage,
|
|
463
|
+
filterBankRefId,
|
|
464
|
+
filterPaymentId,
|
|
465
|
+
filterDirection,
|
|
466
|
+
filterSource
|
|
467
|
+
}) => {
|
|
468
|
+
const offset = (page - 1) * limit;
|
|
469
|
+
const buildPrWhereConditions = () => and(
|
|
470
|
+
isNull(tables.paymentRequest.deletedAt),
|
|
471
|
+
buildMultiFilterConditions(
|
|
472
|
+
tables.paymentRequest.accountId,
|
|
473
|
+
filterAccountId
|
|
474
|
+
),
|
|
475
|
+
buildMultiFilterConditions(tables.paymentRequest.status, filterStatus),
|
|
476
|
+
buildMultiFilterConditions(
|
|
477
|
+
tables.paymentRequest.paymentType,
|
|
478
|
+
filterPaymentType
|
|
479
|
+
),
|
|
480
|
+
buildMultiFilterConditions(
|
|
481
|
+
tables.paymentRequest.currency,
|
|
482
|
+
filterCurrency
|
|
483
|
+
),
|
|
484
|
+
buildRangeFilterConditions(
|
|
485
|
+
tables.paymentRequest.amount,
|
|
486
|
+
filterMinAmount,
|
|
487
|
+
filterMaxAmount
|
|
488
|
+
),
|
|
489
|
+
filterBatchId !== void 0 ? eq(tables.paymentRequest.batchId, filterBatchId) : void 0,
|
|
490
|
+
filterCreditorIban !== void 0 ? eq(tables.paymentRequest.creditorIban, filterCreditorIban) : void 0,
|
|
491
|
+
filterDebtorIban !== void 0 ? eq(tables.paymentRequest.debtorIban, filterDebtorIban) : void 0,
|
|
492
|
+
filterDateFrom !== void 0 ? gte(tables.paymentRequest.createdAt, filterDateFrom) : void 0,
|
|
493
|
+
filterDateTo !== void 0 ? lte(tables.paymentRequest.createdAt, filterDateTo) : void 0,
|
|
494
|
+
filterVariableSymbol !== void 0 ? eq(tables.paymentRequest.vs, filterVariableSymbol) : void 0,
|
|
495
|
+
filterSpecificSymbol !== void 0 ? eq(tables.paymentRequest.ss, filterSpecificSymbol) : void 0,
|
|
496
|
+
filterConstantSymbol !== void 0 ? eq(tables.paymentRequest.ks, filterConstantSymbol) : void 0,
|
|
497
|
+
filterMessage !== void 0 ? like(tables.paymentRequest.message, `%${filterMessage}%`) : void 0,
|
|
498
|
+
filterBankRefId !== void 0 ? eq(tables.paymentRequest.bankRefId, filterBankRefId) : void 0,
|
|
499
|
+
filterPaymentId !== void 0 ? eq(tables.paymentRequest.id, filterPaymentId) : void 0,
|
|
500
|
+
// payment_request is always OUTGOING — exclude branch entirely when filtering INCOMING
|
|
501
|
+
filterDirection === "INCOMING" ? sql`0` : void 0,
|
|
502
|
+
// payment_request is always API (has no bank-synced payments)
|
|
503
|
+
filterSource === "BANK" ? sql`0` : void 0
|
|
289
504
|
);
|
|
505
|
+
const buildPaymentWhereConditions = () => and(
|
|
506
|
+
isNull(tables.payment.deletedAt),
|
|
507
|
+
buildMultiFilterConditions(tables.payment.accountId, filterAccountId),
|
|
508
|
+
buildMultiFilterConditions(tables.payment.status, filterStatus),
|
|
509
|
+
buildMultiFilterConditions(tables.payment.paymentType, filterPaymentType),
|
|
510
|
+
buildMultiFilterConditions(tables.payment.currency, filterCurrency),
|
|
511
|
+
buildRangeFilterConditions(
|
|
512
|
+
tables.payment.amount,
|
|
513
|
+
filterMinAmount,
|
|
514
|
+
filterMaxAmount
|
|
515
|
+
),
|
|
516
|
+
filterBatchId !== void 0 ? eq(tables.payment.batchId, filterBatchId) : void 0,
|
|
517
|
+
filterCreditorIban !== void 0 ? eq(tables.payment.creditorIban, filterCreditorIban) : void 0,
|
|
518
|
+
filterDebtorIban !== void 0 ? eq(tables.payment.debtorIban, filterDebtorIban) : void 0,
|
|
519
|
+
filterDateFrom !== void 0 ? gte(tables.payment.createdAt, filterDateFrom) : void 0,
|
|
520
|
+
filterDateTo !== void 0 ? lte(tables.payment.createdAt, filterDateTo) : void 0,
|
|
521
|
+
filterVariableSymbol !== void 0 ? eq(tables.payment.vs, filterVariableSymbol) : void 0,
|
|
522
|
+
filterSpecificSymbol !== void 0 ? eq(tables.payment.ss, filterSpecificSymbol) : void 0,
|
|
523
|
+
filterConstantSymbol !== void 0 ? eq(tables.payment.ks, filterConstantSymbol) : void 0,
|
|
524
|
+
filterMessage !== void 0 ? like(tables.payment.message, `%${filterMessage}%`) : void 0,
|
|
525
|
+
filterBankRefId !== void 0 ? eq(tables.payment.bankRefId, filterBankRefId) : void 0,
|
|
526
|
+
filterPaymentId !== void 0 ? sql`COALESCE(${tables.payment.paymentRequestId}, ${tables.payment.id}) = ${filterPaymentId}` : void 0,
|
|
527
|
+
filterDirection !== void 0 ? eq(tables.payment.direction, filterDirection) : void 0,
|
|
528
|
+
filterSource === "BANK" ? isNull(tables.payment.paymentRequestId) : filterSource === "API" ? isNotNull(tables.payment.paymentRequestId) : void 0
|
|
529
|
+
);
|
|
530
|
+
const queryInFlight = !isCompletedOnly(filterStatus);
|
|
531
|
+
const queryCompleted = true;
|
|
532
|
+
if (!queryInFlight && queryCompleted) {
|
|
533
|
+
const whereConditions = buildPaymentWhereConditions();
|
|
534
|
+
const sortColumn = resolveColumn(tables.payment, sort.column);
|
|
535
|
+
const [{ totalCount }] = await db.select({ totalCount: sql`count(*)` }).from(tables.payment).where(whereConditions);
|
|
536
|
+
const payments = await db.select().from(tables.payment).where(whereConditions).limit(limit).offset(offset).orderBy(sort.direction === "asc" ? asc(sortColumn) : desc(sortColumn));
|
|
537
|
+
return {
|
|
538
|
+
paymentRequests: payments.map(mapPaymentToPaymentRequest),
|
|
539
|
+
totalCount
|
|
540
|
+
};
|
|
541
|
+
}
|
|
542
|
+
const prWhereConditions = buildPrWhereConditions();
|
|
543
|
+
const paymentWhereConditions = buildPaymentWhereConditions();
|
|
544
|
+
const unionColumns = getUnionColumns();
|
|
545
|
+
const paymentUnionColumns = getPaymentUnionColumns();
|
|
546
|
+
const sortColObj = sort.column in unionColumns ? unionColumns[sort.column] : unionColumns.updatedAt;
|
|
547
|
+
const [{ totalCount: countPR }, { totalCount: countP }] = await Promise.all([
|
|
548
|
+
db.select({ totalCount: sql`count(*)` }).from(tables.paymentRequest).where(prWhereConditions).then(([row]) => row),
|
|
549
|
+
db.select({ totalCount: sql`count(*)` }).from(tables.payment).where(paymentWhereConditions).then(([row]) => row)
|
|
550
|
+
]);
|
|
551
|
+
const paymentRequests = await unionAll(
|
|
552
|
+
db.select(unionColumns).from(tables.paymentRequest).where(prWhereConditions),
|
|
553
|
+
db.select(paymentUnionColumns).from(tables.payment).where(paymentWhereConditions)
|
|
554
|
+
).orderBy(sort.direction === "asc" ? asc(sortColObj) : desc(sortColObj)).limit(limit).offset(offset);
|
|
290
555
|
return {
|
|
291
|
-
|
|
292
|
-
|
|
556
|
+
paymentRequests,
|
|
557
|
+
totalCount: countPR + countP
|
|
293
558
|
};
|
|
294
559
|
};
|
|
295
560
|
|
|
@@ -299,7 +564,6 @@ const sendPaymentInputSchema = z.object({
|
|
|
299
564
|
amount: z.number().positive(),
|
|
300
565
|
paymentType: z.enum(PAYMENT_TYPES),
|
|
301
566
|
chargeBearer: z.enum(CHARGE_BEARERS).optional(),
|
|
302
|
-
executionDate: z.string().optional(),
|
|
303
567
|
instructionPriority: z.enum(INSTRUCTION_PRIORITIES).optional(),
|
|
304
568
|
currency: z.enum(CURRENCY_CODES),
|
|
305
569
|
vs: z.string().optional(),
|
|
@@ -308,7 +572,6 @@ const sendPaymentInputSchema = z.object({
|
|
|
308
572
|
message: z.string().optional(),
|
|
309
573
|
creditor: bankAccountMetadataSchema,
|
|
310
574
|
debtor: bankAccountMetadataSchema,
|
|
311
|
-
purpose: z.string().optional(),
|
|
312
575
|
sendAsSinglePayment: z.boolean().optional()
|
|
313
576
|
});
|
|
314
577
|
|
|
@@ -388,10 +651,20 @@ const ALLOWED_PAYMENT_FILTERS = {
|
|
|
388
651
|
ACCOUNT_ID: "filterPaymentAccountId",
|
|
389
652
|
AMOUNT: "filterPaymentAmount",
|
|
390
653
|
CURRENCY: "filterPaymentCurrency",
|
|
391
|
-
DIRECTION: "
|
|
654
|
+
DIRECTION: "filterPaymentDirection",
|
|
392
655
|
FROM: "filterPaymentDateFrom",
|
|
393
656
|
TO: "filterPaymentDateTo",
|
|
394
|
-
STATUS: "filterPaymentStatus"
|
|
657
|
+
STATUS: "filterPaymentStatus",
|
|
658
|
+
PAYMENT_TYPE: "filterPaymentType",
|
|
659
|
+
MIN_AMOUNT: "filterPaymentMinAmount",
|
|
660
|
+
MAX_AMOUNT: "filterPaymentMaxAmount",
|
|
661
|
+
VARIABLE_SYMBOL: "filterPaymentVariableSymbol",
|
|
662
|
+
SPECIFIC_SYMBOL: "filterPaymentSpecificSymbol",
|
|
663
|
+
CONSTANT_SYMBOL: "filterPaymentConstantSymbol",
|
|
664
|
+
MESSAGE: "filterPaymentMessage",
|
|
665
|
+
CREDITOR_IBAN: "filterPaymentCreditorIban",
|
|
666
|
+
DEBTOR_IBAN: "filterPaymentDebtorIban",
|
|
667
|
+
BATCH_ID: "filterPaymentBatchId"
|
|
395
668
|
};
|
|
396
669
|
const getPaymentsInputSchema = z.object({
|
|
397
670
|
page: z.number().positive(),
|
|
@@ -407,7 +680,17 @@ const getPaymentsInputSchema = z.object({
|
|
|
407
680
|
[ALLOWED_PAYMENT_FILTERS.DIRECTION]: z.union([z.enum(PAYMENT_DIRECTIONS), z.enum(PAYMENT_DIRECTIONS).array()]).optional(),
|
|
408
681
|
[ALLOWED_PAYMENT_FILTERS.FROM]: z.date().optional(),
|
|
409
682
|
[ALLOWED_PAYMENT_FILTERS.TO]: z.date().optional(),
|
|
410
|
-
[ALLOWED_PAYMENT_FILTERS.STATUS]: z.union([z.enum(PAYMENT_STATUSES), z.enum(PAYMENT_STATUSES).array()]).optional()
|
|
683
|
+
[ALLOWED_PAYMENT_FILTERS.STATUS]: z.union([z.enum(PAYMENT_STATUSES), z.enum(PAYMENT_STATUSES).array()]).optional(),
|
|
684
|
+
[ALLOWED_PAYMENT_FILTERS.PAYMENT_TYPE]: z.enum(PAYMENT_TYPES).optional(),
|
|
685
|
+
[ALLOWED_PAYMENT_FILTERS.MIN_AMOUNT]: z.number().positive().optional(),
|
|
686
|
+
[ALLOWED_PAYMENT_FILTERS.MAX_AMOUNT]: z.number().positive().optional(),
|
|
687
|
+
[ALLOWED_PAYMENT_FILTERS.VARIABLE_SYMBOL]: z.string().regex(/^\d{1,10}$/).optional(),
|
|
688
|
+
[ALLOWED_PAYMENT_FILTERS.SPECIFIC_SYMBOL]: z.string().regex(/^\d{1,10}$/).optional(),
|
|
689
|
+
[ALLOWED_PAYMENT_FILTERS.CONSTANT_SYMBOL]: z.string().regex(/^\d{4}$/).optional(),
|
|
690
|
+
[ALLOWED_PAYMENT_FILTERS.MESSAGE]: z.string().optional(),
|
|
691
|
+
[ALLOWED_PAYMENT_FILTERS.CREDITOR_IBAN]: z.string().optional(),
|
|
692
|
+
[ALLOWED_PAYMENT_FILTERS.DEBTOR_IBAN]: z.string().optional(),
|
|
693
|
+
[ALLOWED_PAYMENT_FILTERS.BATCH_ID]: z.uuid().optional()
|
|
411
694
|
});
|
|
412
695
|
|
|
413
696
|
const syncAccountInputSchema = z.object({
|
|
@@ -446,6 +729,8 @@ const updateAccountInputSchema = z.object({
|
|
|
446
729
|
});
|
|
447
730
|
|
|
448
731
|
const getBankAccountsInputSchema = z.object({
|
|
732
|
+
page: z.number().positive().optional(),
|
|
733
|
+
limit: z.number().positive().optional(),
|
|
449
734
|
includeWorkflow: z.boolean().optional(),
|
|
450
735
|
includeBatchCounts: z.boolean().optional(),
|
|
451
736
|
filterIbans: z.array(z.string()).optional(),
|
|
@@ -466,6 +751,34 @@ const handleAuthorizationCallbackInputSchema = z.object({
|
|
|
466
751
|
|
|
467
752
|
const sendPaymentSyncInputSchema = sendPaymentInputSchema;
|
|
468
753
|
|
|
754
|
+
const getPaymentRequestsInputSchema = z.object({
|
|
755
|
+
page: z.number().positive(),
|
|
756
|
+
limit: z.number().positive(),
|
|
757
|
+
sort: z.object({
|
|
758
|
+
column: z.enum(["createdAt", "updatedAt", "amount"]),
|
|
759
|
+
direction: z.enum(["asc", "desc"])
|
|
760
|
+
}),
|
|
761
|
+
filterAccountId: z.union([z.uuid(), z.uuid().array()]).optional(),
|
|
762
|
+
filterStatus: z.union([z.enum(PAYMENT_STATUSES), z.enum(PAYMENT_STATUSES).array()]).optional(),
|
|
763
|
+
filterPaymentType: z.union([z.enum(PAYMENT_TYPES), z.enum(PAYMENT_TYPES).array()]).optional(),
|
|
764
|
+
filterCurrency: z.union([z.enum(CURRENCY_CODES), z.enum(CURRENCY_CODES).array()]).optional(),
|
|
765
|
+
filterMinAmount: z.number().positive().optional(),
|
|
766
|
+
filterMaxAmount: z.number().positive().optional(),
|
|
767
|
+
filterBatchId: z.uuid().optional(),
|
|
768
|
+
filterCreditorIban: z.string().optional(),
|
|
769
|
+
filterDebtorIban: z.string().optional(),
|
|
770
|
+
filterDateFrom: z.date().optional(),
|
|
771
|
+
filterDateTo: z.date().optional(),
|
|
772
|
+
filterVariableSymbol: z.string().optional(),
|
|
773
|
+
filterSpecificSymbol: z.string().optional(),
|
|
774
|
+
filterConstantSymbol: z.string().optional(),
|
|
775
|
+
filterMessage: z.string().optional(),
|
|
776
|
+
filterBankRefId: z.string().optional(),
|
|
777
|
+
filterPaymentId: z.uuid().optional(),
|
|
778
|
+
filterDirection: z.enum(["INCOMING", "OUTGOING"]).optional(),
|
|
779
|
+
filterSource: z.enum(["API", "BANK"]).optional()
|
|
780
|
+
});
|
|
781
|
+
|
|
469
782
|
var __defProp = Object.defineProperty;
|
|
470
783
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
471
784
|
var __decorateClass = (decorators, target, key, kind) => {
|
|
@@ -487,7 +800,9 @@ let BankServiceBase = class extends develitWorker(WorkerEntrypoint) {
|
|
|
487
800
|
return await getAllAccountsQuery(this.db, filters);
|
|
488
801
|
}
|
|
489
802
|
async _getConnectedAccounts() {
|
|
490
|
-
const accounts = await this._getAccounts(
|
|
803
|
+
const { accounts } = await this._getAccounts({
|
|
804
|
+
limit: Number.MAX_SAFE_INTEGER
|
|
805
|
+
});
|
|
491
806
|
return accounts.filter((acc) => acc.status !== "DISABLED");
|
|
492
807
|
}
|
|
493
808
|
async _initiateBankConnector({
|
|
@@ -521,6 +836,27 @@ let BankServiceBase = class extends develitWorker(WorkerEntrypoint) {
|
|
|
521
836
|
env: this.env
|
|
522
837
|
});
|
|
523
838
|
}
|
|
839
|
+
_validatePaymentTypeAndCurrency(paymentType, currency, creditor) {
|
|
840
|
+
const PAYMENT_TYPE_CURRENCY_MAP = {
|
|
841
|
+
DOMESTIC: ["CZK"],
|
|
842
|
+
SEPA: ["EUR"]
|
|
843
|
+
};
|
|
844
|
+
const allowedCurrencies = PAYMENT_TYPE_CURRENCY_MAP[paymentType];
|
|
845
|
+
if (allowedCurrencies && !allowedCurrencies.includes(currency)) {
|
|
846
|
+
throw createInternalError(null, {
|
|
847
|
+
message: `Payment type ${paymentType} requires currency ${allowedCurrencies.join(" or ")}, got ${currency}`,
|
|
848
|
+
code: "VALID-B-008",
|
|
849
|
+
status: 422
|
|
850
|
+
});
|
|
851
|
+
}
|
|
852
|
+
if (paymentType === "SEPA" && !creditor.iban) {
|
|
853
|
+
throw createInternalError(null, {
|
|
854
|
+
message: "SEPA payments require creditor IBAN",
|
|
855
|
+
code: "VALID-B-009",
|
|
856
|
+
status: 422
|
|
857
|
+
});
|
|
858
|
+
}
|
|
859
|
+
}
|
|
524
860
|
async getPayments(input) {
|
|
525
861
|
return this.handleAction(
|
|
526
862
|
{ data: input, schema: getPaymentsInputSchema },
|
|
@@ -804,50 +1140,49 @@ let BankServiceBase = class extends develitWorker(WorkerEntrypoint) {
|
|
|
804
1140
|
}
|
|
805
1141
|
);
|
|
806
1142
|
}
|
|
807
|
-
async addPaymentsToBatch({
|
|
808
|
-
paymentsToBatch
|
|
809
|
-
}) {
|
|
1143
|
+
async addPaymentsToBatch({ paymentIds }) {
|
|
810
1144
|
return this.handleAction(null, {}, async () => {
|
|
811
|
-
this.logInput({
|
|
812
|
-
const
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
eventSignal: "paymentFailed",
|
|
822
|
-
bankPayment: {
|
|
823
|
-
...unsupported,
|
|
824
|
-
status: "FAILED",
|
|
825
|
-
statusReason: "UNSUPPORTED_ACCOUNT"
|
|
826
|
-
},
|
|
827
|
-
metadata: {
|
|
828
|
-
correlationId: unsupported.correlationId,
|
|
829
|
-
entityId: unsupported.id,
|
|
830
|
-
timestamp: (/* @__PURE__ */ new Date()).toDateString()
|
|
831
|
-
}
|
|
832
|
-
}))
|
|
833
|
-
);
|
|
1145
|
+
this.logInput({ paymentIds });
|
|
1146
|
+
const paymentRequests = (await Promise.all(
|
|
1147
|
+
paymentIds.map(
|
|
1148
|
+
(id) => getPaymentRequestByIdQuery(this.db, { paymentId: id })
|
|
1149
|
+
)
|
|
1150
|
+
)).filter((p) => p !== null);
|
|
1151
|
+
const foundIds = new Set(paymentRequests.map((p) => p.id));
|
|
1152
|
+
const missingIds = paymentIds.filter((id) => !foundIds.has(id));
|
|
1153
|
+
if (missingIds.length > 0) {
|
|
1154
|
+
this.logError({ missingIds });
|
|
834
1155
|
}
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
1156
|
+
const byAccount = Map.groupBy(
|
|
1157
|
+
paymentRequests,
|
|
1158
|
+
(p) => `${p.accountId}:${p.paymentType}`
|
|
1159
|
+
);
|
|
1160
|
+
const { accounts } = await this._getAccounts();
|
|
1161
|
+
for (const [, paymentsOfType] of byAccount) {
|
|
1162
|
+
const first2 = paymentsOfType[0];
|
|
1163
|
+
const acc = accounts.find((a) => a.id === first2.accountId);
|
|
1164
|
+
if (!acc) {
|
|
1165
|
+
this.logError({ message: `Account not found: ${first2.accountId}` });
|
|
1166
|
+
await Promise.all(
|
|
1167
|
+
paymentsOfType.map(
|
|
1168
|
+
(p) => updatePaymentRequestStatusCommand(this.db, {
|
|
1169
|
+
id: p.id,
|
|
1170
|
+
status: "FAILED",
|
|
1171
|
+
statusReason: "ACCOUNT_NOT_FOUND"
|
|
1172
|
+
}).command.execute()
|
|
1173
|
+
)
|
|
1174
|
+
);
|
|
840
1175
|
continue;
|
|
841
1176
|
}
|
|
842
|
-
|
|
843
|
-
message: `\u{1F4B0} Processing ${accountAssignedPayments.length} payments for account (${acc.iban}, ${acc.currency})`
|
|
844
|
-
});
|
|
845
|
-
const singlePayments = accountAssignedPayments.filter(
|
|
1177
|
+
const singlePayments = paymentsOfType.filter(
|
|
846
1178
|
(p) => p.sendAsSinglePayment === true
|
|
847
1179
|
);
|
|
848
|
-
const regularPayments =
|
|
1180
|
+
const regularPayments = paymentsOfType.filter(
|
|
849
1181
|
(p) => p.sendAsSinglePayment !== true
|
|
850
1182
|
);
|
|
1183
|
+
this.log({
|
|
1184
|
+
message: `\u{1F4B0} Processing ${paymentsOfType.length} payments for account (${acc.iban}, ${acc.currency})`
|
|
1185
|
+
});
|
|
851
1186
|
for (const singlePayment of singlePayments) {
|
|
852
1187
|
const batchId = uuidv4();
|
|
853
1188
|
const { command: upsertBatch } = upsertBatchCommand(this.db, {
|
|
@@ -860,73 +1195,67 @@ let BankServiceBase = class extends develitWorker(WorkerEntrypoint) {
|
|
|
860
1195
|
metadata: { sizeLimit: 1 }
|
|
861
1196
|
}
|
|
862
1197
|
});
|
|
863
|
-
const { command:
|
|
1198
|
+
const { command: updateRequest } = updatePaymentRequestStatusCommand(
|
|
864
1199
|
this.db,
|
|
865
|
-
{
|
|
866
|
-
paymentRequest: toPaymentRequestInsert(singlePayment, batchId)
|
|
867
|
-
}
|
|
1200
|
+
{ id: singlePayment.id, status: "CREATED", batchId }
|
|
868
1201
|
);
|
|
869
|
-
await this.db.batch([upsertBatch,
|
|
1202
|
+
await this.db.batch([upsertBatch, updateRequest]);
|
|
870
1203
|
this.log({
|
|
871
1204
|
message: `\u2728 Created single payment batch (${singlePayment.paymentType}) for account ${acc.id}`
|
|
872
1205
|
});
|
|
873
1206
|
}
|
|
874
1207
|
if (regularPayments.length > 0) {
|
|
875
|
-
const
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
);
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
const limit = ob.metadata?.sizeLimit ?? acc.batchSizeLimit;
|
|
893
|
-
if (existingPayments.length < limit) {
|
|
894
|
-
availableBatch = ob;
|
|
895
|
-
availableCount = existingPayments.length;
|
|
896
|
-
break;
|
|
897
|
-
}
|
|
898
|
-
}
|
|
899
|
-
if (availableBatch) {
|
|
900
|
-
batchId = availableBatch.id;
|
|
901
|
-
this.log({
|
|
902
|
-
message: `\u{1F504} Found existing OPEN batch (${paymentType}) for account ${acc.id}, merging ${availableCount} existing + ${paymentsOfType.length} new payments`
|
|
903
|
-
});
|
|
904
|
-
} else {
|
|
905
|
-
batchId = uuidv4();
|
|
906
|
-
this.log({
|
|
907
|
-
message: `\u2728 Creating new batch (${paymentType}) for account ${acc.id} with ${paymentsOfType.length} payments`
|
|
908
|
-
});
|
|
1208
|
+
const openBatches = await getAccountOpenBatchesQuery(this.db, {
|
|
1209
|
+
accountId: acc.id,
|
|
1210
|
+
paymentType: first2.paymentType
|
|
1211
|
+
});
|
|
1212
|
+
let batchId;
|
|
1213
|
+
let availableCount = 0;
|
|
1214
|
+
let availableBatch;
|
|
1215
|
+
for (const ob of openBatches) {
|
|
1216
|
+
const existingPayments = await getPaymentRequestsByBatchIdQuery(
|
|
1217
|
+
this.db,
|
|
1218
|
+
{ batchId: ob.id }
|
|
1219
|
+
);
|
|
1220
|
+
const limit = ob.metadata?.sizeLimit ?? acc.batchSizeLimit;
|
|
1221
|
+
if (existingPayments.length < limit) {
|
|
1222
|
+
availableBatch = ob;
|
|
1223
|
+
availableCount = existingPayments.length;
|
|
1224
|
+
break;
|
|
909
1225
|
}
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
paymentType,
|
|
916
|
-
status: "OPEN",
|
|
917
|
-
metadata: { sizeLimit: acc.batchSizeLimit }
|
|
918
|
-
}
|
|
1226
|
+
}
|
|
1227
|
+
if (availableBatch) {
|
|
1228
|
+
batchId = availableBatch.id;
|
|
1229
|
+
this.log({
|
|
1230
|
+
message: `\u{1F504} Found existing OPEN batch (${first2.paymentType}) for account ${acc.id}, merging ${availableCount} existing + ${regularPayments.length} new payments`
|
|
919
1231
|
});
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
paymentRequest: toPaymentRequestInsert(p, batchId)
|
|
923
|
-
}).command
|
|
924
|
-
);
|
|
925
|
-
await this.db.batch([upsertBatch, ...paymentRequestCommands]);
|
|
1232
|
+
} else {
|
|
1233
|
+
batchId = uuidv4();
|
|
926
1234
|
this.log({
|
|
927
|
-
message: `\
|
|
1235
|
+
message: `\u2728 Creating new batch (${first2.paymentType}) for account ${acc.id} with ${regularPayments.length} payments`
|
|
928
1236
|
});
|
|
929
1237
|
}
|
|
1238
|
+
const { command: upsertBatch } = upsertBatchCommand(this.db, {
|
|
1239
|
+
batch: availableBatch ? { ...availableBatch } : {
|
|
1240
|
+
id: batchId,
|
|
1241
|
+
authorizationUrls: [],
|
|
1242
|
+
accountId: acc.id,
|
|
1243
|
+
paymentType: first2.paymentType,
|
|
1244
|
+
status: "OPEN",
|
|
1245
|
+
metadata: { sizeLimit: acc.batchSizeLimit }
|
|
1246
|
+
}
|
|
1247
|
+
});
|
|
1248
|
+
const updateCommands = regularPayments.map(
|
|
1249
|
+
(p) => updatePaymentRequestStatusCommand(this.db, {
|
|
1250
|
+
id: p.id,
|
|
1251
|
+
status: "CREATED",
|
|
1252
|
+
batchId
|
|
1253
|
+
}).command
|
|
1254
|
+
);
|
|
1255
|
+
await this.db.batch([upsertBatch, ...updateCommands]);
|
|
1256
|
+
this.log({
|
|
1257
|
+
message: `\u2705 Batch (${first2.paymentType}) upserted successfully for account ${acc.id}`
|
|
1258
|
+
});
|
|
930
1259
|
}
|
|
931
1260
|
}
|
|
932
1261
|
});
|
|
@@ -983,7 +1312,7 @@ let BankServiceBase = class extends develitWorker(WorkerEntrypoint) {
|
|
|
983
1312
|
async () => {
|
|
984
1313
|
this.logQueuePull(b);
|
|
985
1314
|
const queueHandlerResponse = await this.addPaymentsToBatch({
|
|
986
|
-
|
|
1315
|
+
paymentIds: b.messages.map(({ body }) => body.paymentId)
|
|
987
1316
|
});
|
|
988
1317
|
this.logOutput(queueHandlerResponse);
|
|
989
1318
|
}
|
|
@@ -1049,7 +1378,7 @@ let BankServiceBase = class extends develitWorker(WorkerEntrypoint) {
|
|
|
1049
1378
|
const { credentials, accounts } = await connector.authorizeAccount({
|
|
1050
1379
|
urlParams
|
|
1051
1380
|
});
|
|
1052
|
-
const alreadyExistingAccounts = (await this._getAccounts()).filter(
|
|
1381
|
+
const alreadyExistingAccounts = (await this._getAccounts()).accounts.filter(
|
|
1053
1382
|
(acc) => acc.connectorKey === ottRow.refId && accounts.map((item) => item.iban).includes(acc.iban)
|
|
1054
1383
|
);
|
|
1055
1384
|
const upsertAccounts = accounts.map((acc) => {
|
|
@@ -1097,7 +1426,7 @@ let BankServiceBase = class extends develitWorker(WorkerEntrypoint) {
|
|
|
1097
1426
|
...upsertAccounts,
|
|
1098
1427
|
...createAccountCredentials
|
|
1099
1428
|
]);
|
|
1100
|
-
const fetchedAccounts = await this._getAccounts();
|
|
1429
|
+
const { accounts: fetchedAccounts } = await this._getAccounts();
|
|
1101
1430
|
if (!fetchedAccounts)
|
|
1102
1431
|
throw createInternalError(null, {
|
|
1103
1432
|
message: "Account not found",
|
|
@@ -1105,7 +1434,11 @@ let BankServiceBase = class extends develitWorker(WorkerEntrypoint) {
|
|
|
1105
1434
|
status: 404
|
|
1106
1435
|
});
|
|
1107
1436
|
if (startSync) {
|
|
1108
|
-
|
|
1437
|
+
const newAccountIbans = new Set(accounts.map((a) => a.iban));
|
|
1438
|
+
const accountsToSync = fetchedAccounts.filter(
|
|
1439
|
+
(a) => newAccountIbans.has(a.iban)
|
|
1440
|
+
);
|
|
1441
|
+
for (const account of accountsToSync) {
|
|
1109
1442
|
const { error } = await this.syncAccount({
|
|
1110
1443
|
accountId: account.id
|
|
1111
1444
|
});
|
|
@@ -1147,12 +1480,18 @@ let BankServiceBase = class extends develitWorker(WorkerEntrypoint) {
|
|
|
1147
1480
|
code: "VALID-B-003",
|
|
1148
1481
|
status: 422
|
|
1149
1482
|
});
|
|
1483
|
+
if (account.connectorKey !== connectorKey)
|
|
1484
|
+
throw createInternalError(null, {
|
|
1485
|
+
message: `Connector key mismatch: account uses ${account.connectorKey}, got ${connectorKey}`,
|
|
1486
|
+
code: "VALID-B-010",
|
|
1487
|
+
status: 422
|
|
1488
|
+
});
|
|
1150
1489
|
const payment = {
|
|
1151
1490
|
id: uuidv4(),
|
|
1152
1491
|
bankRefId: uuidv4(),
|
|
1153
1492
|
correlationId: uuidv4(),
|
|
1154
1493
|
amount,
|
|
1155
|
-
connectorKey,
|
|
1494
|
+
connectorKey: account.connectorKey,
|
|
1156
1495
|
accountId: account.id,
|
|
1157
1496
|
direction: "INCOMING",
|
|
1158
1497
|
paymentType: "DOMESTIC",
|
|
@@ -1192,10 +1531,51 @@ let BankServiceBase = class extends develitWorker(WorkerEntrypoint) {
|
|
|
1192
1531
|
{ data: input, schema: sendPaymentInputSchema },
|
|
1193
1532
|
{ successMessage: "Payment queued successfully" },
|
|
1194
1533
|
async (data) => {
|
|
1534
|
+
const incomingPayment = toIncomingPayment(data);
|
|
1535
|
+
const { accounts } = await this._getAccounts();
|
|
1536
|
+
const account = accounts.find(
|
|
1537
|
+
(acc) => acc.iban === incomingPayment.debtorIban && acc.currency === incomingPayment.currency
|
|
1538
|
+
);
|
|
1539
|
+
if (!account) {
|
|
1540
|
+
throw createInternalError(null, {
|
|
1541
|
+
message: `No account found for IBAN ${incomingPayment.debtorIban} with currency ${incomingPayment.currency}`,
|
|
1542
|
+
code: "VALID-B-004",
|
|
1543
|
+
status: 422
|
|
1544
|
+
});
|
|
1545
|
+
}
|
|
1546
|
+
if (account.status !== "AUTHORIZED") {
|
|
1547
|
+
throw createInternalError(null, {
|
|
1548
|
+
message: `Account ${account.iban} is not authorized (status: ${account.status})`,
|
|
1549
|
+
code: "VALID-B-007",
|
|
1550
|
+
status: 422
|
|
1551
|
+
});
|
|
1552
|
+
}
|
|
1553
|
+
const connector = await this._initiateBankConnector({
|
|
1554
|
+
connectorKey: account.connectorKey
|
|
1555
|
+
});
|
|
1556
|
+
if (!connector.supportsPaymentType(data.paymentType)) {
|
|
1557
|
+
throw createInternalError(null, {
|
|
1558
|
+
message: `Connector ${account.connectorKey} does not support ${data.paymentType} payments yet`,
|
|
1559
|
+
code: "VALID-B-006",
|
|
1560
|
+
status: 422
|
|
1561
|
+
});
|
|
1562
|
+
}
|
|
1563
|
+
this._validatePaymentTypeAndCurrency(
|
|
1564
|
+
data.paymentType,
|
|
1565
|
+
data.currency,
|
|
1566
|
+
data.creditor
|
|
1567
|
+
);
|
|
1568
|
+
const accountAssigned = assignAccount(incomingPayment, account);
|
|
1569
|
+
const { command: insertPaymentRequest } = createPaymentRequestCommand(
|
|
1570
|
+
this.db,
|
|
1571
|
+
{ paymentRequest: toPaymentRequestInsert(accountAssigned, null) }
|
|
1572
|
+
);
|
|
1573
|
+
await insertPaymentRequest.execute();
|
|
1195
1574
|
await this.pushToQueue(
|
|
1196
1575
|
this.env.PAYMENTS_READY_TO_BATCH_QUEUE,
|
|
1197
|
-
|
|
1576
|
+
{ paymentId: incomingPayment.id }
|
|
1198
1577
|
);
|
|
1578
|
+
return { paymentId: incomingPayment.id };
|
|
1199
1579
|
}
|
|
1200
1580
|
);
|
|
1201
1581
|
}
|
|
@@ -1205,7 +1585,7 @@ let BankServiceBase = class extends develitWorker(WorkerEntrypoint) {
|
|
|
1205
1585
|
{ successMessage: "Payment initiated successfully" },
|
|
1206
1586
|
async (data) => {
|
|
1207
1587
|
const incomingPayment = toIncomingPayment(data);
|
|
1208
|
-
const accounts = await this._getAccounts();
|
|
1588
|
+
const { accounts } = await this._getAccounts();
|
|
1209
1589
|
const account = accounts.find(
|
|
1210
1590
|
(acc) => acc.iban === incomingPayment.debtorIban && acc.currency === incomingPayment.currency
|
|
1211
1591
|
);
|
|
@@ -1216,12 +1596,31 @@ let BankServiceBase = class extends develitWorker(WorkerEntrypoint) {
|
|
|
1216
1596
|
status: 422
|
|
1217
1597
|
});
|
|
1218
1598
|
}
|
|
1599
|
+
if (account.status !== "AUTHORIZED") {
|
|
1600
|
+
throw createInternalError(null, {
|
|
1601
|
+
message: `Account ${account.iban} is not authorized (status: ${account.status})`,
|
|
1602
|
+
code: "VALID-B-007",
|
|
1603
|
+
status: 422
|
|
1604
|
+
});
|
|
1605
|
+
}
|
|
1219
1606
|
const batchedPayment = toBatchedPayment(
|
|
1220
1607
|
assignAccount(incomingPayment, account)
|
|
1221
1608
|
);
|
|
1222
1609
|
const connector = await this._initiateBankConnector({
|
|
1223
1610
|
connectorKey: account.connectorKey
|
|
1224
1611
|
});
|
|
1612
|
+
if (!connector.supportsPaymentType(data.paymentType)) {
|
|
1613
|
+
throw createInternalError(null, {
|
|
1614
|
+
message: `Connector ${account.connectorKey} does not support ${data.paymentType} payments yet`,
|
|
1615
|
+
code: "VALID-B-006",
|
|
1616
|
+
status: 422
|
|
1617
|
+
});
|
|
1618
|
+
}
|
|
1619
|
+
this._validatePaymentTypeAndCurrency(
|
|
1620
|
+
data.paymentType,
|
|
1621
|
+
data.currency,
|
|
1622
|
+
data.creditor
|
|
1623
|
+
);
|
|
1225
1624
|
const initiate = () => {
|
|
1226
1625
|
switch (data.paymentType) {
|
|
1227
1626
|
case "DOMESTIC":
|
|
@@ -1250,16 +1649,20 @@ let BankServiceBase = class extends develitWorker(WorkerEntrypoint) {
|
|
|
1250
1649
|
{ data: input, schema: getBankAccountsInputSchema },
|
|
1251
1650
|
{ successMessage: "Bank accounts retrieved successfully" },
|
|
1252
1651
|
async ({
|
|
1652
|
+
page,
|
|
1653
|
+
limit,
|
|
1253
1654
|
includeWorkflow,
|
|
1254
1655
|
includeBatchCounts,
|
|
1255
1656
|
filterIbans,
|
|
1256
1657
|
filterCurrencies,
|
|
1257
1658
|
filterBankRefIds
|
|
1258
1659
|
}) => {
|
|
1259
|
-
const accounts = await this._getAccounts({
|
|
1660
|
+
const { accounts, totalCount } = await this._getAccounts({
|
|
1260
1661
|
filterIbans,
|
|
1261
1662
|
filterCurrencies,
|
|
1262
|
-
filterBankRefIds
|
|
1663
|
+
filterBankRefIds,
|
|
1664
|
+
page,
|
|
1665
|
+
limit
|
|
1263
1666
|
});
|
|
1264
1667
|
const accountsWithOptionalFields = await Promise.all(
|
|
1265
1668
|
accounts.map(async (a) => {
|
|
@@ -1293,7 +1696,7 @@ let BankServiceBase = class extends develitWorker(WorkerEntrypoint) {
|
|
|
1293
1696
|
);
|
|
1294
1697
|
return {
|
|
1295
1698
|
accounts: accountsWithOptionalFields,
|
|
1296
|
-
totalCount
|
|
1699
|
+
totalCount
|
|
1297
1700
|
};
|
|
1298
1701
|
}
|
|
1299
1702
|
);
|
|
@@ -1411,6 +1814,34 @@ let BankServiceBase = class extends develitWorker(WorkerEntrypoint) {
|
|
|
1411
1814
|
}
|
|
1412
1815
|
);
|
|
1413
1816
|
}
|
|
1817
|
+
async getPaymentRequests(input) {
|
|
1818
|
+
return this.handleAction(
|
|
1819
|
+
{ data: input, schema: getPaymentRequestsInputSchema },
|
|
1820
|
+
{ successMessage: "Payment requests fetched successfully" },
|
|
1821
|
+
async (params) => {
|
|
1822
|
+
return await getPaymentRequestsWithPaginationQuery(this.db, params);
|
|
1823
|
+
}
|
|
1824
|
+
);
|
|
1825
|
+
}
|
|
1826
|
+
async getPaymentRequest(input) {
|
|
1827
|
+
return this.handleAction(
|
|
1828
|
+
null,
|
|
1829
|
+
{ successMessage: "Payment request fetched successfully" },
|
|
1830
|
+
async () => {
|
|
1831
|
+
const paymentRequest = await getPaymentRequestByIdQuery(this.db, {
|
|
1832
|
+
paymentId: input.paymentId
|
|
1833
|
+
});
|
|
1834
|
+
if (!paymentRequest) {
|
|
1835
|
+
throw createInternalError(null, {
|
|
1836
|
+
message: `Payment request not found: ${input.paymentId}`,
|
|
1837
|
+
code: "NOT-FOUND-B-001",
|
|
1838
|
+
status: 404
|
|
1839
|
+
});
|
|
1840
|
+
}
|
|
1841
|
+
return { paymentRequest };
|
|
1842
|
+
}
|
|
1843
|
+
);
|
|
1844
|
+
}
|
|
1414
1845
|
async getFinbricksSupportedBanks() {
|
|
1415
1846
|
const privateKeyPem = (await this.env.SECRETS_STORE.get({
|
|
1416
1847
|
secretName: "BANK_SERVICE_FINBRICKS_PRIVATE_KEY_PEM"
|
|
@@ -1484,6 +1915,12 @@ __decorateClass([
|
|
|
1484
1915
|
__decorateClass([
|
|
1485
1916
|
action("getBatches")
|
|
1486
1917
|
], BankServiceBase.prototype, "getBatches", 1);
|
|
1918
|
+
__decorateClass([
|
|
1919
|
+
action("get-payment-requests")
|
|
1920
|
+
], BankServiceBase.prototype, "getPaymentRequests", 1);
|
|
1921
|
+
__decorateClass([
|
|
1922
|
+
action("get-payment-request")
|
|
1923
|
+
], BankServiceBase.prototype, "getPaymentRequest", 1);
|
|
1487
1924
|
BankServiceBase = __decorateClass([
|
|
1488
1925
|
service("bank")
|
|
1489
1926
|
], BankServiceBase);
|