Renamed errorMessage to internalError, errorsToShowToUser to errorMessagesFromBank, added didBankReturnError and created a method to determine which error message to show to user

This commit is contained in:
dankito 2021-11-01 16:46:34 +01:00
parent bb520de5d5
commit ed784f1827
13 changed files with 44 additions and 39 deletions

View File

@ -4,7 +4,6 @@ import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import net.dankito.banking.fints.callback.FinTsClientCallback import net.dankito.banking.fints.callback.FinTsClientCallback
import net.dankito.banking.fints.messages.datenelemente.implementierte.tan.* import net.dankito.banking.fints.messages.datenelemente.implementierte.tan.*
import net.dankito.banking.fints.messages.segmente.id.CustomerSegmentId
import net.dankito.banking.fints.model.* import net.dankito.banking.fints.model.*
import net.dankito.banking.fints.response.BankResponse import net.dankito.banking.fints.response.BankResponse
import net.dankito.banking.fints.response.client.* import net.dankito.banking.fints.response.client.*
@ -122,7 +121,7 @@ open class FinTsClient(
tryGetTransactionsOfLast90DaysWithoutTan(bank, account) { response -> tryGetTransactionsOfLast90DaysWithoutTan(bank, account) { response ->
retrievedAccountData.put(account, response.retrievedData.first()) retrievedAccountData.put(account, response.retrievedData.first())
if (response.errorMessage != null) { if (response.internalError != null) {
//getAccountsResponse.errorMessage = response.errorMessage //getAccountsResponse.errorMessage = response.errorMessage
} }

View File

@ -157,7 +157,7 @@ open class FinTsJobExecutor(
if (anonymousBankInfoResponse.successful == false) { if (anonymousBankInfoResponse.successful == false) {
callback(anonymousBankInfoResponse) callback(anonymousBankInfoResponse)
} else if (bank.tanMethodSupportedByBank.isEmpty()) { // should only be a theoretical error } else if (bank.tanMethodSupportedByBank.isEmpty()) { // should only be a theoretical error
callback(BankResponse(true, errorMessage = "Die TAN Verfahren der Bank konnten nicht ermittelt werden")) // TODO: translate callback(BankResponse(true, internalError = "Die TAN Verfahren der Bank konnten nicht ermittelt werden")) // TODO: translate
} else { } else {
bank.tanMethodsAvailableForUser = bank.tanMethodSupportedByBank bank.tanMethodsAvailableForUser = bank.tanMethodSupportedByBank
@ -263,7 +263,7 @@ open class FinTsJobExecutor(
val fromDate = parameter.fromDate val fromDate = parameter.fromDate
?: parameter.account.countDaysForWhichTransactionsAreKept?.let { Date.today.addDays(it * -1) } ?: parameter.account.countDaysForWhichTransactionsAreKept?.let { Date.today.addDays(it * -1) }
?: bookedTransactions.map { it.valueDate }.sortedBy { it.millisSinceEpoch }.firstOrNull() ?: bookedTransactions.map { it.valueDate }.sortedBy { it.millisSinceEpoch }.firstOrNull()
val retrievedData = RetrievedAccountData(parameter.account, successful, balance, bookedTransactions, unbookedTransactions, fromDate, parameter.toDate ?: Date.today, response.errorMessage) val retrievedData = RetrievedAccountData(parameter.account, successful, balance, bookedTransactions, unbookedTransactions, fromDate, parameter.toDate ?: Date.today, response.internalError)
callback( callback(
GetTransactionsResponse(response, listOf(retrievedData), GetTransactionsResponse(response, listOf(retrievedData),
@ -344,7 +344,7 @@ open class FinTsJobExecutor(
this.callback.enterTanGeneratorAtc(bank, newActiveTanMedium) { enteredAtc -> this.callback.enterTanGeneratorAtc(bank, newActiveTanMedium) { enteredAtc ->
if (enteredAtc.hasAtcBeenEntered == false) { if (enteredAtc.hasAtcBeenEntered == false) {
val message = "Bank requires to enter ATC and TAN in order to change TAN medium." // TODO: translate val message = "Bank requires to enter ATC and TAN in order to change TAN medium." // TODO: translate
callback(BankResponse(false, errorMessage = message)) callback(BankResponse(false, internalError = message))
} }
else { else {
sendChangeTanMediumMessage(bank, newActiveTanMedium, enteredAtc, callback) sendChangeTanMediumMessage(bank, newActiveTanMedium, enteredAtc, callback)
@ -526,7 +526,7 @@ open class FinTsJobExecutor(
} }
else { else {
val errorMessage = "There's no last action (like retrieve account transactions, transfer money, ...) to re-send with new TAN method. Probably an internal programming error." // TODO: translate val errorMessage = "There's no last action (like retrieve account transactions, transfer money, ...) to re-send with new TAN method. Probably an internal programming error." // TODO: translate
callback(BankResponse(false, errorMessage = errorMessage)) // should never come to this callback(BankResponse(false, internalError = errorMessage)) // should never come to this
} }
} }
@ -627,7 +627,7 @@ open class FinTsJobExecutor(
if (getBankInfoResponse.successful == false) { if (getBankInfoResponse.successful == false) {
callback(getBankInfoResponse) callback(getBankInfoResponse)
} else if (bank.tanMethodSupportedByBank.isEmpty() || bank.supportedJobs.isEmpty()) { } else if (bank.tanMethodSupportedByBank.isEmpty() || bank.supportedJobs.isEmpty()) {
callback(BankResponse(false, errorMessage = callback(BankResponse(false, internalError =
"Could not retrieve basic bank data like supported tan methods or supported jobs")) // TODO: translate // TODO: add as messageToShowToUser "Could not retrieve basic bank data like supported tan methods or supported jobs")) // TODO: translate // TODO: add as messageToShowToUser
} else { } else {
callback(BankResponse(true)) callback(BankResponse(true))
@ -661,7 +661,7 @@ open class FinTsJobExecutor(
val noTanMethodSelected = !!!bank.isTanMethodSelected val noTanMethodSelected = !!!bank.isTanMethodSelected
val errorMessage = if (noTanMethodSelected) "User did not select a TAN method" else null // TODO: translate val errorMessage = if (noTanMethodSelected) "User did not select a TAN method" else null // TODO: translate
return BankResponse(true, noTanMethodSelected = noTanMethodSelected, errorMessage = errorMessage) return BankResponse(true, noTanMethodSelected = noTanMethodSelected, internalError = errorMessage)
} }
open fun getUsersTanMethod(bank: BankData, done: (Boolean) -> Unit) { open fun getUsersTanMethod(bank: BankData, done: (Boolean) -> Unit) {

View File

@ -48,7 +48,7 @@ open class RequestExecutor(
if (message.createdMessage == null) { if (message.createdMessage == null) {
log.error("Could not create FinTS message to be sent to bank. isJobAllowed ${message.isJobAllowed}, isJobVersionSupported = ${message.isJobVersionSupported}," + log.error("Could not create FinTS message to be sent to bank. isJobAllowed ${message.isJobAllowed}, isJobVersionSupported = ${message.isJobVersionSupported}," +
"allowedVersions = ${message.allowedVersions}, supportedVersions = ${message.supportedVersions}.") "allowedVersions = ${message.allowedVersions}, supportedVersions = ${message.supportedVersions}.")
callback(BankResponse(false, messageThatCouldNotBeCreated = message, errorMessage = "Could not create FinTS message to be sent to bank")) // TODO: translate callback(BankResponse(false, messageThatCouldNotBeCreated = message, internalError = "Could not create FinTS message to be sent to bank")) // TODO: translate
} }
else { else {
getAndHandleResponseForMessage(message.createdMessage, dialogContext) { response -> getAndHandleResponseForMessage(message.createdMessage, dialogContext) { response ->
@ -130,7 +130,7 @@ open class RequestExecutor(
} catch (e: Exception) { } catch (e: Exception) {
logError("Could not decode responseBody:\r\n'$responseBody'", dialogContext, e) logError("Could not decode responseBody:\r\n'$responseBody'", dialogContext, e)
return BankResponse(false, errorMessage = e.getInnerExceptionMessage()) return BankResponse(false, internalError = e.getInnerExceptionMessage())
} }
} }
else { else {
@ -138,7 +138,7 @@ open class RequestExecutor(
logError("Request to $bank (${bank.finTs3ServerAddress}) failed", dialogContext, webResponse.error) logError("Request to $bank (${bank.finTs3ServerAddress}) failed", dialogContext, webResponse.error)
} }
return BankResponse(false, errorMessage = webResponse.error?.getInnerExceptionMessage()) return BankResponse(false, internalError = webResponse.error?.getInnerExceptionMessage())
} }
protected open fun decodeBase64Response(responseBody: String): String { protected open fun decodeBase64Response(responseBody: String): String {

View File

@ -14,9 +14,9 @@ open class BankResponse(
val receivedSegments: List<ReceivedSegment> = listOf(), val receivedSegments: List<ReceivedSegment> = listOf(),
/** /**
* When a serious error occurred during web request or response parsing. * A fints4k internal error like an error occurred during web request or response parsing.
*/ */
val errorMessage: String? = null, val internalError: String? = null,
val noTanMethodSelected: Boolean = false, val noTanMethodSelected: Boolean = false,
val messageThatCouldNotBeCreated: MessageBuilderResult? = null // i think that can be removed val messageThatCouldNotBeCreated: MessageBuilderResult? = null // i think that can be removed
) { ) {
@ -25,7 +25,7 @@ open class BankResponse(
get() = messageThatCouldNotBeCreated == null get() = messageThatCouldNotBeCreated == null
open val responseContainsErrors: Boolean open val responseContainsErrors: Boolean
get() = errorMessage == null && get() = internalError == null &&
(messageFeedback?.isError == true || isPinLocked) (messageFeedback?.isError == true || isPinLocked)
open val isPinLocked: Boolean open val isPinLocked: Boolean
@ -59,7 +59,8 @@ open class BankResponse(
open var tanRequiredButWeWereToldToAbortIfSo = false open var tanRequiredButWeWereToldToAbortIfSo = false
open val successful: Boolean open val successful: Boolean
get() = noTanMethodSelected == false && couldCreateMessage && didReceiveResponse get() = internalError == null &&
noTanMethodSelected == false && couldCreateMessage && didReceiveResponse
&& responseContainsErrors == false && wrongCredentialsEntered == false && responseContainsErrors == false && wrongCredentialsEntered == false
&& tanRequiredButUserDidNotEnterOne == false && tanRequiredButWeWereToldToAbortIfSo == false && tanRequiredButUserDidNotEnterOne == false && tanRequiredButWeWereToldToAbortIfSo == false
@ -157,7 +158,7 @@ open class BankResponse(
return formattedResponse return formattedResponse
} }
return "Error: $errorMessage\n$formattedResponse" return "Error: $internalError\n$formattedResponse"
} }
} }

View File

@ -56,7 +56,7 @@ open class ResponseParser(
} catch (e: Exception) { } catch (e: Exception) {
logError("Could not parse response '$response'", e) logError("Could not parse response '$response'", e)
return BankResponse(true, response, errorMessage = e.getInnerExceptionMessage()) return BankResponse(true, response, internalError = e.getInnerExceptionMessage())
} }
} }

View File

@ -13,12 +13,12 @@ open class FinTsClientResponse(
open val isStrongAuthenticationRequired: Boolean, open val isStrongAuthenticationRequired: Boolean,
open val tanRequired: TanResponse? = null, open val tanRequired: TanResponse? = null,
open val errorsToShowToUser: List<String> = listOf(),
/** /**
* When a serious error occurred during web request or response parsing. * A fints4k internal error like an error occurred during web request or response parsing.
*/ */
open val errorMessage: String? = null, open val internalError: String? = null,
open val errorMessagesFromBank: List<String> = listOf(),
open val wrongCredentialsEntered: Boolean = false, open val wrongCredentialsEntered: Boolean = false,
@ -35,8 +35,8 @@ open class FinTsClientResponse(
constructor(response: BankResponse) : this(response.successful, response.noTanMethodSelected, constructor(response: BankResponse) : this(response.successful, response.noTanMethodSelected,
response.isStrongAuthenticationRequired, response.tanResponse, response.errorsToShowToUser, response.isStrongAuthenticationRequired, response.tanResponse, response.internalError,
response.errorMessage, response.wrongCredentialsEntered, response.errorsToShowToUser, response.wrongCredentialsEntered,
response.tanRequiredButUserDidNotEnterOne, response.tanRequiredButWeWereToldToAbortIfSo, response.tanRequiredButUserDidNotEnterOne, response.tanRequiredButWeWereToldToAbortIfSo,
response.messageThatCouldNotBeCreated?.isJobAllowed ?: true, response.messageThatCouldNotBeCreated?.isJobAllowed ?: true,
response.messageThatCouldNotBeCreated?.isJobVersionSupported ?: true, response.messageThatCouldNotBeCreated?.isJobVersionSupported ?: true,
@ -44,6 +44,15 @@ open class FinTsClientResponse(
response.messageThatCouldNotBeCreated?.supportedVersions ?: listOf()) response.messageThatCouldNotBeCreated?.supportedVersions ?: listOf())
open val errorMessage: String?
get() = internalError
?: if (errorMessagesFromBank.isNotEmpty()) errorMessagesFromBank.joinToString("\n")
else null
open val didBankReturnError: Boolean
get() = internalError == null && errorMessagesFromBank.isNotEmpty()
override fun toString(): String { override fun toString(): String {
if (noTanMethodSelected) { if (noTanMethodSelected) {
return "Error: No TAN method selected" return "Error: No TAN method selected"

View File

@ -19,8 +19,8 @@ open class GetTransactionsResponse(
&& retrievedData.none { it.account.supportsRetrievingAccountTransactions && it.successfullyRetrievedData == false } && retrievedData.none { it.account.supportsRetrievingAccountTransactions && it.successfullyRetrievedData == false }
// TODO: remove again if then in AddAccountResponse errors get displayed that should or extract getRetrievingTransactionsError() and override in AddAccountResponse // TODO: remove again if then in AddAccountResponse errors get displayed that should or extract getRetrievingTransactionsError() and override in AddAccountResponse
override val errorMessage: String? override val internalError: String?
get() = super.errorMessage get() = super.internalError
?: retrievedData.mapNotNull { it.errorMessage }.firstOrNull() ?: retrievedData.mapNotNull { it.errorMessage }.firstOrNull()

View File

@ -6,7 +6,7 @@ import net.dankito.banking.fints.response.ResponseParser
open class GetUserTanMethodsResponse(bankResponse: BankResponse) open class GetUserTanMethodsResponse(bankResponse: BankResponse)
: BankResponse(bankResponse.didReceiveResponse, bankResponse.receivedResponse, bankResponse.receivedSegments, : BankResponse(bankResponse.didReceiveResponse, bankResponse.receivedResponse, bankResponse.receivedSegments,
bankResponse.errorMessage, bankResponse.noTanMethodSelected, bankResponse.messageThatCouldNotBeCreated) { bankResponse.internalError, bankResponse.noTanMethodSelected, bankResponse.messageThatCouldNotBeCreated) {
/** /**
* comdirect sends "9955::Unzulässiges TAN-Verfahren." even though '999' is a valid TAN method * comdirect sends "9955::Unzulässiges TAN-Verfahren." even though '999' is a valid TAN method

View File

@ -1302,7 +1302,7 @@ class ResponseParserTest : FinTsTestBase() {
private fun assertCouldParseResponse(result: BankResponse) { private fun assertCouldParseResponse(result: BankResponse) {
expect(result.successful).isTrue() expect(result.successful).isTrue()
expect(result.responseContainsErrors).isFalse() expect(result.responseContainsErrors).isFalse()
expect(result.errorMessage).toBe(null) expect(result.internalError).toBe(null)
expect(result.errorsToShowToUser).isEmpty() expect(result.errorsToShowToUser).isEmpty()
expect(result.receivedResponse).notToBeNull() expect(result.receivedResponse).notToBeNull()
} }

View File

@ -7,9 +7,10 @@ open class AddAccountResponse(
open val bank: TypedBankData, open val bank: TypedBankData,
retrievedData: List<RetrievedAccountData> = listOf(), retrievedData: List<RetrievedAccountData> = listOf(),
errorToShowToUser: String? = null, errorToShowToUser: String? = null,
didBankReturnError: Boolean = false,
wrongCredentialsEntered: Boolean = false, wrongCredentialsEntered: Boolean = false,
userCancelledAction: Boolean = false userCancelledAction: Boolean = false
) : GetTransactionsResponse(retrievedData, errorToShowToUser, wrongCredentialsEntered, userCancelledAction) { ) : GetTransactionsResponse(retrievedData, errorToShowToUser, didBankReturnError, wrongCredentialsEntered, userCancelledAction) {
constructor(bank: TypedBankData, errorToShowToUser: String?) : this(bank, listOf(), errorToShowToUser) constructor(bank: TypedBankData, errorToShowToUser: String?) : this(bank, listOf(), errorToShowToUser)

View File

@ -4,6 +4,7 @@ package net.dankito.banking.ui.model.responses
open class BankingClientResponse( open class BankingClientResponse(
open val successful: Boolean, open val successful: Boolean,
open val errorToShowToUser: String?, open val errorToShowToUser: String?,
open val didBankReturnError: Boolean,
open val wrongCredentialsEntered: Boolean = false, open val wrongCredentialsEntered: Boolean = false,
open val userCancelledAction: Boolean = false // TODO: not implemented in hbci4jBankingClient yet open val userCancelledAction: Boolean = false // TODO: not implemented in hbci4jBankingClient yet
) { ) {

View File

@ -7,10 +7,11 @@ import net.dankito.banking.ui.model.TypedBankAccount
open class GetTransactionsResponse( open class GetTransactionsResponse(
open val retrievedData: List<RetrievedAccountData>, open val retrievedData: List<RetrievedAccountData>,
errorToShowToUser: String?, errorToShowToUser: String?,
didBankReturnError: Boolean = false,
wrongCredentialsEntered: Boolean = false, wrongCredentialsEntered: Boolean = false,
userCancelledAction: Boolean = false, userCancelledAction: Boolean = false,
open val tanRequiredButWeWereToldToAbortIfSo: Boolean = false open val tanRequiredButWeWereToldToAbortIfSo: Boolean = false
) : BankingClientResponse(true /* any value */, errorToShowToUser, wrongCredentialsEntered, userCancelledAction) { ) : BankingClientResponse(true /* any value */, errorToShowToUser, didBankReturnError, wrongCredentialsEntered, userCancelledAction) {
constructor(account: TypedBankAccount, errorToShowToUser: String) : this(RetrievedAccountData.unsuccessfulList(account), errorToShowToUser) constructor(account: TypedBankAccount, errorToShowToUser: String) : this(RetrievedAccountData.unsuccessfulList(account), errorToShowToUser)

View File

@ -24,18 +24,18 @@ open class fints4kModelMapper(protected val modelCreator: IModelCreator) {
open fun mapResponse(response: FinTsClientResponse): BankingClientResponse { open fun mapResponse(response: FinTsClientResponse): BankingClientResponse {
return BankingClientResponse(response.successful, mapErrorToShowToUser(response), response.wrongCredentialsEntered, response.userCancelledAction) return BankingClientResponse(response.successful, response.errorMessage, response.didBankReturnError, response.wrongCredentialsEntered, response.userCancelledAction)
} }
open fun mapResponse(bank: TypedBankData, response: net.dankito.banking.fints.response.client.AddAccountResponse): AddAccountResponse { open fun mapResponse(bank: TypedBankData, response: net.dankito.banking.fints.response.client.AddAccountResponse): AddAccountResponse {
return AddAccountResponse(bank, map(bank, response.retrievedData), mapErrorToShowToUser(response), response.wrongCredentialsEntered, response.userCancelledAction) 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.GetTransactionsResponse): GetTransactionsResponse {
return GetTransactionsResponse(map(account.bank as TypedBankData, response.retrievedData), return GetTransactionsResponse(map(account.bank as TypedBankData, response.retrievedData),
mapErrorToShowToUser(response), response.wrongCredentialsEntered, response.userCancelledAction, response.tanRequiredButWeWereToldToAbortIfSo) response.errorMessage, response.didBankReturnError, response.wrongCredentialsEntered, response.userCancelledAction, response.tanRequiredButWeWereToldToAbortIfSo)
} }
open fun map(bank: TypedBankData, retrievedData: List<net.dankito.banking.fints.model.RetrievedAccountData>): List<RetrievedAccountData> { open fun map(bank: TypedBankData, retrievedData: List<net.dankito.banking.fints.model.RetrievedAccountData>): List<RetrievedAccountData> {
@ -61,13 +61,6 @@ open class fints4kModelMapper(protected val modelCreator: IModelCreator) {
) )
} }
open fun mapErrorToShowToUser(response: FinTsClientResponse): String? {
val errorMessage = response.errorMessage
return errorMessage ?:
if (response.errorsToShowToUser.isEmpty()) null else response.errorsToShowToUser.joinToString("\n") // TODO: find a better way to choose which of these error messages to show
}
open fun mapBank(bank: TypedBankData, fintsBank: BankData) { open fun mapBank(bank: TypedBankData, fintsBank: BankData) {
bank.bankCode = fintsBank.bankCode bank.bankCode = fintsBank.bankCode