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.WebClientResponse
import net.dankito.utils.multiplatform.Date
import net.dankito.utils.multiplatform.getInnerExceptionMessage
open class FinTsClient(
@ -165,7 +166,7 @@ open class FinTsClient(
}
else if (bank.supportedTanProcedures.isEmpty()) { // should only be a theoretical error
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 {
customer.supportedTanProcedures = bank.supportedTanProcedures
@ -475,7 +476,7 @@ open class FinTsClient(
this.callback.enterTanGeneratorAtc(customer, newActiveTanMedium) { enteredAtc ->
if (enteredAtc.hasAtcBeenEntered == false) {
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 {
sendChangeTanMediumMessage(bank, customer, newActiveTanMedium, enteredAtc, callback)
@ -613,8 +614,8 @@ open class FinTsClient(
if (getBankInfoResponse.isSuccessful == false || bank.supportedTanProcedures.isEmpty()
|| bank.supportedJobs.isEmpty()) {
callback(Response(false, exception =
Exception("Could not retrieve basic bank data like supported tan procedures or supported jobs"))) // TODO: translate // TODO: add as messageToShowToUser
callback(Response(false, errorMessage =
"Could not retrieve basic bank data like supported tan procedures or supported jobs")) // TODO: translate // TODO: add as messageToShowToUser
}
else {
callback(Response(true))
@ -751,7 +752,7 @@ open class FinTsClient(
} catch (e: Exception) {
log.error(e) { "Could not decode responseBody:\r\n'$responseBody'" }
return Response(false, exception = e)
return Response(false, errorMessage = e.getInnerExceptionMessage())
}
}
else {
@ -759,7 +760,7 @@ open class FinTsClient(
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 {
@ -968,7 +969,7 @@ open class FinTsClient(
}
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
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.
*/
val exception: Exception? = null,
val errorMessage: String? = null,
val noTanProcedureSelected: Boolean = false,
val messageCreationError: MessageBuilderResult? = null
) {
@ -25,7 +25,7 @@ open class Response(
get() = messageCreationError == null
open val responseContainsErrors: Boolean
get() = exception == null && messageFeedback?.isError == true
get() = errorMessage == null && messageFeedback?.isError == true
open var tanRequiredButUserDidNotEnterOne = false
@ -119,7 +119,7 @@ open class Response(
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.util.MessageUtils
import net.dankito.utils.multiplatform.Date
import net.dankito.utils.multiplatform.getInnerExceptionMessage
import net.dankito.utils.multiplatform.log.LoggerFactory
@ -51,7 +52,7 @@ open class ResponseParser(
} catch (e: Exception) {
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.
*/
val exception: Exception? = null,
val errorMessage: String? = null,
val userCancelledAction: Boolean = false,
@ -33,7 +33,7 @@ open class FinTsClientResponse(
constructor(response: Response) : this(response.successful, response.noTanProcedureSelected,
response.isStrongAuthenticationRequired, response.tanResponse, response.errorsToShowToUser,
response.exception, response.tanRequiredButUserDidNotEnterOne, response.tanRequiredButWeWereToldToAbortIfSo,
response.errorMessage, response.tanRequiredButUserDidNotEnterOne, response.tanRequiredButWeWereToldToAbortIfSo,
response.messageCreationError?.isJobAllowed ?: true,
response.messageCreationError?.isJobVersionSupported ?: true,
response.messageCreationError?.allowedVersions ?: listOf(),

View File

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

View File

@ -375,7 +375,7 @@ open class TransferMoneyDialog @JvmOverloads constructor(
}
else if (response.userCancelledAction == false) {
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

View File

@ -235,7 +235,7 @@ open class EnterTanDialog(
}
else if (response.userCancelledAction == false) {
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 unbookedTransactionsOfLast90Days: Map<BankAccount, List<Any>> = mapOf(),
val balances: Map<BankAccount, BigDecimal> = mapOf(),
error: Exception? = null,
userCancelledAction: Boolean = false
)
: BankingClientResponse(isSuccessful, errorToShowToUser, error, userCancelledAction) {
: BankingClientResponse(isSuccessful, errorToShowToUser, userCancelledAction) {
override fun toString(): String {
return customer.toString() + " " + super.toString()

View File

@ -4,7 +4,6 @@ package net.dankito.banking.ui.model.responses
open class BankingClientResponse(
val isSuccessful: Boolean,
val errorToShowToUser: String?,
val error: Exception? = null,
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 unbookedTransactions: List<Any> = listOf(),
val balance: BigDecimal? = null,
error: Exception? = null,
userCancelledAction: 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)."))
}
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 {
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
findAccountResult(mapper.findAccountForBankAccount(fints4kCustomer, bankAccount),
response.errorToShowToUser ?: response.error?.message)
response.errorToShowToUser)
}
}
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.response.client.FinTsClientResponse
import net.dankito.banking.fints.response.segments.AccountType
//import net.dankito.utils.exception.ExceptionHelper
open class fints4kModelMapper {
// private val exceptionHelper = ExceptionHelper()
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 {
@ -46,7 +42,6 @@ open class fints4kModelMapper {
mappedBookedTransactions,
mapOf(), // TODO: map unbooked transactions
balances,
response.exception,
response.userCancelledAction)
}
@ -56,14 +51,13 @@ open class fints4kModelMapper {
mapTransactions(bankAccount, response.bookedTransactions),
listOf(), // TODO: map unbooked transactions
response.balance?.toBigDecimal(),
response.exception, response.userCancelledAction, response.tanRequiredButWeWereToldToAbortIfSo)
response.userCancelledAction, response.tanRequiredButWeWereToldToAbortIfSo)
}
open fun mapErrorToShowToUser(response: FinTsClientResponse): String? {
// val innerException = response.exception?.let { exception -> exceptionHelper.getInnerException(exception) }
val innerException = response.exception // TODO
val errorMessage = response.errorMessage
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.util.*
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.File
import net.dankito.utils.multiplatform.toBigDecimal
import org.kapott.hbci.GV.HBCIJob
import org.kapott.hbci.GV_Result.GVRKUms
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 {
@ -160,7 +158,7 @@ open class hbci4jBankingClient(
// Pruefen, ob die Kommunikation mit der Bank grundsaetzlich geklappt hat
if (!status.isOK) {
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.
@ -169,7 +167,7 @@ open class hbci4jBankingClient(
val balanceResult = nullableBalanceJob.jobResult as GVRSaldoReq
if(balanceResult.isOK == false) {
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()
@ -183,7 +181,7 @@ open class hbci4jBankingClient(
// Pruefen, ob der Abruf der Umsaetze geklappt hat
if (result.isOK == false) {
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),
@ -191,7 +189,7 @@ open class hbci4jBankingClient(
}
catch(e: Exception) {
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 {
closeConnection(connection)
@ -200,7 +198,7 @@ open class hbci4jBankingClient(
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> {
@ -252,14 +250,14 @@ open class hbci4jBankingClient(
return BankingClientResponse(status.isOK, status.toString())
} catch(e: Exception) {
log.error("Could not transfer cash for account $bankAccount" , e)
return BankingClientResponse(false, e.localizedMessage, e)
return BankingClientResponse(false, e.getInnerExceptionMessage())
}
finally {
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) {