@develit-services/bank 0.0.14 → 0.0.16

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.
@@ -1,11 +1,11 @@
1
- import { useResult, createInternalError, uuidv4 } from '@develit-io/backend-sdk';
1
+ import { uuidv4, useResult, createInternalError } from '@develit-io/backend-sdk';
2
2
  import { s as schema } from './bank.BeH-ZCJJ.mjs';
3
3
  import { and, eq } from 'drizzle-orm';
4
4
  import { z } from 'zod';
5
5
  import { COUNTRY_CODES_2, CURRENCY_CODES } from '@develit-io/general-codes';
6
+ import { importPKCS8, SignJWT } from 'jose';
6
7
  import 'superjson';
7
8
  import { format, parseISO } from 'date-fns';
8
- import { importPKCS8, SignJWT } from 'jose';
9
9
 
10
10
  const tables = schema;
11
11
 
@@ -33,6 +33,104 @@ const COUNTRY_CODES = COUNTRY_CODES_2;
33
33
  class IBankConnector {
34
34
  }
35
35
 
36
+ async function signFinbricksJws({
37
+ privateKeyPem,
38
+ merchantId,
39
+ jwsData
40
+ }) {
41
+ const privateKey = await importPKCS8(privateKeyPem, "RS256");
42
+ const payload = JSON.stringify(jwsData);
43
+ const jws = await new SignJWT(JSON.parse(payload)).setProtectedHeader({
44
+ alg: "RS256",
45
+ kid: merchantId,
46
+ typ: "JWT"
47
+ }).sign(privateKey);
48
+ const [header, , signature] = jws.split(".");
49
+ return `${header}..${signature}`;
50
+ }
51
+
52
+ const useFinbricksFetch = async (config, init) => {
53
+ const {
54
+ baseUrl,
55
+ endpoint,
56
+ method = "GET",
57
+ merchantId,
58
+ privateKeyPem,
59
+ query,
60
+ body,
61
+ correlationId,
62
+ psuIp = "88.205.47.1",
63
+ psuAgent = "Develit/BankService"
64
+ } = config;
65
+ const url = new URL(`${baseUrl}${endpoint}`);
66
+ if (query) {
67
+ for (const [k, v] of Object.entries(query)) {
68
+ if (v !== void 0 && v !== null)
69
+ url.searchParams.append(k, v.toString());
70
+ }
71
+ }
72
+ const uriWithQuery = `${endpoint}${url.search ? `?${url.searchParams.toString()}` : ""}`;
73
+ const bodyString = body ? JSON.stringify(body) : "";
74
+ const jwsSignature = await signFinbricksJws({
75
+ privateKeyPem,
76
+ merchantId,
77
+ jwsData: {
78
+ uri: uriWithQuery,
79
+ body: bodyString
80
+ }
81
+ });
82
+ const headers = {
83
+ "Content-Type": "application/json",
84
+ "JWS-Signature": jwsSignature,
85
+ "PSU-IP-Address": psuIp,
86
+ "PSU-User-Agent": psuAgent,
87
+ ...init?.headers
88
+ };
89
+ if (correlationId) {
90
+ headers["Correlation-ID"] = correlationId;
91
+ }
92
+ const res = await fetch(url.toString(), {
93
+ method,
94
+ headers,
95
+ body: method !== "GET" ? bodyString : void 0
96
+ });
97
+ if (!res.ok) {
98
+ const text = await res.text().catch(() => "unknown error");
99
+ throw new Error(
100
+ `Finbricks API error: ${res.status} ${res.statusText} \u2013 ${text}`
101
+ );
102
+ }
103
+ return await res.json();
104
+ };
105
+ class FinbricksClient {
106
+ constructor(baseUrl, merchantId, privateKeyPem) {
107
+ this.BASE_URL = baseUrl;
108
+ this.MERCHANT_ID = merchantId;
109
+ this.PRIVATE_KEY_PEM = privateKeyPem;
110
+ }
111
+ async request(params) {
112
+ return useFinbricksFetch({
113
+ baseUrl: this.BASE_URL,
114
+ merchantId: this.MERCHANT_ID,
115
+ privateKeyPem: this.PRIVATE_KEY_PEM,
116
+ ...params
117
+ });
118
+ }
119
+ }
120
+
121
+ const FINBRICKS_ENDPOINTS = {
122
+ AUTHENTICATE_V2: "/v2/auth/authenticate",
123
+ AUTH_TOKEN_STATUS: "/auth/token",
124
+ AUTH_TOKEN_REVOKE: "/auth/revoke",
125
+ ACCOUNT_LIST: "/account/list",
126
+ ACCOUNT_BALANCE: "/account/balance",
127
+ ACCOUNT_TRANSACTIONS: "/account/transactions",
128
+ TRANSACTION_INIT: "/transaction/platform/init",
129
+ TRANSACTION_STATUS: "/transaction/platform/status",
130
+ TRANSACTION_BATCH_INIT: "/transaction/platform/batchPayment/init",
131
+ BATCH_STATUS: "/transaction/platform/batchPayment/status"
132
+ };
133
+
36
134
  const mapReferencesToPayment = (reference) => {
37
135
  const symbols = {
38
136
  vs: void 0,
@@ -76,81 +174,186 @@ const mapFinbricksStatus = (status) => {
76
174
  return "PENDING";
77
175
  }
78
176
  };
177
+ const mapFinbricksTransactionStatus = (status) => {
178
+ switch (status) {
179
+ case "OPENED":
180
+ return "CREATED";
181
+ case "AUTHORIZED":
182
+ return "PENDING";
183
+ case "COMPLETED":
184
+ return "COMPLETED";
185
+ case "BOOKED":
186
+ return "PENDING";
187
+ case "SETTLED":
188
+ return "COMPLETED";
189
+ case "REJECTED":
190
+ return "FAILED";
191
+ case "CLOSED":
192
+ return "FAILED";
193
+ }
194
+ };
195
+ const mapFinbricksBatchStatus = (status) => {
196
+ return status === "REJECTED" ? "FAILED" : status === "AUTHORIZED" ? "PROCESSING" : "READY_TO_SIGN";
197
+ };
198
+ const mapFinbricksTransactionToPayment = (tx, account) => {
199
+ const isIncoming = tx.creditDebitIndicator === "CRDT";
200
+ const related = tx.entryDetails.transactionDetails.relatedParties;
201
+ const base = {
202
+ id: uuidv4(),
203
+ bankRefId: tx.entryReference || tx.fbxReference,
204
+ amount: tx.amount?.value || 0,
205
+ currency: tx.amount?.currency || "CZK",
206
+ paymentType: "DOMESTIC",
207
+ status: mapFinbricksStatus(tx.status),
208
+ message: tx.entryDetails.transactionDetails.remittanceInformation?.unstructured || tx.entryDetails.transactionDetails.additionalRemittanceInformation || null,
209
+ processedAt: new Date(tx.bookingDate.date),
210
+ ...mapReferencesToPayment(
211
+ tx.entryDetails.transactionDetails.remittanceInformation?.structured?.creditorReferenceInformation?.reference || tx.entryDetails.transactionDetails.references?.endToEndIdentification
212
+ ),
213
+ debtorHolderName: isIncoming ? related.debtor?.name || "Unknown" : "Unknown",
214
+ creditorHolderName: isIncoming ? "Unknown" : related.creditor?.name || "Unknown",
215
+ debtorIban: isIncoming ? related.debtorAccount?.identification?.iban || account.identification.iban : account.identification.iban,
216
+ creditorIban: isIncoming ? account.identification.iban : related.creditorAccount?.identification?.iban || account.identification.iban,
217
+ direction: "INCOMING"
218
+ // přepíšeme správným směrem níže
219
+ };
220
+ base.direction = getPaymentDirection(base, account.identification.iban);
221
+ return base;
222
+ };
79
223
 
80
224
  class FinbricksConnector extends IBankConnector {
81
- constructor(PROVIDER, { BASE_URI, MERCHANT_ID, PRIVATE_KEY_PEM }) {
225
+ constructor(provider, { BASE_URI, MERCHANT_ID, PRIVATE_KEY_PEM }) {
82
226
  super();
83
227
  this.connectorKey = "FINBRICKS";
84
- this.apiDictionary = /* @__PURE__ */ new Map([
85
- ["single-payment-domestic", "/transaction/platform/init"],
86
- ["batch-payment-domestic", "/transaction/platform/batchPayment/init"],
87
- ["get-accounts", "/account/list"],
88
- ["get-account-transactions", "/account/transactions"],
89
- ["authenticate-client", "/v2/auth/authenticate"],
90
- ["expiration", "/auth/token"]
91
- ]);
92
- this.PROVIDER = PROVIDER;
93
- this.BASE_URI = BASE_URI;
94
- this.MERCHANT_ID = MERCHANT_ID;
95
- this.PRIVATE_KEY_PEM = PRIVATE_KEY_PEM;
228
+ this.PROVIDER = provider;
229
+ this.finbricks = new FinbricksClient(BASE_URI, MERCHANT_ID, PRIVATE_KEY_PEM);
96
230
  }
97
231
  static {
98
232
  this.FETCH_INTERVAL = 60 * 60 * 5;
99
233
  }
100
- async signFinbricksJws({ jwsData }) {
101
- const privateKey = await importPKCS8(this.PRIVATE_KEY_PEM, "RS256");
102
- const payload = JSON.stringify(jwsData);
103
- const jws = await new SignJWT(JSON.parse(payload)).setProtectedHeader({
104
- alg: "RS256",
105
- kid: this.MERCHANT_ID,
106
- typ: "JWT"
107
- }).sign(privateKey);
108
- return jws;
109
- }
110
- async authenticate({ token }) {
111
- this.lastValidClientId = token;
112
- return this.lastValidClientId;
113
- }
114
- async isClientIdExpired(clientId) {
115
- const query = new URLSearchParams({
116
- merchantId: this.MERCHANT_ID,
117
- provider: this.PROVIDER,
234
+ async connectUserAccount() {
235
+ const clientId = uuidv4();
236
+ const body = {
237
+ merchantId: this.finbricks.MERCHANT_ID,
238
+ clientId,
239
+ paymentProvider: this.PROVIDER,
240
+ scope: "AISP_PISP",
241
+ callbackUrl: "https://example.com/callback"
242
+ };
243
+ const [response, error] = await useResult(
244
+ this.finbricks.request({
245
+ endpoint: FINBRICKS_ENDPOINTS.AUTHENTICATE_V2,
246
+ method: "POST",
247
+ body
248
+ })
249
+ );
250
+ if (error || !response) {
251
+ throw createInternalError(error, {
252
+ message: "Finbricks: failed to connect user"
253
+ });
254
+ }
255
+ return {
256
+ redirectUrl: response.redirectUrl,
118
257
  clientId
119
- });
120
- const uri = this.apiDictionary.get("expiration");
121
- const fullUri = `${uri}?${query.toString()}`;
122
- const signature = await this.signFinbricksJws({
123
- jwsData: {
124
- body: "",
125
- uri: fullUri
258
+ };
259
+ }
260
+ async authenticate({ token: clientId }) {
261
+ if (!!clientId) {
262
+ const isExpired = await this.isClientIdExpired(clientId);
263
+ if (!isExpired) {
264
+ this.lastValidClientId = clientId;
265
+ return clientId;
126
266
  }
127
- });
128
- const [data, error] = await useResult(
129
- fetch(`${this.BASE_URI}${fullUri}`, {
267
+ }
268
+ const newClientId = uuidv4();
269
+ const body = {
270
+ merchantId: this.finbricks.MERCHANT_ID,
271
+ paymentProvider: this.PROVIDER,
272
+ clientId: newClientId,
273
+ scope: "AISP_PISP",
274
+ callbackUrl: `www.example.com/callback`
275
+ };
276
+ const [res, error] = await useResult(
277
+ this.finbricks.request({
278
+ endpoint: "/v2/auth/authenticate",
130
279
  method: "POST",
131
- headers: {
132
- "JWS-Signature": signature,
133
- "Content-Type": "application/json"
134
- },
135
- body: ""
280
+ body
281
+ })
282
+ );
283
+ if (error || !res) {
284
+ throw createInternalError(error, {
285
+ message: `Finbricks: authentication request failed (${this.PROVIDER})`
286
+ });
287
+ }
288
+ this.lastValidClientId = newClientId;
289
+ return res.redirectUrl;
290
+ }
291
+ async revokeAuthentication(clientId) {
292
+ const [_, error] = await useResult(
293
+ this.finbricks.request({
294
+ endpoint: FINBRICKS_ENDPOINTS.AUTH_TOKEN_REVOKE,
295
+ method: "DELETE",
296
+ query: {
297
+ merchantId: this.finbricks.MERCHANT_ID,
298
+ clientId,
299
+ provider: this.PROVIDER
300
+ }
136
301
  })
137
302
  );
138
303
  if (error) {
139
- const body = await data?.json();
140
304
  throw createInternalError(error, {
141
- message: body?.message || "Finbricks API error"
305
+ message: `Finbricks: failed to revoke authentication for clientId ${clientId}`
142
306
  });
143
307
  }
144
- if (!data?.ok) {
145
- const body = await data.json();
308
+ this.lastValidClientId = "";
309
+ }
310
+ async isClientIdExpired(clientId) {
311
+ const [response, error] = await useResult(
312
+ this.finbricks.request({
313
+ endpoint: FINBRICKS_ENDPOINTS.AUTH_TOKEN_STATUS,
314
+ method: "GET",
315
+ query: {
316
+ merchantId: this.finbricks.MERCHANT_ID,
317
+ clientId,
318
+ provider: this.PROVIDER
319
+ }
320
+ })
321
+ );
322
+ if (error) {
323
+ throw createInternalError(error, {
324
+ message: `Finbricks: failed to fetch token info for clientId: ${clientId}`
325
+ });
326
+ }
327
+ if (!response || response.length === 0) return true;
328
+ const record = response.find((token) => token.clientId === clientId);
329
+ if (!record) return true;
330
+ const validTo = new Date(record.validTo);
331
+ return validTo.getTime() < Date.now();
332
+ }
333
+ async listAccounts() {
334
+ if (!this.lastValidClientId) {
146
335
  throw createInternalError(null, {
147
- message: body.message || "Finbricks API error",
148
- code: "FINBRICKS_API_ERROR",
149
- status: data?.status || 500
336
+ message: "Finbricks: missing valid clientId",
337
+ code: "FINBRICKS_CLIENT_ID_MISSING"
338
+ });
339
+ }
340
+ const [response, error] = await useResult(
341
+ this.finbricks.request({
342
+ endpoint: FINBRICKS_ENDPOINTS.ACCOUNT_LIST,
343
+ method: "GET",
344
+ query: {
345
+ merchantId: this.finbricks.MERCHANT_ID,
346
+ paymentProvider: this.PROVIDER,
347
+ clientId: this.lastValidClientId
348
+ }
349
+ })
350
+ );
351
+ if (error || !response) {
352
+ throw createInternalError(error, {
353
+ message: "Finbricks: failed to list accounts"
150
354
  });
151
355
  }
152
- const tokens = await data.json();
153
- return !!tokens.find((token) => token.clientId === clientId);
356
+ return response.accounts;
154
357
  }
155
358
  async preparePayment(payment) {
156
359
  const bankRefId = uuidv4();
@@ -167,111 +370,64 @@ class FinbricksConnector extends IBankConnector {
167
370
  async initiateBatchFromPayments({
168
371
  payments
169
372
  }) {
170
- const uri = this.apiDictionary.get("batch-payment-domestic");
171
373
  const batchId = uuidv4();
172
- const batchBody = {
173
- batchPaymentIdentification: {
174
- merchantId: this.MERCHANT_ID,
175
- debtorAccountIban: payments[0].debtorIban,
176
- clientId: this.lastValidClientId,
177
- callbackUrl: "https://example.com/callback",
178
- merchantBatchId: batchId
179
- },
180
- payments: payments.map((payment) => ({
181
- merchantTransactionId: payment.bankRefId,
182
- creditorAccountIban: payment.creditorIban,
183
- amount: payment.amount
184
- }))
185
- };
186
- const payload = JSON.stringify(batchBody);
187
- const jwsData = {
188
- uri,
189
- body: payload
190
- };
191
- const signature = await this.signFinbricksJws({
192
- jwsData
193
- });
194
- const [data, error] = await useResult(
195
- fetch(`${this.BASE_URI}${uri}`, {
374
+ const [response, error] = await useResult(
375
+ this.finbricks.request({
376
+ endpoint: FINBRICKS_ENDPOINTS.TRANSACTION_BATCH_INIT,
196
377
  method: "POST",
197
- headers: {
198
- "JWS-Signature": signature,
199
- "Content-Type": "application/json"
200
- },
201
- body: payload
378
+ body: {
379
+ batchPaymentIdentification: {
380
+ merchantId: this.finbricks.MERCHANT_ID,
381
+ debtorAccountIban: payments[0].debtorIban,
382
+ clientId: this.lastValidClientId,
383
+ callbackUrl: "https://example.com/callback",
384
+ merchantBatchId: batchId
385
+ },
386
+ payments: payments.map((p) => ({
387
+ merchantTransactionId: p.bankRefId,
388
+ creditorAccountIban: p.creditorIban,
389
+ amount: p.amount
390
+ }))
391
+ }
202
392
  })
203
393
  );
204
- const body = await data?.json();
205
- if (error) {
394
+ if (error || !response) {
206
395
  throw createInternalError(error, {
207
- message: body?.message || "Finbricks API error"
396
+ message: "Finbricks: failed to initiate batch payment"
208
397
  });
209
398
  }
210
- if (!data?.ok) {
211
- console.log("FINBRICKSBODY", body);
212
- throw createInternalError(null, {
213
- message: body?.message || "Finbricks API error",
214
- code: "FINBRICKS_API_ERROR",
215
- status: data?.status || 500
216
- });
217
- }
218
- const { redirectUrl } = body;
219
399
  return {
220
400
  id: batchId,
221
- authorizationUrls: [redirectUrl],
222
- payments: payments.map((payment) => ({
223
- ...payment,
224
- status: "INITIALIZED"
225
- }))
401
+ authorizationUrls: [response.redirectUrl],
402
+ payments: payments.map((p) => ({ ...p, status: "INITIALIZED" }))
226
403
  };
227
404
  }
228
405
  async initiateSinglePayment(payment) {
229
- const uri = this.apiDictionary.get("single-payment-domestic");
230
- const paymentBody = {
231
- merchantId: this.MERCHANT_ID,
232
- merchantTransactionId: payment.bankRefId,
233
- totalPrice: payment.amount,
234
- creditorAccountIban: payment.creditorIban,
235
- debtorAccountIban: payment.debtorIban,
236
- creditorName: payment.creditorHolderName,
237
- description: payment.message || "",
238
- variableSymbol: payment.vs || "",
239
- callbackUrl: "example.com",
240
- paymentProvider: this.PROVIDER
241
- };
242
- const signature = await this.signFinbricksJws({
243
- jwsData: {
244
- body: JSON.stringify(paymentBody),
245
- uri
246
- }
247
- });
248
- const [data, error] = await useResult(
249
- fetch(`${this.BASE_URI}${uri}`, {
406
+ const [response, error] = await useResult(
407
+ this.finbricks.request({
408
+ endpoint: FINBRICKS_ENDPOINTS.TRANSACTION_INIT,
250
409
  method: "POST",
251
- headers: {
252
- "JWS-Signature": signature,
253
- "Content-Type": "application/json"
254
- },
255
- body: JSON.stringify(paymentBody)
410
+ body: {
411
+ merchantId: this.finbricks.MERCHANT_ID,
412
+ merchantTransactionId: payment.bankRefId,
413
+ totalPrice: payment.amount,
414
+ debtorAccountIban: payment.debtorIban,
415
+ creditorAccountIban: payment.creditorIban,
416
+ creditorName: payment.creditorHolderName,
417
+ description: payment.message || "",
418
+ variableSymbol: payment.vs || "",
419
+ callbackUrl: "https://example.com/callback",
420
+ paymentProvider: this.PROVIDER
421
+ }
256
422
  })
257
423
  );
258
- const body = await data?.json();
259
- if (error) {
424
+ if (error || !response) {
260
425
  throw createInternalError(error, {
261
- message: body?.message || "Finbricks API error"
426
+ message: "Finbricks: failed to initiate payment"
262
427
  });
263
428
  }
264
- if (!data?.ok) {
265
- console.log("FINBRICKSBODY", body);
266
- throw createInternalError(null, {
267
- message: body?.message || "Finbricks API error",
268
- code: "FINBRICKS_API_ERROR",
269
- status: data?.status || 500
270
- });
271
- }
272
- const redirectUrl = (await data.json()).redirectUrl;
273
429
  return {
274
- authorizationUrl: redirectUrl,
430
+ authorizationUrl: response.redirectUrl,
275
431
  payment: { ...payment, status: "INITIALIZED" }
276
432
  };
277
433
  }
@@ -279,95 +435,85 @@ class FinbricksConnector extends IBankConnector {
279
435
  account,
280
436
  lastSync
281
437
  }) {
282
- const uri = this.apiDictionary.get("get-account-transactions");
283
438
  const dateFormat = "yyyy-MM-dd";
284
- let cursor = null;
285
- let allPayments = [];
286
439
  const dateFrom = format(lastSync.lastSyncedAt, dateFormat);
287
440
  const dateTo = format(/* @__PURE__ */ new Date(), dateFormat);
288
- do {
289
- const query = new URLSearchParams({
290
- merchantId: this.MERCHANT_ID,
291
- clientId: this.lastValidClientId,
292
- paymentProvider: this.PROVIDER,
293
- bankAccountId: account.identification.number,
294
- dateFrom,
295
- dateTo,
296
- currency: account.currency,
297
- size: "20"
298
- });
299
- console.log("query", query);
300
- if (cursor) query.set("cursor", cursor);
301
- const fullUri = `${uri}?${query.toString()}`;
302
- const jwsData = {
303
- uri: fullUri,
304
- body: ""
305
- };
306
- const signature = await this.signFinbricksJws({ jwsData });
307
- console.log("signature ready", signature);
308
- const [data, error] = await useResult(
309
- fetch(`${this.BASE_URI}${fullUri}`, {
441
+ let cursor = null;
442
+ const allPayments = [];
443
+ const fetchTransactions = async (cursor2) => {
444
+ return useResult(
445
+ this.finbricks.request({
310
446
  method: "GET",
311
- headers: {
312
- "JWS-Signature": signature,
313
- "Content-Type": "application/json"
447
+ endpoint: FINBRICKS_ENDPOINTS.ACCOUNT_TRANSACTIONS,
448
+ query: {
449
+ merchantId: this.finbricks.MERCHANT_ID,
450
+ clientId: this.lastValidClientId,
451
+ paymentProvider: this.PROVIDER,
452
+ bankAccountId: account.identification.number,
453
+ dateFrom,
454
+ dateTo,
455
+ currency: account.currency,
456
+ size: "20",
457
+ cursor: cursor2 ?? void 0
314
458
  }
315
459
  })
316
460
  );
317
- if (error) {
318
- const body = await data?.json();
319
- throw createInternalError(error, {
320
- message: body?.message || "Finbricks API error"
321
- });
322
- }
323
- if (!data?.ok) {
324
- const body = await data.json();
325
- throw createInternalError(null, {
326
- message: body.message || "Finbricks API error",
327
- code: "FINBRICKS_API_ERROR",
328
- status: data?.status || 500
329
- });
461
+ };
462
+ do {
463
+ {
464
+ const [response, error] = await fetchTransactions(cursor);
465
+ if (error || !response) {
466
+ throw createInternalError(error, {
467
+ message: "Finbricks: failed to fetch account transactions"
468
+ });
469
+ }
470
+ const { transactions, links } = response;
471
+ cursor = links?.[0]?.value || null;
472
+ for (const tx of transactions) {
473
+ allPayments.push(mapFinbricksTransactionToPayment(tx, account));
474
+ }
330
475
  }
331
- const { transactions, links } = await data.json();
332
- cursor = links?.[0]?.value || null;
333
- allPayments = [
334
- ...allPayments,
335
- ...transactions.map((tx) => {
336
- const isIncoming = tx.creditDebitIndicator === "CRDT";
337
- const relatedParties = tx.entryDetails?.transactionDetails?.relatedParties;
338
- const paymentInsert = {
339
- id: uuidv4(),
340
- bankRefId: tx.entryReference || tx.fbxReference,
341
- amount: tx.amount?.value || 0,
342
- currency: tx.amount?.currency || "CZK",
343
- debtorHolderName: isIncoming ? relatedParties?.debtor?.name || "Unknown" : "Unknown",
344
- debtorIban: isIncoming ? relatedParties?.debtorAccount?.identification?.iban || account.identification.iban : account.identification.iban,
345
- debtorAccountNumberWithBankCode: isIncoming ? relatedParties?.debtorAccount?.identification?.other?.identification || `${account.identification.number}/${account.identification.bankCode}` : `${account.identification.number}/${account.identification.bankCode}`,
346
- creditorHolderName: isIncoming ? "Unknown" : relatedParties?.creditor?.name || "Unknown",
347
- creditorIban: isIncoming ? account.identification.iban : relatedParties?.creditorAccount?.identification?.iban || account.identification.iban,
348
- creditorAccountNumberWithBankCode: isIncoming ? `${account.identification.number}/${account.identification.bankCode}` : relatedParties?.creditorAccount?.identification?.other?.identification || `${account.identification.number}/${account.identification.bankCode}`,
349
- paymentType: "DOMESTIC",
350
- direction: isIncoming ? "INCOMING" : "OUTGOING",
351
- message: tx.entryDetails?.transactionDetails?.remittanceInformation?.unstructured || tx.entryDetails?.transactionDetails?.additionalRemittanceInformation || null,
352
- ...mapReferencesToPayment(
353
- tx.entryDetails?.transactionDetails?.remittanceInformation?.structured?.creditorReferenceInformation?.reference || tx.entryDetails?.transactionDetails?.references?.endToEndIdentification
354
- ),
355
- processedAt: new Date(tx.bookingDate.date),
356
- status: "COMPLETED"
357
- };
358
- return {
359
- ...paymentInsert,
360
- direction: getPaymentDirection(
361
- paymentInsert,
362
- account.identification.iban
363
- ),
364
- status: mapFinbricksStatus(tx.status)
365
- };
366
- })
367
- ];
368
476
  } while (cursor != null);
369
477
  return allPayments;
370
478
  }
479
+ async getPaymentStatus({
480
+ paymentId
481
+ }) {
482
+ const [response, error] = await useResult(
483
+ this.finbricks.request({
484
+ method: "GET",
485
+ endpoint: FINBRICKS_ENDPOINTS.TRANSACTION_STATUS,
486
+ query: {
487
+ merchantId: this.finbricks.MERCHANT_ID,
488
+ merchantTransactionId: paymentId
489
+ }
490
+ })
491
+ );
492
+ if (error || !response) {
493
+ throw createInternalError(error, {
494
+ message: "Finbricks: failed to fetch payment status"
495
+ });
496
+ }
497
+ return mapFinbricksTransactionStatus(response.resultCode);
498
+ }
499
+ async getBatchStatus({ batchId }) {
500
+ const [response, error] = await useResult(
501
+ this.finbricks.request({
502
+ method: "POST",
503
+ endpoint: FINBRICKS_ENDPOINTS.BATCH_STATUS,
504
+ body: {
505
+ merchantId: this.finbricks.MERCHANT_ID,
506
+ merchantBatchId: batchId
507
+ }
508
+ })
509
+ );
510
+ if (error || !response) {
511
+ throw createInternalError(error, {
512
+ message: "Finbricks: failed to fetch batch status"
513
+ });
514
+ }
515
+ return mapFinbricksBatchStatus(response.batchResultCode);
516
+ }
371
517
  }
372
518
 
373
519
  const isDeposit = (payment, creditorIban) => {
@@ -391,6 +537,9 @@ class ErsteConnector extends IBankConnector {
391
537
  this.PAYMENTS_URI = config.PAYMENTS_URI;
392
538
  this.ACCOUNTS_URI = config.ACCOUNTS_URI;
393
539
  }
540
+ connectUserAccount() {
541
+ throw new Error("Method not implemented.");
542
+ }
394
543
  static {
395
544
  this.FETCH_INTERVAL = 60 * 60 * 5;
396
545
  }
@@ -435,6 +584,9 @@ class ErsteConnector extends IBankConnector {
435
584
  this.accessToken = json.access_token;
436
585
  return json.refresh_token || "";
437
586
  }
587
+ listAccounts() {
588
+ throw new Error("Method not implemented.");
589
+ }
438
590
  async preparePayment(payment) {
439
591
  if (!this.accessToken) {
440
592
  throw createInternalError(null, {
@@ -621,6 +773,12 @@ class ErsteConnector extends IBankConnector {
621
773
  });
622
774
  return payments;
623
775
  }
776
+ getPaymentStatus(_) {
777
+ throw new Error("Method not implemented.");
778
+ }
779
+ getBatchStatus(_) {
780
+ throw new Error("Method not implemented.");
781
+ }
624
782
  }
625
783
 
626
784
  class MockConnector extends IBankConnector {
@@ -634,6 +792,15 @@ class MockConnector extends IBankConnector {
634
792
  async authenticate() {
635
793
  return "";
636
794
  }
795
+ async listAccounts() {
796
+ return [];
797
+ }
798
+ async connectUserAccount() {
799
+ return {
800
+ clientId: uuidv4(),
801
+ redirectUrl: ""
802
+ };
803
+ }
637
804
  async preparePayment(payment) {
638
805
  const bankRefId = uuidv4();
639
806
  return {
@@ -681,6 +848,12 @@ class MockConnector extends IBankConnector {
681
848
  status: "COMPLETED"
682
849
  }));
683
850
  }
851
+ getPaymentStatus(_) {
852
+ throw new Error("Method not implemented.");
853
+ }
854
+ getBatchStatus(_) {
855
+ throw new Error("Method not implemented.");
856
+ }
684
857
  }
685
858
 
686
859
  class MockCobsConnector extends FinbricksConnector {
@@ -701,6 +874,8 @@ const paymentInsertTypeZod = z.object({
701
874
  bankPaymentInitiatedAt: z.coerce.date(),
702
875
  bankPaymentProcessedAt: z.coerce.date(),
703
876
  bankingVs: z.string().max(10),
877
+ bankingSs: z.string().max(10),
878
+ bankingKs: z.string().max(10),
704
879
  message: z.string(),
705
880
  creditorIban: z.string().max(34),
706
881
  creditorHolderName: z.string(),
@@ -708,4 +883,4 @@ const paymentInsertTypeZod = z.object({
708
883
  debtorHolderName: z.string().nullable()
709
884
  });
710
885
 
711
- export { BATCH_STATUSES as B, COUNTRY_CODES as C, ErsteConnector as E, FinbricksConnector as F, IBankConnector as I, MockConnector as M, PAYMENT_TYPES as P, MockCobsConnector as a, PAYMENT_STATUSES as b, PAYMENT_DIRECTIONS as c, getPaymentDirection as g, paymentInsertTypeZod as p, tables as t };
886
+ export { BATCH_STATUSES as B, COUNTRY_CODES as C, ErsteConnector as E, FinbricksConnector as F, IBankConnector as I, MockConnector as M, PAYMENT_TYPES as P, MockCobsConnector as a, FinbricksClient as b, FINBRICKS_ENDPOINTS as c, PAYMENT_STATUSES as d, PAYMENT_DIRECTIONS as e, getPaymentDirection as g, paymentInsertTypeZod as p, signFinbricksJws as s, tables as t, useFinbricksFetch as u };