From 614074b9b9a75f44e57b5f18b72dd3b834427edb Mon Sep 17 00:00:00 2001 From: dankito Date: Mon, 25 May 2020 00:51:30 +0200 Subject: [PATCH] Implemented abortIfTanIsRequired so that at app start we can try to get all accounts' transaction without that user is being asked to enter a TAN if retrieving transaction without TAN isn't supported --- .../net/dankito/banking/fints/FinTsClient.kt | 11 ++++++++++- .../banking/fints/model/DialogContext.kt | 1 + .../fints/model/GetTransactionsParameter.kt | 1 + .../banking/fints/response/Response.kt | 3 +++ .../parameters/GetTransactionsParameter.kt | 1 + .../banking/ui/presenter/BankingPresenter.kt | 19 +++++++++++++++---- .../dankito/banking/fints4kBankingClient.kt | 2 +- .../dankito/banking/hbci4jBankingClient.kt | 2 +- 8 files changed, 33 insertions(+), 7 deletions(-) diff --git a/fints4k/src/main/kotlin/net/dankito/banking/fints/FinTsClient.kt b/fints4k/src/main/kotlin/net/dankito/banking/fints/FinTsClient.kt index 5fb29e48..7298afa0 100644 --- a/fints4k/src/main/kotlin/net/dankito/banking/fints/FinTsClient.kt +++ b/fints4k/src/main/kotlin/net/dankito/banking/fints/FinTsClient.kt @@ -255,13 +255,14 @@ open class FinTsClient @JvmOverloads constructor( val now = Date() val ninetyDaysAgo = Date(now.time - NinetyDaysAgoMilliseconds - now.timezoneOffset * 60 * 1000) // map to UTC - val response = getTransactions(GetTransactionsParameter(account.supportsFeature(AccountFeature.RetrieveBalance), ninetyDaysAgo), bank, customer, account) + val response = getTransactions(GetTransactionsParameter(account.supportsFeature(AccountFeature.RetrieveBalance), ninetyDaysAgo, abortIfTanIsRequired = true), bank, customer, account) account.triedToRetrieveTransactionsOfLast90DaysWithoutTan = true if (response.isSuccessful) { if (response.isStrongAuthenticationRequired == false || hasRetrievedTransactionsWithTanJustBefore) { + // TODO: make use of supportsRetrievingTransactionsOfLast90DaysWithoutTan in UI e.g. in updateAccountsTransactionsIfNoTanIsRequiredAsync() account.supportsRetrievingTransactionsOfLast90DaysWithoutTan = !!! response.isStrongAuthenticationRequired } } @@ -310,6 +311,8 @@ open class FinTsClient @JvmOverloads constructor( val bookedTransactions = mutableListOf() var remainingMt940String = "" + dialogContext.abortIfTanIsRequired = parameter.abortIfTanIsRequired + dialogContext.chunkedResponseHandler = { response -> response.getFirstSegmentById(InstituteSegmentId.AccountTransactionsMt940)?.let { transactionsSegment -> val (chunkTransaction, remainder) = mt940Parser.parseTransactionsChunk(remainingMt940String + transactionsSegment.bookedTransactionsString, account) @@ -699,6 +702,12 @@ open class FinTsClient @JvmOverloads constructor( protected open fun handleMayRequiresTan(response: Response, dialogContext: DialogContext): Response { // TODO: use response from DialogContext if (response.isStrongAuthenticationRequired) { + if (dialogContext.abortIfTanIsRequired) { + response.tanRequiredButWeWereToldToAbortIfSo = true + + return response + } + response.tanResponse?.let { tanResponse -> val customer = dialogContext.customer val enteredTanResult = callback.enterTan(customer, createTanChallenge(tanResponse, customer)) diff --git a/fints4k/src/main/kotlin/net/dankito/banking/fints/model/DialogContext.kt b/fints4k/src/main/kotlin/net/dankito/banking/fints/model/DialogContext.kt index b42d9e0e..f35072ca 100644 --- a/fints4k/src/main/kotlin/net/dankito/banking/fints/model/DialogContext.kt +++ b/fints4k/src/main/kotlin/net/dankito/banking/fints/model/DialogContext.kt @@ -8,6 +8,7 @@ open class DialogContext( bank: BankData, customer: CustomerData, product: ProductData, + var abortIfTanIsRequired: Boolean = false, var currentMessage: MessageBuilderResult? = null, var dialogId: String = InitialDialogId, var response: Response? = null, diff --git a/fints4k/src/main/kotlin/net/dankito/banking/fints/model/GetTransactionsParameter.kt b/fints4k/src/main/kotlin/net/dankito/banking/fints/model/GetTransactionsParameter.kt index ea9f2315..f1c230c2 100644 --- a/fints4k/src/main/kotlin/net/dankito/banking/fints/model/GetTransactionsParameter.kt +++ b/fints4k/src/main/kotlin/net/dankito/banking/fints/model/GetTransactionsParameter.kt @@ -8,5 +8,6 @@ open class GetTransactionsParameter @JvmOverloads constructor( val fromDate: Date? = null, val toDate: Date? = null, val maxCountEntries: Int? = null, + val abortIfTanIsRequired: Boolean = false, val retrievedChunkListener: ((List) -> Unit)? = null ) \ No newline at end of file diff --git a/fints4k/src/main/kotlin/net/dankito/banking/fints/response/Response.kt b/fints4k/src/main/kotlin/net/dankito/banking/fints/response/Response.kt index ac7401f6..803f5d0e 100644 --- a/fints4k/src/main/kotlin/net/dankito/banking/fints/response/Response.kt +++ b/fints4k/src/main/kotlin/net/dankito/banking/fints/response/Response.kt @@ -29,9 +29,12 @@ open class Response( open var tanRequiredButUserDidNotEnterOne = false + open var tanRequiredButWeWereToldToAbortIfSo = false + open val successful: Boolean get() = noTanProcedureSelected == false && couldCreateMessage && didReceiveResponse && responseContainsErrors == false && tanRequiredButUserDidNotEnterOne == false + && tanRequiredButWeWereToldToAbortIfSo == false open val isStrongAuthenticationRequired: Boolean get() = tanResponse?.isStrongAuthenticationRequired == true diff --git a/ui/BankingUiCommon/src/main/java/net/dankito/banking/ui/model/parameters/GetTransactionsParameter.kt b/ui/BankingUiCommon/src/main/java/net/dankito/banking/ui/model/parameters/GetTransactionsParameter.kt index c86683e9..3e00671f 100644 --- a/ui/BankingUiCommon/src/main/java/net/dankito/banking/ui/model/parameters/GetTransactionsParameter.kt +++ b/ui/BankingUiCommon/src/main/java/net/dankito/banking/ui/model/parameters/GetTransactionsParameter.kt @@ -8,6 +8,7 @@ open class GetTransactionsParameter( val alsoRetrieveBalance: Boolean = true, val fromDate: Date? = null, val toDate: Date? = null, + val abortIfTanIsRequired: Boolean = false, val retrievedChunkListener: ((List) -> Unit)? = null ) { diff --git a/ui/BankingUiCommon/src/main/java/net/dankito/banking/ui/presenter/BankingPresenter.kt b/ui/BankingUiCommon/src/main/java/net/dankito/banking/ui/presenter/BankingPresenter.kt index d7d7c446..959077f8 100644 --- a/ui/BankingUiCommon/src/main/java/net/dankito/banking/ui/presenter/BankingPresenter.kt +++ b/ui/BankingUiCommon/src/main/java/net/dankito/banking/ui/presenter/BankingPresenter.kt @@ -17,6 +17,7 @@ import net.dankito.banking.ui.model.tan.TanGeneratorTanMedium import net.dankito.banking.util.IBankIconFinder import net.dankito.banking.fints.banks.IBankFinder import net.dankito.banking.fints.model.BankInfo +import net.dankito.banking.ui.model.parameters.GetTransactionsParameter import net.dankito.banking.ui.model.settings.AppSettings import net.dankito.utils.IThreadPool import net.dankito.utils.ThreadPool @@ -99,6 +100,8 @@ open class BankingPresenter( threadPool.runAsync { readAppSettings() readPersistedAccounts() + + updateAccountsTransactionsIfNoTanIsRequiredAsync() } // preloadBankList asynchronously; on Android it takes approximately 18 seconds till banks are indexed for first time -> do it as early as possible @@ -264,16 +267,16 @@ open class BankingPresenter( open fun fetchAccountTransactionsAsync(bankAccount: BankAccount, callback: (GetTransactionsResponse) -> Unit) { - fetchAccountTransactionsAsync(bankAccount, null, callback) + fetchAccountTransactionsAsync(bankAccount, null, false, callback) } - open fun fetchAccountTransactionsAsync(bankAccount: BankAccount, fromDate: Date?, + open fun fetchAccountTransactionsAsync(bankAccount: BankAccount, fromDate: Date?, abortIfTanIsRequired: Boolean = false, callback: (GetTransactionsResponse) -> Unit) { getClientForAccount(bankAccount.account)?.let { client -> val startDate = Date() - client.getTransactionsAsync(bankAccount, net.dankito.banking.ui.model.parameters.GetTransactionsParameter(true, fromDate, null, { receivedAccountsTransactionChunk(bankAccount, it) } )) { response -> + client.getTransactionsAsync(bankAccount, GetTransactionsParameter(true, fromDate, null, abortIfTanIsRequired, { receivedAccountsTransactionChunk(bankAccount, it) } )) { response -> retrievedAccountTransactions(bankAccount, startDate, response) @@ -283,12 +286,20 @@ open class BankingPresenter( } open fun updateAccountsTransactionsAsync(callback: (GetTransactionsResponse) -> Unit) { + updateAccountsTransactionsAsync(false, callback) + } + + open fun updateAccountsTransactionsIfNoTanIsRequiredAsync() { + updateAccountsTransactionsAsync(true) { } + } + + protected open fun updateAccountsTransactionsAsync(abortIfTanIsRequired: Boolean = false, callback: (GetTransactionsResponse) -> Unit) { clientsForAccounts.keys.forEach { account -> account.bankAccounts.forEach { bankAccount -> if (bankAccount.supportsRetrievingAccountTransactions) { val fromDate = bankAccount.lastRetrievedTransactionsTimestamp?.let { Date(it.time - OneDayMillis) } // one day before last received transactions - fetchAccountTransactionsAsync(bankAccount, fromDate, callback) + fetchAccountTransactionsAsync(bankAccount, fromDate, abortIfTanIsRequired, callback) } } } diff --git a/ui/fints4kBankingClient/src/main/kotlin/net/dankito/banking/fints4kBankingClient.kt b/ui/fints4kBankingClient/src/main/kotlin/net/dankito/banking/fints4kBankingClient.kt index d8f64d1f..85bc5756 100644 --- a/ui/fints4kBankingClient/src/main/kotlin/net/dankito/banking/fints4kBankingClient.kt +++ b/ui/fints4kBankingClient/src/main/kotlin/net/dankito/banking/fints4kBankingClient.kt @@ -106,7 +106,7 @@ open class fints4kBankingClient( callback(GetTransactionsResponse(false, "Cannot find account for ${bankAccount.identifier}")) // TODO: translate } else { - client.getTransactionsAsync(net.dankito.banking.fints.model.GetTransactionsParameter(parameter.alsoRetrieveBalance, parameter.fromDate, parameter.toDate, null, + client.getTransactionsAsync(GetTransactionsParameter(parameter.alsoRetrieveBalance, parameter.fromDate, parameter.toDate, null, parameter.abortIfTanIsRequired, { parameter.retrievedChunkListener?.invoke(mapper.mapTransactions(bankAccount, it)) } ), account) { response -> val mappedResponse = mapper.mapResponse(bankAccount, response) 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 8f341513..ec9c8c35 100644 --- a/ui/hbci4jBankingClient/src/main/kotlin/net/dankito/banking/hbci4jBankingClient.kt +++ b/ui/hbci4jBankingClient/src/main/kotlin/net/dankito/banking/hbci4jBankingClient.kt @@ -143,7 +143,7 @@ open class hbci4jBankingClient( open fun getTransactionsOfLast90Days(bankAccount: BankAccount): GetTransactionsResponse { val ninetyDaysAgo = Date(Date().time - NinetyDaysInMilliseconds) - return getTransactions(bankAccount, GetTransactionsParameter(bankAccount.supportsRetrievingBalance, ninetyDaysAgo)) + return getTransactions(bankAccount, GetTransactionsParameter(bankAccount.supportsRetrievingBalance, ninetyDaysAgo)) // TODO: implement abortIfTanIsRequired } override fun getTransactionsAsync(bankAccount: BankAccount, parameter: GetTransactionsParameter, callback: (GetTransactionsResponse) -> Unit) {