@develit-services/bank 4.2.2 → 4.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.
- package/dist/export/worker.cjs +39 -2
- package/dist/export/worker.mjs +39 -2
- package/dist/export/workflows.cjs +2 -2
- package/dist/export/workflows.mjs +2 -2
- package/dist/shared/{bank.DiJmJkDt.cjs → bank.BSX82jhx.cjs} +94 -30
- package/dist/shared/{bank.BELDXSDV.mjs → bank.BdTj54NO.mjs} +1 -1
- package/dist/shared/{bank.BOMobxtA.mjs → bank.CZ8MQDPa.mjs} +94 -30
- package/dist/shared/{bank.CioJeFzf.cjs → bank.CibQRM2D.cjs} +1 -1
- package/dist/types.cjs +1 -1
- package/dist/types.mjs +1 -1
- package/package.json +1 -1
package/dist/export/worker.cjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const backendSdk = require('@develit-io/backend-sdk');
|
|
4
|
-
const ott_zod = require('../shared/bank.
|
|
4
|
+
const ott_zod = require('../shared/bank.BSX82jhx.cjs');
|
|
5
5
|
const drizzleOrm = require('drizzle-orm');
|
|
6
6
|
const cloudflare_workers = require('cloudflare:workers');
|
|
7
7
|
const d1 = require('drizzle-orm/d1');
|
|
@@ -11,7 +11,7 @@ const database_schema = require('../shared/bank.9Yw4KHyl.cjs');
|
|
|
11
11
|
const generalCodes = require('@develit-io/general-codes');
|
|
12
12
|
require('date-fns');
|
|
13
13
|
require('node:crypto');
|
|
14
|
-
const credentialsResolver = require('../shared/bank.
|
|
14
|
+
const credentialsResolver = require('../shared/bank.CibQRM2D.cjs');
|
|
15
15
|
require('drizzle-orm/zod');
|
|
16
16
|
require('drizzle-orm/sqlite-core');
|
|
17
17
|
|
|
@@ -88,6 +88,43 @@ const sendPaymentInputSchema = zod.z.object({
|
|
|
88
88
|
creditor: backendSdk.bankAccountMetadataSchema,
|
|
89
89
|
debtor: backendSdk.bankAccountMetadataSchema,
|
|
90
90
|
sendAsSinglePayment: zod.z.boolean().optional()
|
|
91
|
+
}).superRefine((data, ctx) => {
|
|
92
|
+
if (data.paymentType === "UNKNOWN") {
|
|
93
|
+
ctx.addIssue({
|
|
94
|
+
code: "custom",
|
|
95
|
+
message: "paymentType=UNKNOWN is not supported. Use DOMESTIC, SEPA, or SWIFT.",
|
|
96
|
+
path: ["paymentType"]
|
|
97
|
+
});
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
if (!data.debtor.iban) {
|
|
101
|
+
ctx.addIssue({
|
|
102
|
+
code: "custom",
|
|
103
|
+
message: "debtor.iban is required",
|
|
104
|
+
path: ["debtor", "iban"]
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
if (data.paymentType === "DOMESTIC" || data.paymentType === "SEPA") {
|
|
108
|
+
if (!data.creditor.iban) {
|
|
109
|
+
ctx.addIssue({
|
|
110
|
+
code: "custom",
|
|
111
|
+
message: `creditor.iban is required for ${data.paymentType} payments`,
|
|
112
|
+
path: ["creditor", "iban"]
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
if (data.paymentType === "SWIFT") {
|
|
118
|
+
const hasIban = !!data.creditor.iban;
|
|
119
|
+
const hasBban = !!data.creditor.number && !!(data.creditor.swiftBic ?? data.creditor.bicCor);
|
|
120
|
+
if (!hasIban && !hasBban) {
|
|
121
|
+
ctx.addIssue({
|
|
122
|
+
code: "custom",
|
|
123
|
+
message: "SWIFT creditor requires either iban OR (number + swiftBic/bicCor)",
|
|
124
|
+
path: ["creditor"]
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
}
|
|
91
128
|
});
|
|
92
129
|
|
|
93
130
|
const sendBatchInputSchema = zod.z.object({
|
package/dist/export/worker.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { bankAccountMetadataSchema, structuredAddressSchema, uuidv4, first, buildMultiFilterConditions as buildMultiFilterConditions$1, workflowInstanceStatusSchema, develitWorker, createInternalError, action, service } from '@develit-io/backend-sdk';
|
|
2
|
-
import { G as tables, g as accountInsertSchema, H as relations, J as initiateConnector, o as isProcessedStatus, p as isTerminalStatus, L as getNonTerminalPaymentRequestsQuery, x as toIncomingPayment, j as assignAccount, u as toBatchedPayment, y as toPaymentRequestInsert, a as FinbricksClient, F as FINBRICKS_ENDPOINTS } from '../shared/bank.
|
|
2
|
+
import { G as tables, g as accountInsertSchema, H as relations, J as initiateConnector, o as isProcessedStatus, p as isTerminalStatus, L as getNonTerminalPaymentRequestsQuery, x as toIncomingPayment, j as assignAccount, u as toBatchedPayment, y as toPaymentRequestInsert, a as FinbricksClient, F as FINBRICKS_ENDPOINTS } from '../shared/bank.CZ8MQDPa.mjs';
|
|
3
3
|
import { eq, sql, and, like, asc, desc, inArray, gte, lte, isNull, count } from 'drizzle-orm';
|
|
4
4
|
import { WorkerEntrypoint } from 'cloudflare:workers';
|
|
5
5
|
import { drizzle } from 'drizzle-orm/d1';
|
|
@@ -9,7 +9,7 @@ import { I as INSTRUCTION_PRIORITIES, C as CHARGE_BEARERS, g as PAYMENT_TYPES, b
|
|
|
9
9
|
import { CURRENCY_CODES } from '@develit-io/general-codes';
|
|
10
10
|
import 'date-fns';
|
|
11
11
|
import 'node:crypto';
|
|
12
|
-
import { h as encrypt, d as createCredentialsResolver, e as updatePaymentRequestStatusCommand, a as getPaymentRequestsByBatchIdQuery, g as getBatchByIdQuery, u as upsertBatchCommand, i as importAesKey, f as createPaymentCommand, b as getAccountByIdQuery } from '../shared/bank.
|
|
12
|
+
import { h as encrypt, d as createCredentialsResolver, e as updatePaymentRequestStatusCommand, a as getPaymentRequestsByBatchIdQuery, g as getBatchByIdQuery, u as upsertBatchCommand, i as importAesKey, f as createPaymentCommand, b as getAccountByIdQuery } from '../shared/bank.BdTj54NO.mjs';
|
|
13
13
|
import 'drizzle-orm/zod';
|
|
14
14
|
import 'drizzle-orm/sqlite-core';
|
|
15
15
|
|
|
@@ -86,6 +86,43 @@ const sendPaymentInputSchema = z.object({
|
|
|
86
86
|
creditor: bankAccountMetadataSchema,
|
|
87
87
|
debtor: bankAccountMetadataSchema,
|
|
88
88
|
sendAsSinglePayment: z.boolean().optional()
|
|
89
|
+
}).superRefine((data, ctx) => {
|
|
90
|
+
if (data.paymentType === "UNKNOWN") {
|
|
91
|
+
ctx.addIssue({
|
|
92
|
+
code: "custom",
|
|
93
|
+
message: "paymentType=UNKNOWN is not supported. Use DOMESTIC, SEPA, or SWIFT.",
|
|
94
|
+
path: ["paymentType"]
|
|
95
|
+
});
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
if (!data.debtor.iban) {
|
|
99
|
+
ctx.addIssue({
|
|
100
|
+
code: "custom",
|
|
101
|
+
message: "debtor.iban is required",
|
|
102
|
+
path: ["debtor", "iban"]
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
if (data.paymentType === "DOMESTIC" || data.paymentType === "SEPA") {
|
|
106
|
+
if (!data.creditor.iban) {
|
|
107
|
+
ctx.addIssue({
|
|
108
|
+
code: "custom",
|
|
109
|
+
message: `creditor.iban is required for ${data.paymentType} payments`,
|
|
110
|
+
path: ["creditor", "iban"]
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
if (data.paymentType === "SWIFT") {
|
|
116
|
+
const hasIban = !!data.creditor.iban;
|
|
117
|
+
const hasBban = !!data.creditor.number && !!(data.creditor.swiftBic ?? data.creditor.bicCor);
|
|
118
|
+
if (!hasIban && !hasBban) {
|
|
119
|
+
ctx.addIssue({
|
|
120
|
+
code: "custom",
|
|
121
|
+
message: "SWIFT creditor requires either iban OR (number + swiftBic/bicCor)",
|
|
122
|
+
path: ["creditor"]
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
}
|
|
89
126
|
});
|
|
90
127
|
|
|
91
128
|
const sendBatchInputSchema = z.object({
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const backendSdk = require('@develit-io/backend-sdk');
|
|
4
|
-
const ott_zod = require('../shared/bank.
|
|
4
|
+
const ott_zod = require('../shared/bank.BSX82jhx.cjs');
|
|
5
5
|
const batchLifecycle = require('../shared/bank.NF8bZBy0.cjs');
|
|
6
6
|
const drizzleOrm = require('drizzle-orm');
|
|
7
|
-
const credentialsResolver = require('../shared/bank.
|
|
7
|
+
const credentialsResolver = require('../shared/bank.CibQRM2D.cjs');
|
|
8
8
|
const cloudflare_workers = require('cloudflare:workers');
|
|
9
9
|
const cloudflare_workflows = require('cloudflare:workflows');
|
|
10
10
|
const d1 = require('drizzle-orm/d1');
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { first, uuidv4, asNonEmpty } from '@develit-io/backend-sdk';
|
|
2
|
-
import { G as tables, H as relations, v as toBatchedPaymentFromPaymentRequest, z as toPreparedPayment, J as initiateConnector, m as isPaymentCompleted } from '../shared/bank.
|
|
2
|
+
import { G as tables, H as relations, v as toBatchedPaymentFromPaymentRequest, z as toPreparedPayment, J as initiateConnector, m as isPaymentCompleted } from '../shared/bank.CZ8MQDPa.mjs';
|
|
3
3
|
import { i as isBatchAuthorized, b as isBatchFailed, d as isBatchProcessing } from '../shared/bank.XqSw509X.mjs';
|
|
4
4
|
import { eq, and, inArray } from 'drizzle-orm';
|
|
5
|
-
import { g as getBatchByIdQuery, a as getPaymentRequestsByBatchIdQuery, c as checksum, u as upsertBatchCommand, b as getAccountByIdQuery, d as createCredentialsResolver, e as updatePaymentRequestStatusCommand, f as createPaymentCommand } from '../shared/bank.
|
|
5
|
+
import { g as getBatchByIdQuery, a as getPaymentRequestsByBatchIdQuery, c as checksum, u as upsertBatchCommand, b as getAccountByIdQuery, d as createCredentialsResolver, e as updatePaymentRequestStatusCommand, f as createPaymentCommand } from '../shared/bank.BdTj54NO.mjs';
|
|
6
6
|
import { WorkflowEntrypoint } from 'cloudflare:workers';
|
|
7
7
|
import { NonRetryableError } from 'cloudflare:workflows';
|
|
8
8
|
import { drizzle } from 'drizzle-orm/d1';
|
|
@@ -322,12 +322,40 @@ function toBatchedPaymentFromPaymentRequest(sp) {
|
|
|
322
322
|
};
|
|
323
323
|
}
|
|
324
324
|
|
|
325
|
+
const MAX_REFERENCE_LENGTH = 30;
|
|
326
|
+
function buildPaymentReference(symbols) {
|
|
327
|
+
const parts = [
|
|
328
|
+
symbols.vs && `VS${symbols.vs}`,
|
|
329
|
+
symbols.ss && `SS${symbols.ss}`,
|
|
330
|
+
symbols.ks && `KS${symbols.ks}`
|
|
331
|
+
].filter(Boolean);
|
|
332
|
+
return parts.join("").slice(0, MAX_REFERENCE_LENGTH);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
const SYMBOL_LIMITS = { vs: 10, ss: 10, ks: 4 };
|
|
336
|
+
function assertSymbolLength(symbol, value) {
|
|
337
|
+
const max = SYMBOL_LIMITS[symbol];
|
|
338
|
+
if (value.length > max) {
|
|
339
|
+
throw new Error(
|
|
340
|
+
`buildEndToEndId: ${symbol.toUpperCase()} exceeds SEPA limit (${value.length} > ${max} chars): "${value}"`
|
|
341
|
+
);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
325
344
|
function buildEndToEndId(payment, options = {}) {
|
|
326
345
|
const { separator = "/" } = options;
|
|
327
346
|
const parts = [];
|
|
328
|
-
if (payment.vs)
|
|
329
|
-
|
|
330
|
-
|
|
347
|
+
if (payment.vs) {
|
|
348
|
+
assertSymbolLength("vs", payment.vs);
|
|
349
|
+
parts.push(`VS${payment.vs}`);
|
|
350
|
+
}
|
|
351
|
+
if (payment.ss) {
|
|
352
|
+
assertSymbolLength("ss", payment.ss);
|
|
353
|
+
parts.push(`SS${payment.ss}`);
|
|
354
|
+
}
|
|
355
|
+
if (payment.ks) {
|
|
356
|
+
assertSymbolLength("ks", payment.ks);
|
|
357
|
+
parts.push(`KS${payment.ks}`);
|
|
358
|
+
}
|
|
331
359
|
if (parts.length === 0) {
|
|
332
360
|
return payment.id.replace(/-/g, "");
|
|
333
361
|
}
|
|
@@ -488,6 +516,10 @@ const mapFinbricksAccountInsert = ({
|
|
|
488
516
|
iban: account.identification.iban
|
|
489
517
|
});
|
|
490
518
|
|
|
519
|
+
const VS_REGEX = /VS[:/\s]*(\d+)/i;
|
|
520
|
+
const SS_REGEX = /SS[:/\s]*(\d+)/i;
|
|
521
|
+
const KS_REGEX = /KS[:/\s]*(\d+)/i;
|
|
522
|
+
const extract = (haystack, regex) => haystack.match(regex)?.[1];
|
|
491
523
|
const mapReferencesToPayment = (reference) => {
|
|
492
524
|
const symbols = {
|
|
493
525
|
vs: void 0,
|
|
@@ -495,19 +527,10 @@ const mapReferencesToPayment = (reference) => {
|
|
|
495
527
|
ks: void 0
|
|
496
528
|
};
|
|
497
529
|
if (!reference) return symbols;
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
}
|
|
503
|
-
if (typeof reference === "string") {
|
|
504
|
-
const vsMatch = reference.match(/VS[:\s]*(\d+)/i);
|
|
505
|
-
const ssMatch = reference.match(/SS[:\s]*(\d+)/i);
|
|
506
|
-
const ksMatch = reference.match(/KS[:\s]*(\d+)/i);
|
|
507
|
-
if (vsMatch) symbols.vs = vsMatch[1];
|
|
508
|
-
if (ssMatch) symbols.ss = ssMatch[1];
|
|
509
|
-
if (ksMatch) symbols.ks = ksMatch[1];
|
|
510
|
-
}
|
|
530
|
+
const haystack = Array.isArray(reference) ? reference.join(" ") : reference;
|
|
531
|
+
symbols.vs = extract(haystack, VS_REGEX);
|
|
532
|
+
symbols.ss = extract(haystack, SS_REGEX);
|
|
533
|
+
symbols.ks = extract(haystack, KS_REGEX);
|
|
511
534
|
return symbols;
|
|
512
535
|
};
|
|
513
536
|
|
|
@@ -590,8 +613,23 @@ function detectPaymentType(tx, isIncoming) {
|
|
|
590
613
|
const mapFinbricksTransactionToPayment = (tx, account) => {
|
|
591
614
|
const isIncoming = tx.creditDebitIndicator === "CRDT";
|
|
592
615
|
const related = tx.entryDetails?.transactionDetails?.relatedParties;
|
|
593
|
-
const
|
|
594
|
-
const
|
|
616
|
+
const td = tx.entryDetails?.transactionDetails;
|
|
617
|
+
const referenceSources = [
|
|
618
|
+
td?.remittanceInformation?.structured?.creditorReferenceInformation?.reference,
|
|
619
|
+
td?.references?.endToEndIdentification,
|
|
620
|
+
td?.remittanceInformation?.unstructured,
|
|
621
|
+
td?.additionalRemittanceInformation,
|
|
622
|
+
td?.additionalTransactionInformation
|
|
623
|
+
];
|
|
624
|
+
const symbols = referenceSources.reduce((acc, src) => {
|
|
625
|
+
if (acc.vs && acc.ss && acc.ks) return acc;
|
|
626
|
+
const parsed = mapReferencesToPayment(src);
|
|
627
|
+
return {
|
|
628
|
+
vs: acc.vs ?? parsed.vs,
|
|
629
|
+
ss: acc.ss ?? parsed.ss,
|
|
630
|
+
ks: acc.ks ?? parsed.ks
|
|
631
|
+
};
|
|
632
|
+
}, {});
|
|
595
633
|
const debtorParsed = parseOtherIdentification(
|
|
596
634
|
related?.debtorAccount?.identification?.other?.identification
|
|
597
635
|
);
|
|
@@ -608,11 +646,9 @@ const mapFinbricksTransactionToPayment = (tx, account) => {
|
|
|
608
646
|
currency: tx.amount?.currency || "CZK",
|
|
609
647
|
paymentType: detectPaymentType(tx, isIncoming),
|
|
610
648
|
status: mapFinbricksStatus(tx.status, !!tx.bookingDate?.date),
|
|
611
|
-
message:
|
|
649
|
+
message: td?.remittanceInformation?.unstructured || td?.additionalRemittanceInformation || td?.additionalTransactionInformation || null,
|
|
612
650
|
processedAt: new Date(tx.bookingDate.date),
|
|
613
|
-
...
|
|
614
|
-
tx.entryDetails.transactionDetails?.remittanceInformation?.structured?.creditorReferenceInformation?.reference || (endToEndId && symbolsRegex.test(endToEndId) ? endToEndId : void 0)
|
|
615
|
-
),
|
|
651
|
+
...symbols,
|
|
616
652
|
creditor: {
|
|
617
653
|
holderName: related?.creditorAccount?.name || related?.creditor?.name || "Unknown",
|
|
618
654
|
iban: isIncoming ? account.iban || void 0 : related?.creditorAccount?.identification?.iban || creditorParsed.iban || void 0,
|
|
@@ -653,6 +689,21 @@ function autoVariableSymbol(paymentId) {
|
|
|
653
689
|
}
|
|
654
690
|
return String(Math.abs(hash) % 1e10).padStart(10, "0");
|
|
655
691
|
}
|
|
692
|
+
function resolveAccountIdentification(account, currency) {
|
|
693
|
+
if (account.iban) {
|
|
694
|
+
return { type: "IBAN", value: account.iban };
|
|
695
|
+
}
|
|
696
|
+
if (account.number) {
|
|
697
|
+
return {
|
|
698
|
+
type: "BBAN",
|
|
699
|
+
value: account.number,
|
|
700
|
+
...currency && { currency }
|
|
701
|
+
};
|
|
702
|
+
}
|
|
703
|
+
throw backendSdk.createInternalError(null, {
|
|
704
|
+
message: "Account has neither IBAN nor account number \u2014 cannot identify for foreign payment"
|
|
705
|
+
});
|
|
706
|
+
}
|
|
656
707
|
function mapToFinbricksAddress(addr) {
|
|
657
708
|
if (!addr) return void 0;
|
|
658
709
|
return {
|
|
@@ -911,6 +962,21 @@ class FinbricksConnector extends IBankConnector {
|
|
|
911
962
|
);
|
|
912
963
|
const clientId = await this.getClientId(debtorAccount.id);
|
|
913
964
|
const creditorAddress = mapToFinbricksAddress(payment.creditor.address);
|
|
965
|
+
const debtorIdentification = resolveAccountIdentification(payment.debtor);
|
|
966
|
+
const creditorIdentification = resolveAccountIdentification(
|
|
967
|
+
payment.creditor,
|
|
968
|
+
payment.currency
|
|
969
|
+
);
|
|
970
|
+
const creditorBic = payment.creditor.swiftBic ?? payment.creditor.bicCor;
|
|
971
|
+
const creditorAgent = creditorIdentification.type === "BBAN" && creditorBic ? {
|
|
972
|
+
financialInstitutionIdentification: { bic: creditorBic }
|
|
973
|
+
} : void 0;
|
|
974
|
+
const reference = buildPaymentReference({
|
|
975
|
+
vs: payment.vs,
|
|
976
|
+
ss: payment.ss,
|
|
977
|
+
ks: payment.ks
|
|
978
|
+
});
|
|
979
|
+
const unstructured = [reference, payment.message?.trim()].filter(Boolean).join(" ").slice(0, 140) || void 0;
|
|
914
980
|
const bankRefId = backendSdk.uuidv4();
|
|
915
981
|
const [response, error] = await backendSdk.useResult(
|
|
916
982
|
this.finbricks.request({
|
|
@@ -930,21 +996,17 @@ class FinbricksConnector extends IBankConnector {
|
|
|
930
996
|
},
|
|
931
997
|
chargeBearer: payment.chargeBearer || "SHA",
|
|
932
998
|
debtor: {
|
|
933
|
-
accountIdentification:
|
|
934
|
-
type: "IBAN",
|
|
935
|
-
value: payment.debtor.iban
|
|
936
|
-
},
|
|
999
|
+
accountIdentification: debtorIdentification,
|
|
937
1000
|
debtorName: payment.debtor.holderName,
|
|
938
1001
|
paymentProvider: this.PROVIDER
|
|
939
1002
|
},
|
|
940
1003
|
creditor: {
|
|
941
|
-
accountIdentification:
|
|
942
|
-
type: "IBAN",
|
|
943
|
-
value: payment.creditor.iban
|
|
944
|
-
},
|
|
1004
|
+
accountIdentification: creditorIdentification,
|
|
945
1005
|
creditorName: payment.creditor.holderName || "",
|
|
946
1006
|
...creditorAddress && { postalAddress: creditorAddress }
|
|
947
1007
|
},
|
|
1008
|
+
...creditorAgent && { creditorAgent },
|
|
1009
|
+
...unstructured && { remittanceInformation: { unstructured } },
|
|
948
1010
|
callbackUrl: `${this.finbricks.REDIRECT_URI}?type=paymentRequest&paymentRequestId=${payment.id}`
|
|
949
1011
|
}
|
|
950
1012
|
})
|
|
@@ -1046,6 +1108,8 @@ class FinbricksConnector extends IBankConnector {
|
|
|
1046
1108
|
creditorName: payment.creditor.holderName,
|
|
1047
1109
|
description: payment.message,
|
|
1048
1110
|
variableSymbol: payment.vs ?? (payment.ss ? void 0 : autoVariableSymbol(payment.id)),
|
|
1111
|
+
specificSymbol: payment.ss,
|
|
1112
|
+
constantSymbol: payment.ks,
|
|
1049
1113
|
callbackUrl: `${this.finbricks.REDIRECT_URI}?type=paymentRequest&paymentRequestId=${payment.id}`,
|
|
1050
1114
|
paymentProvider: this.PROVIDER
|
|
1051
1115
|
}
|
|
@@ -320,12 +320,40 @@ function toBatchedPaymentFromPaymentRequest(sp) {
|
|
|
320
320
|
};
|
|
321
321
|
}
|
|
322
322
|
|
|
323
|
+
const MAX_REFERENCE_LENGTH = 30;
|
|
324
|
+
function buildPaymentReference(symbols) {
|
|
325
|
+
const parts = [
|
|
326
|
+
symbols.vs && `VS${symbols.vs}`,
|
|
327
|
+
symbols.ss && `SS${symbols.ss}`,
|
|
328
|
+
symbols.ks && `KS${symbols.ks}`
|
|
329
|
+
].filter(Boolean);
|
|
330
|
+
return parts.join("").slice(0, MAX_REFERENCE_LENGTH);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
const SYMBOL_LIMITS = { vs: 10, ss: 10, ks: 4 };
|
|
334
|
+
function assertSymbolLength(symbol, value) {
|
|
335
|
+
const max = SYMBOL_LIMITS[symbol];
|
|
336
|
+
if (value.length > max) {
|
|
337
|
+
throw new Error(
|
|
338
|
+
`buildEndToEndId: ${symbol.toUpperCase()} exceeds SEPA limit (${value.length} > ${max} chars): "${value}"`
|
|
339
|
+
);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
323
342
|
function buildEndToEndId(payment, options = {}) {
|
|
324
343
|
const { separator = "/" } = options;
|
|
325
344
|
const parts = [];
|
|
326
|
-
if (payment.vs)
|
|
327
|
-
|
|
328
|
-
|
|
345
|
+
if (payment.vs) {
|
|
346
|
+
assertSymbolLength("vs", payment.vs);
|
|
347
|
+
parts.push(`VS${payment.vs}`);
|
|
348
|
+
}
|
|
349
|
+
if (payment.ss) {
|
|
350
|
+
assertSymbolLength("ss", payment.ss);
|
|
351
|
+
parts.push(`SS${payment.ss}`);
|
|
352
|
+
}
|
|
353
|
+
if (payment.ks) {
|
|
354
|
+
assertSymbolLength("ks", payment.ks);
|
|
355
|
+
parts.push(`KS${payment.ks}`);
|
|
356
|
+
}
|
|
329
357
|
if (parts.length === 0) {
|
|
330
358
|
return payment.id.replace(/-/g, "");
|
|
331
359
|
}
|
|
@@ -486,6 +514,10 @@ const mapFinbricksAccountInsert = ({
|
|
|
486
514
|
iban: account.identification.iban
|
|
487
515
|
});
|
|
488
516
|
|
|
517
|
+
const VS_REGEX = /VS[:/\s]*(\d+)/i;
|
|
518
|
+
const SS_REGEX = /SS[:/\s]*(\d+)/i;
|
|
519
|
+
const KS_REGEX = /KS[:/\s]*(\d+)/i;
|
|
520
|
+
const extract = (haystack, regex) => haystack.match(regex)?.[1];
|
|
489
521
|
const mapReferencesToPayment = (reference) => {
|
|
490
522
|
const symbols = {
|
|
491
523
|
vs: void 0,
|
|
@@ -493,19 +525,10 @@ const mapReferencesToPayment = (reference) => {
|
|
|
493
525
|
ks: void 0
|
|
494
526
|
};
|
|
495
527
|
if (!reference) return symbols;
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
}
|
|
501
|
-
if (typeof reference === "string") {
|
|
502
|
-
const vsMatch = reference.match(/VS[:\s]*(\d+)/i);
|
|
503
|
-
const ssMatch = reference.match(/SS[:\s]*(\d+)/i);
|
|
504
|
-
const ksMatch = reference.match(/KS[:\s]*(\d+)/i);
|
|
505
|
-
if (vsMatch) symbols.vs = vsMatch[1];
|
|
506
|
-
if (ssMatch) symbols.ss = ssMatch[1];
|
|
507
|
-
if (ksMatch) symbols.ks = ksMatch[1];
|
|
508
|
-
}
|
|
528
|
+
const haystack = Array.isArray(reference) ? reference.join(" ") : reference;
|
|
529
|
+
symbols.vs = extract(haystack, VS_REGEX);
|
|
530
|
+
symbols.ss = extract(haystack, SS_REGEX);
|
|
531
|
+
symbols.ks = extract(haystack, KS_REGEX);
|
|
509
532
|
return symbols;
|
|
510
533
|
};
|
|
511
534
|
|
|
@@ -588,8 +611,23 @@ function detectPaymentType(tx, isIncoming) {
|
|
|
588
611
|
const mapFinbricksTransactionToPayment = (tx, account) => {
|
|
589
612
|
const isIncoming = tx.creditDebitIndicator === "CRDT";
|
|
590
613
|
const related = tx.entryDetails?.transactionDetails?.relatedParties;
|
|
591
|
-
const
|
|
592
|
-
const
|
|
614
|
+
const td = tx.entryDetails?.transactionDetails;
|
|
615
|
+
const referenceSources = [
|
|
616
|
+
td?.remittanceInformation?.structured?.creditorReferenceInformation?.reference,
|
|
617
|
+
td?.references?.endToEndIdentification,
|
|
618
|
+
td?.remittanceInformation?.unstructured,
|
|
619
|
+
td?.additionalRemittanceInformation,
|
|
620
|
+
td?.additionalTransactionInformation
|
|
621
|
+
];
|
|
622
|
+
const symbols = referenceSources.reduce((acc, src) => {
|
|
623
|
+
if (acc.vs && acc.ss && acc.ks) return acc;
|
|
624
|
+
const parsed = mapReferencesToPayment(src);
|
|
625
|
+
return {
|
|
626
|
+
vs: acc.vs ?? parsed.vs,
|
|
627
|
+
ss: acc.ss ?? parsed.ss,
|
|
628
|
+
ks: acc.ks ?? parsed.ks
|
|
629
|
+
};
|
|
630
|
+
}, {});
|
|
593
631
|
const debtorParsed = parseOtherIdentification(
|
|
594
632
|
related?.debtorAccount?.identification?.other?.identification
|
|
595
633
|
);
|
|
@@ -606,11 +644,9 @@ const mapFinbricksTransactionToPayment = (tx, account) => {
|
|
|
606
644
|
currency: tx.amount?.currency || "CZK",
|
|
607
645
|
paymentType: detectPaymentType(tx, isIncoming),
|
|
608
646
|
status: mapFinbricksStatus(tx.status, !!tx.bookingDate?.date),
|
|
609
|
-
message:
|
|
647
|
+
message: td?.remittanceInformation?.unstructured || td?.additionalRemittanceInformation || td?.additionalTransactionInformation || null,
|
|
610
648
|
processedAt: new Date(tx.bookingDate.date),
|
|
611
|
-
...
|
|
612
|
-
tx.entryDetails.transactionDetails?.remittanceInformation?.structured?.creditorReferenceInformation?.reference || (endToEndId && symbolsRegex.test(endToEndId) ? endToEndId : void 0)
|
|
613
|
-
),
|
|
649
|
+
...symbols,
|
|
614
650
|
creditor: {
|
|
615
651
|
holderName: related?.creditorAccount?.name || related?.creditor?.name || "Unknown",
|
|
616
652
|
iban: isIncoming ? account.iban || void 0 : related?.creditorAccount?.identification?.iban || creditorParsed.iban || void 0,
|
|
@@ -651,6 +687,21 @@ function autoVariableSymbol(paymentId) {
|
|
|
651
687
|
}
|
|
652
688
|
return String(Math.abs(hash) % 1e10).padStart(10, "0");
|
|
653
689
|
}
|
|
690
|
+
function resolveAccountIdentification(account, currency) {
|
|
691
|
+
if (account.iban) {
|
|
692
|
+
return { type: "IBAN", value: account.iban };
|
|
693
|
+
}
|
|
694
|
+
if (account.number) {
|
|
695
|
+
return {
|
|
696
|
+
type: "BBAN",
|
|
697
|
+
value: account.number,
|
|
698
|
+
...currency && { currency }
|
|
699
|
+
};
|
|
700
|
+
}
|
|
701
|
+
throw createInternalError(null, {
|
|
702
|
+
message: "Account has neither IBAN nor account number \u2014 cannot identify for foreign payment"
|
|
703
|
+
});
|
|
704
|
+
}
|
|
654
705
|
function mapToFinbricksAddress(addr) {
|
|
655
706
|
if (!addr) return void 0;
|
|
656
707
|
return {
|
|
@@ -909,6 +960,21 @@ class FinbricksConnector extends IBankConnector {
|
|
|
909
960
|
);
|
|
910
961
|
const clientId = await this.getClientId(debtorAccount.id);
|
|
911
962
|
const creditorAddress = mapToFinbricksAddress(payment.creditor.address);
|
|
963
|
+
const debtorIdentification = resolveAccountIdentification(payment.debtor);
|
|
964
|
+
const creditorIdentification = resolveAccountIdentification(
|
|
965
|
+
payment.creditor,
|
|
966
|
+
payment.currency
|
|
967
|
+
);
|
|
968
|
+
const creditorBic = payment.creditor.swiftBic ?? payment.creditor.bicCor;
|
|
969
|
+
const creditorAgent = creditorIdentification.type === "BBAN" && creditorBic ? {
|
|
970
|
+
financialInstitutionIdentification: { bic: creditorBic }
|
|
971
|
+
} : void 0;
|
|
972
|
+
const reference = buildPaymentReference({
|
|
973
|
+
vs: payment.vs,
|
|
974
|
+
ss: payment.ss,
|
|
975
|
+
ks: payment.ks
|
|
976
|
+
});
|
|
977
|
+
const unstructured = [reference, payment.message?.trim()].filter(Boolean).join(" ").slice(0, 140) || void 0;
|
|
912
978
|
const bankRefId = uuidv4();
|
|
913
979
|
const [response, error] = await useResult(
|
|
914
980
|
this.finbricks.request({
|
|
@@ -928,21 +994,17 @@ class FinbricksConnector extends IBankConnector {
|
|
|
928
994
|
},
|
|
929
995
|
chargeBearer: payment.chargeBearer || "SHA",
|
|
930
996
|
debtor: {
|
|
931
|
-
accountIdentification:
|
|
932
|
-
type: "IBAN",
|
|
933
|
-
value: payment.debtor.iban
|
|
934
|
-
},
|
|
997
|
+
accountIdentification: debtorIdentification,
|
|
935
998
|
debtorName: payment.debtor.holderName,
|
|
936
999
|
paymentProvider: this.PROVIDER
|
|
937
1000
|
},
|
|
938
1001
|
creditor: {
|
|
939
|
-
accountIdentification:
|
|
940
|
-
type: "IBAN",
|
|
941
|
-
value: payment.creditor.iban
|
|
942
|
-
},
|
|
1002
|
+
accountIdentification: creditorIdentification,
|
|
943
1003
|
creditorName: payment.creditor.holderName || "",
|
|
944
1004
|
...creditorAddress && { postalAddress: creditorAddress }
|
|
945
1005
|
},
|
|
1006
|
+
...creditorAgent && { creditorAgent },
|
|
1007
|
+
...unstructured && { remittanceInformation: { unstructured } },
|
|
946
1008
|
callbackUrl: `${this.finbricks.REDIRECT_URI}?type=paymentRequest&paymentRequestId=${payment.id}`
|
|
947
1009
|
}
|
|
948
1010
|
})
|
|
@@ -1044,6 +1106,8 @@ class FinbricksConnector extends IBankConnector {
|
|
|
1044
1106
|
creditorName: payment.creditor.holderName,
|
|
1045
1107
|
description: payment.message,
|
|
1046
1108
|
variableSymbol: payment.vs ?? (payment.ss ? void 0 : autoVariableSymbol(payment.id)),
|
|
1109
|
+
specificSymbol: payment.ss,
|
|
1110
|
+
constantSymbol: payment.ks,
|
|
1047
1111
|
callbackUrl: `${this.finbricks.REDIRECT_URI}?type=paymentRequest&paymentRequestId=${payment.id}`,
|
|
1048
1112
|
paymentProvider: this.PROVIDER
|
|
1049
1113
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const drizzleOrm = require('drizzle-orm');
|
|
4
|
-
const ott_zod = require('./bank.
|
|
4
|
+
const ott_zod = require('./bank.BSX82jhx.cjs');
|
|
5
5
|
const backendSdk = require('@develit-io/backend-sdk');
|
|
6
6
|
require('./bank.9Yw4KHyl.cjs');
|
|
7
7
|
require('date-fns');
|
package/dist/types.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const ott_zod = require('./shared/bank.
|
|
3
|
+
const ott_zod = require('./shared/bank.BSX82jhx.cjs');
|
|
4
4
|
const database_schema = require('./shared/bank.9Yw4KHyl.cjs');
|
|
5
5
|
const batchLifecycle = require('./shared/bank.NF8bZBy0.cjs');
|
|
6
6
|
const generalCodes = require('@develit-io/general-codes');
|
package/dist/types.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { B as BASE_TERMINAL_STATUSES, C as CsobConnector, D as DbuConnector, E as ErsteConnector, F as FINBRICKS_ENDPOINTS, a as FinbricksClient, b as FinbricksConnector, I as IBankConnector, K as KBConnector, M as MockCobsConnector, c as MockConnector, d as accountCredentialsInsertSchema, e as accountCredentialsSelectSchema, f as accountCredentialsUpdateSchema, g as accountInsertSchema, h as accountSelectSchema, i as accountUpdateSchema, j as assignAccount, k as dbuAccountConfigSchema, l as hasPaymentAccountAssigned, m as isPaymentCompleted, n as isPendingStatus, o as isProcessedStatus, p as isTerminalStatus, q as ottInsertSchema, r as ottSelectSchema, s as ottUpdateSchema, t as signFinbricksJws, u as toBatchedPayment, v as toBatchedPaymentFromPaymentRequest, w as toCompletedPayment, x as toIncomingPayment, y as toPaymentRequestInsert, z as toPreparedPayment, A as useFinbricksFetch } from './shared/bank.
|
|
1
|
+
export { B as BASE_TERMINAL_STATUSES, C as CsobConnector, D as DbuConnector, E as ErsteConnector, F as FINBRICKS_ENDPOINTS, a as FinbricksClient, b as FinbricksConnector, I as IBankConnector, K as KBConnector, M as MockCobsConnector, c as MockConnector, d as accountCredentialsInsertSchema, e as accountCredentialsSelectSchema, f as accountCredentialsUpdateSchema, g as accountInsertSchema, h as accountSelectSchema, i as accountUpdateSchema, j as assignAccount, k as dbuAccountConfigSchema, l as hasPaymentAccountAssigned, m as isPaymentCompleted, n as isPendingStatus, o as isProcessedStatus, p as isTerminalStatus, q as ottInsertSchema, r as ottSelectSchema, s as ottUpdateSchema, t as signFinbricksJws, u as toBatchedPayment, v as toBatchedPaymentFromPaymentRequest, w as toCompletedPayment, x as toIncomingPayment, y as toPaymentRequestInsert, z as toPreparedPayment, A as useFinbricksFetch } from './shared/bank.CZ8MQDPa.mjs';
|
|
2
2
|
export { A as ACCOUNT_STATUSES, B as BATCH_MODES, a as BATCH_STATUES, a as BATCH_STATUSES, C as CHARGE_BEARERS, b as CONNECTOR_KEYS, c as COUNTRY_CODES, d as CREDENTIALS_TYPES, I as INSTRUCTION_PRIORITIES, P as PAYMENT_DIRECTIONS, e as PAYMENT_REQUEST_STATUSES, f as PAYMENT_STATUSES, g as PAYMENT_TYPES, T as TOKEN_TYPES } from './shared/bank.BzDNLxB_.mjs';
|
|
3
3
|
export { i as isBatchAuthorized, a as isBatchCompleted, b as isBatchFailed, c as isBatchInitiated, d as isBatchProcessing, e as isBatchReadyToSign } from './shared/bank.XqSw509X.mjs';
|
|
4
4
|
export { BANK_CODES, CURRENCY_CODES } from '@develit-io/general-codes';
|