Renamed User to BankAccess

This commit is contained in:
dankito 2024-09-16 16:20:17 +02:00
parent 89e21dc38a
commit 72608a444d
9 changed files with 47 additions and 47 deletions

View File

@ -41,7 +41,7 @@ interface BankingClient {
* *
* Optionally specify which [accounts] should be updated. If not specified all accounts will be updated. * Optionally specify which [accounts] should be updated. If not specified all accounts will be updated.
*/ */
suspend fun updateAccountTransactionsAsync(user: User, accounts: List<BankAccount>? = null): Response<List<GetTransactionsResponse>> suspend fun updateAccountTransactionsAsync(bank: BankAccess, accounts: List<BankAccount>? = null): Response<List<GetTransactionsResponse>>
suspend fun transferMoneyAsync(bankCode: String, loginName: String, password: String, recipientName: String, suspend fun transferMoneyAsync(bankCode: String, loginName: String, password: String, recipientName: String,

View File

@ -3,7 +3,7 @@ package net.codinux.banking.client
import net.codinux.banking.client.model.AccountCredentials import net.codinux.banking.client.model.AccountCredentials
import net.codinux.banking.client.model.Amount import net.codinux.banking.client.model.Amount
import net.codinux.banking.client.model.BankAccount import net.codinux.banking.client.model.BankAccount
import net.codinux.banking.client.model.User import net.codinux.banking.client.model.BankAccess
import net.codinux.banking.client.model.options.GetAccountDataOptions import net.codinux.banking.client.model.options.GetAccountDataOptions
import net.codinux.banking.client.model.request.GetAccountDataRequest import net.codinux.banking.client.model.request.GetAccountDataRequest
import net.codinux.banking.client.model.request.TransferMoneyRequest import net.codinux.banking.client.model.request.TransferMoneyRequest
@ -16,23 +16,23 @@ abstract class BankingClientForUserBase(
protected val client: BankingClient protected val client: BankingClient
) : BankingClientForUser { ) : BankingClientForUser {
private lateinit var user: User private lateinit var bank: BankAccess
override suspend fun getAccountDataAsync(options: GetAccountDataOptions) = override suspend fun getAccountDataAsync(options: GetAccountDataOptions) =
client.getAccountDataAsync(GetAccountDataRequest(credentials, options)).also { client.getAccountDataAsync(GetAccountDataRequest(credentials, options)).also {
it.data?.user?.let { retrievedUser -> it.data?.bank?.let { retrievedBank ->
this.user = retrievedUser this.bank = retrievedBank
} }
} }
override suspend fun updateAccountTransactionsAsync(accounts: List<BankAccount>?): Response<List<GetTransactionsResponse>> = override suspend fun updateAccountTransactionsAsync(accounts: List<BankAccount>?): Response<List<GetTransactionsResponse>> =
client.updateAccountTransactionsAsync(user, accounts) client.updateAccountTransactionsAsync(bank, accounts)
override suspend fun transferMoneyAsync(recipientName: String, recipientAccountIdentifier: String, amount: Amount, paymentReference: String?) = override suspend fun transferMoneyAsync(recipientName: String, recipientAccountIdentifier: String, amount: Amount, paymentReference: String?) =
transferMoneyAsync(TransferMoneyRequest(null, recipientName, recipientAccountIdentifier, null, amount, paymentReference = paymentReference)) transferMoneyAsync(TransferMoneyRequest(null, recipientName, recipientAccountIdentifier, null, amount, paymentReference = paymentReference))
override suspend fun transferMoneyAsync(request: TransferMoneyRequest) = override suspend fun transferMoneyAsync(request: TransferMoneyRequest) =
client.transferMoneyAsync(TransferMoneyRequestForUser(user.bankCode, user.loginName, user.password!!, request)) client.transferMoneyAsync(TransferMoneyRequestForUser(bank.bankCode, bank.loginName, bank.password!!, request))
} }

View File

@ -3,7 +3,7 @@ package net.codinux.banking.client
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import net.codinux.banking.client.model.Amount import net.codinux.banking.client.model.Amount
import net.codinux.banking.client.model.BankAccount import net.codinux.banking.client.model.BankAccount
import net.codinux.banking.client.model.User import net.codinux.banking.client.model.BankAccess
import net.codinux.banking.client.model.options.GetAccountDataOptions import net.codinux.banking.client.model.options.GetAccountDataOptions
import net.codinux.banking.client.model.request.GetAccountDataRequest import net.codinux.banking.client.model.request.GetAccountDataRequest
import net.codinux.banking.client.model.request.TransferMoneyRequest import net.codinux.banking.client.model.request.TransferMoneyRequest
@ -19,8 +19,8 @@ fun BankingClient.getAccountData(request: GetAccountDataRequest) = runBlocking {
getAccountDataAsync(request) getAccountDataAsync(request)
} }
fun BankingClient.updateAccountTransactions(user: User, accounts: List<BankAccount>? = null) = runBlocking { fun BankingClient.updateAccountTransactions(bank: BankAccess, accounts: List<BankAccount>? = null) = runBlocking {
updateAccountTransactionsAsync(user, accounts) updateAccountTransactionsAsync(bank, accounts)
} }

View File

@ -7,7 +7,7 @@ import net.codinux.banking.client.model.tan.TanMethod
@Suppress("RUNTIME_ANNOTATION_NOT_SUPPORTED") @Suppress("RUNTIME_ANNOTATION_NOT_SUPPORTED")
@NoArgConstructor @NoArgConstructor
open class User( open class BankAccess(
val bankCode: String, val bankCode: String,
var loginName: String, var loginName: String,
/** /**

View File

@ -1,20 +1,20 @@
package net.codinux.banking.client.model.response package net.codinux.banking.client.model.response
import net.codinux.banking.client.model.AccountTransaction import net.codinux.banking.client.model.AccountTransaction
import net.codinux.banking.client.model.User import net.codinux.banking.client.model.BankAccess
import net.codinux.banking.client.model.config.JsonIgnore import net.codinux.banking.client.model.config.JsonIgnore
import net.codinux.banking.client.model.config.NoArgConstructor import net.codinux.banking.client.model.config.NoArgConstructor
@Suppress("RUNTIME_ANNOTATION_NOT_SUPPORTED") @Suppress("RUNTIME_ANNOTATION_NOT_SUPPORTED")
@NoArgConstructor @NoArgConstructor
open class GetAccountDataResponse( open class GetAccountDataResponse(
val user: User val bank: BankAccess
) { ) {
@get:JsonIgnore @get:JsonIgnore
val bookedTransactions: List<AccountTransaction> val bookedTransactions: List<AccountTransaction>
get() = user.accounts.flatMap { it.bookedTransactions }.sortedByDescending { it.valueDate } get() = bank.accounts.flatMap { it.bookedTransactions }.sortedByDescending { it.valueDate }
override fun toString() = user.toString() override fun toString() = bank.toString()
} }

View File

@ -3,7 +3,7 @@ package net.codinux.banking.client.model.tan
import kotlinx.datetime.Clock import kotlinx.datetime.Clock
import kotlinx.datetime.Instant import kotlinx.datetime.Instant
import net.codinux.banking.client.model.BankAccountViewInfo import net.codinux.banking.client.model.BankAccountViewInfo
import net.codinux.banking.client.model.User import net.codinux.banking.client.model.BankAccess
import net.codinux.banking.client.model.BankViewInfo import net.codinux.banking.client.model.BankViewInfo
import net.codinux.banking.client.model.config.JsonIgnore import net.codinux.banking.client.model.config.JsonIgnore
import net.codinux.banking.client.model.config.NoArgConstructor import net.codinux.banking.client.model.config.NoArgConstructor
@ -24,9 +24,9 @@ open class TanChallenge(
open val selectedTanMethodId: String, open val selectedTanMethodId: String,
/** /**
* When adding an account, frontend has no UserAccount object in BankingClientCallback to know which TanMethods are * When adding an account, frontend has no UserAccount object in BankingClientCallback to know which TanMethods are
* available for User. * available for user.
* Also on other calls to bank server, bank server may returned an updated list of available TanMethods, so that * Also on other calls to bank server, bank server may returned an updated list of available TanMethods, so that
* [User] may contains an outdated list of available TanMethods. * [BankAccess] may contains an outdated list of available TanMethods.
* *
* Therefore i added list with up to date TanMethods here to ensure EnterTanDialog can display user's up to date TanMethods. * Therefore i added list with up to date TanMethods here to ensure EnterTanDialog can display user's up to date TanMethods.
*/ */
@ -43,7 +43,7 @@ open class TanChallenge(
open val tanImage: TanImage? = null, open val tanImage: TanImage? = null,
open val flickerCode: FlickerCode? = null, open val flickerCode: FlickerCode? = null,
open val user: BankViewInfo, open val bank: BankViewInfo,
open val account: BankAccountViewInfo? = null, open val account: BankAccountViewInfo? = null,
/** /**
* Datum und Uhrzeit, bis zu welchem Zeitpunkt eine TAN auf Basis der gesendeten Challenge gültig ist. Nach Ablauf der Gültigkeitsdauer wird die entsprechende TAN entwertet. * Datum und Uhrzeit, bis zu welchem Zeitpunkt eine TAN auf Basis der gesendeten Challenge gültig ist. Nach Ablauf der Gültigkeitsdauer wird die entsprechende TAN entwertet.

View File

@ -4,7 +4,7 @@ import net.codinux.banking.client.BankingClient
import net.codinux.banking.client.BankingClientCallback import net.codinux.banking.client.BankingClientCallback
import net.codinux.banking.client.model.BankAccount import net.codinux.banking.client.model.BankAccount
import net.codinux.banking.client.model.BankAccountFeatures import net.codinux.banking.client.model.BankAccountFeatures
import net.codinux.banking.client.model.User import net.codinux.banking.client.model.BankAccess
import net.codinux.banking.client.model.options.GetAccountDataOptions import net.codinux.banking.client.model.options.GetAccountDataOptions
import net.codinux.banking.client.model.request.GetAccountDataRequest import net.codinux.banking.client.model.request.GetAccountDataRequest
import net.codinux.banking.client.model.request.TransferMoneyRequestForUser import net.codinux.banking.client.model.request.TransferMoneyRequestForUser
@ -35,14 +35,14 @@ open class FinTs4kBankingClient(
return mapper.map(response, request.bankInfo) return mapper.map(response, request.bankInfo)
} }
override suspend fun updateAccountTransactionsAsync(user: User, accounts: List<BankAccount>?): Response<List<GetTransactionsResponse>> { override suspend fun updateAccountTransactionsAsync(bank: BankAccess, accounts: List<BankAccount>?): Response<List<GetTransactionsResponse>> {
val accountsToRequest = (accounts ?: user.accounts).filter { it.supportsAnyFeature(BankAccountFeatures.RetrieveBalance, BankAccountFeatures.RetrieveBalance) } val accountsToRequest = (accounts ?: bank.accounts).filter { it.supportsAnyFeature(BankAccountFeatures.RetrieveBalance, BankAccountFeatures.RetrieveBalance) }
if (accountsToRequest.isNotEmpty()) { if (accountsToRequest.isNotEmpty()) {
var finTsModel: BankData? = null var finTsModel: BankData? = null
val responses = accountsToRequest.map { account -> val responses = accountsToRequest.map { account ->
val parameter = mapper.mapToUpdateAccountTransactionsParameter(user, account, finTsModel) val parameter = mapper.mapToUpdateAccountTransactionsParameter(bank, account, finTsModel)
val response = client.getAccountDataAsync(parameter) val response = client.getAccountDataAsync(parameter)

View File

@ -58,19 +58,19 @@ open class FinTs4kMapper {
bank.serverAddress, bank.bic, bank.name bank.serverAddress, bank.bic, bank.name
) )
open fun mapToUpdateAccountTransactionsParameter(user: User, account: BankAccount, finTsModel: BankData?): GetAccountDataParameter { open fun mapToUpdateAccountTransactionsParameter(bank: BankAccess, account: BankAccount, finTsModel: BankData?): GetAccountDataParameter {
val defaults = GetAccountDataOptions() val defaults = GetAccountDataOptions()
val accountIdentifier = BankAccountIdentifierImpl(account.identifier, account.subAccountNumber, account.iban) val accountIdentifier = BankAccountIdentifierImpl(account.identifier, account.subAccountNumber, account.iban)
val from = account.lastAccountUpdateTime?.toLocalDateTime(TimeZone.EuropeBerlin)?.date // TODO: in case lastTransactionsUpdateTime is not set, this would retrieve all transactions (and require a TAN im most cases) val from = account.lastAccountUpdateTime?.toLocalDateTime(TimeZone.EuropeBerlin)?.date // TODO: in case lastTransactionsUpdateTime is not set, this would retrieve all transactions (and require a TAN im most cases)
val retrieveTransactions = if (from != null) RetrieveTransactions.AccordingToRetrieveFromAndTo else RetrieveTransactions.valueOf(defaults.retrieveTransactions.name) val retrieveTransactions = if (from != null) RetrieveTransactions.AccordingToRetrieveFromAndTo else RetrieveTransactions.valueOf(defaults.retrieveTransactions.name)
// val preferredTanMethods = listOf(mapTanMethodType(user.selectedTanMethod.type)) // TODO: currently we aren't saving TanMethods in database, re-enable as soon as TanMethods get saved // val preferredTanMethods = listOf(mapTanMethodType(bank.selectedTanMethod.type)) // TODO: currently we aren't saving TanMethods in database, re-enable as soon as TanMethods get saved
val preferredTanMethods = defaults.preferredTanMethods?.map { mapTanMethodType(it) } val preferredTanMethods = defaults.preferredTanMethods?.map { mapTanMethodType(it) }
return GetAccountDataParameter(user.bankCode, user.loginName, user.password!!, listOf(accountIdentifier), true, return GetAccountDataParameter(bank.bankCode, bank.loginName, bank.password!!, listOf(accountIdentifier), true,
retrieveTransactions, from, retrieveTransactions, from,
preferredTanMethods = preferredTanMethods, preferredTanMethods = preferredTanMethods,
preferredTanMedium = user.selectedTanMediumIdentifier, preferredTanMedium = bank.selectedTanMediumIdentifier,
finTsModel = finTsModel finTsModel = finTsModel
) )
} }
@ -91,7 +91,7 @@ open class FinTs4kMapper {
open fun map(response: net.dankito.banking.client.model.response.GetAccountDataResponse, bank: BankInfo? = null): Response<GetAccountDataResponse> = open fun map(response: net.dankito.banking.client.model.response.GetAccountDataResponse, bank: BankInfo? = null): Response<GetAccountDataResponse> =
if (response.successful && response.customerAccount != null) { if (response.successful && response.customerAccount != null) {
Response.success(GetAccountDataResponse(mapUser(response.customerAccount!!, bank))) Response.success(GetAccountDataResponse(mapBank(response.customerAccount!!, bank)))
} else { } else {
mapError(response) mapError(response)
} }
@ -99,12 +99,12 @@ open class FinTs4kMapper {
open fun map(responses: List<Triple<BankAccount, GetAccountDataParameter, net.dankito.banking.client.model.response.GetAccountDataResponse>>): Response<List<GetTransactionsResponse>> { open fun map(responses: List<Triple<BankAccount, GetAccountDataParameter, net.dankito.banking.client.model.response.GetAccountDataResponse>>): Response<List<GetTransactionsResponse>> {
val type = if (responses.all { it.third.successful }) ResponseType.Success else ResponseType.Error val type = if (responses.all { it.third.successful }) ResponseType.Success else ResponseType.Error
// TODO: update UserAccount and BankAccount objects according to retrieved data // TODO: update BankAccess and BankAccount objects according to retrieved data
val mappedResponses = responses.map { (account, param, getAccountDataResponse) -> val mappedResponses = responses.map { (account, param, getAccountDataResponse) ->
val user = getAccountDataResponse.customerAccount val bank = getAccountDataResponse.customerAccount
val finTsBankAccount = user?.accounts?.firstOrNull { it.identifier == account.identifier && it.subAccountNumber == account.subAccountNumber } val finTsBankAccount = bank?.accounts?.firstOrNull { it.identifier == account.identifier && it.subAccountNumber == account.subAccountNumber }
if (getAccountDataResponse.successful && user != null && finTsBankAccount != null) { if (getAccountDataResponse.successful && bank != null && finTsBankAccount != null) {
if (finTsBankAccount.lastAccountUpdateTime != null) { if (finTsBankAccount.lastAccountUpdateTime != null) {
account.lastAccountUpdateTime = finTsBankAccount.lastAccountUpdateTime account.lastAccountUpdateTime = finTsBankAccount.lastAccountUpdateTime
} }
@ -127,7 +127,7 @@ open class FinTs4kMapper {
} }
open fun mapToUserAccountViewInfo(bank: BankData): BankViewInfo = BankViewInfo( open fun mapToBankViewInfo(bank: BankData): BankViewInfo = BankViewInfo(
bank.bankCode, bank.customerId, bank.bankName, getBankingGroup(bank.bankName, bank.bic) bank.bankCode, bank.customerId, bank.bankName, getBankingGroup(bank.bankName, bank.bic)
) )
@ -138,17 +138,17 @@ open class FinTs4kMapper {
) )
protected open fun mapUser(user: net.dankito.banking.client.model.CustomerAccount, bank: BankInfo? = null) = User( protected open fun mapBank(bank: net.dankito.banking.client.model.CustomerAccount, info: BankInfo? = null) = BankAccess(
user.bankCode, user.loginName, user.password, bank.bankCode, bank.loginName, bank.password,
bank?.name ?: user.bankName, user.bic, user.customerName, user.userId, info?.name ?: bank.bankName, bank.bic, bank.customerName, bank.userId,
user.accounts.map { mapAccount(it) }.sortedBy { it.type } bank.accounts.map { mapAccount(it) }.sortedBy { it.type }
.onEachIndexed { index, bankAccount -> bankAccount.displayIndex = index }, .onEachIndexed { index, bankAccount -> bankAccount.displayIndex = index },
user.selectedTanMethod?.securityFunction?.code, user.tanMethods.map { mapTanMethod(it) }, bank.selectedTanMethod?.securityFunction?.code, bank.tanMethods.map { mapTanMethod(it) },
user.selectedTanMedium?.mediumName, user.tanMedia.map { mapTanMedium(it) }, bank.selectedTanMedium?.mediumName, bank.tanMedia.map { mapTanMedium(it) },
bank?.bankingGroup ?: getBankingGroup(user.bankName, user.bic), info?.bankingGroup ?: getBankingGroup(bank.bankName, bank.bic),
user.finTsServerAddress bank.finTsServerAddress
) )
protected open fun getBankingGroup(bankName: String, bic: String): BankingGroup? = protected open fun getBankingGroup(bankName: String, bic: String): BankingGroup? =
@ -297,13 +297,13 @@ open class FinTs4kMapper {
// TanMedium has not natural id in FinTS model so we have to create our own one // TanMedium has not natural id in FinTS model so we have to create our own one
val selectedTanMediumName = challenge.bank.selectedTanMedium?.let { selected -> tanMedia.firstOrNull { it == selected } }?.identifier val selectedTanMediumName = challenge.bank.selectedTanMedium?.let { selected -> tanMedia.firstOrNull { it == selected } }?.identifier
val user = mapToUserAccountViewInfo(challenge.bank) val bank = mapToBankViewInfo(challenge.bank)
val account = challenge.account?.let { mapToBankAccountViewInfo(it) } val account = challenge.account?.let { mapToBankAccountViewInfo(it) }
val tanImage = if (challenge is ImageTanChallenge) mapTanImage(challenge.image) else null val tanImage = if (challenge is ImageTanChallenge) mapTanImage(challenge.image) else null
val flickerCode = if (challenge is FlickerCodeTanChallenge) mapFlickerCode(challenge.flickerCode) else null val flickerCode = if (challenge is FlickerCodeTanChallenge) mapFlickerCode(challenge.flickerCode) else null
return object : TanChallenge(type, action, challenge.messageToShowToUser, selectedTanMethodId, tanMethods, selectedTanMediumName, tanMedia, tanImage, flickerCode, user, account, challenge.tanExpirationTime, challenge.challengeCreationTimestamp) { return object : TanChallenge(type, action, challenge.messageToShowToUser, selectedTanMethodId, tanMethods, selectedTanMediumName, tanMedia, tanImage, flickerCode, bank, account, challenge.tanExpirationTime, challenge.challengeCreationTimestamp) {
override fun addTanExpiredCallback(callback: () -> Unit) { override fun addTanExpiredCallback(callback: () -> Unit) {
challenge.addTanExpiredCallback(callback) challenge.addTanExpiredCallback(callback)
} }

View File

@ -88,12 +88,12 @@ class ShowUsage {
private fun printReceivedData(response: Response<GetAccountDataResponse>) { private fun printReceivedData(response: Response<GetAccountDataResponse>) {
response.data?.let { data -> response.data?.let { data ->
val user = data.user val bank = data.bank
println("Kunde: ${user.customerName} ${user.accounts.size} Konten @ ${user.bic} ${user.bankName}") println("Kunde: ${bank.customerName} ${bank.accounts.size} Konten @ ${bank.bic} ${bank.bankName}")
println() println()
println("Konten:") println("Konten:")
user.accounts.sortedBy { it.type }.forEach { account -> bank.accounts.sortedBy { it.type }.forEach { account ->
println("${account.identifier} ${account.productName} ${account.balance} ${account.currency}") println("${account.identifier} ${account.productName} ${account.balance} ${account.currency}")
} }