From 7d90910ffd39f8b5a21b1accab5d4ceac88c8ad1 Mon Sep 17 00:00:00 2001 From: dankito Date: Tue, 15 Oct 2024 19:51:12 +0200 Subject: [PATCH] Converted clientData to Any so that don't have to deserialize client data each time and added serializedClientData --- .../banking/client/model/BankAccess.kt | 19 +++++++++-- .../model/request/TransferMoneyRequest.kt | 3 +- .../request/TransferMoneyRequestForUser.kt | 7 ++-- .../client/fints4k/FinTs4kBankingClient.kt | 11 ++----- .../banking/client/fints4k/FinTs4kMapper.kt | 32 ++++++++++++++----- 5 files changed, 49 insertions(+), 23 deletions(-) diff --git a/BankingClientModel/src/commonMain/kotlin/net/codinux/banking/client/model/BankAccess.kt b/BankingClientModel/src/commonMain/kotlin/net/codinux/banking/client/model/BankAccess.kt index 198dda4f..caf88079 100644 --- a/BankingClientModel/src/commonMain/kotlin/net/codinux/banking/client/model/BankAccess.kt +++ b/BankingClientModel/src/commonMain/kotlin/net/codinux/banking/client/model/BankAccess.kt @@ -71,13 +71,28 @@ open class BankAccess( var wrongCredentialsEntered: Boolean = false /** - * BankingClient specific data of this account that the client needs to fullfil its job. + * BankingClient specific data of this account that the client needs to fulfill its job. * * You should treat it as opaque data, that only makes sense to the BankingClient, and pass it back to the client if set. * * For fints4k e.g. contains the FinTS jobs the bank supports, FinTS specific data like KundensystemID and so on. + * + * The deserialized in-memory only value of [serializedClientData] so that we don't have to deserialize [serializedClientData] each time. */ - var clientData: String? = null + var clientData: Any? = null + + /** + * Serialized version of [clientData]. + * + * The same as with [clientData] you should treat this value as opaque that only makes sense to the client implementation. + * + * [clientData] is the deserialized in-memory model of this value, so that we don't have to serialize this value each time. + * serializedClientData is the serialized version of clientData so that you can store (and restore) it e.g. to your + * database, so that on next application start client implementation doesn't have to fetch all these data again. + * Speeds up e.g. getting account transactions and transferring money with fints4k as FinTS requires quite a lot of + * data before account transactions can be retrieved. + */ + var serializedClientData: String? = null @get:JsonIgnore diff --git a/BankingClientModel/src/commonMain/kotlin/net/codinux/banking/client/model/request/TransferMoneyRequest.kt b/BankingClientModel/src/commonMain/kotlin/net/codinux/banking/client/model/request/TransferMoneyRequest.kt index 37af7e5a..fa76a161 100644 --- a/BankingClientModel/src/commonMain/kotlin/net/codinux/banking/client/model/request/TransferMoneyRequest.kt +++ b/BankingClientModel/src/commonMain/kotlin/net/codinux/banking/client/model/request/TransferMoneyRequest.kt @@ -75,7 +75,8 @@ open class TransferMoneyRequest( val tanMethodsNotSupportedByApplication: List = TanMethodType.TanMethodsNotSupportedByMostApplications, - val clientData: String? = null + val clientData: Any? = null, + var serializedClientData: String? = null ) { override fun toString() = "$amount to $recipientName - $paymentReference" } \ No newline at end of file diff --git a/BankingClientModel/src/commonMain/kotlin/net/codinux/banking/client/model/request/TransferMoneyRequestForUser.kt b/BankingClientModel/src/commonMain/kotlin/net/codinux/banking/client/model/request/TransferMoneyRequestForUser.kt index cc46175f..e1ff34c5 100644 --- a/BankingClientModel/src/commonMain/kotlin/net/codinux/banking/client/model/request/TransferMoneyRequestForUser.kt +++ b/BankingClientModel/src/commonMain/kotlin/net/codinux/banking/client/model/request/TransferMoneyRequestForUser.kt @@ -38,8 +38,9 @@ open class TransferMoneyRequestForUser( preferredTanMethods: List? = TanMethodType.NonVisualOrImageBased, tanMethodsNotSupportedByApplication: List = TanMethodType.TanMethodsNotSupportedByMostApplications, - clientData: String? = null -) : TransferMoneyRequest(senderAccount, recipientName, recipientAccountIdentifier, recipientBankIdentifier, amount, currency, paymentReference, instantTransfer, preferredTanMethods, tanMethodsNotSupportedByApplication, clientData) { + clientData: Any? = null, + serializedClientData: String? = null +) : TransferMoneyRequest(senderAccount, recipientName, recipientAccountIdentifier, recipientBankIdentifier, amount, currency, paymentReference, instantTransfer, preferredTanMethods, tanMethodsNotSupportedByApplication, clientData, serializedClientData) { constructor(bankCode: String, loginName: String, password: String, request: TransferMoneyRequest) : this(bankCode, loginName, password, request.senderAccount, request.recipientName, request.recipientAccountIdentifier, request.recipientBankIdentifier, @@ -51,7 +52,7 @@ open class TransferMoneyRequestForUser( amount: Amount, currency: String = DefaultValues.DefaultCurrency, paymentReference: String? = null, instantTransfer: Boolean = false ) : this(bank.domesticBankCode, bank.loginName, bank.password!!, account?.let { BankAccountIdentifier(it.identifier, it.subAccountNumber, it.iban) }, recipientName, recipientAccountIdentifier, recipientBankIdentifier, amount, currency, paymentReference, instantTransfer, - listOf(bank.selectedTanMethod.type) + TanMethodType.NonVisualOrImageBased, TanMethodType.TanMethodsNotSupportedByMostApplications, bank.clientData) { + listOf(bank.selectedTanMethod.type) + TanMethodType.NonVisualOrImageBased, TanMethodType.TanMethodsNotSupportedByMostApplications, bank.clientData, bank.serializedClientData) { this.bank = bank this.account = account } diff --git a/FinTs4jBankingClient/src/commonMain/kotlin/net/codinux/banking/client/fints4k/FinTs4kBankingClient.kt b/FinTs4jBankingClient/src/commonMain/kotlin/net/codinux/banking/client/fints4k/FinTs4kBankingClient.kt index 42078411..36168d24 100644 --- a/FinTs4jBankingClient/src/commonMain/kotlin/net/codinux/banking/client/fints4k/FinTs4kBankingClient.kt +++ b/FinTs4jBankingClient/src/commonMain/kotlin/net/codinux/banking/client/fints4k/FinTs4kBankingClient.kt @@ -39,19 +39,12 @@ open class FinTs4kBankingClient( val accountsToRequest = (accounts ?: bank.accounts).filter { it.supportsAnyFeature(BankAccountFeatures.RetrieveBalance, BankAccountFeatures.RetrieveTransactions) } if (accountsToRequest.isNotEmpty()) { - var finTsModel: BankData? = null - val responses = accountsToRequest.map { account -> - val parameter = mapper.mapToUpdateAccountTransactionsParameter(bank, account, finTsModel) + val parameter = mapper.mapToUpdateAccountTransactionsParameter(bank, account) val response = client.getAccountDataAsync(parameter) - if (response.finTsModel != null) { - finTsModel = response.finTsModel // so that basic account data doesn't have to be retrieved another time if user has multiple accounts - } - if (response.serializedFinTsModel != null) { - bank.clientData = response.serializedFinTsModel - } + mapper.mapCommonResponseData(bank, response) // so that basic account data doesn't have to be retrieved another time if user has multiple accounts Triple(account, parameter, response) } diff --git a/FinTs4jBankingClient/src/commonMain/kotlin/net/codinux/banking/client/fints4k/FinTs4kMapper.kt b/FinTs4jBankingClient/src/commonMain/kotlin/net/codinux/banking/client/fints4k/FinTs4kMapper.kt index 729b5c08..f867379f 100644 --- a/FinTs4jBankingClient/src/commonMain/kotlin/net/codinux/banking/client/fints4k/FinTs4kMapper.kt +++ b/FinTs4jBankingClient/src/commonMain/kotlin/net/codinux/banking/client/fints4k/FinTs4kMapper.kt @@ -62,7 +62,7 @@ open class FinTs4kMapper { bank.serverAddress, bank.bic, bank.name ) - open fun mapToUpdateAccountTransactionsParameter(bank: BankAccess, account: BankAccount, finTsModel: BankData?): GetAccountDataParameter { + open fun mapToUpdateAccountTransactionsParameter(bank: BankAccess, account: BankAccount): GetAccountDataParameter { val defaults = GetAccountDataOptions() val accountIdentifier = BankAccountIdentifierImpl(account.identifier, account.subAccountNumber, account.iban) @@ -75,8 +75,8 @@ open class FinTs4kMapper { retrieveTransactions, from, preferredTanMethods = preferredTanMethods, preferredTanMedium = bank.selectedTanMediumIdentifier, - finTsModel = finTsModel, - serializedFinTsModel = bank.clientData + finTsModel = bank.clientData as? BankData, + serializedFinTsModel = bank.serializedClientData ) } @@ -90,9 +90,9 @@ open class FinTs4kMapper { allowedTanFormat?.let { net.codinux.banking.fints.messages.datenelemente.implementierte.tan.AllowedTanFormat.valueOf(it.name) } ?: net.codinux.banking.fints.messages.datenelemente.implementierte.tan.AllowedTanFormat.Alphanumeric - open fun map(response: net.dankito.banking.client.model.response.GetAccountDataResponse, bank: BankInfo? = null): Response = + open fun map(response: net.dankito.banking.client.model.response.GetAccountDataResponse, bankInfo: BankInfo? = null): Response = if (response.successful && response.customerAccount != null) { - val bank = mapBank(response.customerAccount!!, bank, response.serializedFinTsModel) + val bank = mapBank(response.customerAccount!!, bankInfo, response) Response.success(GetAccountDataResponse(bank), mapMessageLog(response, bank)) } else { mapError(response, mapMessageLog(response)) @@ -120,6 +120,8 @@ open class FinTs4kMapper { val balance = mapMoney(finTsBankAccount.balance) account.balance = balance + mapCommonResponseData(bank, getAccountDataResponse) + Response.success(GetTransactionsResponse(account, balance, mapBookedTransactions(finTsBankAccount), emptyList(), mapHoldings(finTsBankAccount.statementOfHoldings, finTsBankAccount.currency, finTsBankAccount.lastAccountUpdateTime), finTsBankAccount.lastAccountUpdateTime ?: Clock.System.now(), param.retrieveTransactionsFrom, param.retrieveTransactionsTo), @@ -146,7 +148,7 @@ open class FinTs4kMapper { ) - protected open fun mapBank(bank: net.dankito.banking.client.model.CustomerAccount, info: BankInfo? = null, clientData: String? = null) = BankAccess( + protected open fun mapBank(bank: net.dankito.banking.client.model.CustomerAccount, info: BankInfo? = null, response: FinTsClientResponse? = null) = BankAccess( bank.bankCode, bank.loginName, bank.password, info?.name ?: bank.bankName, bank.bic, bank.customerName, bank.userId, bank.accounts.map { mapAccount(it) }.sortedBy { it.type } @@ -159,7 +161,7 @@ open class FinTs4kMapper { bank.finTsServerAddress, "de" ).apply { - this.clientData = clientData + response?.let { mapCommonResponseData(this, it) } } protected open fun getBankingGroup(bankName: String, bic: String): BankingGroup? = @@ -396,11 +398,14 @@ open class FinTs4kMapper { mapToMoney(request.amount, request.currency), request.paymentReference, request.instantTransfer, request.preferredTanMethods?.map { mapTanMethodType(it) }, request.tanMethodsNotSupportedByApplication.map { mapTanMethodType(it) }, - serializedFinTsModel = request.clientData + finTsModel = request.clientData as? BankData, + serializedFinTsModel = request.serializedClientData ) open fun mapTransferMoneyResponse(response: net.dankito.banking.client.model.response.TransferMoneyResponse, bank: BankAccess? = null, account: BankAccount? = null): Response = if (response.successful) { + bank?.let { mapCommonResponseData(it, response) } + Response.success(TransferMoneyResponse(), mapMessageLog(response, bank, account)) } else { mapError(response, mapMessageLog(response, bank, account)) @@ -451,4 +456,15 @@ open class FinTs4kMapper { protected open fun mapException(exception: Exception?): String? = exception?.stackTraceToString() + + open fun mapCommonResponseData(bank: BankAccess, response: FinTsClientResponse) { + response.finTsModel?.let { + bank.clientData = it + } + + response.serializedFinTsModel?.let { + bank.serializedClientData = it + } + } + } \ No newline at end of file