@develit-services/bank 0.8.7 → 0.8.8
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 +236 -276
- package/dist/export/worker.d.cts +26 -26
- package/dist/export/worker.d.mts +26 -26
- package/dist/export/worker.d.ts +26 -26
- package/dist/export/worker.mjs +237 -277
- package/dist/export/workflows.cjs +58 -96
- package/dist/export/workflows.mjs +59 -97
- package/dist/export/wrangler.d.cts +2 -1
- package/dist/export/wrangler.d.mts +2 -1
- package/dist/export/wrangler.d.ts +2 -1
- package/dist/shared/{bank.Cns5ss41.d.cts → bank.B-NJB8GB.d.cts} +12 -25
- package/dist/shared/{bank.Cns5ss41.d.mts → bank.B-NJB8GB.d.mts} +12 -25
- package/dist/shared/{bank.Cns5ss41.d.ts → bank.B-NJB8GB.d.ts} +12 -25
- package/dist/shared/{bank.DEmzZGZW.mjs → bank.B5bZRvgq.mjs} +2 -5
- package/dist/shared/{bank.CQBfbG8u.d.cts → bank.BP_3WMIF.d.cts} +1 -0
- package/dist/shared/{bank.CQBfbG8u.d.mts → bank.BP_3WMIF.d.mts} +1 -0
- package/dist/shared/{bank.CQBfbG8u.d.ts → bank.BP_3WMIF.d.ts} +1 -0
- package/dist/shared/{bank.CA5ytXxp.mjs → bank.BoZtXQpG.mjs} +1 -1
- package/dist/shared/{bank.D1jqaHaF.mjs → bank.BtszLapg.mjs} +128 -20
- package/dist/shared/{bank.CO89tR9U.d.cts → bank.BzobShUU.d.cts} +1 -1
- package/dist/shared/{bank.C0UN6luZ.mjs → bank.C6jjS1Pl.mjs} +0 -2
- package/dist/shared/{bank.CreoSb2d.d.mts → bank.CAVvvZZO.d.mts} +1 -1
- package/dist/shared/{bank.DwyCCyd0.cjs → bank.CtnsGHM8.cjs} +128 -20
- package/dist/shared/{bank.62VzK9Aj.cjs → bank.DJnDSYqE.cjs} +1 -1
- package/dist/shared/{bank.BYRq3yJf.d.ts → bank.DRTuKO8S.d.ts} +1 -1
- package/dist/shared/{bank.Dm8GHThw.cjs → bank.DT6bg8k5.cjs} +2 -5
- package/dist/shared/{bank.BS7fFjGA.cjs → bank.JVlyPAAb.cjs} +0 -2
- package/dist/types.cjs +3 -3
- package/dist/types.d.cts +10 -6
- package/dist/types.d.mts +10 -6
- package/dist/types.d.ts +10 -6
- package/dist/types.mjs +3 -3
- package/package.json +1 -1
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const backendSdk = require('@develit-io/backend-sdk');
|
|
4
|
-
const drizzle = require('../shared/bank.
|
|
4
|
+
const drizzle = require('../shared/bank.DT6bg8k5.cjs');
|
|
5
5
|
const batchLifecycle = require('../shared/bank.Bg3Pdwm4.cjs');
|
|
6
|
-
const mock_connector = require('../shared/bank.
|
|
6
|
+
const mock_connector = require('../shared/bank.CtnsGHM8.cjs');
|
|
7
7
|
const drizzleOrm = require('drizzle-orm');
|
|
8
|
-
require('drizzle-orm/sqlite-core');
|
|
9
8
|
const cloudflare_workers = require('cloudflare:workers');
|
|
10
9
|
const cloudflare_workflows = require('cloudflare:workflows');
|
|
11
10
|
const d1 = require('drizzle-orm/d1');
|
|
12
11
|
require('node:crypto');
|
|
13
|
-
require('../shared/bank.
|
|
12
|
+
require('../shared/bank.JVlyPAAb.cjs');
|
|
14
13
|
require('drizzle-orm/relations');
|
|
14
|
+
require('drizzle-orm/sqlite-core');
|
|
15
15
|
require('date-fns');
|
|
16
16
|
require('jose');
|
|
17
17
|
require('@develit-io/general-codes');
|
|
18
18
|
require('drizzle-zod');
|
|
19
|
-
require('../shared/bank.
|
|
19
|
+
require('../shared/bank.DJnDSYqE.cjs');
|
|
20
20
|
|
|
21
21
|
const updateAccountLastSyncCommand = (db, {
|
|
22
22
|
lastSyncAt,
|
|
@@ -41,6 +41,23 @@ function pushToQueue$1(queue, message) {
|
|
|
41
41
|
}))
|
|
42
42
|
);
|
|
43
43
|
}
|
|
44
|
+
async function failBatchAndPayments(db, batch, paymentRequests, reason) {
|
|
45
|
+
const prCmds = paymentRequests.filter((p) => p.status !== "FAILED").map(
|
|
46
|
+
(p) => drizzle.updatePaymentRequestStatusCommand(db, {
|
|
47
|
+
id: p.id,
|
|
48
|
+
status: "FAILED",
|
|
49
|
+
statusReason: reason,
|
|
50
|
+
processedAt: /* @__PURE__ */ new Date()
|
|
51
|
+
}).command
|
|
52
|
+
);
|
|
53
|
+
const batchCmd = drizzle.upsertBatchCommand(db, {
|
|
54
|
+
batch: { ...batch, status: "FAILED" }
|
|
55
|
+
}).command;
|
|
56
|
+
const allCmds = [batchCmd, ...prCmds];
|
|
57
|
+
if (allCmds.length > 0) {
|
|
58
|
+
await db.batch(allCmds);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
44
61
|
class BankProcessBatch extends cloudflare_workers.WorkflowEntrypoint {
|
|
45
62
|
async run(event, step) {
|
|
46
63
|
const { batchId } = event.payload;
|
|
@@ -110,7 +127,9 @@ class BankProcessBatch extends cloudflare_workers.WorkflowEntrypoint {
|
|
|
110
127
|
accountId: batch.accountId
|
|
111
128
|
});
|
|
112
129
|
if (!account) {
|
|
113
|
-
|
|
130
|
+
const msg = `Account not found: ${batch.accountId}`;
|
|
131
|
+
await failBatchAndPayments(db, batch, paymentRequests, msg);
|
|
132
|
+
throw new cloudflare_workflows.NonRetryableError(msg);
|
|
114
133
|
}
|
|
115
134
|
const resolveCredentials = await drizzle.createCredentialsResolver(db, this.env);
|
|
116
135
|
const connector = await mock_connector.initiateConnector({
|
|
@@ -143,17 +162,7 @@ class BankProcessBatch extends cloudflare_workers.WorkflowEntrypoint {
|
|
|
143
162
|
const message = err instanceof Error ? err.message : typeof err === "object" && err !== null && "message" in err ? String(err.message) : String(err);
|
|
144
163
|
const status = typeof err === "object" && err !== null && "status" in err ? Number(err.status) : 0;
|
|
145
164
|
if (status >= 400 && status < 500) {
|
|
146
|
-
|
|
147
|
-
(p) => drizzle.updatePaymentRequestStatusCommand(db, {
|
|
148
|
-
id: p.id,
|
|
149
|
-
status: "FAILED",
|
|
150
|
-
statusReason: message,
|
|
151
|
-
processedAt: /* @__PURE__ */ new Date()
|
|
152
|
-
}).command
|
|
153
|
-
);
|
|
154
|
-
if (updateCommands.length > 0) {
|
|
155
|
-
await db.batch(updateCommands);
|
|
156
|
-
}
|
|
165
|
+
await failBatchAndPayments(db, batch, paymentRequests, message);
|
|
157
166
|
throw new cloudflare_workflows.NonRetryableError(message);
|
|
158
167
|
}
|
|
159
168
|
throw new Error(message);
|
|
@@ -164,7 +173,9 @@ class BankProcessBatch extends cloudflare_workers.WorkflowEntrypoint {
|
|
|
164
173
|
metadata
|
|
165
174
|
} = result;
|
|
166
175
|
if (!authorizationUrls || authorizationUrls.length === 0) {
|
|
167
|
-
|
|
176
|
+
const msg = "Failed to retrieve authorization URLs";
|
|
177
|
+
await failBatchAndPayments(db, batch, paymentRequests, msg);
|
|
178
|
+
throw new cloudflare_workflows.NonRetryableError(msg);
|
|
168
179
|
}
|
|
169
180
|
return {
|
|
170
181
|
authorizationUrls,
|
|
@@ -217,14 +228,13 @@ class BankProcessBatch extends cloudflare_workers.WorkflowEntrypoint {
|
|
|
217
228
|
id: p.id,
|
|
218
229
|
status: "COMPLETED",
|
|
219
230
|
bankRefId: `MOCK-${backendSdk.uuidv4()}`,
|
|
220
|
-
processedAt
|
|
221
|
-
deletedAt: /* @__PURE__ */ new Date()
|
|
231
|
+
processedAt
|
|
222
232
|
}).command
|
|
223
233
|
);
|
|
224
234
|
const updateBatchCommand = drizzle.upsertBatchCommand(db, {
|
|
225
235
|
batch: {
|
|
226
236
|
...batch,
|
|
227
|
-
status: "
|
|
237
|
+
status: "COMPLETED",
|
|
228
238
|
authorizationUrls: batchResult.authorizationUrls,
|
|
229
239
|
metadata: batchResult.metadata,
|
|
230
240
|
batchPaymentInitiatedAt: /* @__PURE__ */ new Date()
|
|
@@ -347,84 +357,57 @@ class BankSyncAccountPayments extends cloudflare_workers.WorkflowEntrypoint {
|
|
|
347
357
|
"process new payments and update lastSyncAt",
|
|
348
358
|
async () => {
|
|
349
359
|
const eventsToEmit = [];
|
|
350
|
-
const
|
|
351
|
-
const
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
drizzleOrm.
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
drizzleOrm.eq(
|
|
359
|
-
drizzle.tables.paymentRequest.connectorKey,
|
|
360
|
-
account.connectorKey
|
|
361
|
-
),
|
|
362
|
-
drizzleOrm.isNull(drizzle.tables.paymentRequest.deletedAt)
|
|
360
|
+
const bankRefIds = paymentsToInsert.map((p) => p.parsed.bankRefId).filter((id) => id != null);
|
|
361
|
+
const matchingRequests = bankRefIds.length > 0 ? await db.select().from(drizzle.tables.paymentRequest).where(
|
|
362
|
+
drizzleOrm.and(
|
|
363
|
+
drizzleOrm.inArray(drizzle.tables.paymentRequest.bankRefId, bankRefIds),
|
|
364
|
+
drizzleOrm.eq(drizzle.tables.paymentRequest.accountId, account.id),
|
|
365
|
+
drizzleOrm.eq(
|
|
366
|
+
drizzle.tables.paymentRequest.connectorKey,
|
|
367
|
+
account.connectorKey
|
|
363
368
|
)
|
|
364
|
-
)
|
|
365
|
-
]
|
|
366
|
-
const requestById = Object.fromEntries(
|
|
367
|
-
matchingByPrId.map((r) => [r.id, r])
|
|
368
|
-
);
|
|
369
|
+
)
|
|
370
|
+
) : [];
|
|
369
371
|
const requestByBankRefId = Object.fromEntries(
|
|
370
|
-
|
|
372
|
+
matchingRequests.map((r) => [r.bankRefId, r])
|
|
371
373
|
);
|
|
372
374
|
const enrichedPayments = paymentsToInsert.map((p) => {
|
|
373
|
-
const req = p.parsed.
|
|
375
|
+
const req = p.parsed.bankRefId && requestByBankRefId[p.parsed.bankRefId] || null;
|
|
374
376
|
if (!req) return p;
|
|
375
377
|
return {
|
|
376
378
|
...p,
|
|
377
379
|
parsed: {
|
|
378
380
|
...p.parsed,
|
|
379
|
-
//
|
|
380
|
-
paymentRequestId: p.parsed.paymentRequestId ?? req.id,
|
|
381
|
-
createdAt: req.createdAt ?? p.parsed.createdAt,
|
|
382
|
-
batchId: p.parsed.batchId ?? req.batchId,
|
|
383
|
-
refId: p.parsed.refId ?? req.refId,
|
|
384
|
-
chargeBearer: p.parsed.chargeBearer ?? req.chargeBearer,
|
|
385
|
-
instructionPriority: p.parsed.instructionPriority ?? req.instructionPriority,
|
|
386
|
-
message: p.parsed.message ?? req.message,
|
|
381
|
+
// queue-bus: transaction matching (DBU doesn't echo these in statements)
|
|
387
382
|
vs: p.parsed.vs ?? req.vs,
|
|
388
383
|
ss: p.parsed.ss ?? req.ss,
|
|
389
384
|
ks: p.parsed.ks ?? req.ks,
|
|
385
|
+
message: p.parsed.message ?? req.message,
|
|
386
|
+
// queue-bus: party creation
|
|
390
387
|
creditor: {
|
|
391
388
|
...p.parsed.creditor,
|
|
392
|
-
holderName: p.parsed.creditor?.holderName ?? req.creditor?.holderName
|
|
393
|
-
address: p.parsed.creditor?.address ?? req.creditor?.address,
|
|
394
|
-
swiftBic: p.parsed.creditor?.swiftBic ?? req.creditor?.swiftBic
|
|
389
|
+
holderName: p.parsed.creditor?.holderName ?? req.creditor?.holderName
|
|
395
390
|
},
|
|
396
391
|
debtor: {
|
|
397
392
|
...p.parsed.debtor,
|
|
398
393
|
holderName: p.parsed.debtor?.holderName ?? req.debtor?.holderName
|
|
399
394
|
}
|
|
395
|
+
// NOT enriched: chargeBearer, instructionPriority, refId, batchId,
|
|
396
|
+
// createdAt, address, swiftBic — no downstream consumer in payment table
|
|
400
397
|
}
|
|
401
398
|
};
|
|
402
399
|
});
|
|
403
400
|
const createCommands = enrichedPayments.map(
|
|
404
401
|
(p) => drizzle.createPaymentCommand(db, { payment: p.parsed }).command
|
|
405
402
|
);
|
|
406
|
-
const
|
|
407
|
-
(
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
p.parsed.paymentRequestId ? drizzleOrm.eq(drizzle.tables.paymentRequest.id, p.parsed.paymentRequestId) : void 0,
|
|
415
|
-
// Fallback: match via bankRefId (set during processBatch)
|
|
416
|
-
drizzleOrm.and(
|
|
417
|
-
drizzleOrm.isNotNull(drizzle.tables.paymentRequest.bankRefId),
|
|
418
|
-
drizzleOrm.eq(drizzle.tables.paymentRequest.bankRefId, p.parsed.bankRefId),
|
|
419
|
-
drizzleOrm.eq(drizzle.tables.paymentRequest.accountId, account.id),
|
|
420
|
-
drizzleOrm.eq(
|
|
421
|
-
drizzle.tables.paymentRequest.connectorKey,
|
|
422
|
-
account.connectorKey
|
|
423
|
-
),
|
|
424
|
-
drizzleOrm.isNull(drizzle.tables.paymentRequest.deletedAt)
|
|
425
|
-
)
|
|
426
|
-
)
|
|
427
|
-
)
|
|
403
|
+
const prCompleteCommands = matchingRequests.filter(
|
|
404
|
+
(req) => req.status !== "COMPLETED" && req.status !== "FAILED"
|
|
405
|
+
).map(
|
|
406
|
+
(req) => drizzle.updatePaymentRequestStatusCommand(db, {
|
|
407
|
+
id: req.id,
|
|
408
|
+
status: "COMPLETED",
|
|
409
|
+
processedAt: /* @__PURE__ */ new Date()
|
|
410
|
+
}).command
|
|
428
411
|
);
|
|
429
412
|
eventsToEmit.push(
|
|
430
413
|
...enrichedPayments.map((p) => ({
|
|
@@ -456,7 +439,7 @@ class BankSyncAccountPayments extends cloudflare_workers.WorkflowEntrypoint {
|
|
|
456
439
|
backendSdk.asNonEmpty([
|
|
457
440
|
updateLastSyncCommand,
|
|
458
441
|
...createCommands,
|
|
459
|
-
...
|
|
442
|
+
...prCompleteCommands
|
|
460
443
|
])
|
|
461
444
|
);
|
|
462
445
|
await pushToQueue(
|
|
@@ -464,27 +447,6 @@ class BankSyncAccountPayments extends cloudflare_workers.WorkflowEntrypoint {
|
|
|
464
447
|
eventsToEmit
|
|
465
448
|
);
|
|
466
449
|
}
|
|
467
|
-
const paymentRequestIds = enrichedPayments.map((p) => p.parsed.paymentRequestId).filter((id) => id != null);
|
|
468
|
-
if (paymentRequestIds.length > 0) {
|
|
469
|
-
const processedPRs = await db.select({ batchId: drizzle.tables.paymentRequest.batchId }).from(drizzle.tables.paymentRequest).where(drizzleOrm.inArray(drizzle.tables.paymentRequest.id, paymentRequestIds));
|
|
470
|
-
const batchIds = [
|
|
471
|
-
...new Set(
|
|
472
|
-
processedPRs.map((pr) => pr.batchId).filter((id) => id != null)
|
|
473
|
-
)
|
|
474
|
-
];
|
|
475
|
-
for (const batchId of batchIds) {
|
|
476
|
-
const allPRsInBatch = await db.select({ deletedAt: drizzle.tables.paymentRequest.deletedAt }).from(drizzle.tables.paymentRequest).where(drizzleOrm.eq(drizzle.tables.paymentRequest.batchId, batchId));
|
|
477
|
-
const allDone = allPRsInBatch.length > 0 && allPRsInBatch.every((pr) => pr.deletedAt != null);
|
|
478
|
-
if (allDone) {
|
|
479
|
-
const batch = await drizzle.getBatchByIdQuery(db, { batchId });
|
|
480
|
-
if (batch && batch.status !== "COMPLETED" && batch.status !== "FAILED") {
|
|
481
|
-
await drizzle.upsertBatchCommand(db, {
|
|
482
|
-
batch: { ...batch, status: "COMPLETED" }
|
|
483
|
-
}).command.execute();
|
|
484
|
-
}
|
|
485
|
-
}
|
|
486
|
-
}
|
|
487
|
-
}
|
|
488
450
|
return {
|
|
489
451
|
...lastSyncMetadata,
|
|
490
452
|
newLastSyncAt: now
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
import { first, uuidv4, asNonEmpty } from '@develit-io/backend-sdk';
|
|
2
|
-
import { t as tables, g as getBatchByIdQuery, a as getPaymentRequestsByBatchIdQuery, c as checksum, u as upsertBatchCommand, b as getAccountByIdQuery, d as createCredentialsResolver, e as updatePaymentRequestStatusCommand, f as createPaymentCommand } from '../shared/bank.
|
|
2
|
+
import { t as tables, g as getBatchByIdQuery, a as getPaymentRequestsByBatchIdQuery, c as checksum, u as upsertBatchCommand, b as getAccountByIdQuery, d as createCredentialsResolver, e as updatePaymentRequestStatusCommand, f as createPaymentCommand } from '../shared/bank.B5bZRvgq.mjs';
|
|
3
3
|
import { f as isBatchSigned, a as isBatchFailed, c as isBatchOpen, g as isPaymentCompleted } from '../shared/bank.CbAwwIhZ.mjs';
|
|
4
|
-
import { e as toBatchedPaymentFromPaymentRequest, i as toPreparedPayment, j as initiateConnector } from '../shared/bank.
|
|
5
|
-
import { eq,
|
|
6
|
-
import 'drizzle-orm/sqlite-core';
|
|
4
|
+
import { e as toBatchedPaymentFromPaymentRequest, i as toPreparedPayment, j as initiateConnector } from '../shared/bank.BtszLapg.mjs';
|
|
5
|
+
import { eq, and, inArray } from 'drizzle-orm';
|
|
7
6
|
import { WorkflowEntrypoint } from 'cloudflare:workers';
|
|
8
7
|
import { NonRetryableError } from 'cloudflare:workflows';
|
|
9
8
|
import { drizzle } from 'drizzle-orm/d1';
|
|
10
9
|
import 'node:crypto';
|
|
11
|
-
import '../shared/bank.
|
|
10
|
+
import '../shared/bank.C6jjS1Pl.mjs';
|
|
12
11
|
import 'drizzle-orm/relations';
|
|
12
|
+
import 'drizzle-orm/sqlite-core';
|
|
13
13
|
import 'date-fns';
|
|
14
14
|
import 'jose';
|
|
15
15
|
import '@develit-io/general-codes';
|
|
16
16
|
import 'drizzle-zod';
|
|
17
|
-
import '../shared/bank.
|
|
17
|
+
import '../shared/bank.BoZtXQpG.mjs';
|
|
18
18
|
|
|
19
19
|
const updateAccountLastSyncCommand = (db, {
|
|
20
20
|
lastSyncAt,
|
|
@@ -39,6 +39,23 @@ function pushToQueue$1(queue, message) {
|
|
|
39
39
|
}))
|
|
40
40
|
);
|
|
41
41
|
}
|
|
42
|
+
async function failBatchAndPayments(db, batch, paymentRequests, reason) {
|
|
43
|
+
const prCmds = paymentRequests.filter((p) => p.status !== "FAILED").map(
|
|
44
|
+
(p) => updatePaymentRequestStatusCommand(db, {
|
|
45
|
+
id: p.id,
|
|
46
|
+
status: "FAILED",
|
|
47
|
+
statusReason: reason,
|
|
48
|
+
processedAt: /* @__PURE__ */ new Date()
|
|
49
|
+
}).command
|
|
50
|
+
);
|
|
51
|
+
const batchCmd = upsertBatchCommand(db, {
|
|
52
|
+
batch: { ...batch, status: "FAILED" }
|
|
53
|
+
}).command;
|
|
54
|
+
const allCmds = [batchCmd, ...prCmds];
|
|
55
|
+
if (allCmds.length > 0) {
|
|
56
|
+
await db.batch(allCmds);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
42
59
|
class BankProcessBatch extends WorkflowEntrypoint {
|
|
43
60
|
async run(event, step) {
|
|
44
61
|
const { batchId } = event.payload;
|
|
@@ -108,7 +125,9 @@ class BankProcessBatch extends WorkflowEntrypoint {
|
|
|
108
125
|
accountId: batch.accountId
|
|
109
126
|
});
|
|
110
127
|
if (!account) {
|
|
111
|
-
|
|
128
|
+
const msg = `Account not found: ${batch.accountId}`;
|
|
129
|
+
await failBatchAndPayments(db, batch, paymentRequests, msg);
|
|
130
|
+
throw new NonRetryableError(msg);
|
|
112
131
|
}
|
|
113
132
|
const resolveCredentials = await createCredentialsResolver(db, this.env);
|
|
114
133
|
const connector = await initiateConnector({
|
|
@@ -141,17 +160,7 @@ class BankProcessBatch extends WorkflowEntrypoint {
|
|
|
141
160
|
const message = err instanceof Error ? err.message : typeof err === "object" && err !== null && "message" in err ? String(err.message) : String(err);
|
|
142
161
|
const status = typeof err === "object" && err !== null && "status" in err ? Number(err.status) : 0;
|
|
143
162
|
if (status >= 400 && status < 500) {
|
|
144
|
-
|
|
145
|
-
(p) => updatePaymentRequestStatusCommand(db, {
|
|
146
|
-
id: p.id,
|
|
147
|
-
status: "FAILED",
|
|
148
|
-
statusReason: message,
|
|
149
|
-
processedAt: /* @__PURE__ */ new Date()
|
|
150
|
-
}).command
|
|
151
|
-
);
|
|
152
|
-
if (updateCommands.length > 0) {
|
|
153
|
-
await db.batch(updateCommands);
|
|
154
|
-
}
|
|
163
|
+
await failBatchAndPayments(db, batch, paymentRequests, message);
|
|
155
164
|
throw new NonRetryableError(message);
|
|
156
165
|
}
|
|
157
166
|
throw new Error(message);
|
|
@@ -162,7 +171,9 @@ class BankProcessBatch extends WorkflowEntrypoint {
|
|
|
162
171
|
metadata
|
|
163
172
|
} = result;
|
|
164
173
|
if (!authorizationUrls || authorizationUrls.length === 0) {
|
|
165
|
-
|
|
174
|
+
const msg = "Failed to retrieve authorization URLs";
|
|
175
|
+
await failBatchAndPayments(db, batch, paymentRequests, msg);
|
|
176
|
+
throw new NonRetryableError(msg);
|
|
166
177
|
}
|
|
167
178
|
return {
|
|
168
179
|
authorizationUrls,
|
|
@@ -215,14 +226,13 @@ class BankProcessBatch extends WorkflowEntrypoint {
|
|
|
215
226
|
id: p.id,
|
|
216
227
|
status: "COMPLETED",
|
|
217
228
|
bankRefId: `MOCK-${uuidv4()}`,
|
|
218
|
-
processedAt
|
|
219
|
-
deletedAt: /* @__PURE__ */ new Date()
|
|
229
|
+
processedAt
|
|
220
230
|
}).command
|
|
221
231
|
);
|
|
222
232
|
const updateBatchCommand = upsertBatchCommand(db, {
|
|
223
233
|
batch: {
|
|
224
234
|
...batch,
|
|
225
|
-
status: "
|
|
235
|
+
status: "COMPLETED",
|
|
226
236
|
authorizationUrls: batchResult.authorizationUrls,
|
|
227
237
|
metadata: batchResult.metadata,
|
|
228
238
|
batchPaymentInitiatedAt: /* @__PURE__ */ new Date()
|
|
@@ -345,84 +355,57 @@ class BankSyncAccountPayments extends WorkflowEntrypoint {
|
|
|
345
355
|
"process new payments and update lastSyncAt",
|
|
346
356
|
async () => {
|
|
347
357
|
const eventsToEmit = [];
|
|
348
|
-
const
|
|
349
|
-
const
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
eq(
|
|
357
|
-
tables.paymentRequest.connectorKey,
|
|
358
|
-
account.connectorKey
|
|
359
|
-
),
|
|
360
|
-
isNull(tables.paymentRequest.deletedAt)
|
|
358
|
+
const bankRefIds = paymentsToInsert.map((p) => p.parsed.bankRefId).filter((id) => id != null);
|
|
359
|
+
const matchingRequests = bankRefIds.length > 0 ? await db.select().from(tables.paymentRequest).where(
|
|
360
|
+
and(
|
|
361
|
+
inArray(tables.paymentRequest.bankRefId, bankRefIds),
|
|
362
|
+
eq(tables.paymentRequest.accountId, account.id),
|
|
363
|
+
eq(
|
|
364
|
+
tables.paymentRequest.connectorKey,
|
|
365
|
+
account.connectorKey
|
|
361
366
|
)
|
|
362
|
-
)
|
|
363
|
-
]
|
|
364
|
-
const requestById = Object.fromEntries(
|
|
365
|
-
matchingByPrId.map((r) => [r.id, r])
|
|
366
|
-
);
|
|
367
|
+
)
|
|
368
|
+
) : [];
|
|
367
369
|
const requestByBankRefId = Object.fromEntries(
|
|
368
|
-
|
|
370
|
+
matchingRequests.map((r) => [r.bankRefId, r])
|
|
369
371
|
);
|
|
370
372
|
const enrichedPayments = paymentsToInsert.map((p) => {
|
|
371
|
-
const req = p.parsed.
|
|
373
|
+
const req = p.parsed.bankRefId && requestByBankRefId[p.parsed.bankRefId] || null;
|
|
372
374
|
if (!req) return p;
|
|
373
375
|
return {
|
|
374
376
|
...p,
|
|
375
377
|
parsed: {
|
|
376
378
|
...p.parsed,
|
|
377
|
-
//
|
|
378
|
-
paymentRequestId: p.parsed.paymentRequestId ?? req.id,
|
|
379
|
-
createdAt: req.createdAt ?? p.parsed.createdAt,
|
|
380
|
-
batchId: p.parsed.batchId ?? req.batchId,
|
|
381
|
-
refId: p.parsed.refId ?? req.refId,
|
|
382
|
-
chargeBearer: p.parsed.chargeBearer ?? req.chargeBearer,
|
|
383
|
-
instructionPriority: p.parsed.instructionPriority ?? req.instructionPriority,
|
|
384
|
-
message: p.parsed.message ?? req.message,
|
|
379
|
+
// queue-bus: transaction matching (DBU doesn't echo these in statements)
|
|
385
380
|
vs: p.parsed.vs ?? req.vs,
|
|
386
381
|
ss: p.parsed.ss ?? req.ss,
|
|
387
382
|
ks: p.parsed.ks ?? req.ks,
|
|
383
|
+
message: p.parsed.message ?? req.message,
|
|
384
|
+
// queue-bus: party creation
|
|
388
385
|
creditor: {
|
|
389
386
|
...p.parsed.creditor,
|
|
390
|
-
holderName: p.parsed.creditor?.holderName ?? req.creditor?.holderName
|
|
391
|
-
address: p.parsed.creditor?.address ?? req.creditor?.address,
|
|
392
|
-
swiftBic: p.parsed.creditor?.swiftBic ?? req.creditor?.swiftBic
|
|
387
|
+
holderName: p.parsed.creditor?.holderName ?? req.creditor?.holderName
|
|
393
388
|
},
|
|
394
389
|
debtor: {
|
|
395
390
|
...p.parsed.debtor,
|
|
396
391
|
holderName: p.parsed.debtor?.holderName ?? req.debtor?.holderName
|
|
397
392
|
}
|
|
393
|
+
// NOT enriched: chargeBearer, instructionPriority, refId, batchId,
|
|
394
|
+
// createdAt, address, swiftBic — no downstream consumer in payment table
|
|
398
395
|
}
|
|
399
396
|
};
|
|
400
397
|
});
|
|
401
398
|
const createCommands = enrichedPayments.map(
|
|
402
399
|
(p) => createPaymentCommand(db, { payment: p.parsed }).command
|
|
403
400
|
);
|
|
404
|
-
const
|
|
405
|
-
(
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
p.parsed.paymentRequestId ? eq(tables.paymentRequest.id, p.parsed.paymentRequestId) : void 0,
|
|
413
|
-
// Fallback: match via bankRefId (set during processBatch)
|
|
414
|
-
and(
|
|
415
|
-
isNotNull(tables.paymentRequest.bankRefId),
|
|
416
|
-
eq(tables.paymentRequest.bankRefId, p.parsed.bankRefId),
|
|
417
|
-
eq(tables.paymentRequest.accountId, account.id),
|
|
418
|
-
eq(
|
|
419
|
-
tables.paymentRequest.connectorKey,
|
|
420
|
-
account.connectorKey
|
|
421
|
-
),
|
|
422
|
-
isNull(tables.paymentRequest.deletedAt)
|
|
423
|
-
)
|
|
424
|
-
)
|
|
425
|
-
)
|
|
401
|
+
const prCompleteCommands = matchingRequests.filter(
|
|
402
|
+
(req) => req.status !== "COMPLETED" && req.status !== "FAILED"
|
|
403
|
+
).map(
|
|
404
|
+
(req) => updatePaymentRequestStatusCommand(db, {
|
|
405
|
+
id: req.id,
|
|
406
|
+
status: "COMPLETED",
|
|
407
|
+
processedAt: /* @__PURE__ */ new Date()
|
|
408
|
+
}).command
|
|
426
409
|
);
|
|
427
410
|
eventsToEmit.push(
|
|
428
411
|
...enrichedPayments.map((p) => ({
|
|
@@ -454,7 +437,7 @@ class BankSyncAccountPayments extends WorkflowEntrypoint {
|
|
|
454
437
|
asNonEmpty([
|
|
455
438
|
updateLastSyncCommand,
|
|
456
439
|
...createCommands,
|
|
457
|
-
...
|
|
440
|
+
...prCompleteCommands
|
|
458
441
|
])
|
|
459
442
|
);
|
|
460
443
|
await pushToQueue(
|
|
@@ -462,27 +445,6 @@ class BankSyncAccountPayments extends WorkflowEntrypoint {
|
|
|
462
445
|
eventsToEmit
|
|
463
446
|
);
|
|
464
447
|
}
|
|
465
|
-
const paymentRequestIds = enrichedPayments.map((p) => p.parsed.paymentRequestId).filter((id) => id != null);
|
|
466
|
-
if (paymentRequestIds.length > 0) {
|
|
467
|
-
const processedPRs = await db.select({ batchId: tables.paymentRequest.batchId }).from(tables.paymentRequest).where(inArray(tables.paymentRequest.id, paymentRequestIds));
|
|
468
|
-
const batchIds = [
|
|
469
|
-
...new Set(
|
|
470
|
-
processedPRs.map((pr) => pr.batchId).filter((id) => id != null)
|
|
471
|
-
)
|
|
472
|
-
];
|
|
473
|
-
for (const batchId of batchIds) {
|
|
474
|
-
const allPRsInBatch = await db.select({ deletedAt: tables.paymentRequest.deletedAt }).from(tables.paymentRequest).where(eq(tables.paymentRequest.batchId, batchId));
|
|
475
|
-
const allDone = allPRsInBatch.length > 0 && allPRsInBatch.every((pr) => pr.deletedAt != null);
|
|
476
|
-
if (allDone) {
|
|
477
|
-
const batch = await getBatchByIdQuery(db, { batchId });
|
|
478
|
-
if (batch && batch.status !== "COMPLETED" && batch.status !== "FAILED") {
|
|
479
|
-
await upsertBatchCommand(db, {
|
|
480
|
-
batch: { ...batch, status: "COMPLETED" }
|
|
481
|
-
}).command.execute();
|
|
482
|
-
}
|
|
483
|
-
}
|
|
484
|
-
}
|
|
485
|
-
}
|
|
486
448
|
return {
|
|
487
449
|
...lastSyncMetadata,
|
|
488
450
|
newLastSyncAt: now
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { B as BankServiceWranglerConfig } from '../shared/bank.
|
|
1
|
+
import { B as BankServiceWranglerConfig } from '../shared/bank.BP_3WMIF.cjs';
|
|
2
2
|
|
|
3
3
|
declare function defineBankServiceWrangler(config: BankServiceWranglerConfig): {
|
|
4
4
|
vars: {
|
|
@@ -9,6 +9,7 @@ declare function defineBankServiceWrangler(config: BankServiceWranglerConfig): {
|
|
|
9
9
|
FINBRICKS_BASE_URI: "https://api.sandbox.finbricks.com";
|
|
10
10
|
FINBRICKS_MERCHANT_ID: string;
|
|
11
11
|
CRON_BATCH_STATUSES: string;
|
|
12
|
+
CRON_PAYMENT_STATUSES: string;
|
|
12
13
|
BANK_AUTH_RECIPIENT: string;
|
|
13
14
|
DBUCS_BASE_URI: string;
|
|
14
15
|
DBUCS_USERNAME: string;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { B as BankServiceWranglerConfig } from '../shared/bank.
|
|
1
|
+
import { B as BankServiceWranglerConfig } from '../shared/bank.BP_3WMIF.mjs';
|
|
2
2
|
|
|
3
3
|
declare function defineBankServiceWrangler(config: BankServiceWranglerConfig): {
|
|
4
4
|
vars: {
|
|
@@ -9,6 +9,7 @@ declare function defineBankServiceWrangler(config: BankServiceWranglerConfig): {
|
|
|
9
9
|
FINBRICKS_BASE_URI: "https://api.sandbox.finbricks.com";
|
|
10
10
|
FINBRICKS_MERCHANT_ID: string;
|
|
11
11
|
CRON_BATCH_STATUSES: string;
|
|
12
|
+
CRON_PAYMENT_STATUSES: string;
|
|
12
13
|
BANK_AUTH_RECIPIENT: string;
|
|
13
14
|
DBUCS_BASE_URI: string;
|
|
14
15
|
DBUCS_USERNAME: string;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { B as BankServiceWranglerConfig } from '../shared/bank.
|
|
1
|
+
import { B as BankServiceWranglerConfig } from '../shared/bank.BP_3WMIF.js';
|
|
2
2
|
|
|
3
3
|
declare function defineBankServiceWrangler(config: BankServiceWranglerConfig): {
|
|
4
4
|
vars: {
|
|
@@ -9,6 +9,7 @@ declare function defineBankServiceWrangler(config: BankServiceWranglerConfig): {
|
|
|
9
9
|
FINBRICKS_BASE_URI: "https://api.sandbox.finbricks.com";
|
|
10
10
|
FINBRICKS_MERCHANT_ID: string;
|
|
11
11
|
CRON_BATCH_STATUSES: string;
|
|
12
|
+
CRON_PAYMENT_STATUSES: string;
|
|
12
13
|
BANK_AUTH_RECIPIENT: string;
|
|
13
14
|
DBUCS_BASE_URI: string;
|
|
14
15
|
DBUCS_USERNAME: string;
|
|
@@ -90,6 +90,12 @@ type ConnectedAccount = {
|
|
|
90
90
|
declare abstract class IBankConnector {
|
|
91
91
|
/** Unique identifier for this bank connector (e.g., 'ERSTE', 'FINBRICKS', 'MOCK') */
|
|
92
92
|
abstract connectorKey: ConnectorKey;
|
|
93
|
+
/**
|
|
94
|
+
* Lifecycle mode for payment status resolution:
|
|
95
|
+
* - 'batch': statuses are resolved via updateBatchStatuses (getBatchStatus polling)
|
|
96
|
+
* - 'per-payment': statuses are resolved via updatePaymentStatuses (getPaymentStatus polling per payment)
|
|
97
|
+
*/
|
|
98
|
+
abstract readonly lifecycleMode: 'batch' | 'per-payment';
|
|
93
99
|
/** List of bank accounts connected through this connector instance */
|
|
94
100
|
abstract connectedAccounts: ConnectedAccount[];
|
|
95
101
|
/** Optional resolver for loading credentials on demand */
|
|
@@ -2630,7 +2636,7 @@ declare const batch: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
|
|
|
2630
2636
|
tableName: "batch";
|
|
2631
2637
|
dataType: "string";
|
|
2632
2638
|
columnType: "SQLiteText";
|
|
2633
|
-
data: "
|
|
2639
|
+
data: "OPEN" | "PROCESSING" | "READY_TO_SIGN" | "SIGNED" | "SIGNATURE_FAILED" | "FAILED" | "COMPLETED";
|
|
2634
2640
|
driverParam: string;
|
|
2635
2641
|
notNull: false;
|
|
2636
2642
|
hasDefault: false;
|
|
@@ -2643,7 +2649,7 @@ declare const batch: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
|
|
|
2643
2649
|
generated: undefined;
|
|
2644
2650
|
}, {}, {
|
|
2645
2651
|
length: number | undefined;
|
|
2646
|
-
$type: "
|
|
2652
|
+
$type: "OPEN" | "PROCESSING" | "READY_TO_SIGN" | "SIGNED" | "SIGNATURE_FAILED" | "FAILED" | "COMPLETED";
|
|
2647
2653
|
}>;
|
|
2648
2654
|
statusReason: drizzle_orm_sqlite_core.SQLiteColumn<{
|
|
2649
2655
|
name: "status_reason";
|
|
@@ -2895,25 +2901,6 @@ declare const payment: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
|
|
|
2895
2901
|
}, {}, {
|
|
2896
2902
|
length: number | undefined;
|
|
2897
2903
|
}>;
|
|
2898
|
-
paymentRequestId: drizzle_orm_sqlite_core.SQLiteColumn<{
|
|
2899
|
-
name: "payment_request_id";
|
|
2900
|
-
tableName: "payment";
|
|
2901
|
-
dataType: "string";
|
|
2902
|
-
columnType: "SQLiteText";
|
|
2903
|
-
data: string;
|
|
2904
|
-
driverParam: string;
|
|
2905
|
-
notNull: false;
|
|
2906
|
-
hasDefault: false;
|
|
2907
|
-
isPrimaryKey: false;
|
|
2908
|
-
isAutoincrement: false;
|
|
2909
|
-
hasRuntimeDefault: false;
|
|
2910
|
-
enumValues: [string, ...string[]];
|
|
2911
|
-
baseColumn: never;
|
|
2912
|
-
identity: undefined;
|
|
2913
|
-
generated: undefined;
|
|
2914
|
-
}, {}, {
|
|
2915
|
-
length: number | undefined;
|
|
2916
|
-
}>;
|
|
2917
2904
|
refId: drizzle_orm_sqlite_core.SQLiteColumn<{
|
|
2918
2905
|
name: "ref_id";
|
|
2919
2906
|
tableName: "payment";
|
|
@@ -3073,7 +3060,7 @@ declare const payment: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
|
|
|
3073
3060
|
tableName: "payment";
|
|
3074
3061
|
dataType: "string";
|
|
3075
3062
|
columnType: "SQLiteText";
|
|
3076
|
-
data: "
|
|
3063
|
+
data: "SIGNED" | "FAILED" | "COMPLETED" | "CREATED" | "PREPARED" | "PENDING";
|
|
3077
3064
|
driverParam: string;
|
|
3078
3065
|
notNull: true;
|
|
3079
3066
|
hasDefault: false;
|
|
@@ -3086,7 +3073,7 @@ declare const payment: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
|
|
|
3086
3073
|
generated: undefined;
|
|
3087
3074
|
}, {}, {
|
|
3088
3075
|
length: number | undefined;
|
|
3089
|
-
$type: "
|
|
3076
|
+
$type: "SIGNED" | "FAILED" | "COMPLETED" | "CREATED" | "PREPARED" | "PENDING";
|
|
3090
3077
|
}>;
|
|
3091
3078
|
statusReason: drizzle_orm_sqlite_core.SQLiteColumn<{
|
|
3092
3079
|
name: "status_reason";
|
|
@@ -3667,7 +3654,7 @@ declare const paymentRequest: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
|
|
|
3667
3654
|
tableName: "payment_request";
|
|
3668
3655
|
dataType: "string";
|
|
3669
3656
|
columnType: "SQLiteText";
|
|
3670
|
-
data: "
|
|
3657
|
+
data: "SIGNED" | "FAILED" | "COMPLETED" | "CREATED" | "PREPARED" | "PENDING";
|
|
3671
3658
|
driverParam: string;
|
|
3672
3659
|
notNull: true;
|
|
3673
3660
|
hasDefault: false;
|
|
@@ -3680,7 +3667,7 @@ declare const paymentRequest: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
|
|
|
3680
3667
|
generated: undefined;
|
|
3681
3668
|
}, {}, {
|
|
3682
3669
|
length: number | undefined;
|
|
3683
|
-
$type: "
|
|
3670
|
+
$type: "SIGNED" | "FAILED" | "COMPLETED" | "CREATED" | "PREPARED" | "PENDING";
|
|
3684
3671
|
}>;
|
|
3685
3672
|
statusReason: drizzle_orm_sqlite_core.SQLiteColumn<{
|
|
3686
3673
|
name: "status_reason";
|