@develit-services/bank 0.3.60 → 0.4.0

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 (45) hide show
  1. package/dist/database/schema.cjs +9 -9
  2. package/dist/database/schema.d.cts +4 -5
  3. package/dist/database/schema.d.mts +4 -5
  4. package/dist/database/schema.d.ts +4 -5
  5. package/dist/database/schema.mjs +3 -3
  6. package/dist/export/worker.cjs +91 -85
  7. package/dist/export/worker.d.cts +23 -766
  8. package/dist/export/worker.d.mts +23 -766
  9. package/dist/export/worker.d.ts +23 -766
  10. package/dist/export/worker.mjs +72 -66
  11. package/dist/export/workflows.cjs +215 -211
  12. package/dist/export/workflows.d.cts +4 -4
  13. package/dist/export/workflows.d.mts +4 -4
  14. package/dist/export/workflows.d.ts +4 -4
  15. package/dist/export/workflows.mjs +210 -206
  16. package/dist/export/wrangler.d.cts +3 -1
  17. package/dist/export/wrangler.d.mts +3 -1
  18. package/dist/export/wrangler.d.ts +3 -1
  19. package/dist/shared/bank.B51e8oDT.mjs +104 -0
  20. package/dist/shared/{bank.Dh_H_5rC.d.cts → bank.BJvgLwyZ.d.cts} +2 -0
  21. package/dist/shared/{bank.Dh_H_5rC.d.mts → bank.BJvgLwyZ.d.mts} +2 -0
  22. package/dist/shared/{bank.Dh_H_5rC.d.ts → bank.BJvgLwyZ.d.ts} +2 -0
  23. package/dist/shared/bank.BUSlmr6r.mjs +13 -0
  24. package/dist/shared/{bank.CMbfx0u7.cjs → bank.BeIpkWR-.cjs} +3 -14
  25. package/dist/shared/bank.Bg3Pdwm4.cjs +44 -0
  26. package/dist/shared/bank.CDoYUKBx.d.cts +748 -0
  27. package/dist/shared/bank.CDoYUKBx.d.mts +748 -0
  28. package/dist/shared/bank.CDoYUKBx.d.ts +748 -0
  29. package/dist/shared/{bank.CNEv3Rac.cjs → bank.CfSZTfWS.cjs} +634 -179
  30. package/dist/shared/{bank.XJJV8p4b.d.cts → bank.CsJuzqZH.d.cts} +2401 -2117
  31. package/dist/shared/{bank.XJJV8p4b.d.mts → bank.CsJuzqZH.d.mts} +2401 -2117
  32. package/dist/shared/{bank.XJJV8p4b.d.ts → bank.CsJuzqZH.d.ts} +2401 -2117
  33. package/dist/shared/bank.DEvSNsEs.cjs +114 -0
  34. package/dist/shared/{bank.DgGcjhmM.mjs → bank.DinCwx0P.mjs} +627 -179
  35. package/dist/shared/bank.Dpx6PvkA.mjs +33 -0
  36. package/dist/shared/bank.c38V_FCq.cjs +15 -0
  37. package/dist/shared/{bank.BqGzJNC6.mjs → bank.qc8ALZwm.mjs} +4 -14
  38. package/dist/types.cjs +51 -33
  39. package/dist/types.d.cts +164 -39
  40. package/dist/types.d.mts +164 -39
  41. package/dist/types.d.ts +164 -39
  42. package/dist/types.mjs +4 -3
  43. package/package.json +7 -10
  44. package/dist/shared/bank.CXpc8168.cjs +0 -212
  45. package/dist/shared/bank.DSsVeR3F.mjs +0 -202
@@ -2,37 +2,70 @@
2
2
 
3
3
  const backendSdk = require('@develit-io/backend-sdk');
4
4
  const dateFns = require('date-fns');
5
- const database_schema = require('./bank.CMbfx0u7.cjs');
6
- const drizzleOrm = require('drizzle-orm');
5
+ const generalCodes = require('@develit-io/general-codes');
6
+ require('./bank.BeIpkWR-.cjs');
7
+ require('drizzle-orm');
7
8
  const jose = require('jose');
8
- require('@develit-io/general-codes');
9
9
  require('node:crypto');
10
10
 
11
11
  class IBankConnector {
12
12
  }
13
13
 
14
- const mapReferencesToPayment = (reference) => {
15
- const symbols = {
16
- vs: void 0,
17
- ss: void 0,
18
- ks: void 0
14
+ function toIncomingPayment(input) {
15
+ return {
16
+ id: backendSdk.uuidv4(),
17
+ correlationId: input.correlationId,
18
+ refId: input.refId,
19
+ amount: input.amount,
20
+ direction: "OUTGOING",
21
+ paymentType: input.paymentType,
22
+ currency: input.currency,
23
+ status: "CREATED",
24
+ statusReason: null,
25
+ batchId: null,
26
+ initiatedAt: null,
27
+ // Will be set in preparePayment when sent to bank
28
+ processedAt: null,
29
+ vs: input.vs || null,
30
+ ss: input.ss || null,
31
+ ks: input.ks || null,
32
+ message: input.message || null,
33
+ creditor: input.creditor,
34
+ creditorIban: input.creditor.iban || null,
35
+ debtor: input.debtor,
36
+ debtorIban: input.debtor.iban || null,
37
+ sendAsSinglePayment: input.sendAsSinglePayment
19
38
  };
20
- if (!reference) return symbols;
21
- if (Array.isArray(reference) && reference.length > 0) {
22
- symbols.vs = reference.find((ref) => ref.includes("VS")) || void 0;
23
- symbols.ss = reference.find((ref) => ref.includes("SS")) || void 0;
24
- symbols.ks = reference.find((ref) => ref.includes("KS")) || void 0;
25
- }
26
- if (typeof reference === "string") {
27
- const vsMatch = reference.match(/VS[:\s]*(\d+)/i);
28
- const ssMatch = reference.match(/SS[:\s]*(\d+)/i);
29
- const ksMatch = reference.match(/KS[:\s]*(\d+)/i);
30
- if (vsMatch) symbols.vs = vsMatch[1];
31
- if (ssMatch) symbols.ss = ssMatch[1];
32
- if (ksMatch) symbols.ks = ksMatch[1];
33
- }
34
- return symbols;
35
- };
39
+ }
40
+ function assignAccount(payment, account) {
41
+ return {
42
+ ...payment,
43
+ accountId: account.id,
44
+ connectorKey: account.connectorKey
45
+ };
46
+ }
47
+ function toBatchedPayment(payment) {
48
+ return payment;
49
+ }
50
+ function toPreparedPayment(payment, bankRefId, initiatedAt) {
51
+ return {
52
+ ...payment,
53
+ status: "PREPARED",
54
+ bankRefId,
55
+ initiatedAt: initiatedAt ?? /* @__PURE__ */ new Date()
56
+ };
57
+ }
58
+ function toCompletedPayment(payment, status, bankRefId, processedAt) {
59
+ return {
60
+ ...payment,
61
+ bankRefId,
62
+ status,
63
+ processedAt: processedAt ?? /* @__PURE__ */ new Date()
64
+ };
65
+ }
66
+ function batchTransform(payments, transformer) {
67
+ return payments.map(transformer);
68
+ }
36
69
 
37
70
  async function signFinbricksJws({
38
71
  privateKeyPem,
@@ -195,6 +228,29 @@ const mapFinbricksAccountInsert = ({
195
228
  iban: account.identification.iban
196
229
  });
197
230
 
231
+ const mapReferencesToPayment = (reference) => {
232
+ const symbols = {
233
+ vs: void 0,
234
+ ss: void 0,
235
+ ks: void 0
236
+ };
237
+ if (!reference) return symbols;
238
+ if (Array.isArray(reference) && reference.length > 0) {
239
+ symbols.vs = reference.find((ref) => ref.includes("VS")) || void 0;
240
+ symbols.ss = reference.find((ref) => ref.includes("SS")) || void 0;
241
+ symbols.ks = reference.find((ref) => ref.includes("KS")) || void 0;
242
+ }
243
+ if (typeof reference === "string") {
244
+ const vsMatch = reference.match(/VS[:\s]*(\d+)/i);
245
+ const ssMatch = reference.match(/SS[:\s]*(\d+)/i);
246
+ const ksMatch = reference.match(/KS[:\s]*(\d+)/i);
247
+ if (vsMatch) symbols.vs = vsMatch[1];
248
+ if (ssMatch) symbols.ss = ssMatch[1];
249
+ if (ksMatch) symbols.ks = ksMatch[1];
250
+ }
251
+ return symbols;
252
+ };
253
+
198
254
  const mapFinbricksTransactionToPayment = (tx, account) => {
199
255
  const isIncoming = tx.creditDebitIndicator === "CRDT";
200
256
  const related = tx.entryDetails?.transactionDetails?.relatedParties;
@@ -332,9 +388,6 @@ class FinbricksConnector extends IBankConnector {
332
388
  )
333
389
  };
334
390
  }
335
- async authenticate(code) {
336
- return "";
337
- }
338
391
  async revokeAuthentication(clientId) {
339
392
  const [_, error] = await backendSdk.useResult(
340
393
  this.finbricks.request({
@@ -401,45 +454,7 @@ class FinbricksConnector extends IBankConnector {
401
454
  }
402
455
  return response.accounts;
403
456
  }
404
- async listAccounts() {
405
- const accounts = (await Promise.all(
406
- this.connectedAccounts.map(
407
- (acc) => this.getAccountsForClient({ clientId: acc.token })
408
- )
409
- )).flat();
410
- const uniqueAccounts = Array.from(
411
- new Map(accounts.map((acc) => [acc.identification.iban, acc])).values()
412
- );
413
- return uniqueAccounts.map((acc) => ({
414
- connectorKey: this.connectorKey,
415
- bankRefId: acc.id,
416
- currency: acc.currency,
417
- sync: false,
418
- status: "AUTHORIZED",
419
- countryCode: acc.servicer.countryCode,
420
- bankCode: acc.servicer.bankCode,
421
- number: acc.identification.accountNumber.split("/")[0],
422
- name: acc.productName,
423
- iban: acc.identification.iban,
424
- holderName: acc.ownersNames.join(", ")
425
- }));
426
- }
427
- async preparePayment(payment) {
428
- return {
429
- ...payment,
430
- bankRefId: backendSdk.uuidv4(),
431
- // merchantTransactionId
432
- direction: "OUTGOING",
433
- paymentType: payment.paymentType,
434
- status: "PREPARED",
435
- initiatedAt: /* @__PURE__ */ new Date(),
436
- accountId: this.connectedAccounts.find(
437
- (acc) => acc.iban === payment.debtorIban
438
- ).id,
439
- connectorKey: this.PROVIDER
440
- };
441
- }
442
- async initiateBatchFromPayments({
457
+ async initiateBatch({
443
458
  batchId,
444
459
  payments
445
460
  }) {
@@ -463,7 +478,7 @@ class FinbricksConnector extends IBankConnector {
463
478
  merchantBatchId: batchId
464
479
  },
465
480
  payments: payments.map((p) => ({
466
- merchantTransactionId: p.bankRefId,
481
+ merchantTransactionId: p.id,
467
482
  creditorAccountIban: p.creditor.iban,
468
483
  amount: p.amount,
469
484
  variableSymbol: p.vs,
@@ -479,10 +494,13 @@ class FinbricksConnector extends IBankConnector {
479
494
  console.error("FINBRICKS BATCH ERROR", error);
480
495
  throw backendSdk.createInternalError(error);
481
496
  }
497
+ const initiatedAt = /* @__PURE__ */ new Date();
482
498
  return {
483
499
  id: batchId,
484
500
  authorizationUrls: [response.redirectUrl],
485
- payments: payments.map((p) => ({ ...p, status: "INITIALIZED" }))
501
+ payments: payments.map(
502
+ (p) => toPreparedPayment(p, void 0, initiatedAt)
503
+ )
486
504
  };
487
505
  }
488
506
  async initiateForeignPayment(payment) {
@@ -538,7 +556,8 @@ class FinbricksConnector extends IBankConnector {
538
556
  payment: {
539
557
  ...payment,
540
558
  bankRefId,
541
- status: "INITIALIZED",
559
+ status: "PREPARED",
560
+ initiatedAt: /* @__PURE__ */ new Date(),
542
561
  accountId: this.connectedAccounts.find(
543
562
  (acc) => acc.iban === payment.debtorIban
544
563
  ).id,
@@ -588,7 +607,8 @@ class FinbricksConnector extends IBankConnector {
588
607
  payment: {
589
608
  ...payment,
590
609
  bankRefId,
591
- status: "INITIALIZED",
610
+ status: "PREPARED",
611
+ initiatedAt: /* @__PURE__ */ new Date(),
592
612
  accountId: this.connectedAccounts.find(
593
613
  (acc) => acc.iban === payment.debtorIban
594
614
  ).id,
@@ -603,7 +623,7 @@ class FinbricksConnector extends IBankConnector {
603
623
  method: "POST",
604
624
  body: {
605
625
  merchantId: this.finbricks.MERCHANT_ID,
606
- merchantTransactionId: payment.bankRefId,
626
+ merchantTransactionId: payment.id,
607
627
  totalPrice: payment.amount,
608
628
  debtorAccountIban: payment.debtor.iban,
609
629
  creditorAccountIban: payment.creditor.iban,
@@ -624,7 +644,11 @@ class FinbricksConnector extends IBankConnector {
624
644
  }
625
645
  return {
626
646
  authorizationUrl: response.redirectUrl,
627
- payment: { ...payment, status: "INITIALIZED" }
647
+ payment: {
648
+ ...payment,
649
+ status: "PREPARED",
650
+ initiatedAt: /* @__PURE__ */ new Date()
651
+ }
628
652
  };
629
653
  }
630
654
  async getAllAccountPayments({
@@ -726,6 +750,36 @@ class FinbricksConnector extends IBankConnector {
726
750
  }
727
751
  }
728
752
 
753
+ class CreditasConnector extends FinbricksConnector {
754
+ constructor(config) {
755
+ super("CREDITAS", config);
756
+ }
757
+ }
758
+
759
+ class FioConnector extends FinbricksConnector {
760
+ constructor(config) {
761
+ super("FIO", config);
762
+ }
763
+ }
764
+
765
+ class AirBankConnector extends FinbricksConnector {
766
+ constructor(config) {
767
+ super("AIRBANK", config);
768
+ }
769
+ }
770
+
771
+ class CSASConnector extends FinbricksConnector {
772
+ constructor(config) {
773
+ super("CSAS", config);
774
+ }
775
+ }
776
+
777
+ class MonetaConnector extends FinbricksConnector {
778
+ constructor(config) {
779
+ super("MONETA", config);
780
+ }
781
+ }
782
+
729
783
  const isDeposit = (payment, creditorIban) => {
730
784
  return payment.creditor.iban === creditorIban;
731
785
  };
@@ -734,6 +788,414 @@ const getPaymentDirection = (payment, iban) => {
734
788
  return "OUTGOING";
735
789
  };
736
790
 
791
+ const initiateConnector = ({
792
+ bank,
793
+ env,
794
+ connectedAccounts
795
+ }) => {
796
+ switch (bank) {
797
+ case "ERSTE":
798
+ return new ErsteConnector({
799
+ API_KEY: env.ERSTE_API_KEY,
800
+ CLIENT_ID: env.ERSTE_CLIENT_ID,
801
+ CLIENT_SECRET: env.ERSTE_CLIENT_SECRET,
802
+ REDIRECT_URI: env.REDIRECT_URI,
803
+ AUTH_URI: env.ERSTE_AUTH_URI,
804
+ PAYMENTS_URI: env.ERSTE_PAYMENTS_URI,
805
+ ACCOUNTS_URI: env.ERSTE_ACCOUNTS_URI,
806
+ connectedAccounts
807
+ });
808
+ case "CREDITAS":
809
+ return new CreditasConnector({
810
+ BASE_URI: env.FINBRICKS_BASE_URI,
811
+ MERCHANT_ID: env.FINBRICKS_MERCHANT_ID,
812
+ PRIVATE_KEY_PEM: env.FINBRICKS_PRIVATE_KEY_PEM,
813
+ REDIRECT_URI: env.REDIRECT_URI,
814
+ connectedAccounts
815
+ });
816
+ case "MOCK_COBS":
817
+ return new MockCobsConnector({
818
+ BASE_URI: env.FINBRICKS_BASE_URI,
819
+ MERCHANT_ID: env.FINBRICKS_MERCHANT_ID,
820
+ PRIVATE_KEY_PEM: env.FINBRICKS_PRIVATE_KEY_PEM,
821
+ REDIRECT_URI: env.REDIRECT_URI,
822
+ connectedAccounts
823
+ });
824
+ case "FIO":
825
+ return new FioConnector({
826
+ BASE_URI: env.FINBRICKS_BASE_URI,
827
+ MERCHANT_ID: env.FINBRICKS_MERCHANT_ID,
828
+ PRIVATE_KEY_PEM: env.FINBRICKS_PRIVATE_KEY_PEM,
829
+ REDIRECT_URI: env.REDIRECT_URI,
830
+ connectedAccounts
831
+ });
832
+ case "MONETA":
833
+ return new MonetaConnector({
834
+ BASE_URI: env.FINBRICKS_BASE_URI,
835
+ MERCHANT_ID: env.FINBRICKS_MERCHANT_ID,
836
+ PRIVATE_KEY_PEM: env.FINBRICKS_PRIVATE_KEY_PEM,
837
+ REDIRECT_URI: env.REDIRECT_URI,
838
+ connectedAccounts
839
+ });
840
+ case "AIRBANK":
841
+ return new AirBankConnector({
842
+ BASE_URI: env.FINBRICKS_BASE_URI,
843
+ MERCHANT_ID: env.FINBRICKS_MERCHANT_ID,
844
+ PRIVATE_KEY_PEM: env.FINBRICKS_PRIVATE_KEY_PEM,
845
+ REDIRECT_URI: env.REDIRECT_URI,
846
+ connectedAccounts
847
+ });
848
+ case "CSAS":
849
+ return new CSASConnector({
850
+ BASE_URI: env.FINBRICKS_BASE_URI,
851
+ MERCHANT_ID: env.FINBRICKS_MERCHANT_ID,
852
+ PRIVATE_KEY_PEM: env.FINBRICKS_PRIVATE_KEY_PEM,
853
+ REDIRECT_URI: env.REDIRECT_URI,
854
+ connectedAccounts
855
+ });
856
+ case "DBU":
857
+ return new DbuConnector({
858
+ BASE_URL: env.DBUCS_BASE_URI,
859
+ USERNAME: env.DBUCS_USERNAME,
860
+ KV: env.BANK_KV
861
+ });
862
+ default:
863
+ const mockConnector = new MockConnector();
864
+ mockConnector.connectedAccounts = connectedAccounts;
865
+ return mockConnector;
866
+ }
867
+ };
868
+ function mod97(string) {
869
+ let checksum = string.slice(0, 2);
870
+ let fragment = "";
871
+ for (let offset = 2; offset < string.length; offset += 7) {
872
+ fragment = checksum + string.substring(offset, offset + 7);
873
+ checksum = (parseInt(fragment, 10) % 97).toString();
874
+ }
875
+ return parseInt(checksum, 10);
876
+ }
877
+ const calculateCzechIban = (accountNumber, bankCode) => {
878
+ const paddedBankCode = bankCode.padStart(4, "0");
879
+ let prefix = "";
880
+ let mainAccount = accountNumber;
881
+ if (accountNumber.includes("-")) {
882
+ const parts = accountNumber.split("-");
883
+ prefix = parts[0];
884
+ mainAccount = parts[1];
885
+ }
886
+ const paddedPrefix = prefix.padStart(6, "0");
887
+ const paddedAccount = mainAccount.padStart(10, "0");
888
+ const basicIban = paddedBankCode + paddedPrefix + paddedAccount;
889
+ const rearranged = basicIban + "1215";
890
+ const remainder = mod97(rearranged);
891
+ const checkDigits = (98 - remainder).toString().padStart(2, "0");
892
+ return `CZ${checkDigits}${basicIban}`;
893
+ };
894
+
895
+ class DbuConnector extends IBankConnector {
896
+ constructor({ BASE_URL, USERNAME, KV }) {
897
+ super();
898
+ this.connectorKey = "DBU";
899
+ this.connectedAccounts = [];
900
+ this.baseUrl = BASE_URL;
901
+ this.username = USERNAME;
902
+ this.kv = KV;
903
+ this.sessionId = backendSdk.uuidv4();
904
+ this.allowedPostEndpoints = ["/required-transactions", "/import/data"];
905
+ }
906
+ async makeRequest(endpoint, requestId, options = {}) {
907
+ const { method = "GET", headers = {}, query = {}, body } = options;
908
+ if (method === "POST" && !this.allowedPostEndpoints.includes(endpoint)) {
909
+ throw backendSdk.createInternalError(null, {
910
+ message: `DBU API endpoint ${endpoint} does not support POST method`,
911
+ code: "DBU_INVALID_METHOD"
912
+ });
913
+ }
914
+ const auth = btoa("devizova_burza:Fu7psMt7i59ct43D5Y3s");
915
+ const defaultHeaders = {
916
+ "x-dcs-username": this.username,
917
+ "x-dcs-session-id": `session-${this.sessionId}`,
918
+ "x-dcs-request-id": `request-${requestId}`,
919
+ "Content-Type": "application/json",
920
+ Authorization: `Basic ${auth}`,
921
+ ...headers
922
+ };
923
+ const baseUrl = this.baseUrl.endsWith("/") ? this.baseUrl.slice(0, -1) : this.baseUrl;
924
+ const cleanEndpoint = endpoint.startsWith("/") ? endpoint.slice(1) : endpoint;
925
+ const url = new URL(`${baseUrl}/${cleanEndpoint}`);
926
+ Object.entries(query).forEach(([key, value]) => {
927
+ if (value !== void 0 && value !== null) {
928
+ url.searchParams.append(key, value);
929
+ }
930
+ });
931
+ const fetchOptions = {
932
+ method,
933
+ headers: defaultHeaders
934
+ };
935
+ console.log("DBU Request:", url.toString(), fetchOptions);
936
+ if (body && method !== "GET") {
937
+ fetchOptions.body = JSON.stringify(body);
938
+ }
939
+ const response = await fetch(url.toString(), fetchOptions);
940
+ if (!response.ok) {
941
+ throw backendSdk.createInternalError(
942
+ new Error(`DBU API error: ${response.status}`),
943
+ {
944
+ message: `DBU request failed: ${response.statusText}`
945
+ }
946
+ );
947
+ }
948
+ return response.json();
949
+ }
950
+ mapDbuCurrencyCode(dbuCurrency) {
951
+ const currency = dbuCurrency.toUpperCase();
952
+ if (generalCodes.CURRENCY_CODES.includes(currency))
953
+ return currency;
954
+ throw backendSdk.createInternalError(null, {
955
+ message: `Unknown DBU currency code: ${dbuCurrency}`,
956
+ code: "DBU_UNKNOWN_CURRENCY"
957
+ });
958
+ }
959
+ mapDbuTransactionToPayment(transaction, account) {
960
+ const isIncoming = transaction.accountNumberCredit === account.number;
961
+ const direction = isIncoming ? "INCOMING" : "OUTGOING";
962
+ const creditorIban = calculateCzechIban(
963
+ transaction.accountNumberCredit,
964
+ transaction.bankCodeCredit
965
+ );
966
+ const debtorIban = calculateCzechIban(
967
+ transaction.accountNumberDebit,
968
+ transaction.bankCodeDebit
969
+ );
970
+ const parsed = {
971
+ id: backendSdk.uuidv4(),
972
+ correlationId: backendSdk.uuidv4(),
973
+ connectorKey: "DBU",
974
+ accountId: account.id,
975
+ bankRefId: transaction.idRequiredTransaction.toString(),
976
+ amount: transaction.realizedAmount || transaction.amount,
977
+ direction,
978
+ paymentType: "DOMESTIC",
979
+ //TODO: DBU handles domestic transactions only?
980
+ currency: this.mapDbuCurrencyCode(transaction.currencyCode),
981
+ status: this.mapDbuStatusToPaymentStatus(transaction.status),
982
+ initiatedAt: transaction.validFrom ? new Date(transaction.validFrom) : /* @__PURE__ */ new Date(),
983
+ processedAt: transaction.realizationDate ? new Date(transaction.realizationDate) : null,
984
+ vs: transaction.varSymbol,
985
+ ss: transaction.specSymbol,
986
+ ks: transaction.constSymbol,
987
+ message: transaction.textMessage,
988
+ creditor: {
989
+ number: transaction.accountNumberCredit,
990
+ bankCode: transaction.bankCodeCredit,
991
+ iban: creditorIban
992
+ },
993
+ debtor: {
994
+ number: transaction.accountNumberDebit,
995
+ bankCode: transaction.bankCodeDebit,
996
+ iban: debtorIban
997
+ },
998
+ debtorIban
999
+ };
1000
+ return {
1001
+ raw: transaction,
1002
+ parsed
1003
+ };
1004
+ }
1005
+ mapDbuStatusToPaymentStatus(dbuStatus) {
1006
+ const statusCode = dbuStatus.trim();
1007
+ switch (statusCode) {
1008
+ // COMPLETED - Transaction is fully realized
1009
+ case "3":
1010
+ return "COMPLETED";
1011
+ // PREPARED - Transaction is new and ready for processing
1012
+ case "0":
1013
+ return "PREPARED";
1014
+ // PENDING - Transaction is partially processed or on hold
1015
+ case "1":
1016
+ // RQT_STATUS_READY_FOR_REAL
1017
+ case "2":
1018
+ // RQT_STATUS_PARTIAL_REALIZED
1019
+ case "4":
1020
+ // RQT_STATUS_PARTIAL_HOLDED
1021
+ case "5":
1022
+ // RQT_STATUS_HOLDED
1023
+ case "6":
1024
+ // RQT_STATUS_WAIT_FOR_COT
1025
+ case "11":
1026
+ // RQT_STATUS_UNHOLDED
1027
+ case "30":
1028
+ // RQT_STATUS_RQ_TO_HD
1029
+ case "31":
1030
+ // RQT_STATUS_RQ_TO_HD_SENT
1031
+ case "32":
1032
+ // RQT_STATUS_WAIT_TO_HD_VERIFY
1033
+ case "34":
1034
+ // RQT_STATUS_HD_NEW_COLLECTION
1035
+ case "35":
1036
+ // RQT_STATUS_HD_RQ_COLLECTION
1037
+ case "40":
1038
+ // RQT_STATUS_SIPO_CHARGE
1039
+ case "50":
1040
+ // RQT_STATUS_4E
1041
+ case "51":
1042
+ // RQT_STATUS_4E_EDIT
1043
+ case "60":
1044
+ // RQT_STATUS_READY_TO_CANCELLED
1045
+ case "61":
1046
+ // RQT_STATUS_READY_TO_UNHOLDED
1047
+ case "63":
1048
+ // RQT_STATUS_READY_TO_REVERTED
1049
+ case "64":
1050
+ // RQT_STATUS_CC_CREATED
1051
+ case "65":
1052
+ // RQT_STATUS_CC_WAIT_FOR_RATE
1053
+ case "66":
1054
+ // RQT_STATUS_WAIT_FOR_DEBTOR
1055
+ case "70":
1056
+ // RQT_STATUS_RQ_TO_SEPA
1057
+ case "71":
1058
+ // RQT_STATUS_RQ_TO_SEPA_SENT
1059
+ case "72":
1060
+ // RQT_STATUS_RQ_TO_SEPA_CNC
1061
+ case "73":
1062
+ // RQT_STATUS_RQ_TO_SEPA_CNC_URG
1063
+ case "74":
1064
+ // RQT_STATUS_RQ_TO_SEPA_CNC_CLIENT
1065
+ case "75":
1066
+ // RQT_STATUS_RQ_TO_SEPA_056
1067
+ case "80":
1068
+ return "PENDING";
1069
+ // FAILED - Transaction is cancelled, rejected, reverted, suspended or expired
1070
+ case "10":
1071
+ // RQT_STATUS_CANCELLED
1072
+ case "12":
1073
+ // RQT_STATUS_SUSPENDED
1074
+ case "13":
1075
+ // RQT_STATUS_REVERTED
1076
+ case "14":
1077
+ // RQT_STATUS_EXPIRED
1078
+ case "15":
1079
+ // RQT_STATUS_REJECTED
1080
+ case "33":
1081
+ // RQT_STATUS_HD_CANCELLED
1082
+ case "39":
1083
+ return "FAILED";
1084
+ // Default to PENDING for unknown status codes
1085
+ default:
1086
+ return "PENDING";
1087
+ }
1088
+ }
1089
+ async getAuthUri({ ott }) {
1090
+ throw backendSdk.createInternalError(null, {
1091
+ message: "DBU connector does not require authorization",
1092
+ code: "DBU_NO_AUTH_REQUIRED"
1093
+ });
1094
+ }
1095
+ async authorizeAccount({ urlParams }) {
1096
+ return {
1097
+ credentials: [],
1098
+ accounts: []
1099
+ };
1100
+ }
1101
+ async listAccounts() {
1102
+ return [];
1103
+ }
1104
+ async initiateBatch({
1105
+ batchId,
1106
+ payments
1107
+ }) {
1108
+ throw backendSdk.createInternalError(null, {
1109
+ message: "DBU batch payments not implemented yet",
1110
+ code: "DBU_BATCH_NOT_IMPLEMENTED"
1111
+ });
1112
+ }
1113
+ async initiateSEPAPayment(payment) {
1114
+ throw backendSdk.createInternalError(null, {
1115
+ message: "DBU SEPA payment creation not implemented yet",
1116
+ code: "DBU_SEPA_PAYMENT_NOT_IMPLEMENTED"
1117
+ });
1118
+ }
1119
+ async initiateSinglePayment(payment) {
1120
+ throw backendSdk.createInternalError(null, {
1121
+ message: "DBU single payment creation not implemented yet",
1122
+ code: "DBU_PAYMENT_NOT_IMPLEMENTED"
1123
+ });
1124
+ }
1125
+ async getAllAccountPayments({
1126
+ account,
1127
+ filter
1128
+ }) {
1129
+ try {
1130
+ const dateFrom = dateFns.format(filter.dateFrom, "yyyy-MM-dd");
1131
+ const dateTo = dateFns.format(filter.dateTo || /* @__PURE__ */ new Date(), "yyyy-MM-dd");
1132
+ const allPayments = [];
1133
+ let offset = 0;
1134
+ const limit = 10;
1135
+ let hasMoreData = true;
1136
+ let pageNumber = 1;
1137
+ const baseRequestId = backendSdk.uuidv4();
1138
+ while (hasMoreData) {
1139
+ const response = await this.makeRequest(
1140
+ "/required-transactions",
1141
+ `${baseRequestId}_page${pageNumber}`,
1142
+ {
1143
+ method: "GET",
1144
+ query: {
1145
+ // Date filtering
1146
+ "filter.validFromStart": dateFrom,
1147
+ "filter.validFromEnd": dateTo,
1148
+ // Pagination parameters
1149
+ offset: offset.toString(),
1150
+ limit: limit.toString()
1151
+ }
1152
+ }
1153
+ );
1154
+ if (!response.transactions?.transaction || response.transactions.transaction.length === 0) {
1155
+ hasMoreData = false;
1156
+ break;
1157
+ }
1158
+ for (const transaction of response.transactions.transaction) {
1159
+ try {
1160
+ const payment = this.mapDbuTransactionToPayment(
1161
+ transaction,
1162
+ account
1163
+ );
1164
+ allPayments.push(payment);
1165
+ } catch (error) {
1166
+ console.error("Failed to map DBU transaction:", error, transaction);
1167
+ }
1168
+ }
1169
+ if (response.transactions.transaction.length < limit) {
1170
+ hasMoreData = false;
1171
+ } else {
1172
+ offset += limit;
1173
+ pageNumber += 1;
1174
+ }
1175
+ hasMoreData = false;
1176
+ }
1177
+ return allPayments;
1178
+ } catch (error) {
1179
+ throw backendSdk.createInternalError(error, {
1180
+ message: "Failed to fetch payments from DBU API"
1181
+ });
1182
+ }
1183
+ }
1184
+ async getPaymentStatus({
1185
+ paymentId
1186
+ }) {
1187
+ return "PENDING";
1188
+ }
1189
+ async getBatchStatus({
1190
+ batchId
1191
+ }) {
1192
+ return {
1193
+ status: "OPEN",
1194
+ apiResponse: {}
1195
+ };
1196
+ }
1197
+ }
1198
+
737
1199
  class ErsteConnector extends IBankConnector {
738
1200
  constructor(config) {
739
1201
  super();
@@ -782,40 +1244,49 @@ class ErsteConnector extends IBankConnector {
782
1244
  ]
783
1245
  };
784
1246
  }
785
- async authenticate(tokens) {
786
- const grantType = tokens?.refreshToken ? "refresh_token" : "authorization_code";
787
- let bodyParams = {
788
- client_id: this.CLIENT_ID,
789
- client_secret: this.CLIENT_SECRET,
790
- grant_type: grantType
791
- };
792
- if (tokens?.token) {
793
- bodyParams = {
794
- ...bodyParams,
795
- code: tokens.token,
796
- redirect_uri: this.REDIRECT_URI
797
- };
798
- }
799
- if (tokens?.refreshToken) bodyParams.refresh_token = tokens?.refreshToken;
800
- const body = new URLSearchParams(bodyParams);
801
- const result = await fetch(`${this.AUTH_URI}/token`, {
802
- method: "POST",
803
- body: body.toString(),
804
- headers: { "Content-Type": "application/x-www-form-urlencoded" }
805
- });
806
- if (result.status !== 200) {
807
- throw backendSdk.createInternalError(null, {
808
- message: await result.text()
809
- });
810
- }
811
- const json = await result.json();
812
- this.accessToken = json.access_token;
813
- return json.refresh_token || "";
814
- }
815
- listAccounts() {
816
- throw new Error("Method not implemented.");
817
- }
818
- async preparePayment(payment) {
1247
+ // async authenticate(tokens?: {
1248
+ // refreshToken?: string
1249
+ // token?: string
1250
+ // }): Promise<string> {
1251
+ // const grantType = tokens?.refreshToken
1252
+ // ? 'refresh_token'
1253
+ // : 'authorization_code'
1254
+ // let bodyParams: Record<string, string> = {
1255
+ // client_id: this.CLIENT_ID!,
1256
+ // client_secret: this.CLIENT_SECRET!,
1257
+ // grant_type: grantType,
1258
+ // }
1259
+ // if (tokens?.token) {
1260
+ // bodyParams = {
1261
+ // ...bodyParams,
1262
+ // code: tokens.token,
1263
+ // redirect_uri: this.REDIRECT_URI,
1264
+ // }
1265
+ // }
1266
+ // if (tokens?.refreshToken) bodyParams.refresh_token = tokens?.refreshToken
1267
+ // const body = new URLSearchParams(bodyParams)
1268
+ // const result = await fetch(`${this.AUTH_URI}/token`, {
1269
+ // method: 'POST',
1270
+ // body: body.toString(),
1271
+ // headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
1272
+ // })
1273
+ // if (result.status !== 200) {
1274
+ // throw createInternalError(null, {
1275
+ // message: await result.text(),
1276
+ // })
1277
+ // }
1278
+ // const json = (await result.json()) as {
1279
+ // access_token: string
1280
+ // refresh_token?: string
1281
+ // }
1282
+ // this.accessToken = json.access_token
1283
+ // return json.refresh_token || ''
1284
+ // }
1285
+ /**
1286
+ * Erste-specific: Prepare individual payment
1287
+ * This is an internal method used by initiateBatch
1288
+ */
1289
+ async prepareErstePayment(payment) {
819
1290
  if (!this.accessToken) {
820
1291
  throw backendSdk.createInternalError(null, {
821
1292
  message: "Internal authentication failed",
@@ -865,14 +1336,19 @@ class ErsteConnector extends IBankConnector {
865
1336
  connectorKey: "ERSTE"
866
1337
  };
867
1338
  }
868
- async initiateBatchFromPayments({
1339
+ async initiateBatch({
869
1340
  batchId,
870
1341
  payments
871
1342
  }) {
872
- const allRefIds = payments.map((payment) => payment.bankRefId);
1343
+ const preparedPayments = [];
1344
+ for (const payment of payments) {
1345
+ const prepared = await this.prepareErstePayment(payment);
1346
+ preparedPayments.push(prepared);
1347
+ }
1348
+ const allRefIds = preparedPayments.map((payment) => payment.bankRefId);
873
1349
  if (allRefIds.length === 0) {
874
1350
  throw backendSdk.createInternalError(null, {
875
- message: "No valid payments to include in batch",
1351
+ message: "No payments to include in batch",
876
1352
  status: 400
877
1353
  });
878
1354
  }
@@ -883,7 +1359,10 @@ class ErsteConnector extends IBankConnector {
883
1359
  throw backendSdk.createInternalError(signError);
884
1360
  }
885
1361
  const [authUri, authUriError] = await backendSdk.useResult(
886
- this.getBatchAuthorizationURI(signInfo)
1362
+ this.getBatchAuthorizationURI({
1363
+ signHash: signInfo.signHash,
1364
+ signId: signInfo.signId
1365
+ })
887
1366
  );
888
1367
  if (authUriError) {
889
1368
  throw backendSdk.createInternalError(authUriError);
@@ -891,14 +1370,11 @@ class ErsteConnector extends IBankConnector {
891
1370
  return {
892
1371
  id: batchId,
893
1372
  authorizationUrls: [authUri || ""],
894
- payments: payments.map((payment) => ({
895
- ...payment,
896
- status: "INITIALIZED"
897
- })),
1373
+ payments: preparedPayments,
898
1374
  metadata: signInfo
899
1375
  };
900
1376
  }
901
- initiateSinglePayment() {
1377
+ initiateSinglePayment(payment) {
902
1378
  throw new Error("Method not implemented.");
903
1379
  }
904
1380
  async sendBatchPaymentForAuthorization(paymentIds) {
@@ -1029,21 +1505,18 @@ class ErsteConnector extends IBankConnector {
1029
1505
  }
1030
1506
  }
1031
1507
 
1508
+ class MockCobsConnector extends FinbricksConnector {
1509
+ constructor(config) {
1510
+ super("MOCK_COBS", config);
1511
+ }
1512
+ }
1513
+
1032
1514
  class MockConnector extends IBankConnector {
1033
1515
  constructor() {
1034
1516
  super();
1035
1517
  this.connectorKey = "MOCK";
1036
1518
  this.connectedAccounts = [];
1037
1519
  }
1038
- initiateSEPAPayment(payment) {
1039
- throw new Error("Method not implemented.");
1040
- }
1041
- async authenticate() {
1042
- return "";
1043
- }
1044
- async listAccounts() {
1045
- return [];
1046
- }
1047
1520
  async getAuthUri({
1048
1521
  accountId
1049
1522
  }) {
@@ -1055,79 +1528,55 @@ class MockConnector extends IBankConnector {
1055
1528
  accounts: []
1056
1529
  };
1057
1530
  }
1058
- async preparePayment(payment) {
1059
- const bankRefId = backendSdk.uuidv4();
1060
- return {
1531
+ async initiateSinglePayment(payment) {
1532
+ const preparedPayment = {
1061
1533
  ...payment,
1062
- id: backendSdk.uuidv4(),
1063
- bankRefId,
1064
- direction: "OUTGOING",
1065
- paymentType: "DOMESTIC",
1534
+ bankRefId: backendSdk.uuidv4(),
1066
1535
  status: "PREPARED",
1067
- initiatedAt: /* @__PURE__ */ new Date(),
1068
- accountId: this.connectedAccounts.find(
1069
- (acc) => acc.iban === payment.debtor.iban
1070
- ).id,
1071
- connectorKey: "MOCK"
1536
+ initiatedAt: /* @__PURE__ */ new Date()
1072
1537
  };
1073
- }
1074
- async initiateSinglePayment(payment) {
1075
1538
  return {
1076
- payment: {
1077
- ...payment,
1078
- status: "INITIALIZED"
1079
- },
1080
- authorizationUrl: "http://mock.com"
1539
+ payment: preparedPayment,
1540
+ authorizationUrl: "http://mock.com/auto-approve"
1081
1541
  };
1082
1542
  }
1083
- async initiateBatchFromPayments({
1543
+ async initiateSEPAPayment(payment) {
1544
+ return this.initiateSinglePayment(payment);
1545
+ }
1546
+ async initiateBatch({
1084
1547
  batchId,
1085
1548
  payments
1086
1549
  }) {
1550
+ const preparedPayments = payments.map((payment) => ({
1551
+ ...payment,
1552
+ bankRefId: backendSdk.uuidv4(),
1553
+ status: "PREPARED",
1554
+ initiatedAt: /* @__PURE__ */ new Date()
1555
+ }));
1087
1556
  return {
1088
- id: backendSdk.uuidv4(),
1089
- authorizationUrls: ["http://mock.com"],
1090
- payments: payments.map(
1091
- (payment) => ({
1092
- ...payment,
1093
- status: "INITIALIZED"
1094
- })
1095
- )
1557
+ id: batchId,
1558
+ authorizationUrls: ["http://mock.com/auto-approve"],
1559
+ payments: preparedPayments
1096
1560
  };
1097
1561
  }
1098
1562
  async getAllAccountPayments({
1099
- db
1563
+ account,
1564
+ filter
1100
1565
  }) {
1101
- const payments = await db.select().from(tables.payment).where(
1102
- drizzleOrm.and(
1103
- drizzleOrm.eq(tables.payment.status, "INITIALIZED"),
1104
- drizzleOrm.eq(tables.payment.direction, "OUTGOING")
1105
- )
1106
- );
1107
- return payments.map((payment) => ({
1108
- raw: payment,
1109
- parsed: {
1110
- ...payment,
1111
- status: "COMPLETED"
1112
- }
1113
- }));
1114
- }
1115
- getPaymentStatus(_) {
1116
- throw new Error("Method not implemented.");
1566
+ return [];
1117
1567
  }
1118
- getBatchStatus(_) {
1119
- throw new Error("Method not implemented.");
1568
+ async getPaymentStatus(_) {
1569
+ return "COMPLETED";
1120
1570
  }
1121
- }
1122
-
1123
- class MockCobsConnector extends FinbricksConnector {
1124
- constructor(config) {
1125
- super("MOCK_COBS", config);
1571
+ async getBatchStatus(_) {
1572
+ return {
1573
+ status: "SIGNED",
1574
+ apiResponse: { mock: true }
1575
+ };
1126
1576
  }
1127
1577
  }
1128
1578
 
1129
- const tables = database_schema.schema;
1130
-
1579
+ exports.DbuConnector = DbuConnector;
1131
1580
  exports.ErsteConnector = ErsteConnector;
1132
1581
  exports.FINBRICKS_ENDPOINTS = FINBRICKS_ENDPOINTS;
1133
1582
  exports.FinbricksClient = FinbricksClient;
@@ -1135,6 +1584,12 @@ exports.FinbricksConnector = FinbricksConnector;
1135
1584
  exports.IBankConnector = IBankConnector;
1136
1585
  exports.MockCobsConnector = MockCobsConnector;
1137
1586
  exports.MockConnector = MockConnector;
1587
+ exports.assignAccount = assignAccount;
1588
+ exports.batchTransform = batchTransform;
1589
+ exports.initiateConnector = initiateConnector;
1138
1590
  exports.signFinbricksJws = signFinbricksJws;
1139
- exports.tables = tables;
1591
+ exports.toBatchedPayment = toBatchedPayment;
1592
+ exports.toCompletedPayment = toCompletedPayment;
1593
+ exports.toIncomingPayment = toIncomingPayment;
1594
+ exports.toPreparedPayment = toPreparedPayment;
1140
1595
  exports.useFinbricksFetch = useFinbricksFetch;