Added FinTsClientConfiguration to centralize configuration of FinTsClient

This commit is contained in:
dankito 2024-08-20 10:43:52 +02:00
parent 8f079d1404
commit 6f5eabf144
7 changed files with 85 additions and 62 deletions

View File

@ -7,6 +7,7 @@ import net.dankito.banking.client.model.response.ErrorCode
import net.dankito.banking.client.model.response.GetAccountDataResponse import net.dankito.banking.client.model.response.GetAccountDataResponse
import net.dankito.banking.client.model.response.TransferMoneyResponse import net.dankito.banking.client.model.response.TransferMoneyResponse
import net.dankito.banking.fints.callback.FinTsClientCallback import net.dankito.banking.fints.callback.FinTsClientCallback
import net.dankito.banking.fints.config.FinTsClientConfiguration
import net.dankito.banking.fints.mapper.FinTsModelMapper import net.dankito.banking.fints.mapper.FinTsModelMapper
import net.dankito.banking.fints.model.* import net.dankito.banking.fints.model.*
import net.dankito.banking.fints.response.client.FinTsClientResponse import net.dankito.banking.fints.response.client.FinTsClientResponse
@ -14,16 +15,11 @@ import net.dankito.banking.fints.response.client.GetAccountInfoResponse
import net.dankito.banking.fints.response.client.GetAccountTransactionsResponse import net.dankito.banking.fints.response.client.GetAccountTransactionsResponse
import net.dankito.banking.fints.response.segments.AccountType import net.dankito.banking.fints.response.segments.AccountType
import net.dankito.banking.fints.util.BicFinder import net.dankito.banking.fints.util.BicFinder
import net.dankito.banking.fints.util.FinTsServerAddressFinder
import net.dankito.banking.fints.webclient.IWebClient
import kotlin.jvm.JvmOverloads
open class FinTsClient @JvmOverloads constructor( open class FinTsClient(
open var callback: FinTsClientCallback, protected open val config: FinTsClientConfiguration,
protected open val jobExecutor: FinTsJobExecutor = FinTsJobExecutor(), open var callback: FinTsClientCallback
protected open val finTsServerAddressFinder: FinTsServerAddressFinder = FinTsServerAddressFinder(),
protected open val product: ProductData = ProductData("15E53C26816138699C7B6A3E8", "1.0.0") // TODO: get version dynamically
) { ) {
companion object { // TODO: use the English names companion object { // TODO: use the English names
@ -31,7 +27,7 @@ open class FinTsClient @JvmOverloads constructor(
} }
constructor(callback: FinTsClientCallback, webClient: IWebClient) : this(callback, FinTsJobExecutor(RequestExecutor(webClient = webClient))) // Swift does not support default parameter values -> create constructor overloads constructor(callback: FinTsClientCallback) : this(FinTsClientConfiguration(), callback)
protected open val mapper = FinTsModelMapper() protected open val mapper = FinTsModelMapper()
@ -44,7 +40,7 @@ open class FinTsClient @JvmOverloads constructor(
} }
open suspend fun getAccountDataAsync(param: GetAccountDataParameter): GetAccountDataResponse { open suspend fun getAccountDataAsync(param: GetAccountDataParameter): GetAccountDataResponse {
val finTsServerAddress = finTsServerAddressFinder.findFinTsServerAddress(param.bankCode) val finTsServerAddress = config.finTsServerAddressFinder.findFinTsServerAddress(param.bankCode)
if (finTsServerAddress.isNullOrBlank()) { if (finTsServerAddress.isNullOrBlank()) {
return GetAccountDataResponse(ErrorCode.BankDoesNotSupportFinTs3, "Either bank does not support FinTS 3.0 or we don't know its FinTS server address", null, listOf()) return GetAccountDataResponse(ErrorCode.BankDoesNotSupportFinTs3, "Either bank does not support FinTS 3.0 or we don't know its FinTS server address", null, listOf())
} }
@ -88,9 +84,9 @@ open class FinTsClient @JvmOverloads constructor(
} }
protected open suspend fun getAccountData(param: GetAccountDataParameter, bank: BankData, account: AccountData): GetAccountTransactionsResponse { protected open suspend fun getAccountData(param: GetAccountDataParameter, bank: BankData, account: AccountData): GetAccountTransactionsResponse {
val context = JobContext(JobContextType.GetTransactions, this.callback, product, bank, account) val context = JobContext(JobContextType.GetTransactions, this.callback, config, bank, account)
return jobExecutor.getTransactionsAsync(context, mapper.toGetAccountTransactionsParameter(param, bank, account)) return config.jobExecutor.getTransactionsAsync(context, mapper.toGetAccountTransactionsParameter(param, bank, account))
} }
@ -100,7 +96,7 @@ open class FinTsClient @JvmOverloads constructor(
} }
open suspend fun transferMoneyAsync(param: TransferMoneyParameter): TransferMoneyResponse { open suspend fun transferMoneyAsync(param: TransferMoneyParameter): TransferMoneyResponse {
val finTsServerAddress = finTsServerAddressFinder.findFinTsServerAddress(param.bankCode) val finTsServerAddress = config.finTsServerAddressFinder.findFinTsServerAddress(param.bankCode)
if (finTsServerAddress.isNullOrBlank()) { if (finTsServerAddress.isNullOrBlank()) {
return TransferMoneyResponse(ErrorCode.BankDoesNotSupportFinTs3, "Either bank does not FinTS 3.0 or we don't know its FinTS server address", listOf(), null) return TransferMoneyResponse(ErrorCode.BankDoesNotSupportFinTs3, "Either bank does not FinTS 3.0 or we don't know its FinTS server address", listOf(), null)
} }
@ -146,9 +142,9 @@ open class FinTsClient @JvmOverloads constructor(
accountToUse = selectedAccount accountToUse = selectedAccount
} }
val context = JobContext(JobContextType.TransferMoney, this.callback, product, bank, accountToUse) val context = JobContext(JobContextType.TransferMoney, this.callback, config, bank, accountToUse)
val response = jobExecutor.transferMoneyAsync(context, BankTransferData(param.recipientName, param.recipientAccountIdentifier, recipientBankIdentifier, val response = config.jobExecutor.transferMoneyAsync(context, BankTransferData(param.recipientName, param.recipientAccountIdentifier, recipientBankIdentifier,
param.amount, param.reference, param.instantPayment)) param.amount, param.reference, param.instantPayment))
return TransferMoneyResponse(mapper.mapErrorCode(response), mapper.mapErrorMessages(response), mapper.mergeMessageLog(previousJobResponse, response), bank) return TransferMoneyResponse(mapper.mapErrorCode(response), mapper.mapErrorMessages(response), mapper.mergeMessageLog(previousJobResponse, response), bank)
@ -173,11 +169,11 @@ open class FinTsClient @JvmOverloads constructor(
// return GetAccountInfoResponse(it) // return GetAccountInfoResponse(it)
} }
val context = JobContext(JobContextType.GetAccountInfo, this.callback, product, bank) val context = JobContext(JobContextType.GetAccountInfo, this.callback, config, bank)
/* First dialog: Get user's basic data like BPD, customer system ID and her TAN methods */ /* First dialog: Get user's basic data like BPD, customer system ID and her TAN methods */
val newUserInfoResponse = jobExecutor.retrieveBasicDataLikeUsersTanMethods(context, param.preferredTanMethods, param.preferredTanMedium) val newUserInfoResponse = config.jobExecutor.retrieveBasicDataLikeUsersTanMethods(context, param.preferredTanMethods, param.preferredTanMedium)
if (newUserInfoResponse.successful == false) { // bank parameter (FinTS server address, ...) already seem to be wrong if (newUserInfoResponse.successful == false) { // bank parameter (FinTS server address, ...) already seem to be wrong
return GetAccountInfoResponse(context, newUserInfoResponse) return GetAccountInfoResponse(context, newUserInfoResponse)
@ -186,7 +182,7 @@ open class FinTsClient @JvmOverloads constructor(
/* Second dialog, executed in retrieveBasicDataLikeUsersTanMethods() if required: some banks require that in order to initialize a dialog with /* Second dialog, executed in retrieveBasicDataLikeUsersTanMethods() if required: some banks require that in order to initialize a dialog with
strong customer authorization TAN media is required */ strong customer authorization TAN media is required */
val getAccountsResponse = jobExecutor.getAccounts(context) val getAccountsResponse = config.jobExecutor.getAccounts(context)
return GetAccountInfoResponse(context, getAccountsResponse) return GetAccountInfoResponse(context, getAccountsResponse)
} }

View File

@ -4,6 +4,7 @@ import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.datetime.* import kotlinx.datetime.*
import net.dankito.banking.fints.callback.FinTsClientCallback import net.dankito.banking.fints.callback.FinTsClientCallback
import net.dankito.banking.fints.config.FinTsClientConfiguration
import net.dankito.banking.fints.extensions.minusDays import net.dankito.banking.fints.extensions.minusDays
import net.dankito.banking.fints.extensions.todayAtEuropeBerlin import net.dankito.banking.fints.extensions.todayAtEuropeBerlin
import net.dankito.banking.fints.messages.datenelemente.implementierte.tan.* import net.dankito.banking.fints.messages.datenelemente.implementierte.tan.*
@ -18,14 +19,11 @@ import net.dankito.banking.fints.webclient.IWebClient
* [addAccountAsync] gets user's TAN methods, user's TAN media, user's bank accounts and may even current balance and account transactions of last 90 days. * [addAccountAsync] gets user's TAN methods, user's TAN media, user's bank accounts and may even current balance and account transactions of last 90 days.
*/ */
open class FinTsClientDeprecated( open class FinTsClientDeprecated(
open var callback: FinTsClientCallback, protected val config: FinTsClientConfiguration,
protected open val jobExecutor: FinTsJobExecutor = FinTsJobExecutor(), open var callback: FinTsClientCallback
protected open val product: ProductData = ProductData("15E53C26816138699C7B6A3E8", "1.0.0") // TODO: get version dynamically
) { ) {
constructor(callback: FinTsClientCallback) : this(callback, FinTsJobExecutor()) // Swift does not support default parameter values -> create constructor overloads constructor(callback: FinTsClientCallback) : this(FinTsClientConfiguration(), callback)
constructor(callback: FinTsClientCallback, webClient: IWebClient) : this(callback, FinTsJobExecutor(RequestExecutor(webClient = webClient)))
/** /**
@ -48,20 +46,20 @@ open class FinTsClientDeprecated(
* On success [bank] parameter is updated afterwards. * On success [bank] parameter is updated afterwards.
*/ */
open suspend fun getAnonymousBankInfo(bank: BankData): FinTsClientResponse { open suspend fun getAnonymousBankInfo(bank: BankData): FinTsClientResponse {
val context = JobContext(JobContextType.AnonymousBankInfo, this.callback, product, bank) val context = JobContext(JobContextType.AnonymousBankInfo, this.callback, config, bank)
val response = jobExecutor.getAnonymousBankInfo(context) val response = config.jobExecutor.getAnonymousBankInfo(context)
return FinTsClientResponse(context, response) return FinTsClientResponse(context, response)
} }
open suspend fun addAccountAsync(parameter: AddAccountParameter): AddAccountResponse { open suspend fun addAccountAsync(parameter: AddAccountParameter): AddAccountResponse {
val bank = parameter.bank val bank = parameter.bank
val context = JobContext(JobContextType.AddAccount, this.callback, product, bank) val context = JobContext(JobContextType.AddAccount, this.callback, config, bank)
/* First dialog: Get user's basic data like BPD, customer system ID and her TAN methods */ /* First dialog: Get user's basic data like BPD, customer system ID and her TAN methods */
val newUserInfoResponse = jobExecutor.retrieveBasicDataLikeUsersTanMethods(context, parameter.preferredTanMethods, parameter.preferredTanMedium) val newUserInfoResponse = config.jobExecutor.retrieveBasicDataLikeUsersTanMethods(context, parameter.preferredTanMethods, parameter.preferredTanMedium)
if (newUserInfoResponse.successful == false) { // bank parameter (FinTS server address, ...) already seem to be wrong if (newUserInfoResponse.successful == false) { // bank parameter (FinTS server address, ...) already seem to be wrong
return AddAccountResponse(context, newUserInfoResponse) return AddAccountResponse(context, newUserInfoResponse)
@ -77,7 +75,7 @@ open class FinTsClientDeprecated(
/* Third dialog: Now we can initialize our first dialog with strong customer authorization. Use it to get UPD and customer's accounts */ /* Third dialog: Now we can initialize our first dialog with strong customer authorization. Use it to get UPD and customer's accounts */
val getAccountsResponse = jobExecutor.getAccounts(context) val getAccountsResponse = config.jobExecutor.getAccounts(context)
if (getAccountsResponse.successful == false) { if (getAccountsResponse.successful == false) {
return AddAccountResponse(context, getAccountsResponse) return AddAccountResponse(context, getAccountsResponse)
@ -138,33 +136,33 @@ open class FinTsClientDeprecated(
open suspend fun getAccountTransactionsAsync(parameter: GetAccountTransactionsParameter): GetAccountTransactionsResponse { open suspend fun getAccountTransactionsAsync(parameter: GetAccountTransactionsParameter): GetAccountTransactionsResponse {
val context = JobContext(JobContextType.GetTransactions, this.callback, product, parameter.bank, parameter.account) val context = JobContext(JobContextType.GetTransactions, this.callback, config, parameter.bank, parameter.account)
return jobExecutor.getTransactionsAsync(context, parameter) return config.jobExecutor.getTransactionsAsync(context, parameter)
} }
open suspend fun getTanMediaList(bank: BankData, tanMediaKind: TanMedienArtVersion = TanMedienArtVersion.Alle, open suspend fun getTanMediaList(bank: BankData, tanMediaKind: TanMedienArtVersion = TanMedienArtVersion.Alle,
tanMediumClass: TanMediumKlasse = TanMediumKlasse.AlleMedien): GetTanMediaListResponse { tanMediumClass: TanMediumKlasse = TanMediumKlasse.AlleMedien): GetTanMediaListResponse {
val context = JobContext(JobContextType.GetTanMedia, this.callback, product, bank) val context = JobContext(JobContextType.GetTanMedia, this.callback, config, bank)
return jobExecutor.getTanMediaList(context, tanMediaKind, tanMediumClass) return config.jobExecutor.getTanMediaList(context, tanMediaKind, tanMediumClass)
} }
open suspend fun changeTanMedium(newActiveTanMedium: TanGeneratorTanMedium, bank: BankData): FinTsClientResponse { open suspend fun changeTanMedium(newActiveTanMedium: TanGeneratorTanMedium, bank: BankData): FinTsClientResponse {
val context = JobContext(JobContextType.ChangeTanMedium, this.callback, product, bank) val context = JobContext(JobContextType.ChangeTanMedium, this.callback, config, bank)
val response = jobExecutor.changeTanMedium(context, newActiveTanMedium) val response = config.jobExecutor.changeTanMedium(context, newActiveTanMedium)
return FinTsClientResponse(context, response) return FinTsClientResponse(context, response)
} }
open suspend fun doBankTransferAsync(bankTransferData: BankTransferData, bank: BankData, account: AccountData): FinTsClientResponse { open suspend fun doBankTransferAsync(bankTransferData: BankTransferData, bank: BankData, account: AccountData): FinTsClientResponse {
val context = JobContext(JobContextType.TransferMoney, this.callback, product, bank, account) val context = JobContext(JobContextType.TransferMoney, this.callback, config, bank, account)
return jobExecutor.transferMoneyAsync(context, bankTransferData) return config.jobExecutor.transferMoneyAsync(context, bankTransferData)
} }
} }

View File

@ -1,35 +1,23 @@
package net.dankito.banking.fints package net.dankito.banking.fints
import net.dankito.banking.fints.callback.FinTsClientCallback import net.dankito.banking.fints.callback.FinTsClientCallback
import net.dankito.banking.fints.messages.MessageBuilder import net.dankito.banking.fints.config.FinTsClientConfiguration
import net.dankito.banking.fints.model.* import net.dankito.banking.fints.model.*
import net.dankito.banking.fints.model.mapper.ModelMapper
import net.dankito.banking.fints.response.client.AddAccountResponse import net.dankito.banking.fints.response.client.AddAccountResponse
import net.dankito.banking.fints.response.client.FinTsClientResponse import net.dankito.banking.fints.response.client.FinTsClientResponse
import net.dankito.banking.fints.response.client.GetAccountTransactionsResponse import net.dankito.banking.fints.response.client.GetAccountTransactionsResponse
import net.dankito.banking.fints.util.IBase64Service
import net.dankito.banking.fints.util.PureKotlinBase64Service
import net.dankito.banking.fints.util.TanMethodSelector
import net.dankito.banking.fints.webclient.IWebClient
import net.dankito.banking.fints.webclient.KtorWebClient
open class FinTsClientForCustomer( open class FinTsClientForCustomer(
val bank: BankData, val bank: BankData,
callback: FinTsClientCallback, config: FinTsClientConfiguration,
requestExecutor: RequestExecutor = RequestExecutor(), callback: FinTsClientCallback
messageBuilder: MessageBuilder = MessageBuilder(),
modelMapper: ModelMapper = ModelMapper(messageBuilder),
protected open val tanMethodSelector: TanMethodSelector = TanMethodSelector(),
product: ProductData = ProductData("15E53C26816138699C7B6A3E8", "1.0.0") // TODO: get version dynamically)
) { ) {
constructor(bank: BankData, callback: FinTsClientCallback, webClient: IWebClient = KtorWebClient(), base64Service: IBase64Service = PureKotlinBase64Service(), constructor(bank: BankData, callback: FinTsClientCallback) : this(bank, FinTsClientConfiguration(), callback)
product: ProductData = ProductData("15E53C26816138699C7B6A3E8", "1.0.0")) // TODO: get version dynamically)
: this(bank, callback, RequestExecutor(MessageBuilder(), webClient, base64Service), product = product)
protected val client = FinTsClientDeprecated(callback, FinTsJobExecutor(requestExecutor, messageBuilder, modelMapper, tanMethodSelector), product) protected val client = FinTsClientDeprecated(config, callback)
open val messageLogWithoutSensitiveData: List<MessageLogEntry> = mutableListOf() open val messageLogWithoutSensitiveData: List<MessageLogEntry> = mutableListOf()

View File

@ -0,0 +1,26 @@
package net.dankito.banking.fints.config
import net.dankito.banking.fints.FinTsJobExecutor
import net.dankito.banking.fints.RequestExecutor
import net.dankito.banking.fints.log.MessageLogCollector
import net.dankito.banking.fints.messages.MessageBuilder
import net.dankito.banking.fints.model.mapper.ModelMapper
import net.dankito.banking.fints.util.FinTsServerAddressFinder
import net.dankito.banking.fints.util.IBase64Service
import net.dankito.banking.fints.util.PureKotlinBase64Service
import net.dankito.banking.fints.util.TanMethodSelector
import net.dankito.banking.fints.webclient.IWebClient
import net.dankito.banking.fints.webclient.KtorWebClient
class FinTsClientConfiguration(
var options: FinTsClientOptions = FinTsClientOptions(),
messageBuilder: MessageBuilder = MessageBuilder(),
webClient: IWebClient = KtorWebClient(),
base64Service: IBase64Service = PureKotlinBase64Service(),
requestExecutor: RequestExecutor = RequestExecutor(messageBuilder, webClient, base64Service),
modelMapper: ModelMapper = ModelMapper(messageBuilder),
tanMethodSelector: TanMethodSelector = TanMethodSelector(),
var jobExecutor: FinTsJobExecutor = FinTsJobExecutor(requestExecutor, messageBuilder, modelMapper, tanMethodSelector),
var finTsServerAddressFinder: FinTsServerAddressFinder = FinTsServerAddressFinder(),
var messageLogCollector: MessageLogCollector = MessageLogCollector()
)

View File

@ -0,0 +1,12 @@
package net.dankito.banking.fints.config
import net.dankito.banking.fints.model.ProductData
data class FinTsClientOptions(
val version: String = "1.0.0", // TODO: get version dynamically
val productName: String = "15E53C26816138699C7B6A3E8"
) {
val product: ProductData by lazy { ProductData(productName, version) }
}

View File

@ -2,6 +2,7 @@ package net.dankito.banking.fints.model
import kotlinx.atomicfu.atomic import kotlinx.atomicfu.atomic
import net.dankito.banking.fints.callback.FinTsClientCallback import net.dankito.banking.fints.callback.FinTsClientCallback
import net.dankito.banking.fints.config.FinTsClientConfiguration
import net.dankito.banking.fints.log.IMessageLogAppender import net.dankito.banking.fints.log.IMessageLogAppender
import net.dankito.banking.fints.log.MessageContext import net.dankito.banking.fints.log.MessageContext
import net.dankito.banking.fints.log.MessageLogCollector import net.dankito.banking.fints.log.MessageLogCollector
@ -17,14 +18,13 @@ import kotlin.reflect.KClass
open class JobContext( open class JobContext(
open val type: JobContextType, open val type: JobContextType,
open val callback: FinTsClientCallback, open val callback: FinTsClientCallback,
product: ProductData, open val config: FinTsClientConfiguration,
bank: BankData, bank: BankData,
/** /**
* Only set if the current context is for a specific account (like get account's transactions). * Only set if the current context is for a specific account (like get account's transactions).
*/ */
open val account: AccountData? = null, open val account: AccountData? = null
protected open val messageLogCollector: MessageLogCollector = MessageLogCollector() ) : MessageBaseData(bank, config.options.product), IMessageLogAppender {
) : MessageBaseData(bank, product), IMessageLogAppender {
companion object { companion object {
private val JobCount = atomic(0) // this variable is accessed from multiple threads, so make it thread safe private val JobCount = atomic(0) // this variable is accessed from multiple threads, so make it thread safe
@ -38,7 +38,7 @@ open class JobContext(
open val responseParser: ResponseParser = ResponseParser(logAppender = this) open val responseParser: ResponseParser = ResponseParser(logAppender = this)
open val messageLogWithoutSensitiveData: List<MessageLogEntry> open val messageLogWithoutSensitiveData: List<MessageLogEntry>
get() = messageLogCollector.messageLogWithoutSensitiveData get() = config.messageLogCollector.messageLogWithoutSensitiveData
open var dialog: DialogContext = DialogContext() // create null value so that variable is not null open var dialog: DialogContext = DialogContext() // create null value so that variable is not null
@ -72,11 +72,11 @@ open class JobContext(
open fun addMessageLog(type: MessageLogEntryType, message: String) { open fun addMessageLog(type: MessageLogEntryType, message: String) {
messageLogCollector.addMessageLog(type, message, createMessageContext()) config.messageLogCollector.addMessageLog(type, message, createMessageContext())
} }
override fun logError(loggingClass: KClass<*>, message: String, e: Exception?) { override fun logError(loggingClass: KClass<*>, message: String, e: Exception?) {
messageLogCollector.logError(loggingClass, message, createMessageContext(), e) config.messageLogCollector.logError(loggingClass, message, createMessageContext(), e)
} }
protected open fun createMessageContext(): MessageContext { protected open fun createMessageContext(): MessageContext {

View File

@ -2,6 +2,7 @@ package net.dankito.banking.fints
import kotlinx.datetime.LocalDate import kotlinx.datetime.LocalDate
import net.dankito.banking.fints.callback.SimpleFinTsClientCallback import net.dankito.banking.fints.callback.SimpleFinTsClientCallback
import net.dankito.banking.fints.config.FinTsClientConfiguration
import net.dankito.banking.fints.extensions.randomWithSeed import net.dankito.banking.fints.extensions.randomWithSeed
import net.dankito.banking.fints.messages.datenelemente.abgeleiteteformate.Datum import net.dankito.banking.fints.messages.datenelemente.abgeleiteteformate.Datum
import net.dankito.banking.fints.messages.datenelemente.abgeleiteteformate.Laenderkennzeichen import net.dankito.banking.fints.messages.datenelemente.abgeleiteteformate.Laenderkennzeichen
@ -55,6 +56,8 @@ abstract class FinTsTestBase {
const val Time = 182752 const val Time = 182752
val ClientConfig = FinTsClientConfiguration()
init { init {
Bank.changeTanMediumParameters = ChangeTanMediaParameters(JobParameters("", 1, 1, 1, ":0:0"), false, false, false, false, false, listOf()) Bank.changeTanMediumParameters = ChangeTanMediaParameters(JobParameters("", 1, 1, 1, ":0:0"), false, false, false, false, false, listOf())
@ -72,7 +75,7 @@ abstract class FinTsTestBase {
protected open fun createContext(bank: BankData = Bank, dialogId: String = DialogContext.InitialDialogId): JobContext { protected open fun createContext(bank: BankData = Bank, dialogId: String = DialogContext.InitialDialogId): JobContext {
val context = JobContext(JobContextType.AnonymousBankInfo, SimpleFinTsClientCallback(), Product, bank) val context = JobContext(JobContextType.AnonymousBankInfo, SimpleFinTsClientCallback(), ClientConfig, bank)
context.startNewDialog(dialogId = dialogId) context.startNewDialog(dialogId = dialogId)
return context return context