Clarified that getTransactionsAsync() only retrieves the transactions of one account; also fixed data model in regard to this

This commit is contained in:
dankito 2021-11-13 15:17:06 +01:00
parent e90579a1b7
commit e87adc8499
24 changed files with 182 additions and 122 deletions

View File

@ -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<GetAccountTransactionsResponse>()
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<AccountData, RetrievedAccountData>,
retrievedTransactionsResponses: List<GetAccountTransactionsResponse>,
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) {
getAccountTransactionsAsync(createGetAccountTransactionsOfLast90DaysParameter(bank, account), callback)
}
protected open fun createGetAccountTransactionsOfLast90DaysParameter(bank: BankData, account: AccountData): GetAccountTransactionsParameter {
val ninetyDaysAgo = Date.today.addDays(-90)
getTransactionsAsync(GetTransactionsParameter(account, account.supportsRetrievingBalance, ninetyDaysAgo, abortIfTanIsRequired = true), bank) { response ->
callback(response)
}
return GetAccountTransactionsParameter(bank, account, account.supportsRetrievingBalance, ninetyDaysAgo, abortIfTanIsRequired = true)
}
open fun getTransactionsAsync(parameter: GetTransactionsParameter, bank: BankData, callback: (GetTransactionsResponse) -> Unit) {
open fun getAccountTransactionsAsync(parameter: GetAccountTransactionsParameter, callback: (GetAccountTransactionsResponse) -> Unit) {
val context = JobContext(JobContextType.GetTransactions, this.callback, product, bank, parameter.account)
val context = JobContext(JobContextType.GetTransactions, this.callback, product, parameter.bank, parameter.account)
jobExecutor.getTransactionsAsync(context, parameter, callback)
}

View File

@ -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)
}

View File

@ -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<BalanceSegment>(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)

View File

@ -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<Segment>(KreditkartenUmsaetze(generator.resetSegmentNumber(2), parameter))

View File

@ -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
}

View File

@ -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),

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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),

View File

@ -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<AccountTransaction>) -> 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)
}

View File

@ -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<AccountTransaction>) -> Unit)? = null
) {
open var account: AccountData = account
internal set
internal open var isSettingMaxCountEntriesAllowedByBank = false
internal open val maxCountEntriesIfSettingItIsAllowed: Int?

View File

@ -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<RetrievedAccountData> {
return listOf(unsuccessful(account))
}
}

View File

@ -6,12 +6,34 @@ import net.dankito.banking.fints.response.BankResponse
open class AddAccountResponse(
context: JobContext,
response: BankResponse,
open val bank: BankData,
retrievedData: List<RetrievedAccountData> = listOf()
) : GetTransactionsResponse(context, response, retrievedData) {
getAccountsResponse: BankResponse,
open val retrievedTransactionsResponses: List<GetAccountTransactionsResponse> = 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<String>
get() {
val allMessages = super.errorMessagesFromBank.toMutableList()
allMessages.addAll(retrievedTransactionsResponses.flatMap { it.errorMessagesFromBank })
return allMessages
}
open val retrievedData: List<RetrievedAccountData>
get() = retrievedTransactionsResponses.mapNotNull { it.retrievedData }
}

View File

@ -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"
}
}

View File

@ -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<RetrievedAccountData> = 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<GetAccountTransactionsResponse>,
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<GetAccountTransactionsResponse>): Boolean {
return retrievedResponses.isNotEmpty() &&
retrievedResponses.none { it.retrievedData?.account?.supportsRetrievingAccountTransactions == true && it.retrievedData?.successfullyRetrievedData == false }
}
}
open val retrievedData: List<RetrievedAccountData>
get() = retrievedResponses.mapNotNull { it.retrievedData }
override fun toString(): String {

View File

@ -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()

View File

@ -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<GetTransactionsResponse>()
val response = AtomicReference<GetAccountTransactionsResponse>()
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()
}

View File

@ -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)))
}

View File

@ -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)

View File

@ -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)

View File

@ -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,
protected open fun doGetAccountTransactionsAsync(parameter: net.dankito.banking.fints.model.GetAccountTransactionsParameter,
account: TypedBankAccount, callback: (GetTransactionsResponse) -> Unit) {
client.getTransactionsAsync(parameter) { response ->
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)

View File

@ -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)
}

View File

@ -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))
}