@develit-services/bank 0.8.0 → 0.8.1

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/README.md CHANGED
@@ -161,6 +161,37 @@ Planovana uloha (`CRON_BATCH_STATUSES`) pravidelne vola `update-batch-statuses`,
161
161
  - Aktualizuje stavy batchu a jednotlivych plateb
162
162
  - Emituje eventy pro zmenene platby
163
163
 
164
+ ## Synchronni odeslani platby (sendPaymentSync)
165
+
166
+ Alternativa k batch flow. Akce `send-payment-sync` odesle platbu **synchronne** primo do banky a vrati `authorizationUrl` pro podpis uzivatelem.
167
+
168
+ ```
169
+ SendPaymentSyncInput (API vstup)
170
+
171
+
172
+ Resolve uctu (debtorIban + currency)
173
+
174
+
175
+ Inicializace konektoru
176
+
177
+
178
+ connector.initiate*Payment() (DOMESTIC/SEPA/SWIFT)
179
+
180
+
181
+ { authorizationUrl } → vraceno volajicimu
182
+ ```
183
+
184
+ ### Klicove rozdily oproti batch flow
185
+
186
+ | | `send-payment` (batch) | `send-payment-sync` (sync) |
187
+ |---|---|---|
188
+ | Zpracovani | Asynchronni (queue → batch → workflow) | Synchronni (primo connector) |
189
+ | Ulozeni do DB | Ano (payment + batch) | Ne (prijde az pres sync) |
190
+ | Autorizacni URL | Az po `process-batch` | Ihned v response |
191
+ | Pouziti | Hromadne platby, backoffice | Uzivatelska akce, okamzita platba |
192
+
193
+ Platba se do systemu (DB) dostane az nasledne pres `syncAccountPayments` workflow, ktery periodicky stahuje transakce z banky.
194
+
164
195
  ## Synchronizace uctu
165
196
 
166
197
  Kazdy pripojeny ucet ma workflow `SyncAccountPayments`, ktery bezi v nekonecne smycce:
@@ -286,6 +317,7 @@ Bank service je **RPC worker** - nema vlastni verejne HTTP endpointy. Vsechny ak
286
317
  | Akce | Popis |
287
318
  |------|-------|
288
319
  | `send-payment` | Odesle platbu (vlozi do fronty pro batchovani) |
320
+ | `send-payment-sync` | Odesle platbu synchronne primo do banky, vrati `authorizationUrl` (bez queue/batch/DB) |
289
321
  | `get-payments` | Seznam plateb s paginaci a filtry (ucet, castka, mena, smer, datum, stav) |
290
322
  | `simulate-deposit` | Testovaci: vytvori prichozi platbu ve stavu COMPLETED |
291
323
 
@@ -378,4 +410,6 @@ Format: `{CATEGORY}-B-{NUMBER}`
378
410
  | `VALID-B-001` | 400 | Invalid connector key |
379
411
  | `VALID-B-002` | 400 | One-time token expired |
380
412
  | `VALID-B-003` | 422 | Unsupported account |
413
+ | `VALID-B-004` | 422 | No account found for single payment (IBAN + currency mismatch) |
414
+ | `VALID-B-005` | 400 | Unsupported payment type for single payment |
381
415
  | `SYS-B-001` | 501 | Not implemented |
@@ -434,6 +434,8 @@ const disconnectAccountInputSchema = zod.z.object({
434
434
  accountId: zod.z.uuid()
435
435
  });
436
436
 
437
+ const sendPaymentSyncInputSchema = sendPaymentInputSchema;
438
+
437
439
  var __defProp = Object.defineProperty;
438
440
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
439
441
  var __decorateClass = (decorators, target, key, kind) => {
@@ -1042,6 +1044,52 @@ let BankServiceBase = class extends backendSdk.develitWorker(cloudflare_workers.
1042
1044
  }
1043
1045
  );
1044
1046
  }
1047
+ async sendPaymentSync(input) {
1048
+ return this.handleAction(
1049
+ { data: input, schema: sendPaymentSyncInputSchema },
1050
+ { successMessage: "Payment initiated successfully" },
1051
+ async (data) => {
1052
+ const incomingPayment = mock_connector.toIncomingPayment(data);
1053
+ const accounts = await this._getAccounts();
1054
+ const account = accounts.find(
1055
+ (acc) => acc.iban === incomingPayment.debtorIban && acc.currency === incomingPayment.currency
1056
+ );
1057
+ if (!account) {
1058
+ throw backendSdk.createInternalError(null, {
1059
+ message: `No account found for IBAN ${incomingPayment.debtorIban} with currency ${incomingPayment.currency}`,
1060
+ code: "VALID-B-004",
1061
+ status: 422
1062
+ });
1063
+ }
1064
+ const batchedPayment = mock_connector.toBatchedPayment(
1065
+ mock_connector.assignAccount(incomingPayment, account)
1066
+ );
1067
+ const connector = await this._initiateBankConnector({
1068
+ connectorKey: account.connectorKey
1069
+ });
1070
+ const initiate = () => {
1071
+ switch (data.paymentType) {
1072
+ case "DOMESTIC":
1073
+ return connector.initiateDomesticPayment(batchedPayment);
1074
+ case "SEPA":
1075
+ return connector.initiateSEPAPayment(batchedPayment);
1076
+ case "SWIFT":
1077
+ return connector.initiateForeignPayment(batchedPayment);
1078
+ default:
1079
+ throw backendSdk.createInternalError(null, {
1080
+ message: `Unsupported payment type for single payment: ${data.paymentType}`,
1081
+ code: "VALID-B-005",
1082
+ status: 400
1083
+ });
1084
+ }
1085
+ };
1086
+ const initiated = await initiate();
1087
+ return {
1088
+ authorizationUrl: initiated.authorizationUrl
1089
+ };
1090
+ }
1091
+ );
1092
+ }
1045
1093
  async getBankAccounts(input) {
1046
1094
  return this.handleAction(
1047
1095
  { data: input, schema: getBankAccountsInputSchema },
@@ -1245,6 +1293,9 @@ __decorateClass([
1245
1293
  __decorateClass([
1246
1294
  backendSdk.action("send-payment")
1247
1295
  ], BankServiceBase.prototype, "sendPayment", 1);
1296
+ __decorateClass([
1297
+ backendSdk.action("send-payment-sync")
1298
+ ], BankServiceBase.prototype, "sendPaymentSync", 1);
1248
1299
  __decorateClass([
1249
1300
  backendSdk.action("get-bank-accounts")
1250
1301
  ], BankServiceBase.prototype, "getBankAccounts", 1);
@@ -1,7 +1,7 @@
1
1
  import { A as AccountSelectType, P as PaymentSelectType, B as BatchSelectType, L as LastSyncMetadata, C as ConfigEnvironmentBank, t as tables, a as ConnectorKey, I as IBankConnector } from '../shared/bank.BJ7LqYtJ.cjs';
2
2
  import * as _develit_io_backend_sdk from '@develit-io/backend-sdk';
3
3
  import { WorkflowInstanceStatus, IRPCResponse } from '@develit-io/backend-sdk';
4
- import { S as SendPaymentInput, a as SendPaymentOutput } from '../shared/bank.COC0tqmL.cjs';
4
+ import { S as SendPaymentInput, a as SendPaymentOutput, b as SendPaymentSyncInput, c as SendPaymentSyncOutput } from '../shared/bank.C0p-hLzn.cjs';
5
5
  import { WorkerEntrypoint } from 'cloudflare:workers';
6
6
  import { DrizzleD1Database } from 'drizzle-orm/d1';
7
7
  import { z } from 'zod';
@@ -1875,7 +1875,26 @@ declare class BankServiceBase extends BankServiceBase_base {
1875
1875
  */
1876
1876
  authorizeAccount(input: AuthorizeAccountInput): Promise<IRPCResponse<AuthorizeAccountOutput>>;
1877
1877
  simulateDeposit(input: SimulateDepositInput): Promise<IRPCResponse<SimulateDepositOutput>>;
1878
+ /**
1879
+ * Queues a payment for asynchronous batch processing.
1880
+ *
1881
+ * The payment is pushed to `PAYMENTS_READY_TO_BATCH_QUEUE` and later grouped
1882
+ * into a batch by `addPaymentsToBatch`. The batch must then be submitted via
1883
+ * `processBatch` to actually send it to the bank.
1884
+ *
1885
+ * @see {@link sendPaymentSync} for synchronous (immediate) payment submission
1886
+ */
1878
1887
  sendPayment(input: SendPaymentInput): Promise<IRPCResponse<SendPaymentOutput>>;
1888
+ /**
1889
+ * Sends a payment synchronously directly to the bank via the connector.
1890
+ *
1891
+ * Unlike {@link sendPayment}, this method bypasses the queue/batch pipeline
1892
+ * and returns the authorization URL immediately. The payment is **not** stored
1893
+ * in the database — it will arrive later through the `syncAccountPayments` workflow.
1894
+ *
1895
+ * @returns Authorization URL for the user to sign the payment at the bank
1896
+ */
1897
+ sendPaymentSync(input: SendPaymentSyncInput): Promise<IRPCResponse<SendPaymentSyncOutput>>;
1879
1898
  getBankAccounts(input: GetBankAccountsInput): Promise<IRPCResponse<GetBankAccountsOutput>>;
1880
1899
  updateAccount(input: UpdateAccountInput): Promise<IRPCResponse<UpdateAccountOutput>>;
1881
1900
  disconnectAccount(input: DisconnectAccountInput): Promise<IRPCResponse<DisconnectAccountOutput>>;
@@ -1,7 +1,7 @@
1
1
  import { A as AccountSelectType, P as PaymentSelectType, B as BatchSelectType, L as LastSyncMetadata, C as ConfigEnvironmentBank, t as tables, a as ConnectorKey, I as IBankConnector } from '../shared/bank.BJ7LqYtJ.mjs';
2
2
  import * as _develit_io_backend_sdk from '@develit-io/backend-sdk';
3
3
  import { WorkflowInstanceStatus, IRPCResponse } from '@develit-io/backend-sdk';
4
- import { S as SendPaymentInput, a as SendPaymentOutput } from '../shared/bank.COC0tqmL.mjs';
4
+ import { S as SendPaymentInput, a as SendPaymentOutput, b as SendPaymentSyncInput, c as SendPaymentSyncOutput } from '../shared/bank.C0p-hLzn.mjs';
5
5
  import { WorkerEntrypoint } from 'cloudflare:workers';
6
6
  import { DrizzleD1Database } from 'drizzle-orm/d1';
7
7
  import { z } from 'zod';
@@ -1875,7 +1875,26 @@ declare class BankServiceBase extends BankServiceBase_base {
1875
1875
  */
1876
1876
  authorizeAccount(input: AuthorizeAccountInput): Promise<IRPCResponse<AuthorizeAccountOutput>>;
1877
1877
  simulateDeposit(input: SimulateDepositInput): Promise<IRPCResponse<SimulateDepositOutput>>;
1878
+ /**
1879
+ * Queues a payment for asynchronous batch processing.
1880
+ *
1881
+ * The payment is pushed to `PAYMENTS_READY_TO_BATCH_QUEUE` and later grouped
1882
+ * into a batch by `addPaymentsToBatch`. The batch must then be submitted via
1883
+ * `processBatch` to actually send it to the bank.
1884
+ *
1885
+ * @see {@link sendPaymentSync} for synchronous (immediate) payment submission
1886
+ */
1878
1887
  sendPayment(input: SendPaymentInput): Promise<IRPCResponse<SendPaymentOutput>>;
1888
+ /**
1889
+ * Sends a payment synchronously directly to the bank via the connector.
1890
+ *
1891
+ * Unlike {@link sendPayment}, this method bypasses the queue/batch pipeline
1892
+ * and returns the authorization URL immediately. The payment is **not** stored
1893
+ * in the database — it will arrive later through the `syncAccountPayments` workflow.
1894
+ *
1895
+ * @returns Authorization URL for the user to sign the payment at the bank
1896
+ */
1897
+ sendPaymentSync(input: SendPaymentSyncInput): Promise<IRPCResponse<SendPaymentSyncOutput>>;
1879
1898
  getBankAccounts(input: GetBankAccountsInput): Promise<IRPCResponse<GetBankAccountsOutput>>;
1880
1899
  updateAccount(input: UpdateAccountInput): Promise<IRPCResponse<UpdateAccountOutput>>;
1881
1900
  disconnectAccount(input: DisconnectAccountInput): Promise<IRPCResponse<DisconnectAccountOutput>>;
@@ -1,7 +1,7 @@
1
1
  import { A as AccountSelectType, P as PaymentSelectType, B as BatchSelectType, L as LastSyncMetadata, C as ConfigEnvironmentBank, t as tables, a as ConnectorKey, I as IBankConnector } from '../shared/bank.BJ7LqYtJ.js';
2
2
  import * as _develit_io_backend_sdk from '@develit-io/backend-sdk';
3
3
  import { WorkflowInstanceStatus, IRPCResponse } from '@develit-io/backend-sdk';
4
- import { S as SendPaymentInput, a as SendPaymentOutput } from '../shared/bank.COC0tqmL.js';
4
+ import { S as SendPaymentInput, a as SendPaymentOutput, b as SendPaymentSyncInput, c as SendPaymentSyncOutput } from '../shared/bank.C0p-hLzn.js';
5
5
  import { WorkerEntrypoint } from 'cloudflare:workers';
6
6
  import { DrizzleD1Database } from 'drizzle-orm/d1';
7
7
  import { z } from 'zod';
@@ -1875,7 +1875,26 @@ declare class BankServiceBase extends BankServiceBase_base {
1875
1875
  */
1876
1876
  authorizeAccount(input: AuthorizeAccountInput): Promise<IRPCResponse<AuthorizeAccountOutput>>;
1877
1877
  simulateDeposit(input: SimulateDepositInput): Promise<IRPCResponse<SimulateDepositOutput>>;
1878
+ /**
1879
+ * Queues a payment for asynchronous batch processing.
1880
+ *
1881
+ * The payment is pushed to `PAYMENTS_READY_TO_BATCH_QUEUE` and later grouped
1882
+ * into a batch by `addPaymentsToBatch`. The batch must then be submitted via
1883
+ * `processBatch` to actually send it to the bank.
1884
+ *
1885
+ * @see {@link sendPaymentSync} for synchronous (immediate) payment submission
1886
+ */
1878
1887
  sendPayment(input: SendPaymentInput): Promise<IRPCResponse<SendPaymentOutput>>;
1888
+ /**
1889
+ * Sends a payment synchronously directly to the bank via the connector.
1890
+ *
1891
+ * Unlike {@link sendPayment}, this method bypasses the queue/batch pipeline
1892
+ * and returns the authorization URL immediately. The payment is **not** stored
1893
+ * in the database — it will arrive later through the `syncAccountPayments` workflow.
1894
+ *
1895
+ * @returns Authorization URL for the user to sign the payment at the bank
1896
+ */
1897
+ sendPaymentSync(input: SendPaymentSyncInput): Promise<IRPCResponse<SendPaymentSyncOutput>>;
1879
1898
  getBankAccounts(input: GetBankAccountsInput): Promise<IRPCResponse<GetBankAccountsOutput>>;
1880
1899
  updateAccount(input: UpdateAccountInput): Promise<IRPCResponse<UpdateAccountOutput>>;
1881
1900
  disconnectAccount(input: DisconnectAccountInput): Promise<IRPCResponse<DisconnectAccountOutput>>;
@@ -432,6 +432,8 @@ const disconnectAccountInputSchema = z.object({
432
432
  accountId: z.uuid()
433
433
  });
434
434
 
435
+ const sendPaymentSyncInputSchema = sendPaymentInputSchema;
436
+
435
437
  var __defProp = Object.defineProperty;
436
438
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
437
439
  var __decorateClass = (decorators, target, key, kind) => {
@@ -1040,6 +1042,52 @@ let BankServiceBase = class extends develitWorker(WorkerEntrypoint) {
1040
1042
  }
1041
1043
  );
1042
1044
  }
1045
+ async sendPaymentSync(input) {
1046
+ return this.handleAction(
1047
+ { data: input, schema: sendPaymentSyncInputSchema },
1048
+ { successMessage: "Payment initiated successfully" },
1049
+ async (data) => {
1050
+ const incomingPayment = toIncomingPayment(data);
1051
+ const accounts = await this._getAccounts();
1052
+ const account = accounts.find(
1053
+ (acc) => acc.iban === incomingPayment.debtorIban && acc.currency === incomingPayment.currency
1054
+ );
1055
+ if (!account) {
1056
+ throw createInternalError(null, {
1057
+ message: `No account found for IBAN ${incomingPayment.debtorIban} with currency ${incomingPayment.currency}`,
1058
+ code: "VALID-B-004",
1059
+ status: 422
1060
+ });
1061
+ }
1062
+ const batchedPayment = toBatchedPayment(
1063
+ assignAccount(incomingPayment, account)
1064
+ );
1065
+ const connector = await this._initiateBankConnector({
1066
+ connectorKey: account.connectorKey
1067
+ });
1068
+ const initiate = () => {
1069
+ switch (data.paymentType) {
1070
+ case "DOMESTIC":
1071
+ return connector.initiateDomesticPayment(batchedPayment);
1072
+ case "SEPA":
1073
+ return connector.initiateSEPAPayment(batchedPayment);
1074
+ case "SWIFT":
1075
+ return connector.initiateForeignPayment(batchedPayment);
1076
+ default:
1077
+ throw createInternalError(null, {
1078
+ message: `Unsupported payment type for single payment: ${data.paymentType}`,
1079
+ code: "VALID-B-005",
1080
+ status: 400
1081
+ });
1082
+ }
1083
+ };
1084
+ const initiated = await initiate();
1085
+ return {
1086
+ authorizationUrl: initiated.authorizationUrl
1087
+ };
1088
+ }
1089
+ );
1090
+ }
1043
1091
  async getBankAccounts(input) {
1044
1092
  return this.handleAction(
1045
1093
  { data: input, schema: getBankAccountsInputSchema },
@@ -1243,6 +1291,9 @@ __decorateClass([
1243
1291
  __decorateClass([
1244
1292
  action("send-payment")
1245
1293
  ], BankServiceBase.prototype, "sendPayment", 1);
1294
+ __decorateClass([
1295
+ action("send-payment-sync")
1296
+ ], BankServiceBase.prototype, "sendPaymentSync", 1);
1246
1297
  __decorateClass([
1247
1298
  action("get-bank-accounts")
1248
1299
  ], BankServiceBase.prototype, "getBankAccounts", 1);