Removed exception from Response as this only crashed iOS app. Choosing now on mapper level which message to show in UI

This commit is contained in:
dankito 2020-08-16 23:55:24 +02:00
parent 8adab38d54
commit 321814a0ca
16 changed files with 55 additions and 45 deletions

View File

@ -0,0 +1,19 @@
package net.dankito.utils.multiplatform
fun Throwable?.getInnerExceptionMessage(maxDepth: Int = 3): String? {
return this?.getInnerException(maxDepth)?.message
}
fun Throwable.getInnerException(maxDepth: Int = 3): Throwable {
var innerException = this
var depth = 0
while (innerException.cause is Throwable && depth < maxDepth) {
innerException = innerException.cause as Throwable
depth++
}
return innerException
}

View File

@ -31,6 +31,7 @@ import net.dankito.banking.fints.webclient.IWebClient
import net.dankito.banking.fints.webclient.KtorWebClient import net.dankito.banking.fints.webclient.KtorWebClient
import net.dankito.banking.fints.webclient.WebClientResponse import net.dankito.banking.fints.webclient.WebClientResponse
import net.dankito.utils.multiplatform.Date import net.dankito.utils.multiplatform.Date
import net.dankito.utils.multiplatform.getInnerExceptionMessage
open class FinTsClient( open class FinTsClient(
@ -165,7 +166,7 @@ open class FinTsClient(
} }
else if (bank.supportedTanProcedures.isEmpty()) { // should only be a theoretical error else if (bank.supportedTanProcedures.isEmpty()) { // should only be a theoretical error
callback(AddAccountResponse(Response(true, callback(AddAccountResponse(Response(true,
exception = Exception("Die TAN Verfahren der Bank konnten nicht ermittelt werden")), bank, customer)) // TODO: translate errorMessage = "Die TAN Verfahren der Bank konnten nicht ermittelt werden"), bank, customer)) // TODO: translate
} }
else { else {
customer.supportedTanProcedures = bank.supportedTanProcedures customer.supportedTanProcedures = bank.supportedTanProcedures
@ -475,7 +476,7 @@ open class FinTsClient(
this.callback.enterTanGeneratorAtc(customer, newActiveTanMedium) { enteredAtc -> this.callback.enterTanGeneratorAtc(customer, 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(FinTsClientResponse(Response(false, exception = Exception(message)))) callback(FinTsClientResponse(Response(false, errorMessage = message)))
} }
else { else {
sendChangeTanMediumMessage(bank, customer, newActiveTanMedium, enteredAtc, callback) sendChangeTanMediumMessage(bank, customer, newActiveTanMedium, enteredAtc, callback)
@ -613,8 +614,8 @@ open class FinTsClient(
if (getBankInfoResponse.isSuccessful == false || bank.supportedTanProcedures.isEmpty() if (getBankInfoResponse.isSuccessful == false || bank.supportedTanProcedures.isEmpty()
|| bank.supportedJobs.isEmpty()) { || bank.supportedJobs.isEmpty()) {
callback(Response(false, exception = callback(Response(false, errorMessage =
Exception("Could not retrieve basic bank data like supported tan procedures or supported jobs"))) // TODO: translate // TODO: add as messageToShowToUser "Could not retrieve basic bank data like supported tan procedures or supported jobs")) // TODO: translate // TODO: add as messageToShowToUser
} }
else { else {
callback(Response(true)) callback(Response(true))
@ -751,7 +752,7 @@ open class FinTsClient(
} catch (e: Exception) { } catch (e: Exception) {
log.error(e) { "Could not decode responseBody:\r\n'$responseBody'" } log.error(e) { "Could not decode responseBody:\r\n'$responseBody'" }
return Response(false, exception = e) return Response(false, errorMessage = e.getInnerExceptionMessage())
} }
} }
else { else {
@ -759,7 +760,7 @@ open class FinTsClient(
log.error(webResponse.error) { "Request to $bank (${bank.finTs3ServerAddress}) failed" } log.error(webResponse.error) { "Request to $bank (${bank.finTs3ServerAddress}) failed" }
} }
return Response(false, exception = webResponse.error) return Response(false, errorMessage = webResponse.error.getInnerExceptionMessage())
} }
protected open fun decodeBase64Response(responseBody: String): String { protected open fun decodeBase64Response(responseBody: String): String {
@ -968,7 +969,7 @@ open class FinTsClient(
} }
else { else {
val errorMessage = "There's no last action (like retrieve account transactions, transfer money, ...) to re-send with new TAN procedure. 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 procedure. Probably an internal programming error." // TODO: translate
callback(Response(false, exception = Exception(errorMessage))) // should never come to this callback(Response(false, errorMessage = errorMessage)) // should never come to this
} }
} }

View File

@ -16,7 +16,7 @@ open class Response(
/** /**
* When a serious error occurred during web request or response parsing. * When a serious error occurred during web request or response parsing.
*/ */
val exception: Exception? = null, val errorMessage: String? = null,
val noTanProcedureSelected: Boolean = false, val noTanProcedureSelected: Boolean = false,
val messageCreationError: MessageBuilderResult? = null val messageCreationError: MessageBuilderResult? = null
) { ) {
@ -25,7 +25,7 @@ open class Response(
get() = messageCreationError == null get() = messageCreationError == null
open val responseContainsErrors: Boolean open val responseContainsErrors: Boolean
get() = exception == null && messageFeedback?.isError == true get() = errorMessage == null && messageFeedback?.isError == true
open var tanRequiredButUserDidNotEnterOne = false open var tanRequiredButUserDidNotEnterOne = false
@ -119,7 +119,7 @@ open class Response(
return formattedResponse return formattedResponse
} }
return "Error: $exception\n$formattedResponse" return "Error: $errorMessage\n$formattedResponse"
} }
} }

View File

@ -18,6 +18,7 @@ import net.dankito.banking.fints.model.Amount
import net.dankito.banking.fints.response.segments.* import net.dankito.banking.fints.response.segments.*
import net.dankito.banking.fints.util.MessageUtils import net.dankito.banking.fints.util.MessageUtils
import net.dankito.utils.multiplatform.Date import net.dankito.utils.multiplatform.Date
import net.dankito.utils.multiplatform.getInnerExceptionMessage
import net.dankito.utils.multiplatform.log.LoggerFactory import net.dankito.utils.multiplatform.log.LoggerFactory
@ -51,7 +52,7 @@ open class ResponseParser(
} catch (e: Exception) { } catch (e: Exception) {
log.error(e) { "Could not parse response '$response'" } log.error(e) { "Could not parse response '$response'" }
return Response(true, response, exception = e) return Response(true, response, errorMessage = e.getInnerExceptionMessage())
} }
} }

View File

@ -18,7 +18,7 @@ open class FinTsClientResponse(
/** /**
* When a serious error occurred during web request or response parsing. * When a serious error occurred during web request or response parsing.
*/ */
val exception: Exception? = null, val errorMessage: String? = null,
val userCancelledAction: Boolean = false, val userCancelledAction: Boolean = false,
@ -33,7 +33,7 @@ open class FinTsClientResponse(
constructor(response: Response) : this(response.successful, response.noTanProcedureSelected, constructor(response: Response) : this(response.successful, response.noTanProcedureSelected,
response.isStrongAuthenticationRequired, response.tanResponse, response.errorsToShowToUser, response.isStrongAuthenticationRequired, response.tanResponse, response.errorsToShowToUser,
response.exception, response.tanRequiredButUserDidNotEnterOne, response.tanRequiredButWeWereToldToAbortIfSo, response.errorMessage, response.tanRequiredButUserDidNotEnterOne, response.tanRequiredButWeWereToldToAbortIfSo,
response.messageCreationError?.isJobAllowed ?: true, response.messageCreationError?.isJobAllowed ?: true,
response.messageCreationError?.isJobVersionSupported ?: true, response.messageCreationError?.isJobVersionSupported ?: true,
response.messageCreationError?.allowedVersions ?: listOf(), response.messageCreationError?.allowedVersions ?: listOf(),

View File

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

View File

@ -375,7 +375,7 @@ open class TransferMoneyDialog @JvmOverloads constructor(
} }
else if (response.userCancelledAction == false) { else if (response.userCancelledAction == false) {
dialogService.showErrorMessage(String.format(messages["transfer.money.dialog.message.transfer.cash.error"], dialogService.showErrorMessage(String.format(messages["transfer.money.dialog.message.transfer.cash.error"],
transferData.amount, currency, transferData.creditorName, response.errorToShowToUser), null, response.error, currentStage) transferData.amount, currency, transferData.creditorName, response.errorToShowToUser), null, null, currentStage)
} }
if (response.isSuccessful || response.userCancelledAction) { // do not close dialog if an error occurred if (response.isSuccessful || response.userCancelledAction) { // do not close dialog if an error occurred

View File

@ -235,7 +235,7 @@ open class EnterTanDialog(
} }
else if (response.userCancelledAction == false) { else if (response.userCancelledAction == false) {
dialogService.showErrorMessageOnUiThread(String.format(messages["enter.tan.dialog.tan.error.changing.tan.medium"], dialogService.showErrorMessageOnUiThread(String.format(messages["enter.tan.dialog.tan.error.changing.tan.medium"],
newUsedTanMedium.displayName, response.errorToShowToUser), null, response.error, currentStage) newUsedTanMedium.displayName, response.errorToShowToUser), null, null, currentStage)
} }
} }

View File

@ -14,10 +14,9 @@ open class AddAccountResponse(
val bookedTransactionsOfLast90Days: Map<BankAccount, List<AccountTransaction>> = mapOf(), val bookedTransactionsOfLast90Days: Map<BankAccount, List<AccountTransaction>> = mapOf(),
val unbookedTransactionsOfLast90Days: Map<BankAccount, List<Any>> = mapOf(), val unbookedTransactionsOfLast90Days: Map<BankAccount, List<Any>> = mapOf(),
val balances: Map<BankAccount, BigDecimal> = mapOf(), val balances: Map<BankAccount, BigDecimal> = mapOf(),
error: Exception? = null,
userCancelledAction: Boolean = false userCancelledAction: Boolean = false
) )
: BankingClientResponse(isSuccessful, errorToShowToUser, error, userCancelledAction) { : BankingClientResponse(isSuccessful, errorToShowToUser, userCancelledAction) {
override fun toString(): String { override fun toString(): String {
return customer.toString() + " " + super.toString() return customer.toString() + " " + super.toString()

View File

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

View File

@ -12,8 +12,7 @@ open class GetTransactionsResponse(
val bookedTransactions: List<AccountTransaction> = listOf(), val bookedTransactions: List<AccountTransaction> = listOf(),
val unbookedTransactions: List<Any> = listOf(), val unbookedTransactions: List<Any> = listOf(),
val balance: BigDecimal? = null, val balance: BigDecimal? = null,
error: Exception? = null,
userCancelledAction: Boolean = false, userCancelledAction: Boolean = false,
val tanRequiredButWeWereToldToAbortIfSo: Boolean = false val tanRequiredButWeWereToldToAbortIfSo: Boolean = false
) )
: BankingClientResponse(isSuccessful, errorToShowToUser, error, userCancelledAction) : BankingClientResponse(isSuccessful, errorToShowToUser, userCancelledAction)

View File

@ -169,7 +169,7 @@ struct EnterTanDialog: View {
self.errorMessage = Message(title: Text("TAN medium change"), message: Text("TAN medium successfully changed to \(newTanMedium.displayName).")) self.errorMessage = Message(title: Text("TAN medium change"), message: Text("TAN medium successfully changed to \(newTanMedium.displayName)."))
} }
else { else {
self.errorMessage = Message(title: Text("TAN medium change"), message: Text("Could not change TAN medium to \(newTanMedium.displayName). Error: \(changeTanMediumResponse.errorToShowToUser ?? changeTanMediumResponse.error?.message ?? "").")) self.errorMessage = Message(title: Text("TAN medium change"), message: Text("Could not change TAN medium to \(newTanMedium.displayName). Error: \(changeTanMediumResponse.errorToShowToUser ?? "")."))
} }
} }

View File

@ -210,7 +210,7 @@ struct TransferMoneyDialog: View {
}) })
} }
else { else {
self.transferMoneyResponseMessage = Message(message: Text("Could not transfer \(data.amount) \("") to \(data.creditorName). Error: \(response.errorToShowToUser ?? response.error?.message ?? "").")) self.transferMoneyResponseMessage = Message(message: Text("Could not transfer \(data.amount) \("") to \(data.creditorName). Error: \(response.errorToShowToUser ?? "")."))
} }
} }
} }

View File

@ -153,7 +153,7 @@ open class fints4kBankingClient(
didTryToGetAccountDataFromBank = !!! response.isSuccessful didTryToGetAccountDataFromBank = !!! response.isSuccessful
findAccountResult(mapper.findAccountForBankAccount(fints4kCustomer, bankAccount), findAccountResult(mapper.findAccountForBankAccount(fints4kCustomer, bankAccount),
response.errorToShowToUser ?: response.error?.message) response.errorToShowToUser)
} }
} }
else { else {

View File

@ -15,17 +15,13 @@ import net.dankito.banking.fints.model.CustomerData
import net.dankito.banking.fints.model.Money import net.dankito.banking.fints.model.Money
import net.dankito.banking.fints.response.client.FinTsClientResponse import net.dankito.banking.fints.response.client.FinTsClientResponse
import net.dankito.banking.fints.response.segments.AccountType import net.dankito.banking.fints.response.segments.AccountType
//import net.dankito.utils.exception.ExceptionHelper
open class fints4kModelMapper { open class fints4kModelMapper {
// private val exceptionHelper = ExceptionHelper()
open fun mapResponse(response: FinTsClientResponse): BankingClientResponse { open fun mapResponse(response: FinTsClientResponse): BankingClientResponse {
return BankingClientResponse(response.isSuccessful, mapErrorToShowToUser(response), response.exception, response.userCancelledAction) return BankingClientResponse(response.isSuccessful, mapErrorToShowToUser(response), response.userCancelledAction)
} }
open fun mapResponse(customer: Customer, response: net.dankito.banking.fints.response.client.AddAccountResponse): AddAccountResponse { open fun mapResponse(customer: Customer, response: net.dankito.banking.fints.response.client.AddAccountResponse): AddAccountResponse {
@ -46,7 +42,6 @@ open class fints4kModelMapper {
mappedBookedTransactions, mappedBookedTransactions,
mapOf(), // TODO: map unbooked transactions mapOf(), // TODO: map unbooked transactions
balances, balances,
response.exception,
response.userCancelledAction) response.userCancelledAction)
} }
@ -56,14 +51,13 @@ open class fints4kModelMapper {
mapTransactions(bankAccount, response.bookedTransactions), mapTransactions(bankAccount, response.bookedTransactions),
listOf(), // TODO: map unbooked transactions listOf(), // TODO: map unbooked transactions
response.balance?.toBigDecimal(), response.balance?.toBigDecimal(),
response.exception, response.userCancelledAction, response.tanRequiredButWeWereToldToAbortIfSo) response.userCancelledAction, response.tanRequiredButWeWereToldToAbortIfSo)
} }
open fun mapErrorToShowToUser(response: FinTsClientResponse): String? { open fun mapErrorToShowToUser(response: FinTsClientResponse): String? {
// val innerException = response.exception?.let { exception -> exceptionHelper.getInnerException(exception) } val errorMessage = response.errorMessage
val innerException = response.exception // TODO
return innerException?.message ?: response.errorsToShowToUser.joinToString("\n") return errorMessage ?: response.errorsToShowToUser.joinToString("\n") // TODO: find a better way to choose which of these error messages to show
} }

View File

@ -15,10 +15,8 @@ import net.dankito.banking.util.hbci4jModelMapper
import net.dankito.banking.bankfinder.BankInfo import net.dankito.banking.bankfinder.BankInfo
import net.dankito.banking.util.* import net.dankito.banking.util.*
import net.dankito.utils.ThreadPool import net.dankito.utils.ThreadPool
import net.dankito.utils.multiplatform.BigDecimal import net.dankito.utils.multiplatform.*
import net.dankito.utils.multiplatform.Date import net.dankito.utils.multiplatform.Date
import net.dankito.utils.multiplatform.File
import net.dankito.utils.multiplatform.toBigDecimal
import org.kapott.hbci.GV.HBCIJob import org.kapott.hbci.GV.HBCIJob
import org.kapott.hbci.GV_Result.GVRKUms import org.kapott.hbci.GV_Result.GVRKUms
import org.kapott.hbci.GV_Result.GVRSaldoReq import org.kapott.hbci.GV_Result.GVRSaldoReq
@ -91,7 +89,7 @@ open class hbci4jBankingClient(
} }
} }
return AddAccountResponse(false, null, customer, error = connection.error) return AddAccountResponse(false, connection.error.getInnerExceptionMessage(), customer)
} }
protected open fun tryToRetrieveAccountTransactionsForAddedAccounts(customer: Customer): AddAccountResponse { protected open fun tryToRetrieveAccountTransactionsForAddedAccounts(customer: Customer): AddAccountResponse {
@ -160,7 +158,7 @@ open class hbci4jBankingClient(
// Pruefen, ob die Kommunikation mit der Bank grundsaetzlich geklappt hat // Pruefen, ob die Kommunikation mit der Bank grundsaetzlich geklappt hat
if (!status.isOK) { if (!status.isOK) {
log.error("Could not connect to bank ${credentials.bankCode} ${status.toString()}: ${status.errorString}") log.error("Could not connect to bank ${credentials.bankCode} ${status.toString()}: ${status.errorString}")
return GetTransactionsResponse(bankAccount, false, null, error = Exception("Could not connect to bank ${credentials.bankCode}: ${status.toString()}")) return GetTransactionsResponse(bankAccount, false, "Could not connect to bank ${credentials.bankCode}: ${status.toString()}")
} }
// Auswertung des Saldo-Abrufs. // Auswertung des Saldo-Abrufs.
@ -169,7 +167,7 @@ open class hbci4jBankingClient(
val balanceResult = nullableBalanceJob.jobResult as GVRSaldoReq val balanceResult = nullableBalanceJob.jobResult as GVRSaldoReq
if(balanceResult.isOK == false) { if(balanceResult.isOK == false) {
log.error("Could not fetch balance of bank account $bankAccount: $balanceResult", balanceResult.getJobStatus().exceptions) log.error("Could not fetch balance of bank account $bankAccount: $balanceResult", balanceResult.getJobStatus().exceptions)
return GetTransactionsResponse(bankAccount, false, null, error = Exception("Could not fetch balance of bank account $bankAccount: $balanceResult")) return GetTransactionsResponse(bankAccount, false, "Could not fetch balance of bank account $bankAccount: $balanceResult")
} }
balance = balanceResult.entries[0].ready.value.bigDecimalValue.toBigDecimal() balance = balanceResult.entries[0].ready.value.bigDecimalValue.toBigDecimal()
@ -183,7 +181,7 @@ open class hbci4jBankingClient(
// Pruefen, ob der Abruf der Umsaetze geklappt hat // Pruefen, ob der Abruf der Umsaetze geklappt hat
if (result.isOK == false) { if (result.isOK == false) {
log.error("Could not get fetch account transactions of bank account $bankAccount: $result", result.getJobStatus().exceptions) log.error("Could not get fetch account transactions of bank account $bankAccount: $result", result.getJobStatus().exceptions)
return GetTransactionsResponse(bankAccount, false, null, error = Exception("Could not fetch account transactions of bank account $bankAccount: $result")) return GetTransactionsResponse(bankAccount, false, "Could not fetch account transactions of bank account $bankAccount: $result")
} }
return GetTransactionsResponse(bankAccount, true, null, accountTransactionMapper.mapAccountTransactions(bankAccount, result), return GetTransactionsResponse(bankAccount, true, null, accountTransactionMapper.mapAccountTransactions(bankAccount, result),
@ -191,7 +189,7 @@ open class hbci4jBankingClient(
} }
catch(e: Exception) { catch(e: Exception) {
log.error("Could not get accounting details for bank ${credentials.bankCode}", e) log.error("Could not get accounting details for bank ${credentials.bankCode}", e)
return GetTransactionsResponse(bankAccount, false, null, error = e) return GetTransactionsResponse(bankAccount, false, e.getInnerExceptionMessage())
} }
finally { finally {
closeConnection(connection) closeConnection(connection)
@ -200,7 +198,7 @@ open class hbci4jBankingClient(
closeConnection(connection) closeConnection(connection)
return GetTransactionsResponse(bankAccount, false, null, error = connection.error) return GetTransactionsResponse(bankAccount, false, connection.error.getInnerExceptionMessage())
} }
protected open fun executeJobsForGetAccountingEntries(handle: HBCIHandler, bankAccount: BankAccount, parameter: GetTransactionsParameter): Triple<HBCIJob?, HBCIJob, HBCIExecStatus> { protected open fun executeJobsForGetAccountingEntries(handle: HBCIHandler, bankAccount: BankAccount, parameter: GetTransactionsParameter): Triple<HBCIJob?, HBCIJob, HBCIExecStatus> {
@ -252,14 +250,14 @@ open class hbci4jBankingClient(
return BankingClientResponse(status.isOK, status.toString()) return BankingClientResponse(status.isOK, status.toString())
} catch(e: Exception) { } catch(e: Exception) {
log.error("Could not transfer cash for account $bankAccount" , e) log.error("Could not transfer cash for account $bankAccount" , e)
return BankingClientResponse(false, e.localizedMessage, e) return BankingClientResponse(false, e.getInnerExceptionMessage())
} }
finally { finally {
closeConnection(connection) closeConnection(connection)
} }
} }
return BankingClientResponse(false, "Could not connect", connection.error) return BankingClientResponse(false, connection.error.getInnerExceptionMessage() ?: "Could not connect")
} }
protected open fun createTransferCashJob(handle: HBCIHandler, data: TransferMoneyData, bankAccount: BankAccount) { protected open fun createTransferCashJob(handle: HBCIHandler, data: TransferMoneyData, bankAccount: BankAccount) {