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 29b706e8..2a39e0a1 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 @@ -24,4 +24,5 @@ open class RetrievedAccountData( } } + } \ No newline at end of file diff --git a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/response/BankResponse.kt b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/response/BankResponse.kt index 0f6263a4..98c8cea0 100644 --- a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/response/BankResponse.kt +++ b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/response/BankResponse.kt @@ -27,14 +27,23 @@ open class BankResponse( open val responseContainsErrors: Boolean get() = errorMessage == null && messageFeedback?.isError == true + open val wrongCredentialsEntered: Boolean + get() { + val wrongCredentialsEnteredFeedbacks = segmentFeedbacks.flatMap { it.feedbacks } + .filter { it.responseCode in 9910..9949 || (it.responseCode == 9210 && it.message.contains("Unbekannt", true)) } // this is not 100 % correct, there are e.g. messages like "9941 TAN ungültig" or "9910 Chipkarte gesperrt", see p. 22-23 FinTS_Rueckmeldungscodes -> + .filterNot { it.message.contains("TAN", true) || it.message.contains("Chipkarte", true) } // ... try to filter these + + return wrongCredentialsEnteredFeedbacks.isNotEmpty() + } + open var tanRequiredButUserDidNotEnterOne = false open var tanRequiredButWeWereToldToAbortIfSo = false open val successful: Boolean get() = noTanMethodSelected == false && couldCreateMessage && didReceiveResponse - && responseContainsErrors == false && tanRequiredButUserDidNotEnterOne == false - && tanRequiredButWeWereToldToAbortIfSo == false + && responseContainsErrors == false && wrongCredentialsEntered == false + && tanRequiredButUserDidNotEnterOne == false && tanRequiredButWeWereToldToAbortIfSo == false open val isStrongAuthenticationRequired: Boolean get() = tanResponse?.isStrongAuthenticationRequired == true diff --git a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/response/client/FinTsClientResponse.kt b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/response/client/FinTsClientResponse.kt index 0b68dc67..81def99b 100644 --- a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/response/client/FinTsClientResponse.kt +++ b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/response/client/FinTsClientResponse.kt @@ -20,6 +20,8 @@ open class FinTsClientResponse( */ open val errorMessage: String? = null, + open val wrongCredentialsEntered: Boolean = false, + open val userCancelledAction: Boolean = false, open val tanRequiredButWeWereToldToAbortIfSo: Boolean = false, @@ -33,7 +35,8 @@ open class FinTsClientResponse( constructor(response: BankResponse) : this(response.successful, response.noTanMethodSelected, response.isStrongAuthenticationRequired, response.tanResponse, response.errorsToShowToUser, - response.errorMessage, response.tanRequiredButUserDidNotEnterOne, response.tanRequiredButWeWereToldToAbortIfSo, + response.errorMessage, response.wrongCredentialsEntered, + response.tanRequiredButUserDidNotEnterOne, response.tanRequiredButWeWereToldToAbortIfSo, response.messageCreationError?.isJobAllowed ?: true, response.messageCreationError?.isJobVersionSupported ?: true, response.messageCreationError?.allowedVersions ?: listOf(), diff --git a/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/model/RetrievedAccountData.kt b/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/model/RetrievedAccountData.kt index 3f3fce79..93729e2b 100644 --- a/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/model/RetrievedAccountData.kt +++ b/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/model/RetrievedAccountData.kt @@ -12,4 +12,18 @@ open class RetrievedAccountData( open val unbookedTransactions: List, open val retrievedTransactionsFrom: Date?, open val retrievedTransactionsTo: Date? -) \ No newline at end of file +) { + + companion object { + + fun unsuccessful(account: TypedBankAccount): RetrievedAccountData { + return RetrievedAccountData(account, false, null, listOf(), listOf(), null, null) + } + + fun unsuccessfulList(account: TypedBankAccount): List { + return listOf(unsuccessful(account)) + } + + } + +} \ No newline at end of file diff --git a/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/model/responses/AddAccountResponse.kt b/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/model/responses/AddAccountResponse.kt index e4b7eed7..264c6656 100644 --- a/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/model/responses/AddAccountResponse.kt +++ b/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/model/responses/AddAccountResponse.kt @@ -7,8 +7,9 @@ open class AddAccountResponse( open val bank: TypedBankData, retrievedData: List = listOf(), errorToShowToUser: String?, + wrongCredentialsEntered: Boolean = false, userCancelledAction: Boolean = false -) : GetTransactionsResponse(retrievedData, errorToShowToUser, userCancelledAction) { +) : GetTransactionsResponse(retrievedData, errorToShowToUser, wrongCredentialsEntered, userCancelledAction) { constructor(bank: TypedBankData, errorToShowToUser: String?) : this(bank, listOf(), errorToShowToUser) diff --git a/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/model/responses/BankingClientResponse.kt b/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/model/responses/BankingClientResponse.kt index 1ab0b899..f423c1a1 100644 --- a/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/model/responses/BankingClientResponse.kt +++ b/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/model/responses/BankingClientResponse.kt @@ -4,6 +4,7 @@ package net.dankito.banking.ui.model.responses open class BankingClientResponse( open val successful: Boolean, open val errorToShowToUser: String?, + open val wrongCredentialsEntered: Boolean = false, open val userCancelledAction: Boolean = false // TODO: not implemented in hbci4jBankingClient yet ) { diff --git a/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/model/responses/GetTransactionsResponse.kt b/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/model/responses/GetTransactionsResponse.kt index e65fde7a..ff36a2ab 100644 --- a/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/model/responses/GetTransactionsResponse.kt +++ b/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/model/responses/GetTransactionsResponse.kt @@ -7,11 +7,15 @@ import net.dankito.banking.ui.model.TypedBankAccount open class GetTransactionsResponse( open val retrievedData: List, errorToShowToUser: String?, + wrongCredentialsEntered: Boolean = false, userCancelledAction: Boolean = false, open val tanRequiredButWeWereToldToAbortIfSo: Boolean = false -) : BankingClientResponse(true /* any value */, errorToShowToUser, userCancelledAction) { +) : BankingClientResponse(true /* any value */, errorToShowToUser, wrongCredentialsEntered, userCancelledAction) { - constructor(account: TypedBankAccount, errorToShowToUser: String) : this(listOf(RetrievedAccountData(account, false, null, listOf(), listOf(), null, null)), errorToShowToUser) + constructor(account: TypedBankAccount, errorToShowToUser: String) : this(RetrievedAccountData.unsuccessfulList(account), errorToShowToUser) + + constructor(account: TypedBankAccount, response: BankingClientResponse) : this(RetrievedAccountData.unsuccessfulList(account), response.errorToShowToUser, + response.wrongCredentialsEntered, response.userCancelledAction, (response as? GetTransactionsResponse)?.tanRequiredButWeWereToldToAbortIfSo ?: false) constructor(retrievedData: RetrievedAccountData) : this(listOf(retrievedData)) @@ -20,6 +24,7 @@ open class GetTransactionsResponse( override val successful: Boolean get() = errorToShowToUser == null + && wrongCredentialsEntered == false && retrievedData.isNotEmpty() && retrievedData.none { it.account.supportsRetrievingAccountTransactions && it.successfullyRetrievedData == false } 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 c44ad01c..3fc9413f 100644 --- a/ui/fints4kBankingClient/src/commonMain/kotlin/net/dankito/banking/fints4kBankingClient.kt +++ b/ui/fints4kBankingClient/src/commonMain/kotlin/net/dankito/banking/fints4kBankingClient.kt @@ -80,9 +80,14 @@ open class fints4kBankingClient( override fun getTransactionsAsync(parameter: GetTransactionsParameter, callback: (GetTransactionsResponse) -> Unit) { val account = parameter.account - findAccountForAccount(account) { accountData, errorMessage -> + findAccountForAccount(account) { accountData, response -> if (accountData == null) { - callback(GetTransactionsResponse(account, errorMessage ?: "")) + if (response != null) { + callback(GetTransactionsResponse(account, response)) + } + else { // should never be the case + callback(GetTransactionsResponse(account, "")) + } } else { val mappedParameter = GetTransactionsParameter(accountData, parameter.alsoRetrieveBalance, parameter.fromDate, @@ -113,9 +118,15 @@ open class fints4kBankingClient( override fun transferMoneyAsync(data: TransferMoneyData, callback: (BankingClientResponse) -> Unit) { - findAccountForAccount(data.account) { account, errorMessage -> + findAccountForAccount(data.account) { account, response -> if (account == null) { - callback(BankingClientResponse(false, errorMessage)) + if (response != null) { + callback(response) + } + else { // should never be the case + callback(BankingClientResponse(false, "Konnte Kontodaten nicht vom Bankserver abrufen für ${data.account.identifier}. " + + "Besteht eine Netzwerkverbindung und sind der eingegebenen Benutzername und Passwort korrekt?")) // TODO: translate + } } else { val mappedData = BankTransferData(data.recipientName, data.recipientAccountId, data.recipientBankCode, data.amount.toMoney(), data.reference, data.realTimeTransfer) @@ -149,7 +160,7 @@ open class fints4kBankingClient( } - protected open fun findAccountForAccount(account: TypedBankAccount, findAccountResult: (AccountData?, error: String?) -> Unit) { + protected open fun findAccountForAccount(account: TypedBankAccount, findAccountResult: (AccountData?, BankingClientResponse?) -> Unit) { val mappedAccount = mapper.findMatchingAccount(fintsBank, account) if (mappedAccount != null) { @@ -158,10 +169,10 @@ open class fints4kBankingClient( else { // then try to get account data by fetching data from bank addAccountAsync { response -> if (response.successful) { - findAccountResult(mapper.findMatchingAccount(fintsBank, account), response.errorToShowToUser) + findAccountResult(mapper.findMatchingAccount(fintsBank, account), response) } else { - findAccountResult(null, response.errorToShowToUser) + findAccountResult(null, 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 42690a19..0e68c79a 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 @@ -24,18 +24,18 @@ open class fints4kModelMapper(protected val modelCreator: IModelCreator) { open fun mapResponse(response: FinTsClientResponse): BankingClientResponse { - return BankingClientResponse(response.successful, mapErrorToShowToUser(response), response.userCancelledAction) + return BankingClientResponse(response.successful, mapErrorToShowToUser(response), response.wrongCredentialsEntered, response.userCancelledAction) } open fun mapResponse(bank: TypedBankData, response: net.dankito.banking.fints.response.client.AddAccountResponse): AddAccountResponse { - return AddAccountResponse(bank, map(bank, response.retrievedData), mapErrorToShowToUser(response), response.userCancelledAction) + return AddAccountResponse(bank, map(bank, response.retrievedData), mapErrorToShowToUser(response), response.wrongCredentialsEntered, response.userCancelledAction) } open fun mapResponse(account: TypedBankAccount, response: net.dankito.banking.fints.response.client.GetTransactionsResponse): GetTransactionsResponse { return GetTransactionsResponse(map(account.bank as TypedBankData, response.retrievedData), - mapErrorToShowToUser(response), response.userCancelledAction, response.tanRequiredButWeWereToldToAbortIfSo) + mapErrorToShowToUser(response), response.wrongCredentialsEntered, response.userCancelledAction, response.tanRequiredButWeWereToldToAbortIfSo) } open fun map(bank: TypedBankData, retrievedData: List): List { 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 43d6fe7e..76a6a917 100644 --- a/ui/hbci4jBankingClient/src/main/kotlin/net/dankito/banking/hbci4jBankingClient.kt +++ b/ui/hbci4jBankingClient/src/main/kotlin/net/dankito/banking/hbci4jBankingClient.kt @@ -102,11 +102,11 @@ open class hbci4jBankingClient( response.retrievedData.first() } else { - RetrievedAccountData(account, false, null, listOf(), listOf(), null) + RetrievedAccountData.unsuccessful(account) } } - return AddAccountResponse(bank, retrievedData, null, userCancelledAction) + return AddAccountResponse(bank, retrievedData, null, false, userCancelledAction) }