@develit-services/bank 0.8.6 → 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.
Files changed (38) hide show
  1. package/dist/database/schema.cjs +1 -1
  2. package/dist/database/schema.d.cts +1 -1
  3. package/dist/database/schema.d.mts +1 -1
  4. package/dist/database/schema.d.ts +1 -1
  5. package/dist/database/schema.mjs +1 -1
  6. package/dist/export/worker.cjs +550 -153
  7. package/dist/export/worker.d.cts +259 -47
  8. package/dist/export/worker.d.mts +259 -47
  9. package/dist/export/worker.d.ts +259 -47
  10. package/dist/export/worker.mjs +551 -154
  11. package/dist/export/workflows.cjs +95 -17
  12. package/dist/export/workflows.mjs +96 -18
  13. package/dist/export/wrangler.d.cts +2 -1
  14. package/dist/export/wrangler.d.mts +2 -1
  15. package/dist/export/wrangler.d.ts +2 -1
  16. package/dist/shared/{bank.BliD3oCT.d.ts → bank.B-NJB8GB.d.cts} +34 -10
  17. package/dist/shared/{bank.BliD3oCT.d.cts → bank.B-NJB8GB.d.mts} +34 -10
  18. package/dist/shared/{bank.BliD3oCT.d.mts → bank.B-NJB8GB.d.ts} +34 -10
  19. package/dist/shared/{bank.Cpy9PULF.mjs → bank.B5bZRvgq.mjs} +28 -5
  20. package/dist/shared/{bank.CQBfbG8u.d.cts → bank.BP_3WMIF.d.cts} +1 -0
  21. package/dist/shared/{bank.CQBfbG8u.d.mts → bank.BP_3WMIF.d.mts} +1 -0
  22. package/dist/shared/{bank.CQBfbG8u.d.ts → bank.BP_3WMIF.d.ts} +1 -0
  23. package/dist/shared/{bank.DDHrdFgy.mjs → bank.BoZtXQpG.mjs} +1 -1
  24. package/dist/shared/{bank.DRrBrAdI.mjs → bank.BtszLapg.mjs} +211 -43
  25. package/dist/shared/{bank.BoMDujsl.d.ts → bank.BzobShUU.d.cts} +17 -7
  26. package/dist/shared/{bank.C4VOdIx1.mjs → bank.C6jjS1Pl.mjs} +32 -4
  27. package/dist/shared/{bank.lbzMqyr3.d.cts → bank.CAVvvZZO.d.mts} +17 -7
  28. package/dist/shared/{bank.CQURey1E.cjs → bank.CtnsGHM8.cjs} +210 -43
  29. package/dist/shared/{bank.C-T1FQxg.cjs → bank.DJnDSYqE.cjs} +1 -1
  30. package/dist/shared/{bank.B6U8sUZn.d.mts → bank.DRTuKO8S.d.ts} +17 -7
  31. package/dist/shared/{bank.BOnP9p9Y.cjs → bank.DT6bg8k5.cjs} +28 -5
  32. package/dist/shared/{bank.SQ4Mmr8u.cjs → bank.JVlyPAAb.cjs} +32 -4
  33. package/dist/types.cjs +2 -3
  34. package/dist/types.d.cts +14 -18
  35. package/dist/types.d.mts +14 -18
  36. package/dist/types.d.ts +14 -18
  37. package/dist/types.mjs +2 -2
  38. package/package.json +2 -2
@@ -3,7 +3,7 @@
3
3
  const backendSdk = require('@develit-io/backend-sdk');
4
4
  const dateFns = require('date-fns');
5
5
  const generalCodes = require('@develit-io/general-codes');
6
- require('./bank.SQ4Mmr8u.cjs');
6
+ require('./bank.JVlyPAAb.cjs');
7
7
  require('drizzle-orm');
8
8
  const jose = require('jose');
9
9
  require('node:crypto');
@@ -62,9 +62,6 @@ function toCompletedPayment(payment, status, bankRefId, processedAt) {
62
62
  processedAt: processedAt ?? /* @__PURE__ */ new Date()
63
63
  };
64
64
  }
65
- function batchTransform(payments, transformer) {
66
- return payments.map(transformer);
67
- }
68
65
  function toPaymentRequestInsert(payment, batchId) {
69
66
  return {
70
67
  id: payment.id,
@@ -86,7 +83,8 @@ function toPaymentRequestInsert(payment, batchId) {
86
83
  creditor: payment.creditor,
87
84
  creditorIban: payment.creditorIban ?? null,
88
85
  debtor: payment.debtor,
89
- debtorIban: payment.debtorIban ?? null
86
+ debtorIban: payment.debtorIban ?? null,
87
+ sendAsSinglePayment: payment.sendAsSinglePayment ?? null
90
88
  };
91
89
  }
92
90
  function toBatchedPaymentFromPaymentRequest(sp) {
@@ -119,6 +117,9 @@ function toBatchedPaymentFromPaymentRequest(sp) {
119
117
  }
120
118
 
121
119
  class IBankConnector {
120
+ supportsPaymentType(paymentType) {
121
+ return paymentType === "DOMESTIC";
122
+ }
122
123
  // ── Deprecated methods (backward compatibility) ────────────────────
123
124
  /**
124
125
  * @deprecated Use initiateDomesticBatch, initiateSEPABatch, or initiateForeignBatch instead.
@@ -206,6 +207,17 @@ class IBankConnector {
206
207
  }
207
208
  }
208
209
 
210
+ function buildEndToEndId(payment) {
211
+ const parts = [];
212
+ if (payment.vs) parts.push(`VS${payment.vs}`);
213
+ if (payment.ss) parts.push(`SS${payment.ss}`);
214
+ if (payment.ks) parts.push(`KS${payment.ks}`);
215
+ if (parts.length === 0) {
216
+ return payment.id.replace(/-/g, "");
217
+ }
218
+ return `/${parts.join("/")}`;
219
+ }
220
+
209
221
  async function signFinbricksJws({
210
222
  privateKeyPem,
211
223
  merchantId,
@@ -262,6 +274,18 @@ const useFinbricksFetch = async (config, init) => {
262
274
  if (correlationId) {
263
275
  headers["Correlation-ID"] = correlationId;
264
276
  }
277
+ console.log(
278
+ "[Finbricks] request",
279
+ JSON.stringify(
280
+ {
281
+ method,
282
+ url: url.toString(),
283
+ body: body ?? null
284
+ },
285
+ null,
286
+ 2
287
+ )
288
+ );
265
289
  const res = await fetch(url.toString(), {
266
290
  method,
267
291
  headers,
@@ -269,11 +293,30 @@ const useFinbricksFetch = async (config, init) => {
269
293
  });
270
294
  if (!res.ok) {
271
295
  const text = await res.text().catch(() => "unknown error");
296
+ console.error("[Finbricks] error response", {
297
+ status: res.status,
298
+ statusText: res.statusText,
299
+ url: url.toString(),
300
+ body: text
301
+ });
272
302
  throw new Error(
273
303
  `Finbricks API error: ${res.status} ${res.statusText} \u2013 ${text}`
274
304
  );
275
305
  }
276
- return await res.json();
306
+ const json = await res.json();
307
+ console.log(
308
+ "[Finbricks] response",
309
+ JSON.stringify(
310
+ {
311
+ status: res.status,
312
+ url: url.toString(),
313
+ body: json
314
+ },
315
+ null,
316
+ 2
317
+ )
318
+ );
319
+ return json;
277
320
  };
278
321
  class FinbricksClient {
279
322
  constructor(baseUrl, merchantId, privateKeyPem, redirectUri) {
@@ -328,16 +371,16 @@ const mapFinbricksStatus = (status) => {
328
371
  return "PENDING";
329
372
  }
330
373
  };
331
- const mapFinbricksTransactionStatus = (status) => {
374
+ const mapFinbricksTransactionStatus = (status, finalBankStatus) => {
332
375
  switch (status) {
333
376
  case "OPENED":
334
- return "CREATED";
377
+ return "PREPARED";
335
378
  case "AUTHORIZED":
336
- return "PENDING";
379
+ return finalBankStatus ? "COMPLETED" : "PENDING";
337
380
  case "COMPLETED":
338
- return "COMPLETED";
381
+ return finalBankStatus ? "COMPLETED" : "PENDING";
339
382
  case "BOOKED":
340
- return "PENDING";
383
+ return finalBankStatus ? "COMPLETED" : "PENDING";
341
384
  case "SETTLED":
342
385
  return "COMPLETED";
343
386
  case "REJECTED":
@@ -391,24 +434,81 @@ const mapReferencesToPayment = (reference) => {
391
434
  return symbols;
392
435
  };
393
436
 
437
+ const SEPA_COUNTRIES = /* @__PURE__ */ new Set([
438
+ "AT",
439
+ "BE",
440
+ "BG",
441
+ "CY",
442
+ "CZ",
443
+ "DE",
444
+ "DK",
445
+ "EE",
446
+ "ES",
447
+ "FI",
448
+ "FR",
449
+ "GR",
450
+ "HR",
451
+ "HU",
452
+ "IE",
453
+ "IT",
454
+ "LT",
455
+ "LU",
456
+ "LV",
457
+ "MT",
458
+ "NL",
459
+ "PL",
460
+ "PT",
461
+ "RO",
462
+ "SE",
463
+ "SI",
464
+ "SK",
465
+ "IS",
466
+ "LI",
467
+ "NO",
468
+ "CH",
469
+ "GB",
470
+ "MC",
471
+ "SM",
472
+ "VA",
473
+ "AD",
474
+ "GI",
475
+ "XK"
476
+ ]);
477
+ function detectPaymentType(tx, isIncoming) {
478
+ const related = tx.entryDetails?.transactionDetails?.relatedParties;
479
+ const otherParty = isIncoming ? related?.debtorAccount : related?.creditorAccount;
480
+ if (otherParty?.identification?.other?.identification) return "DOMESTIC";
481
+ const otherIban = otherParty?.identification?.iban;
482
+ const otherCountry = otherIban?.slice(0, 2);
483
+ if (otherCountry === "CZ") return "DOMESTIC";
484
+ if (otherIban && otherCountry) {
485
+ if (SEPA_COUNTRIES.has(otherCountry) && tx.amount?.currency === "EUR")
486
+ return "SEPA";
487
+ return "SWIFT";
488
+ }
489
+ if (tx.amount?.currency === "EUR") return "SEPA";
490
+ if (tx.amount?.currency !== "CZK") return "SWIFT";
491
+ return "DOMESTIC";
492
+ }
394
493
  const mapFinbricksTransactionToPayment = (tx, account) => {
395
494
  const isIncoming = tx.creditDebitIndicator === "CRDT";
396
495
  const related = tx.entryDetails?.transactionDetails?.relatedParties;
496
+ const endToEndId = tx.entryDetails.transactionDetails?.references?.endToEndIdentification;
497
+ const symbolsRegex = /^\/VS\d+/;
397
498
  const base = {
398
499
  id: backendSdk.uuidv4(),
399
500
  correlationId: backendSdk.uuidv4(),
400
- //TODO(kleinpetr): use real correlationId once available
401
501
  connectorKey: account.connectorKey,
402
502
  accountId: account.id,
403
503
  bankRefId: tx.fbxReference,
404
504
  amount: tx.amount?.value || 0,
405
505
  currency: tx.amount?.currency || "CZK",
406
- paymentType: "DOMESTIC",
506
+ paymentType: detectPaymentType(tx, isIncoming),
407
507
  status: mapFinbricksStatus(tx.status),
408
508
  message: tx.entryDetails.transactionDetails?.remittanceInformation?.unstructured || tx.entryDetails.transactionDetails?.additionalRemittanceInformation || tx.entryDetails.transactionDetails?.additionalTransactionInformation || null,
409
509
  processedAt: new Date(tx.bookingDate.date),
410
510
  ...mapReferencesToPayment(
411
- tx.entryDetails.transactionDetails?.remittanceInformation?.structured?.creditorReferenceInformation?.reference || tx.entryDetails.transactionDetails?.references?.endToEndIdentification
511
+ tx.entryDetails.transactionDetails?.remittanceInformation?.structured?.creditorReferenceInformation?.reference || (endToEndId && symbolsRegex.test(endToEndId) ? endToEndId : void 0)
412
512
  ),
413
513
  creditor: {
414
514
  holderName: related?.creditorAccount?.name || related?.creditor?.name || "Unknown",
@@ -435,6 +535,13 @@ const mapFinbricksTransactionToPayment = (tx, account) => {
435
535
  return base;
436
536
  };
437
537
 
538
+ function autoVariableSymbol(paymentId) {
539
+ let hash = 0;
540
+ for (let i = 0; i < paymentId.length; i++) {
541
+ hash = (hash << 5) - hash + paymentId.charCodeAt(i) | 0;
542
+ }
543
+ return String(Math.abs(hash) % 1e10).padStart(10, "0");
544
+ }
438
545
  class FinbricksConnector extends IBankConnector {
439
546
  constructor(provider, {
440
547
  BASE_URI,
@@ -446,6 +553,7 @@ class FinbricksConnector extends IBankConnector {
446
553
  }) {
447
554
  super();
448
555
  this.connectorKey = "FINBRICKS";
556
+ this.lifecycleMode = "batch";
449
557
  this.connectedAccounts = [];
450
558
  this.PROVIDER = provider;
451
559
  this.finbricks = new FinbricksClient(
@@ -457,6 +565,9 @@ class FinbricksConnector extends IBankConnector {
457
565
  this.connectedAccounts = connectedAccounts;
458
566
  this.resolveCredentials = resolveCredentials;
459
567
  }
568
+ supportsPaymentType(paymentType) {
569
+ return paymentType === "DOMESTIC" || paymentType === "SEPA" || paymentType === "SWIFT";
570
+ }
460
571
  async getClientId(accountId) {
461
572
  if (!this.resolveCredentials) {
462
573
  throw backendSdk.createInternalError(null, {
@@ -646,7 +757,7 @@ class FinbricksConnector extends IBankConnector {
646
757
  merchantTransactionId: p.id,
647
758
  creditorAccountIban: p.creditor.iban,
648
759
  amount: p.amount,
649
- variableSymbol: p.vs,
760
+ variableSymbol: p.vs ?? (p.ss ? void 0 : autoVariableSymbol(p.id)),
650
761
  specificSymbol: p.ss,
651
762
  constantSymbol: p.ks,
652
763
  description: p.message
@@ -754,7 +865,7 @@ class FinbricksConnector extends IBankConnector {
754
865
  },
755
866
  paymentIdentification: {
756
867
  merchantTransactionId: bankRefId,
757
- endToEndIdentification: payment.id
868
+ endToEndIdentification: buildEndToEndId(payment)
758
869
  },
759
870
  amount: payment.amount,
760
871
  debtor: {
@@ -804,7 +915,7 @@ class FinbricksConnector extends IBankConnector {
804
915
  creditorAccountIban: payment.creditor.iban,
805
916
  creditorName: payment.creditor.holderName,
806
917
  description: payment.message,
807
- variableSymbol: payment.vs,
918
+ variableSymbol: payment.vs ?? (payment.ss ? void 0 : autoVariableSymbol(payment.id)),
808
919
  callbackUrl: `${this.finbricks.REDIRECT_URI}?type=payment&paymentId=${payment.id}`,
809
920
  paymentProvider: this.PROVIDER
810
921
  }
@@ -895,7 +1006,10 @@ class FinbricksConnector extends IBankConnector {
895
1006
  message: "Finbricks: failed to fetch payment status"
896
1007
  });
897
1008
  }
898
- return mapFinbricksTransactionStatus(response.resultCode);
1009
+ return mapFinbricksTransactionStatus(
1010
+ response.resultCode,
1011
+ response.finalBankStatus ?? false
1012
+ );
899
1013
  }
900
1014
  async getBatchStatus({
901
1015
  batchId,
@@ -948,6 +1062,7 @@ class AirBankConnector extends FinbricksConnector {
948
1062
  class CreditasConnector extends FinbricksConnector {
949
1063
  constructor(config) {
950
1064
  super("CREDITAS", config);
1065
+ this.lifecycleMode = "per-payment";
951
1066
  }
952
1067
  /**
953
1068
  * Creditas bank doesn't support batch payments at all.
@@ -1147,24 +1262,64 @@ function mod97(string) {
1147
1262
  }
1148
1263
  return parseInt(checksum, 10);
1149
1264
  }
1265
+ const parseCzechIban = (iban) => {
1266
+ const stripped = iban.replace(/\s/g, "").toUpperCase();
1267
+ if (!stripped.startsWith("CZ") || stripped.length !== 24) {
1268
+ throw new Error(`Invalid Czech IBAN: ${iban}`);
1269
+ }
1270
+ const bankCode = stripped.slice(4, 8);
1271
+ const prefix = stripped.slice(8, 14).replace(/^0+/, "");
1272
+ const main = stripped.slice(14, 24).replace(/^0+/, "");
1273
+ const accountNumber = prefix ? `${prefix}-${main}` : main;
1274
+ return { bankCode, accountNumber };
1275
+ };
1150
1276
  const calculateCzechIban = (accountNumber, bankCode) => {
1151
1277
  const paddedBankCode = bankCode.padStart(4, "0");
1152
1278
  let prefix = "";
1153
1279
  let mainAccount = accountNumber;
1154
1280
  if (accountNumber.includes("-")) {
1155
1281
  const parts = accountNumber.split("-");
1282
+ if (parts.length !== 2) {
1283
+ throw new Error(
1284
+ `Invalid account number format: expected "prefix-main" or "main", got "${accountNumber}"`
1285
+ );
1286
+ }
1156
1287
  prefix = parts[0];
1157
1288
  mainAccount = parts[1];
1158
1289
  }
1159
1290
  const paddedPrefix = prefix.padStart(6, "0");
1160
1291
  const paddedAccount = mainAccount.padStart(10, "0");
1161
1292
  const basicIban = paddedBankCode + paddedPrefix + paddedAccount;
1162
- const rearranged = basicIban + "1215";
1293
+ const rearranged = basicIban + "123500";
1163
1294
  const remainder = mod97(rearranged);
1164
1295
  const checkDigits = (98 - remainder).toString().padStart(2, "0");
1165
1296
  return `CZ${checkDigits}${basicIban}`;
1166
1297
  };
1167
1298
 
1299
+ function parseFlatAddress(addr, fallbackCountry) {
1300
+ if (!addr) {
1301
+ return {
1302
+ streetName: null,
1303
+ buildingNumber: null,
1304
+ city: null,
1305
+ zip: null,
1306
+ countryCode: fallbackCountry
1307
+ };
1308
+ }
1309
+ const parts = addr.split(",").map((p) => p.trim());
1310
+ const streetPart = parts[0];
1311
+ const cityPart = parts[1];
1312
+ const countryCode = parts[2]?.trim() || fallbackCountry;
1313
+ const streetMatch = streetPart?.match(/^(.+?)\s+(\d+\w*)$/);
1314
+ const cityMatch = cityPart?.match(/^(\d[\d ]*?)\s+(.+)$/);
1315
+ return {
1316
+ streetName: streetMatch?.[1] ?? streetPart ?? null,
1317
+ buildingNumber: streetMatch?.[2] ?? null,
1318
+ city: cityMatch?.[2] ?? cityPart ?? null,
1319
+ zip: cityMatch?.[1]?.replace(/\s/g, "") ?? null,
1320
+ countryCode
1321
+ };
1322
+ }
1168
1323
  class DbuConnector extends IBankConnector {
1169
1324
  constructor({
1170
1325
  BASE_URL,
@@ -1177,6 +1332,7 @@ class DbuConnector extends IBankConnector {
1177
1332
  }) {
1178
1333
  super();
1179
1334
  this.connectorKey = "DBU";
1335
+ this.lifecycleMode = "per-payment";
1180
1336
  this.connectedAccounts = [];
1181
1337
  this.baseUrl = BASE_URL;
1182
1338
  this.username = USERNAME;
@@ -1425,11 +1581,25 @@ class DbuConnector extends IBankConnector {
1425
1581
  }
1426
1582
  return Number(account.bankRefId);
1427
1583
  }
1584
+ resolveAccountDetails(account) {
1585
+ if (account.number && account.bankCode) {
1586
+ return { number: account.number, bankCode: account.bankCode };
1587
+ }
1588
+ if (account.iban) {
1589
+ const { bankCode, accountNumber } = parseCzechIban(account.iban);
1590
+ return { number: accountNumber, bankCode };
1591
+ }
1592
+ throw backendSdk.createInternalError(null, {
1593
+ message: "DBU: account has neither number+bankCode nor iban",
1594
+ code: "DBU_MISSING_ACCOUNT_DETAILS"
1595
+ });
1596
+ }
1428
1597
  async initiateInstantPayment(payment) {
1598
+ const creditor = this.resolveAccountDetails(payment.creditor);
1429
1599
  const body = {
1430
- accountNumberCredit: payment.creditor.number,
1600
+ accountNumberCredit: creditor.number,
1431
1601
  idAccountDebit: this.resolveIdAccountDebit(payment),
1432
- bankCodeCredit: payment.creditor.bankCode,
1602
+ bankCodeCredit: creditor.bankCode,
1433
1603
  amount: payment.amount,
1434
1604
  currencyCode: "CZK",
1435
1605
  channelCode: "WWW",
@@ -1461,11 +1631,13 @@ class DbuConnector extends IBankConnector {
1461
1631
  if (payment.instructionPriority === "INST") {
1462
1632
  return this.initiateInstantPayment(payment);
1463
1633
  }
1634
+ const debtor = this.resolveAccountDetails(payment.debtor);
1635
+ const creditor = this.resolveAccountDetails(payment.creditor);
1464
1636
  const body = {
1465
- accountNumberDebit: payment.debtor.number,
1466
- accountNumberCredit: payment.creditor.number,
1467
- bankCodeDebit: payment.debtor.bankCode,
1468
- bankCodeCredit: payment.creditor.bankCode,
1637
+ accountNumberDebit: debtor.number,
1638
+ accountNumberCredit: creditor.number,
1639
+ bankCodeDebit: debtor.bankCode,
1640
+ bankCodeCredit: creditor.bankCode,
1469
1641
  amount: payment.amount,
1470
1642
  currencyCode: "CZK",
1471
1643
  actionTypeCode: "TRANSFER",
@@ -1482,20 +1654,14 @@ class DbuConnector extends IBankConnector {
1482
1654
  constSymbol: payment.ks,
1483
1655
  uniqueExternalId: payment.id,
1484
1656
  with4EyeApproval: "Y",
1485
- debtorAddress: {
1486
- streetName: null,
1487
- buildingNumber: null,
1488
- city: null,
1489
- zip: null,
1490
- countryCode: payment.debtor.countryCode || "CZ"
1491
- },
1492
- creditorAddress: {
1493
- streetName: null,
1494
- buildingNumber: null,
1495
- city: null,
1496
- zip: null,
1497
- countryCode: payment.creditor.countryCode || "CZ"
1498
- }
1657
+ debtorAddress: parseFlatAddress(
1658
+ payment.debtor.address,
1659
+ payment.debtor.countryCode || "CZ"
1660
+ ),
1661
+ creditorAddress: parseFlatAddress(
1662
+ payment.creditor.address,
1663
+ payment.creditor.countryCode || "CZ"
1664
+ )
1499
1665
  };
1500
1666
  const response = await this.makeRequest(
1501
1667
  "/required-transactions",
@@ -1549,7 +1715,7 @@ class DbuConnector extends IBankConnector {
1549
1715
  const limit = 10;
1550
1716
  let hasMoreData = true;
1551
1717
  let pageNumber = 1;
1552
- const baseRequestId = backendSdk.uuidv4();
1718
+ const baseRequestId = backendSdk.uuidv4().replace(/-/g, "");
1553
1719
  while (hasMoreData) {
1554
1720
  const response = await this.makeRequest(
1555
1721
  "/required-transactions",
@@ -1575,7 +1741,7 @@ class DbuConnector extends IBankConnector {
1575
1741
  }
1576
1742
  for (const transaction of response.transactions.transaction) {
1577
1743
  const status = transaction.status.trim();
1578
- if (status === "0" || status === "50") continue;
1744
+ if (status === "0" || status === "50" || status === "51") continue;
1579
1745
  try {
1580
1746
  const payment = this.mapDbuTransactionToPayment(
1581
1747
  transaction,
@@ -1623,6 +1789,7 @@ class ErsteConnector extends IBankConnector {
1623
1789
  constructor(config) {
1624
1790
  super();
1625
1791
  this.connectorKey = "ERSTE";
1792
+ this.lifecycleMode = "batch";
1626
1793
  this.accessToken = null;
1627
1794
  this.API_KEY = config.API_KEY;
1628
1795
  this.CLIENT_ID = config.CLIENT_ID;
@@ -1728,7 +1895,7 @@ class ErsteConnector extends IBankConnector {
1728
1895
  }
1729
1896
  const paymentBody = {
1730
1897
  paymentIdentification: {
1731
- endToEndIdentification: payment.id,
1898
+ endToEndIdentification: buildEndToEndId(payment),
1732
1899
  instructionIdentification: payment.id
1733
1900
  },
1734
1901
  paymentTypeInformation: { instructionPriority: "NORM" },
@@ -1954,6 +2121,7 @@ class MockConnector extends IBankConnector {
1954
2121
  constructor() {
1955
2122
  super();
1956
2123
  this.connectorKey = "MOCK";
2124
+ this.lifecycleMode = "batch";
1957
2125
  this.connectedAccounts = [];
1958
2126
  }
1959
2127
  supportsBatch(_paymentType) {
@@ -2040,7 +2208,6 @@ exports.KBConnector = KBConnector;
2040
2208
  exports.MockCobsConnector = MockCobsConnector;
2041
2209
  exports.MockConnector = MockConnector;
2042
2210
  exports.assignAccount = assignAccount;
2043
- exports.batchTransform = batchTransform;
2044
2211
  exports.initiateConnector = initiateConnector;
2045
2212
  exports.mapFinbricksTransactionStatus = mapFinbricksTransactionStatus;
2046
2213
  exports.signFinbricksJws = signFinbricksJws;
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- const paymentRequest_schema = require('./bank.SQ4Mmr8u.cjs');
3
+ const paymentRequest_schema = require('./bank.JVlyPAAb.cjs');
4
4
 
5
5
  const schema = {
6
6
  __proto__: null,
@@ -1,4 +1,4 @@
1
- import { X as CurrencyCode, H as BankCode, U as CountryCode } from './bank.BliD3oCT.mjs';
1
+ import { d as CurrencyCode, J as BankCode, V as CountryCode } from './bank.B-NJB8GB.js';
2
2
  import { z } from 'zod';
3
3
 
4
4
  type ReferenceType = `${'VS' | 'SS' | 'KS'}:${number}`;
@@ -210,6 +210,18 @@ type FinbricksAccountTransactionsResponse = {
210
210
  transactions: FinbricksTransaction[];
211
211
  };
212
212
 
213
+ /**
214
+ * @deprecated Use IncomingPayment from './payment-lifecycle' instead
215
+ * This type is kept for backward compatibility during migration
216
+ */
217
+
218
+ /**
219
+ * Message pushed to PAYMENTS_READY_TO_BATCH_QUEUE after payment_request is created in DB
220
+ */
221
+ type PaymentQueueMessage = {
222
+ paymentId: string;
223
+ };
224
+
213
225
  declare const sendPaymentInputSchema: z.ZodObject<{
214
226
  correlationId: z.ZodString;
215
227
  refId: z.ZodOptional<z.ZodString>;
@@ -225,7 +237,6 @@ declare const sendPaymentInputSchema: z.ZodObject<{
225
237
  OUR: "OUR";
226
238
  BEN: "BEN";
227
239
  }>>;
228
- executionDate: z.ZodOptional<z.ZodString>;
229
240
  instructionPriority: z.ZodOptional<z.ZodEnum<{
230
241
  NORM: "NORM";
231
242
  HIGH: "HIGH";
@@ -980,12 +991,13 @@ declare const sendPaymentInputSchema: z.ZodObject<{
980
991
  bsb: z.ZodOptional<z.ZodString>;
981
992
  brBankNumber: z.ZodOptional<z.ZodString>;
982
993
  }, z.core.$strip>;
983
- purpose: z.ZodOptional<z.ZodString>;
984
994
  sendAsSinglePayment: z.ZodOptional<z.ZodBoolean>;
985
995
  }, z.core.$strip>;
986
996
  interface SendPaymentInput extends z.infer<typeof sendPaymentInputSchema> {
987
997
  }
988
- type SendPaymentOutput = void;
998
+ type SendPaymentOutput = {
999
+ paymentId: string;
1000
+ };
989
1001
 
990
1002
  declare const sendPaymentSyncInputSchema: z.ZodObject<{
991
1003
  correlationId: z.ZodString;
@@ -1002,7 +1014,6 @@ declare const sendPaymentSyncInputSchema: z.ZodObject<{
1002
1014
  OUR: "OUR";
1003
1015
  BEN: "BEN";
1004
1016
  }>>;
1005
- executionDate: z.ZodOptional<z.ZodString>;
1006
1017
  instructionPriority: z.ZodOptional<z.ZodEnum<{
1007
1018
  NORM: "NORM";
1008
1019
  HIGH: "HIGH";
@@ -1757,7 +1768,6 @@ declare const sendPaymentSyncInputSchema: z.ZodObject<{
1757
1768
  bsb: z.ZodOptional<z.ZodString>;
1758
1769
  brBankNumber: z.ZodOptional<z.ZodString>;
1759
1770
  }, z.core.$strip>;
1760
- purpose: z.ZodOptional<z.ZodString>;
1761
1771
  sendAsSinglePayment: z.ZodOptional<z.ZodBoolean>;
1762
1772
  }, z.core.$strip>;
1763
1773
  interface SendPaymentSyncInput extends z.infer<typeof sendPaymentSyncInputSchema> {
@@ -1767,4 +1777,4 @@ type SendPaymentSyncOutput = {
1767
1777
  authorizationUrl: string;
1768
1778
  };
1769
1779
 
1770
- export type { FinbricksSupportedBanksResponse as F, ReferenceType as R, SendPaymentInput as S, SendPaymentOutput as a, SendPaymentSyncInput as b, SendPaymentSyncOutput as c, FinbricksAccount as d, FinbricksAccountTransactionsResponse as e, FinbricksAccountsListResponse as f, FinbricksAuthTokenResponse as g, FinbricksBatchResponse as h, FinbricksConnectAccountResponse as i, FinbricksPaymentResponse as j, FinbricksSupportedBank as k };
1780
+ export type { FinbricksSupportedBanksResponse as F, PaymentQueueMessage as P, ReferenceType as R, SendPaymentInput as S, SendPaymentOutput as a, SendPaymentSyncInput as b, SendPaymentSyncOutput as c, FinbricksAccount as d, FinbricksAccountTransactionsResponse as e, FinbricksAccountsListResponse as f, FinbricksAuthTokenResponse as g, FinbricksBatchResponse as h, FinbricksConnectAccountResponse as i, FinbricksPaymentResponse as j, FinbricksSupportedBank as k };
@@ -1,13 +1,13 @@
1
1
  'use strict';
2
2
 
3
- const backendSdk = require('@develit-io/backend-sdk');
4
3
  const drizzleOrm = require('drizzle-orm');
5
- require('./bank.SQ4Mmr8u.cjs');
4
+ const backendSdk = require('@develit-io/backend-sdk');
5
+ require('./bank.JVlyPAAb.cjs');
6
6
  require('date-fns');
7
7
  require('jose');
8
8
  require('@develit-io/general-codes');
9
9
  const node_crypto = require('node:crypto');
10
- const database_schema = require('./bank.C-T1FQxg.cjs');
10
+ const database_schema = require('./bank.DJnDSYqE.cjs');
11
11
 
12
12
  const createPaymentCommand = (db, { payment }) => {
13
13
  return {
@@ -15,6 +15,19 @@ const createPaymentCommand = (db, { payment }) => {
15
15
  ...payment,
16
16
  creditorIban: payment.creditor.iban,
17
17
  debtorIban: payment.debtor.iban
18
+ }).onConflictDoUpdate({
19
+ // Unique index: (connector_key, bank_ref_id)
20
+ target: [tables.payment.connectorKey, tables.payment.bankRefId],
21
+ set: {
22
+ status: drizzleOrm.sql`excluded.status`,
23
+ statusReason: drizzleOrm.sql`excluded.status_reason`,
24
+ processedAt: drizzleOrm.sql`excluded.processed_at`,
25
+ updatedAt: drizzleOrm.sql`excluded.updated_at`,
26
+ // Keep existing refId if already set, otherwise use enriched value
27
+ refId: drizzleOrm.sql`coalesce(payment.ref_id, excluded.ref_id)`,
28
+ // Keep existing batchId if already set, otherwise use enriched value
29
+ batchId: drizzleOrm.sql`coalesce(payment.bank_execution_batch_id, excluded.bank_execution_batch_id)`
30
+ }
18
31
  }).returning()
19
32
  };
20
33
  };
@@ -39,7 +52,12 @@ const upsertBatchCommand = (db, { batch }) => {
39
52
  const updatePaymentRequestStatusCommand = (db, values) => {
40
53
  const { id, ...set } = values;
41
54
  return {
42
- command: db.update(tables.paymentRequest).set(set).where(drizzleOrm.eq(tables.paymentRequest.id, id)).returning()
55
+ command: db.update(tables.paymentRequest).set(set).where(
56
+ drizzleOrm.and(
57
+ drizzleOrm.eq(tables.paymentRequest.id, id),
58
+ drizzleOrm.isNull(tables.paymentRequest.deletedAt)
59
+ )
60
+ ).returning()
43
61
  };
44
62
  };
45
63
 
@@ -60,7 +78,12 @@ const getCredentialsByAccountId = async (db, encryptionKey, { accountId }) => {
60
78
  };
61
79
 
62
80
  const getPaymentRequestsByBatchIdQuery = async (db, { batchId }) => {
63
- return await db.select().from(tables.paymentRequest).where(drizzleOrm.eq(tables.paymentRequest.batchId, batchId));
81
+ return await db.select().from(tables.paymentRequest).where(
82
+ drizzleOrm.and(
83
+ drizzleOrm.eq(tables.paymentRequest.batchId, batchId),
84
+ drizzleOrm.isNull(tables.paymentRequest.deletedAt)
85
+ )
86
+ );
64
87
  };
65
88
 
66
89
  async function importAesKey(base64Key) {
@@ -28,7 +28,8 @@ const BATCH_STATUSES = [
28
28
  "READY_TO_SIGN",
29
29
  "SIGNED",
30
30
  "SIGNATURE_FAILED",
31
- "FAILED"
31
+ "FAILED",
32
+ "COMPLETED"
32
33
  ];
33
34
  const ACCOUNT_STATUSES = ["AUTHORIZED", "DISABLED", "EXPIRED"];
34
35
  const COUNTRY_CODES = generalCodes.COUNTRY_CODES_2;
@@ -174,7 +175,17 @@ const payment = sqliteCore.sqliteTable(
174
175
  debtor: sqliteCore.text("debtor", { mode: "json" }).$type().notNull(),
175
176
  debtorIban: sqliteCore.text("debtor_iban")
176
177
  },
177
- (t) => [sqliteCore.unique().on(t.connectorKey, t.bankRefId)]
178
+ (t) => [
179
+ sqliteCore.unique().on(t.connectorKey, t.bankRefId),
180
+ sqliteCore.index("payment_account_id_idx").on(t.accountId),
181
+ sqliteCore.index("payment_account_id_status_idx").on(t.accountId, t.status),
182
+ sqliteCore.index("payment_account_id_created_at_idx").on(t.accountId, t.createdAt),
183
+ sqliteCore.index("payment_created_at_idx").on(t.createdAt),
184
+ sqliteCore.index("payment_direction_idx").on(t.direction),
185
+ sqliteCore.index("payment_batch_id_idx").on(t.batchId),
186
+ sqliteCore.index("payment_creditor_iban_idx").on(t.creditorIban),
187
+ sqliteCore.index("payment_debtor_iban_idx").on(t.debtorIban)
188
+ ]
178
189
  );
179
190
  const paymentRelations = relations.relations(payment, ({ one }) => ({
180
191
  batch: one(batch, { fields: [payment.batchId], references: [batch.id] })
@@ -217,9 +228,26 @@ const paymentRequest = sqliteCore.sqliteTable(
217
228
  creditor: sqliteCore.text("creditor", { mode: "json" }).$type().notNull(),
218
229
  creditorIban: sqliteCore.text("creditor_iban"),
219
230
  debtor: sqliteCore.text("debtor", { mode: "json" }).$type().notNull(),
220
- debtorIban: sqliteCore.text("debtor_iban")
231
+ debtorIban: sqliteCore.text("debtor_iban"),
232
+ sendAsSinglePayment: sqliteCore.integer("send_as_single_payment", {
233
+ mode: "boolean"
234
+ })
221
235
  },
222
- (t) => [sqliteCore.index("payment_request_batch_id_idx").on(t.batchId)]
236
+ (t) => [
237
+ sqliteCore.index("payment_request_batch_id_idx").on(t.batchId),
238
+ sqliteCore.index("payment_request_account_id_idx").on(t.accountId),
239
+ sqliteCore.index("payment_request_creditor_iban_idx").on(t.creditorIban),
240
+ sqliteCore.index("payment_request_debtor_iban_idx").on(t.debtorIban),
241
+ sqliteCore.index("payment_request_status_idx").on(t.status),
242
+ sqliteCore.index("payment_request_created_at_idx").on(t.createdAt),
243
+ sqliteCore.index("payment_request_account_status_idx").on(t.accountId, t.status),
244
+ sqliteCore.index("payment_request_status_created_at_idx").on(t.status, t.createdAt),
245
+ sqliteCore.index("payment_request_account_status_created_at_idx").on(
246
+ t.accountId,
247
+ t.status,
248
+ t.createdAt
249
+ )
250
+ ]
223
251
  );
224
252
  const paymentRequestRelations = relations.relations(paymentRequest, ({ one }) => ({
225
253
  batch: one(batch, {