From e87adc8499009a7269991fc1dee104a118cb7aaf Mon Sep 17 00:00:00 2001 From: dankito Date: Sat, 13 Nov 2021 15:17:06 +0100 Subject: [PATCH] Clarified that getTransactionsAsync() only retrieves the transactions of one account; also fixed data model in regard to this --- .../net/dankito/banking/fints/FinTsClient.kt | 45 +++++++++---------- .../banking/fints/FinTsClientForCustomer.kt | 8 ++-- .../dankito/banking/fints/FinTsJobExecutor.kt | 24 ++++------ .../banking/fints/messages/MessageBuilder.kt | 6 +-- .../account/MaximaleAnzahlEintraege.kt | 4 +- .../KontoumsaetzeZeitraumMt940Base.kt | 4 +- .../KontoumsaetzeZeitraumMt940Version5.kt | 5 +-- .../KontoumsaetzeZeitraumMt940Version6.kt | 5 +-- .../KontoumsaetzeZeitraumMt940Version7.kt | 5 +-- .../umsaetze/KreditkartenUmsaetze.kt | 4 +- .../model/GetAccountTransactionsParameter.kt | 30 +++++++++++++ .../fints/model/GetTransactionsParameter.kt | 5 +-- .../fints/model/RetrievedAccountData.kt | 8 ---- .../response/client/AddAccountResponse.kt | 30 +++++++++++-- .../client/GetAccountTransactionsResponse.kt | 31 +++++++++++++ .../client/GetTransactionsResponse.kt | 42 +++++++++-------- .../fints/messages/MessageBuilderTest.kt | 8 ++-- .../banking/fints/FinTsClientTestBase.kt | 9 ++-- .../testaccess/TestAccessBankingClient.kt | 2 +- .../net/dankito/banking/ui/IBankingClient.kt | 5 +-- .../banking/ui/presenter/BankingPresenter.kt | 2 +- .../dankito/banking/fints4kBankingClient.kt | 16 ++++--- .../banking/mapper/fints4kModelMapper.kt | 4 +- .../dankito/banking/hbci4jBankingClient.kt | 2 +- 24 files changed, 182 insertions(+), 122 deletions(-) create mode 100644 fints4k/src/commonMain/kotlin/net/dankito/banking/fints/model/GetAccountTransactionsParameter.kt create mode 100644 fints4k/src/commonMain/kotlin/net/dankito/banking/fints/response/client/GetAccountTransactionsResponse.kt diff --git a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/FinTsClient.kt b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/FinTsClient.kt index 232098b2..2fae3443 100644 --- a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/FinTsClient.kt +++ b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/FinTsClient.kt @@ -64,7 +64,7 @@ open class FinTsClient @JvmOverloads constructor( jobExecutor.retrieveBasicDataLikeUsersTanMethods(context, parameter.preferredTanMethods, parameter.preferredTanMedium) { newUserInfoResponse -> if (newUserInfoResponse.successful == false) { // bank parameter (FinTS server address, ...) already seem to be wrong - callback(AddAccountResponse(context, newUserInfoResponse, bank)) + callback(AddAccountResponse(context, newUserInfoResponse)) return@retrieveBasicDataLikeUsersTanMethods } @@ -82,7 +82,7 @@ open class FinTsClient @JvmOverloads constructor( jobExecutor.getAccounts(context) { getAccountsResponse -> if (getAccountsResponse.successful == false) { - callback(AddAccountResponse(context, getAccountsResponse, context.bank)) + callback(AddAccountResponse(context, getAccountsResponse)) return@getAccounts } @@ -92,8 +92,7 @@ open class FinTsClient @JvmOverloads constructor( addAccountGetAccountBalancesAndTransactions(context, getAccountsResponse, callback) } else { - val retrievedAccountData = context.bank.accounts.associateBy( { it }, { RetrievedAccountData.balanceAndTransactionsNotRequestedByUser(it) } ) - addAccountDone(context, getAccountsResponse, retrievedAccountData, callback) + addAccountDone(context, getAccountsResponse, listOf(), callback) } } } @@ -102,38 +101,34 @@ open class FinTsClient @JvmOverloads constructor( callback: (AddAccountResponse) -> Unit) { val bank = context.bank - val retrievedAccountData = bank.accounts.associateBy( { it }, { RetrievedAccountData.unsuccessful(it) } ).toMutableMap() + val retrievedTransactionsResponses = mutableListOf() val accountsSupportingRetrievingTransactions = bank.accounts.filter { it.supportsRetrievingBalance || it.supportsRetrievingAccountTransactions } val countAccountsSupportingRetrievingTransactions = accountsSupportingRetrievingTransactions.size var countRetrievedAccounts = 0 if (countAccountsSupportingRetrievingTransactions == 0) { - addAccountDone(context, getAccountsResponse, retrievedAccountData, callback) - return // no necessary just to make it clearer that code below doesn't get called + addAccountDone(context, getAccountsResponse, retrievedTransactionsResponses, callback) + return // not necessary just to make it clearer that code below doesn't get called } accountsSupportingRetrievingTransactions.forEach { account -> - tryGetTransactionsOfLast90DaysWithoutTan(bank, account) { response -> - retrievedAccountData.put(account, response.retrievedData.first()) - - if (response.internalError != null) { // TODO: errors from response get lost! User then only sees "null" as error message - //getAccountsResponse.errorMessage = response.errorMessage - } + tryGetAccountTransactionsOfLast90DaysWithoutTan(bank, account) { response -> + retrievedTransactionsResponses.add(response) countRetrievedAccounts++ if (countRetrievedAccounts == countAccountsSupportingRetrievingTransactions) { - addAccountDone(context, getAccountsResponse, retrievedAccountData, callback) + addAccountDone(context, getAccountsResponse, retrievedTransactionsResponses, callback) } } } } protected open fun addAccountDone(context: JobContext, getAccountsResponse: BankResponse, - retrievedAccountData: Map, + retrievedTransactionsResponses: List, callback: (AddAccountResponse) -> Unit) { - callback(AddAccountResponse(context, getAccountsResponse, context.bank, retrievedAccountData.values.toList())) + callback(AddAccountResponse(context, getAccountsResponse, retrievedTransactionsResponses)) } @@ -143,18 +138,20 @@ open class FinTsClient @JvmOverloads constructor( * * Check if bank supports this. */ - open fun tryGetTransactionsOfLast90DaysWithoutTan(bank: BankData, account: AccountData, callback: (GetTransactionsResponse) -> Unit) { + open fun tryGetAccountTransactionsOfLast90DaysWithoutTan(bank: BankData, account: AccountData, callback: (GetAccountTransactionsResponse) -> Unit) { - val ninetyDaysAgo = Date.today.addDays(-90) - - getTransactionsAsync(GetTransactionsParameter(account, account.supportsRetrievingBalance, ninetyDaysAgo, abortIfTanIsRequired = true), bank) { response -> - callback(response) - } + getAccountTransactionsAsync(createGetAccountTransactionsOfLast90DaysParameter(bank, account), callback) } - open fun getTransactionsAsync(parameter: GetTransactionsParameter, bank: BankData, callback: (GetTransactionsResponse) -> Unit) { + protected open fun createGetAccountTransactionsOfLast90DaysParameter(bank: BankData, account: AccountData): GetAccountTransactionsParameter { + val ninetyDaysAgo = Date.today.addDays(-90) - val context = JobContext(JobContextType.GetTransactions, this.callback, product, bank, parameter.account) + return GetAccountTransactionsParameter(bank, account, account.supportsRetrievingBalance, ninetyDaysAgo, abortIfTanIsRequired = true) + } + + open fun getAccountTransactionsAsync(parameter: GetAccountTransactionsParameter, callback: (GetAccountTransactionsResponse) -> Unit) { + + val context = JobContext(JobContextType.GetTransactions, this.callback, product, parameter.bank, parameter.account) jobExecutor.getTransactionsAsync(context, parameter, callback) } diff --git a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/FinTsClientForCustomer.kt b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/FinTsClientForCustomer.kt index f82521ff..0d7d1608 100644 --- a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/FinTsClientForCustomer.kt +++ b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/FinTsClientForCustomer.kt @@ -6,9 +6,7 @@ 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.FinTsClientResponse -import net.dankito.banking.fints.response.client.GetTransactionsResponse -import net.dankito.banking.fints.transactions.IAccountTransactionsParser -import net.dankito.banking.fints.transactions.Mt940AccountTransactionsParser +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 @@ -50,8 +48,8 @@ open class FinTsClientForCustomer( } - open fun getTransactionsAsync(parameter: GetTransactionsParameter, callback: (GetTransactionsResponse) -> Unit) { - client.getTransactionsAsync(parameter, bank, callback) + open fun getAccountTransactionsAsync(parameter: GetAccountTransactionsParameter, callback: (GetAccountTransactionsResponse) -> Unit) { + client.getAccountTransactionsAsync(parameter, callback) } diff --git a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/FinTsJobExecutor.kt b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/FinTsJobExecutor.kt index af05bdd5..8adb74fc 100644 --- a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/FinTsJobExecutor.kt +++ b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/FinTsJobExecutor.kt @@ -10,10 +10,7 @@ import net.dankito.banking.fints.model.* import net.dankito.banking.fints.model.mapper.ModelMapper import net.dankito.banking.fints.response.BankResponse import net.dankito.banking.fints.response.InstituteSegmentId -import net.dankito.banking.fints.response.client.FinTsClientResponse -import net.dankito.banking.fints.response.client.GetTanMediaListResponse -import net.dankito.banking.fints.response.client.GetTransactionsResponse -import net.dankito.banking.fints.response.client.GetUserTanMethodsResponse +import net.dankito.banking.fints.response.client.* import net.dankito.banking.fints.response.segments.* import net.dankito.banking.fints.tan.FlickerCodeDecoder import net.dankito.banking.fints.tan.TanImageDecoder @@ -178,14 +175,14 @@ open class FinTsJobExecutor( } - open fun getTransactionsAsync(context: JobContext, parameter: GetTransactionsParameter, callback: (GetTransactionsResponse) -> Unit) { + open fun getTransactionsAsync(context: JobContext, parameter: GetAccountTransactionsParameter, callback: (GetAccountTransactionsResponse) -> Unit) { val dialogContext = context.startNewDialog() initDialogWithStrongCustomerAuthentication(context) { initDialogResponse -> if (initDialogResponse.successful == false) { - callback(GetTransactionsResponse(context, initDialogResponse, RetrievedAccountData.unsuccessfulList(parameter.account))) + callback(GetAccountTransactionsResponse(context, initDialogResponse, RetrievedAccountData.unsuccessful(parameter.account))) } else { // we now retrieved the fresh account information from FinTS server, use that one @@ -193,7 +190,7 @@ open class FinTsJobExecutor( mayGetBalance(context, parameter) { balanceResponse -> if (dialogContext.didBankCloseDialog) { - callback(GetTransactionsResponse(context, balanceResponse ?: initDialogResponse, RetrievedAccountData.unsuccessfulList(parameter.account))) + callback(GetAccountTransactionsResponse(context, balanceResponse ?: initDialogResponse, RetrievedAccountData.unsuccessful(parameter.account))) } else { getTransactionsAfterInitAndGetBalance(context, parameter, balanceResponse, callback) @@ -207,8 +204,8 @@ open class FinTsJobExecutor( return context.bank.accounts.firstOrNull { it.accountIdentifier == account.accountIdentifier } ?: account } - protected open fun getTransactionsAfterInitAndGetBalance(context: JobContext, parameter: GetTransactionsParameter, - balanceResponse: BankResponse?, callback: (GetTransactionsResponse) -> Unit) { + protected open fun getTransactionsAfterInitAndGetBalance(context: JobContext, parameter: GetAccountTransactionsParameter, + balanceResponse: BankResponse?, callback: (GetAccountTransactionsResponse) -> Unit) { var balance: Money? = balanceResponse?.getFirstSegmentById(InstituteSegmentId.Balance)?.let { Money(it.balance, it.currency) } @@ -248,15 +245,12 @@ open class FinTsJobExecutor( ?: bookedTransactions.map { it.valueDate }.sortedBy { it.millisSinceEpoch }.firstOrNull() val retrievedData = RetrievedAccountData(parameter.account, successful, balance, bookedTransactions, unbookedTransactions, fromDate, parameter.toDate ?: Date.today, response.internalError) - callback( - GetTransactionsResponse(context, response, listOf(retrievedData), - if (parameter.maxCountEntries != null) parameter.isSettingMaxCountEntriesAllowedByBank else null - ) - ) + callback(GetAccountTransactionsResponse(context, response, retrievedData, + if (parameter.maxCountEntries != null) parameter.isSettingMaxCountEntriesAllowedByBank else null)) } } - protected open fun mayGetBalance(context: JobContext, parameter: GetTransactionsParameter, callback: (BankResponse?) -> Unit) { + protected open fun mayGetBalance(context: JobContext, parameter: GetAccountTransactionsParameter, callback: (BankResponse?) -> Unit) { if (parameter.alsoRetrieveBalance && parameter.account.supportsRetrievingBalance) { val message = messageBuilder.createGetBalanceMessage(context, parameter.account) diff --git a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/messages/MessageBuilder.kt b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/messages/MessageBuilder.kt index 1016e3ed..4233cabd 100644 --- a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/messages/MessageBuilder.kt +++ b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/messages/MessageBuilder.kt @@ -155,7 +155,7 @@ open class MessageBuilder(protected val generator: ISegmentNumberGenerator = Seg } - open fun createGetTransactionsMessage(context: JobContext, parameter: GetTransactionsParameter): MessageBuilderResult { + open fun createGetTransactionsMessage(context: JobContext, parameter: GetAccountTransactionsParameter): MessageBuilderResult { val result = supportsGetTransactionsMt940(parameter.account) @@ -173,7 +173,7 @@ open class MessageBuilder(protected val generator: ISegmentNumberGenerator = Seg } protected open fun createGetTransactionsMessageMt940(context: JobContext, result: MessageBuilderResult, - parameter: GetTransactionsParameter): MessageBuilderResult { + parameter: GetAccountTransactionsParameter): MessageBuilderResult { if (parameter.maxCountEntries != null) { parameter.isSettingMaxCountEntriesAllowedByBank = determineIsSettingMaxCountEntriesAllowed(context.bank, InstituteSegmentId.AccountTransactionsMt940Parameters, listOf(5, 6, 7)) @@ -197,7 +197,7 @@ open class MessageBuilder(protected val generator: ISegmentNumberGenerator = Seg } protected open fun createGetCreditCardTransactionsMessage(context: JobContext, result: MessageBuilderResult, - parameter: GetTransactionsParameter): MessageBuilderResult { + parameter: GetAccountTransactionsParameter): MessageBuilderResult { val segments = mutableListOf(KreditkartenUmsaetze(generator.resetSegmentNumber(2), parameter)) diff --git a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/messages/datenelemente/implementierte/account/MaximaleAnzahlEintraege.kt b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/messages/datenelemente/implementierte/account/MaximaleAnzahlEintraege.kt index 865550a2..e020cdb2 100644 --- a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/messages/datenelemente/implementierte/account/MaximaleAnzahlEintraege.kt +++ b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/messages/datenelemente/implementierte/account/MaximaleAnzahlEintraege.kt @@ -2,7 +2,7 @@ package net.dankito.banking.fints.messages.datenelemente.implementierte.account import net.dankito.banking.fints.messages.Existenzstatus import net.dankito.banking.fints.messages.datenelemente.basisformate.NumerischesDatenelement -import net.dankito.banking.fints.model.GetTransactionsParameter +import net.dankito.banking.fints.model.GetAccountTransactionsParameter /** @@ -11,6 +11,6 @@ import net.dankito.banking.fints.model.GetTransactionsParameter */ open class MaximaleAnzahlEintraege(maxAmount: Int?, existenzstatus: Existenzstatus) : NumerischesDatenelement(maxAmount, 4, existenzstatus) { - constructor(parameter: GetTransactionsParameter) : this(parameter.maxCountEntriesIfSettingItIsAllowed, if (parameter.isSettingMaxCountEntriesAllowedByBank) Existenzstatus.Optional else Existenzstatus.NotAllowed) // > 0. O: „Eingabe Anzahl Einträge erlaubt“ (BPD) = „J“. N: sonst + constructor(parameter: GetAccountTransactionsParameter) : this(parameter.maxCountEntriesIfSettingItIsAllowed, if (parameter.isSettingMaxCountEntriesAllowedByBank) Existenzstatus.Optional else Existenzstatus.NotAllowed) // > 0. O: „Eingabe Anzahl Einträge erlaubt“ (BPD) = „J“. N: sonst } \ No newline at end of file diff --git a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/messages/segmente/implementierte/umsaetze/KontoumsaetzeZeitraumMt940Base.kt b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/messages/segmente/implementierte/umsaetze/KontoumsaetzeZeitraumMt940Base.kt index 1b370e9c..fcb54ad5 100644 --- a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/messages/segmente/implementierte/umsaetze/KontoumsaetzeZeitraumMt940Base.kt +++ b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/messages/segmente/implementierte/umsaetze/KontoumsaetzeZeitraumMt940Base.kt @@ -9,7 +9,7 @@ import net.dankito.banking.fints.messages.datenelementgruppen.Datenelementgruppe import net.dankito.banking.fints.messages.datenelementgruppen.implementierte.Segmentkopf import net.dankito.banking.fints.messages.segmente.Segment import net.dankito.banking.fints.messages.segmente.id.CustomerSegmentId -import net.dankito.banking.fints.model.GetTransactionsParameter +import net.dankito.banking.fints.model.GetAccountTransactionsParameter /** @@ -26,7 +26,7 @@ abstract class KontoumsaetzeZeitraumMt940Base( segmentVersion: Int, segmentNumber: Int, account: Datenelementgruppe, - parameter: GetTransactionsParameter + parameter: GetAccountTransactionsParameter ) : Segment(listOf( Segmentkopf(CustomerSegmentId.AccountTransactionsMt940, segmentVersion, segmentNumber), diff --git a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/messages/segmente/implementierte/umsaetze/KontoumsaetzeZeitraumMt940Version5.kt b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/messages/segmente/implementierte/umsaetze/KontoumsaetzeZeitraumMt940Version5.kt index d217b8c9..93315799 100644 --- a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/messages/segmente/implementierte/umsaetze/KontoumsaetzeZeitraumMt940Version5.kt +++ b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/messages/segmente/implementierte/umsaetze/KontoumsaetzeZeitraumMt940Version5.kt @@ -1,8 +1,7 @@ package net.dankito.banking.fints.messages.segmente.implementierte.umsaetze import net.dankito.banking.fints.messages.datenelementgruppen.implementierte.account.Kontoverbindung -import net.dankito.banking.fints.model.AccountData -import net.dankito.banking.fints.model.GetTransactionsParameter +import net.dankito.banking.fints.model.GetAccountTransactionsParameter /** @@ -17,5 +16,5 @@ import net.dankito.banking.fints.model.GetTransactionsParameter */ open class KontoumsaetzeZeitraumMt940Version5( segmentNumber: Int, - parameter: GetTransactionsParameter + parameter: GetAccountTransactionsParameter ) : KontoumsaetzeZeitraumMt940Base(5, segmentNumber, Kontoverbindung(parameter.account), parameter) \ No newline at end of file diff --git a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/messages/segmente/implementierte/umsaetze/KontoumsaetzeZeitraumMt940Version6.kt b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/messages/segmente/implementierte/umsaetze/KontoumsaetzeZeitraumMt940Version6.kt index 3e7fe93b..6ae4cfd4 100644 --- a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/messages/segmente/implementierte/umsaetze/KontoumsaetzeZeitraumMt940Version6.kt +++ b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/messages/segmente/implementierte/umsaetze/KontoumsaetzeZeitraumMt940Version6.kt @@ -1,8 +1,7 @@ package net.dankito.banking.fints.messages.segmente.implementierte.umsaetze import net.dankito.banking.fints.messages.datenelementgruppen.implementierte.account.Kontoverbindung -import net.dankito.banking.fints.model.AccountData -import net.dankito.banking.fints.model.GetTransactionsParameter +import net.dankito.banking.fints.model.GetAccountTransactionsParameter /** @@ -17,6 +16,6 @@ import net.dankito.banking.fints.model.GetTransactionsParameter */ open class KontoumsaetzeZeitraumMt940Version6( segmentNumber: Int, - parameter: GetTransactionsParameter + parameter: GetAccountTransactionsParameter ) : KontoumsaetzeZeitraumMt940Base(6, segmentNumber, Kontoverbindung(parameter.account), parameter) \ No newline at end of file diff --git a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/messages/segmente/implementierte/umsaetze/KontoumsaetzeZeitraumMt940Version7.kt b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/messages/segmente/implementierte/umsaetze/KontoumsaetzeZeitraumMt940Version7.kt index c7aed1f7..491b79fe 100644 --- a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/messages/segmente/implementierte/umsaetze/KontoumsaetzeZeitraumMt940Version7.kt +++ b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/messages/segmente/implementierte/umsaetze/KontoumsaetzeZeitraumMt940Version7.kt @@ -1,9 +1,8 @@ package net.dankito.banking.fints.messages.segmente.implementierte.umsaetze import net.dankito.banking.fints.messages.datenelementgruppen.implementierte.account.KontoverbindungInternational -import net.dankito.banking.fints.model.AccountData import net.dankito.banking.fints.model.BankData -import net.dankito.banking.fints.model.GetTransactionsParameter +import net.dankito.banking.fints.model.GetAccountTransactionsParameter /** @@ -18,6 +17,6 @@ import net.dankito.banking.fints.model.GetTransactionsParameter */ open class KontoumsaetzeZeitraumMt940Version7( segmentNumber: Int, - parameter: GetTransactionsParameter, + parameter: GetAccountTransactionsParameter, bank: BankData ) : KontoumsaetzeZeitraumMt940Base(7, segmentNumber, KontoverbindungInternational(parameter.account, bank), parameter) \ No newline at end of file diff --git a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/messages/segmente/implementierte/umsaetze/KreditkartenUmsaetze.kt b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/messages/segmente/implementierte/umsaetze/KreditkartenUmsaetze.kt index 86bf0ddc..19c57682 100644 --- a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/messages/segmente/implementierte/umsaetze/KreditkartenUmsaetze.kt +++ b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/messages/segmente/implementierte/umsaetze/KreditkartenUmsaetze.kt @@ -9,12 +9,12 @@ import net.dankito.banking.fints.messages.datenelementgruppen.implementierte.Seg import net.dankito.banking.fints.messages.datenelementgruppen.implementierte.account.Kontoverbindung import net.dankito.banking.fints.messages.segmente.Segment import net.dankito.banking.fints.messages.segmente.id.CustomerSegmentId -import net.dankito.banking.fints.model.GetTransactionsParameter +import net.dankito.banking.fints.model.GetAccountTransactionsParameter open class KreditkartenUmsaetze( segmentNumber: Int, - parameter: GetTransactionsParameter + parameter: GetAccountTransactionsParameter ) : Segment(listOf( Segmentkopf(CustomerSegmentId.CreditCardTransactions, 2, segmentNumber), Kontoverbindung(parameter.account), diff --git a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/model/GetAccountTransactionsParameter.kt b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/model/GetAccountTransactionsParameter.kt new file mode 100644 index 00000000..e0b9a875 --- /dev/null +++ b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/model/GetAccountTransactionsParameter.kt @@ -0,0 +1,30 @@ +package net.dankito.banking.fints.model + +import net.dankito.utils.multiplatform.Date +import kotlin.jvm.JvmOverloads + + +open class GetAccountTransactionsParameter @JvmOverloads constructor( + bank: BankData, + account: AccountData, + alsoRetrieveBalance: Boolean = true, + fromDate: Date? = null, + toDate: Date? = null, + + /** + * Be aware this is by far not supported by all banks. + * And it depends on the actual job if setting maxCountEntries is supported or not. + */ + maxCountEntries: Int? = null, + abortIfTanIsRequired: Boolean = false, + retrievedChunkListener: ((Collection) -> Unit)? = null +) : GetTransactionsParameter(bank, alsoRetrieveBalance, fromDate, toDate, maxCountEntries, abortIfTanIsRequired, retrievedChunkListener) { + + open var account: AccountData = account + internal set + + + constructor(parameter: GetTransactionsParameter, account: AccountData) : this(parameter.bank, account, parameter.alsoRetrieveBalance, + parameter.fromDate, parameter.toDate, parameter.maxCountEntries, parameter.abortIfTanIsRequired, parameter.retrievedChunkListener) + +} \ No newline at end of file diff --git a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/model/GetTransactionsParameter.kt b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/model/GetTransactionsParameter.kt index 3e97d72d..e17dfc4f 100644 --- a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/model/GetTransactionsParameter.kt +++ b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/model/GetTransactionsParameter.kt @@ -5,7 +5,7 @@ import kotlin.jvm.JvmOverloads open class GetTransactionsParameter @JvmOverloads constructor( - account: AccountData, + open val bank: BankData, open val alsoRetrieveBalance: Boolean = true, open val fromDate: Date? = null, open val toDate: Date? = null, @@ -20,9 +20,6 @@ open class GetTransactionsParameter @JvmOverloads constructor( open val retrievedChunkListener: ((Collection) -> Unit)? = null ) { - open var account: AccountData = account - internal set - internal open var isSettingMaxCountEntriesAllowedByBank = false internal open val maxCountEntriesIfSettingItIsAllowed: Int? diff --git a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/model/RetrievedAccountData.kt b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/model/RetrievedAccountData.kt index b80859af..125addab 100644 --- a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/model/RetrievedAccountData.kt +++ b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/model/RetrievedAccountData.kt @@ -16,18 +16,10 @@ open class RetrievedAccountData( companion object { - fun balanceAndTransactionsNotRequestedByUser(account: AccountData): RetrievedAccountData { - return RetrievedAccountData(account, true, null, listOf(), listOf(), null, null) - } - fun unsuccessful(account: AccountData): RetrievedAccountData { return RetrievedAccountData(account, false, null, listOf(), listOf(), null, null) } - fun unsuccessfulList(account: AccountData): List { - return listOf(unsuccessful(account)) - } - } diff --git a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/response/client/AddAccountResponse.kt b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/response/client/AddAccountResponse.kt index 95b07c7e..8fac0505 100644 --- a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/response/client/AddAccountResponse.kt +++ b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/response/client/AddAccountResponse.kt @@ -6,12 +6,34 @@ import net.dankito.banking.fints.response.BankResponse open class AddAccountResponse( context: JobContext, - response: BankResponse, - open val bank: BankData, - retrievedData: List = listOf() -) : GetTransactionsResponse(context, response, retrievedData) { + getAccountsResponse: BankResponse, + open val retrievedTransactionsResponses: List = listOf() +) : FinTsClientResponse(context, getAccountsResponse) { + + open val bank: BankData = context.bank override val successful: Boolean get() = super.successful && bank.accounts.isNotEmpty() + && bank.accounts.size == retrievedTransactionsResponses.size + && retrievedTransactionsResponses.none { it.noTanMethodSelected } + && retrievedTransactionsResponses.none { it.isPinLocked } + && retrievedTransactionsResponses.none { it.wrongCredentialsEntered } + && retrievedTransactionsResponses.none { it.internalError != null } + && retrievedTransactionsResponses.none { it.errorMessagesFromBank.isNotEmpty() } + + override val internalError: String? + get() = super.internalError + ?: retrievedTransactionsResponses.mapNotNull { it.internalError }.joinToString("\r\n") + .ifBlank { null } // if mapNotNull { it.internalError } results in an empty list, then joinToString() results in an empty string -> return null then + + override val errorMessagesFromBank: List + get() { + val allMessages = super.errorMessagesFromBank.toMutableList() + allMessages.addAll(retrievedTransactionsResponses.flatMap { it.errorMessagesFromBank }) + return allMessages + } + + open val retrievedData: List + get() = retrievedTransactionsResponses.mapNotNull { it.retrievedData } } \ No newline at end of file diff --git a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/response/client/GetAccountTransactionsResponse.kt b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/response/client/GetAccountTransactionsResponse.kt new file mode 100644 index 00000000..31cca4c8 --- /dev/null +++ b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/response/client/GetAccountTransactionsResponse.kt @@ -0,0 +1,31 @@ +package net.dankito.banking.fints.response.client + +import net.dankito.banking.fints.model.JobContext +import net.dankito.banking.fints.model.RetrievedAccountData +import net.dankito.banking.fints.response.BankResponse + + +open class GetAccountTransactionsResponse( + context: JobContext, + response: BankResponse, + open val retrievedData: RetrievedAccountData?, + /** + * This value is only set if [GetTransactionsParameter.maxCountEntries] was set to tell caller if maxCountEntries parameter has been evaluated or not + */ + open var isSettingMaxCountEntriesAllowedByBank: Boolean? = null +) : FinTsClientResponse(context, response) { + + override val successful: Boolean + get() = super.successful + && retrievedData?.successfullyRetrievedData == true + + override val internalError: String? + get() = super.internalError + ?: retrievedData?.errorMessage + + + override fun toString(): String { + return super.toString() + ": Retrieved data: $retrievedData" + } + +} \ No newline at end of file diff --git a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/response/client/GetTransactionsResponse.kt b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/response/client/GetTransactionsResponse.kt index bb1d782a..8ab62382 100644 --- a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/response/client/GetTransactionsResponse.kt +++ b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/response/client/GetTransactionsResponse.kt @@ -1,29 +1,35 @@ package net.dankito.banking.fints.response.client -import net.dankito.banking.fints.model.JobContext import net.dankito.banking.fints.model.RetrievedAccountData -import net.dankito.banking.fints.response.BankResponse open class GetTransactionsResponse( - context: JobContext, - response: BankResponse, - open val retrievedData: List = listOf(), - /** - * This value is only set if [GetTransactionsParameter.maxCountEntries] was set to tell caller if maxCountEntries parameter has been evaluated or not - */ - open var isSettingMaxCountEntriesAllowedByBank: Boolean? = null -) : FinTsClientResponse(context, response) { + open val retrievedResponses: List, + errorMessage: String? = null +) : FinTsClientResponse(isSuccessful(retrievedResponses), retrievedResponses.any { it.noTanMethodSelected }, + retrievedResponses.any { it.isStrongAuthenticationRequired }, retrievedResponses.map { it.tanRequired }.firstOrNull(), + retrievedResponses.flatMap { it.messageLogWithoutSensitiveData }, + errorMessage ?: retrievedResponses.mapNotNull { it.internalError }.joinToString("\r\n"), + retrievedResponses.flatMap { it.errorMessagesFromBank }, retrievedResponses.any { it.isPinLocked }, + retrievedResponses.any { it.wrongCredentialsEntered }, retrievedResponses.any { it.userCancelledAction }, + retrievedResponses.any { it.tanRequiredButWeWereToldToAbortIfSo }, + retrievedResponses.any { it.isJobAllowed }, retrievedResponses.any { it.isJobAllowed }, + retrievedResponses.flatMap { it.allowedVersions }.toSet().toList(), + retrievedResponses.flatMap { it.supportedVersions }.toSet().toList() +) { - override val successful: Boolean - get() = super.successful - && retrievedData.isNotEmpty() - && retrievedData.none { it.account.supportsRetrievingAccountTransactions && it.successfullyRetrievedData == false } + companion object { - // TODO: remove again if then in AddAccountResponse errors get displayed that should or extract getRetrievingTransactionsError() and override in AddAccountResponse - override val internalError: String? - get() = super.internalError - ?: retrievedData.mapNotNull { it.errorMessage }.firstOrNull() + fun isSuccessful(retrievedResponses: List): Boolean { + return retrievedResponses.isNotEmpty() && + retrievedResponses.none { it.retrievedData?.account?.supportsRetrievingAccountTransactions == true && it.retrievedData?.successfullyRetrievedData == false } + } + + } + + + open val retrievedData: List + get() = retrievedResponses.mapNotNull { it.retrievedData } override fun toString(): String { diff --git a/fints4k/src/commonTest/kotlin/net/dankito/banking/fints/messages/MessageBuilderTest.kt b/fints4k/src/commonTest/kotlin/net/dankito/banking/fints/messages/MessageBuilderTest.kt index e944fbd9..fb5708ea 100644 --- a/fints4k/src/commonTest/kotlin/net/dankito/banking/fints/messages/MessageBuilderTest.kt +++ b/fints4k/src/commonTest/kotlin/net/dankito/banking/fints/messages/MessageBuilderTest.kt @@ -132,7 +132,7 @@ class MessageBuilderTest : FinTsTestBase() { val context = createContext() // when - val result = underTest.createGetTransactionsMessage(context, GetTransactionsParameter(Account)) + val result = underTest.createGetTransactionsMessage(context, GetAccountTransactionsParameter(Bank, Account)) // then expect(result.isJobAllowed).toBe(false) @@ -151,7 +151,7 @@ class MessageBuilderTest : FinTsTestBase() { val context = createContext() // when - val result = underTest.createGetTransactionsMessage(context, GetTransactionsParameter(account)) + val result = underTest.createGetTransactionsMessage(context, GetAccountTransactionsParameter(Bank, account)) // then expect(result.isJobAllowed).toBe(true) @@ -175,7 +175,7 @@ class MessageBuilderTest : FinTsTestBase() { val maxCountEntries = 99 // when - val result = underTest.createGetTransactionsMessage(context, GetTransactionsParameter(account, false, fromDate, toDate, maxCountEntries)) + val result = underTest.createGetTransactionsMessage(context, GetAccountTransactionsParameter(Bank, account, false, fromDate, toDate, maxCountEntries)) // then expect(result.createdMessage).notToBeNull() @@ -210,7 +210,7 @@ class MessageBuilderTest : FinTsTestBase() { // when val result = underTest.createGetTransactionsMessage(context, // TODO: test Aufsetzpunkt / continuationId - GetTransactionsParameter(account, false, fromDate, toDate, maxCountEntries, false)) + GetAccountTransactionsParameter(Bank, account, false, fromDate, toDate, maxCountEntries, false)) // then expect(result.createdMessage).notToBeNull() diff --git a/fints4k/src/jvm6Test/kotlin/net/dankito/banking/fints/FinTsClientTestBase.kt b/fints4k/src/jvm6Test/kotlin/net/dankito/banking/fints/FinTsClientTestBase.kt index 51a45ad3..a47a82d4 100644 --- a/fints4k/src/jvm6Test/kotlin/net/dankito/banking/fints/FinTsClientTestBase.kt +++ b/fints4k/src/jvm6Test/kotlin/net/dankito/banking/fints/FinTsClientTestBase.kt @@ -15,10 +15,7 @@ import net.dankito.banking.fints.messages.datenelemente.implementierte.tan.TanMe import net.dankito.banking.fints.messages.datenelemente.implementierte.tan.TanMediumKlasse import net.dankito.banking.fints.messages.segmente.id.CustomerSegmentId import net.dankito.banking.fints.model.* -import net.dankito.banking.fints.response.client.AddAccountResponse -import net.dankito.banking.fints.response.client.FinTsClientResponse -import net.dankito.banking.fints.response.client.GetTanMediaListResponse -import net.dankito.banking.fints.response.client.GetTransactionsResponse +import net.dankito.banking.fints.response.client.* import net.dankito.utils.multiplatform.Date import net.dankito.utils.multiplatform.DateFormatter import net.dankito.utils.multiplatform.UUID @@ -144,7 +141,7 @@ open class FinTsClientTestBase { fun getTransactions() { // given - val response = AtomicReference() + val response = AtomicReference() val countDownLatch = CountDownLatch(1) underTest.addAccountAsync(Bank.toAddAccountParameter(false)) { // retrieve basic data, e.g. accounts @@ -154,7 +151,7 @@ open class FinTsClientTestBase { // when // some banks support retrieving account transactions of last 90 days without TAN - underTest.tryGetTransactionsOfLast90DaysWithoutTan(Bank, account!!) { + underTest.tryGetAccountTransactionsOfLast90DaysWithoutTan(Bank, account!!) { response.set(it) countDownLatch.countDown() } diff --git a/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/service/testaccess/TestAccessBankingClient.kt b/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/service/testaccess/TestAccessBankingClient.kt index 47c8dc67..2c42d92d 100644 --- a/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/service/testaccess/TestAccessBankingClient.kt +++ b/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/service/testaccess/TestAccessBankingClient.kt @@ -45,7 +45,7 @@ open class TestAccessBankingClient( } } - override fun getTransactionsAsync(parameter: GetTransactionsParameter, callback: (GetTransactionsResponse) -> Unit) { + override fun getAccountTransactionsAsync(parameter: GetTransactionsParameter, callback: (GetTransactionsResponse) -> Unit) { asyncRunner.runAsync { callback(GetTransactionsResponse(createRetrievedAccountData(parameter.account))) } diff --git a/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/IBankingClient.kt b/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/IBankingClient.kt index 71420d96..926c4c2a 100644 --- a/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/IBankingClient.kt +++ b/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/IBankingClient.kt @@ -15,10 +15,7 @@ interface IBankingClient { fun addAccountAsync(callback: (AddAccountResponse) -> Unit) - fun getTransactionsAsync( - parameter: GetTransactionsParameter, - callback: (GetTransactionsResponse) -> Unit - ) + fun getAccountTransactionsAsync(parameter: GetTransactionsParameter, callback: (GetTransactionsResponse) -> Unit) fun transferMoneyAsync(data: TransferMoneyData, callback: (BankingClientResponse) -> Unit) diff --git a/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/presenter/BankingPresenter.kt b/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/presenter/BankingPresenter.kt index c8d00467..5f6780ba 100644 --- a/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/presenter/BankingPresenter.kt +++ b/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/presenter/BankingPresenter.kt @@ -371,7 +371,7 @@ open class BankingPresenter( getBankingClientForBank(account.bank)?.let { client -> val startDate = Date() - client.getTransactionsAsync(GetTransactionsParameter(account,true, fromDate, null, abortIfTanIsRequired, { receivedAccountTransactionChunk(account, it) } )) { response -> + client.getAccountTransactionsAsync(GetTransactionsParameter(account,true, fromDate, null, abortIfTanIsRequired, { receivedAccountTransactionChunk(account, it) } )) { response -> if (response.tanRequiredButWeWereToldToAbortIfSo == false) { // don't call retrievedAccountTransactions() if aborted due to TAN required but we told client to abort if so retrievedAccountTransactions(response, startDate, fromDate == null) diff --git a/ui/fints4kBankingClient/src/commonMain/kotlin/net/dankito/banking/fints4kBankingClient.kt b/ui/fints4kBankingClient/src/commonMain/kotlin/net/dankito/banking/fints4kBankingClient.kt index 24518e4d..7964bfd1 100644 --- a/ui/fints4kBankingClient/src/commonMain/kotlin/net/dankito/banking/fints4kBankingClient.kt +++ b/ui/fints4kBankingClient/src/commonMain/kotlin/net/dankito/banking/fints4kBankingClient.kt @@ -84,7 +84,8 @@ open class fints4kBankingClient( } - override fun getTransactionsAsync(parameter: GetTransactionsParameter, callback: (GetTransactionsResponse) -> Unit) { + // we currently leave the data model of the UI layer untouched as this may changes soon anyway + override fun getAccountTransactionsAsync(parameter: GetTransactionsParameter, callback: (GetTransactionsResponse) -> Unit) { val account = parameter.account findAccountForAccount(account) { accountData, response -> @@ -97,25 +98,26 @@ open class fints4kBankingClient( } } else { - val mappedParameter = GetTransactionsParameter(accountData, parameter.alsoRetrieveBalance, parameter.fromDate, + val mappedParameter = GetAccountTransactionsParameter(fintsBank, accountData, parameter.alsoRetrieveBalance, parameter.fromDate, parameter.toDate, null, parameter.abortIfTanIsRequired) { parameter.retrievedChunkListener?.invoke(mapper.mapTransactions(account, it)) } - doGetTransactionsAsync(mappedParameter, account, callback) + doGetAccountTransactionsAsync(mappedParameter, account, callback) } } } - protected open fun doGetTransactionsAsync(parameter: net.dankito.banking.fints.model.GetTransactionsParameter, - account: TypedBankAccount, callback: (GetTransactionsResponse) -> Unit) { - client.getTransactionsAsync(parameter) { response -> + protected open fun doGetAccountTransactionsAsync(parameter: net.dankito.banking.fints.model.GetAccountTransactionsParameter, + account: TypedBankAccount, callback: (GetTransactionsResponse) -> Unit) { + client.getAccountTransactionsAsync(parameter) { response -> handleGetTransactionsResponse(account, response, callback) } } - protected open fun handleGetTransactionsResponse(account: TypedBankAccount, response: net.dankito.banking.fints.response.client.GetTransactionsResponse, + protected open fun handleGetTransactionsResponse(account: TypedBankAccount, response: net.dankito.banking.fints.response.client.GetAccountTransactionsResponse, callback: (GetTransactionsResponse) -> Unit) { + // we currently leave the data model of the UI layer untouched as this may changes soon anyway val mappedResponse = mapper.mapResponse(account, response) saveData(response) diff --git a/ui/fints4kBankingClient/src/commonMain/kotlin/net/dankito/banking/mapper/fints4kModelMapper.kt b/ui/fints4kBankingClient/src/commonMain/kotlin/net/dankito/banking/mapper/fints4kModelMapper.kt index 16d48199..e0fbf542 100644 --- a/ui/fints4kBankingClient/src/commonMain/kotlin/net/dankito/banking/mapper/fints4kModelMapper.kt +++ b/ui/fints4kBankingClient/src/commonMain/kotlin/net/dankito/banking/mapper/fints4kModelMapper.kt @@ -32,9 +32,9 @@ open class fints4kModelMapper(protected val modelCreator: IModelCreator) { return AddAccountResponse(bank, map(bank, response.retrievedData), response.errorMessage, response.didBankReturnError, response.wrongCredentialsEntered, response.userCancelledAction) } - open fun mapResponse(account: TypedBankAccount, response: net.dankito.banking.fints.response.client.GetTransactionsResponse): GetTransactionsResponse { + open fun mapResponse(account: TypedBankAccount, response: net.dankito.banking.fints.response.client.GetAccountTransactionsResponse): GetTransactionsResponse { - return GetTransactionsResponse(map(account.bank as TypedBankData, response.retrievedData), + return GetTransactionsResponse(response.retrievedData?.let { map(account.bank as TypedBankData, it)?.let { listOf(it) } } ?: listOf(), response.errorMessage, response.didBankReturnError, response.wrongCredentialsEntered, response.userCancelledAction, response.tanRequiredButWeWereToldToAbortIfSo) } diff --git a/ui/hbci4jBankingClient/src/main/kotlin/net/dankito/banking/hbci4jBankingClient.kt b/ui/hbci4jBankingClient/src/main/kotlin/net/dankito/banking/hbci4jBankingClient.kt index 76a6a917..e0f6d187 100644 --- a/ui/hbci4jBankingClient/src/main/kotlin/net/dankito/banking/hbci4jBankingClient.kt +++ b/ui/hbci4jBankingClient/src/main/kotlin/net/dankito/banking/hbci4jBankingClient.kt @@ -136,7 +136,7 @@ open class hbci4jBankingClient( return getTransactions(GetTransactionsParameter(account, account.supportsRetrievingBalance, ninetyDaysAgo)) // TODO: implement abortIfTanIsRequired } - override fun getTransactionsAsync(parameter: GetTransactionsParameter, callback: (GetTransactionsResponse) -> Unit) { + override fun getAccountTransactionsAsync(parameter: GetTransactionsParameter, callback: (GetTransactionsResponse) -> Unit) { asyncRunner.runAsync { callback(getTransactions(parameter)) }