Removed bankAccount property from GetTransactionsResponse

This commit is contained in:
dankito 2020-09-19 02:35:57 +02:00
parent da5e285d61
commit 99205b53c9
10 changed files with 78 additions and 64 deletions

View File

@ -347,19 +347,18 @@ open class FinTsClient(
open fun getTransactionsAsync(parameter: GetTransactionsParameter, bank: BankData,
account: AccountData, callback: (GetTransactionsResponse) -> Unit) {
// TODO: or add default RetrievedAccountData if an error occurs?
val dialogContext = DialogContext(bank, product)
initDialog(dialogContext) { initDialogResponse ->
if (initDialogResponse.successful == false) {
callback(GetTransactionsResponse(initDialogResponse))
callback(GetTransactionsResponse(initDialogResponse, RetrievedAccountData.unsuccessfulList(account)))
}
else {
mayGetBalance(parameter, account, dialogContext) { balanceResponse ->
if (balanceResponse.successful == false && balanceResponse.couldCreateMessage == true) { // don't break here if required HKSAL message is not implemented
closeDialog(dialogContext)
callback(GetTransactionsResponse(balanceResponse))
callback(GetTransactionsResponse(balanceResponse, RetrievedAccountData.unsuccessfulList(account)))
}
else {
getTransactionsAfterInitAndGetBalance(parameter, account, dialogContext, balanceResponse, callback)
@ -374,7 +373,8 @@ open class FinTsClient(
val balance: Money? = balanceResponse.getFirstSegmentById<BalanceSegment>(InstituteSegmentId.Balance)?.let {
Money(it.balance, it.currency)
}
val retrievedData = RetrievedAccountData(account, balance, listOf(), listOf())
val bookedTransactions = mutableSetOf<AccountTransaction>()
val unbookedTransactions = mutableSetOf<Any>()
val message = messageBuilder.createGetTransactionsMessage(parameter, account, dialogContext)
@ -386,17 +386,19 @@ open class FinTsClient(
response.getFirstSegmentById<ReceivedAccountTransactions>(InstituteSegmentId.AccountTransactionsMt940)?.let { transactionsSegment ->
val (chunkTransaction, remainder) = mt940Parser.parseTransactionsChunk(remainingMt940String + transactionsSegment.bookedTransactionsString, account)
retrievedData.addBookedTransactions(chunkTransaction)
bookedTransactions.addAll(chunkTransaction)
remainingMt940String = remainder
parameter.retrievedChunkListener?.invoke(retrievedData.bookedTransactions)
parameter.retrievedChunkListener?.invoke(bookedTransactions)
}
}
getAndHandleResponseForMessage(message, dialogContext) { response ->
closeDialog(dialogContext)
callback(GetTransactionsResponse(response, listOf(retrievedData),
val successful = response.successful && (parameter.alsoRetrieveBalance == false || balance != null)
callback(GetTransactionsResponse(response, listOf(RetrievedAccountData(account, successful, balance, bookedTransactions, unbookedTransactions)),
if (parameter.maxCountEntries != null) parameter.isSettingMaxCountEntriesAllowedByBank else null
))
}

View File

@ -3,17 +3,21 @@ package net.dankito.banking.fints.model
open class RetrievedAccountData(
open val accountData: AccountData,
open val successfullyRetrievedData: Boolean,
open val balance: Money?,
open var bookedTransactions: Collection<AccountTransaction>,
open var unbookedTransactions: List<Any>
open var unbookedTransactions: Collection<Any>
) {
open fun addBookedTransactions(transactions: List<AccountTransaction>) {
val bookedTransactions = this.bookedTransactions.toMutableSet() // some banks like Postbank return some transactions multiple times -> remove these
companion object {
bookedTransactions.addAll(transactions)
this.bookedTransactions = bookedTransactions
fun unsuccessful(account: AccountData): RetrievedAccountData {
return RetrievedAccountData(account, false, null, listOf(), listOf())
}
fun unsuccessfulList(account: AccountData): List<RetrievedAccountData> {
return listOf(unsuccessful(account))
}
}
}

View File

@ -10,7 +10,6 @@ import androidx.appcompat.app.AlertDialog
import androidx.appcompat.widget.SearchView
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProviders
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import kotlinx.android.synthetic.main.fragment_home.*
@ -161,7 +160,7 @@ class HomeFragment : Fragment() {
presenter.addSelectedBankAccountsChangedListener { updateMenuItemsStateAndTransactionsToDisplay() }
presenter.addRetrievedAccountTransactionsResponseListener { response ->
handleGetTransactionsResponse(response)
handleGetTransactionsResponseOffUiThread(response)
}
updateMenuItemsStateAndTransactionsToDisplay()
@ -181,22 +180,28 @@ class HomeFragment : Fragment() {
presenter.updateSelectedBankAccountTransactionsAsync { }
}
private fun handleGetTransactionsResponse(response: GetTransactionsResponse) {
private fun handleGetTransactionsResponseOffUiThread(response: GetTransactionsResponse) {
context?.asActivity()?.let { activity ->
activity.runOnUiThread {
if (response.isSuccessful) {
handleGetTransactionsResponseOnUiThread(activity, response)
}
}
}
private fun handleGetTransactionsResponseOnUiThread(context: Context, response: GetTransactionsResponse) {
response.retrievedData.forEach { retrievedData ->
if (retrievedData.successfullyRetrievedData) {
updateTransactionsToDisplayOnUiThread()
}
else if (response.userCancelledAction == false) { // if user cancelled entering TAN then don't show a error message
AlertDialog.Builder(activity)
.setMessage(activity.getString(R.string.fragment_home_could_not_retrieve_account_transactions,
response.bankAccount.displayName, response.errorToShowToUser))
AlertDialog.Builder(context)
.setMessage(context.getString(R.string.fragment_home_could_not_retrieve_account_transactions,
retrievedData.account.displayName, response.errorToShowToUser))
.setPositiveButton(android.R.string.ok) { dialog, _ -> dialog.dismiss() }
.show()
}
}
}
}
private fun newTransferToSameRemittee() {

View File

@ -143,14 +143,16 @@ open class AccountTransactionsView(private val presenter: BankingPresenter) : Vi
}
protected open fun handleGetTransactionsResponseOnUiThread(response: GetTransactionsResponse) {
if (response.isSuccessful) {
response.retrievedData.forEach { retrievedData ->
if (retrievedData.successfullyRetrievedData) {
updateTransactionsToDisplay()
}
else if (response.userCancelledAction == false) { // if user cancelled entering TAN then don't show a error message
JavaFxDialogService().showErrorMessageOnUiThread(
String.format(messages["account.transactions.control.view.could.not.retrieve.account.transactions"], response.bankAccount.displayName, response.errorToShowToUser)
String.format(messages["account.transactions.control.view.could.not.retrieve.account.transactions"], retrievedData.account.displayName, response.errorToShowToUser)
)
}
}
}
}

View File

@ -5,6 +5,7 @@ import net.dankito.utils.multiplatform.BigDecimal
open class RetrievedAccountData(
open val account: TypedBankAccount,
open val successfullyRetrievedData: Boolean,
open val balance: BigDecimal?,
open val bookedTransactions: Collection<IAccountTransaction>,
open val unbookedTransactions: List<Any>

View File

@ -1,11 +1,9 @@
package net.dankito.banking.ui.model.responses
import net.dankito.banking.ui.model.RetrievedAccountData
import net.dankito.banking.ui.model.TypedBankAccount
open class GetTransactionsResponse(
open val bankAccount: TypedBankAccount,
isSuccessful: Boolean,
errorToShowToUser: String?,
open val retrievedData: List<RetrievedAccountData> = listOf(),

View File

@ -161,9 +161,7 @@ open class BankingPresenter(
persistAccountOffUiThread(account)
response.retrievedData.forEach { retrievedData ->
retrievedAccountTransactions(GetTransactionsResponse(retrievedData.account, true, null,
listOf(retrievedData)), startDate, false
)
retrievedAccountTransactions(GetTransactionsResponse(true, null, listOf(retrievedData)), startDate, false)
}
findIconForBankAsync(account)
@ -355,7 +353,7 @@ open class BankingPresenter(
asyncRunner.runAsync { // don't block retrieving next chunk by blocked saving to db / json
updateAccountTransactions(bankAccount, accountTransactionsChunk)
callRetrievedAccountTransactionsResponseListener(GetTransactionsResponse(bankAccount, true, null, listOf(RetrievedAccountData(bankAccount, null, accountTransactionsChunk, listOf()))))
callRetrievedAccountTransactionsResponseListener(GetTransactionsResponse(true, null, listOf(RetrievedAccountData(bankAccount, true, null, accountTransactionsChunk, listOf()))))
}
}
}

View File

@ -78,7 +78,7 @@ open class fints4kBankingClient(
override fun getTransactionsAsync(bankAccount: TypedBankAccount, parameter: GetTransactionsParameter, callback: (GetTransactionsResponse) -> Unit) {
findAccountForBankAccount(bankAccount) { account, errorMessage ->
if (account == null) {
callback(GetTransactionsResponse(bankAccount, false, errorMessage))
callback(GetTransactionsResponse(false, errorMessage))
}
else {
val mappedParameter = GetTransactionsParameter(parameter.alsoRetrieveBalance, parameter.fromDate,

View File

@ -39,7 +39,7 @@ open class fints4kModelMapper(protected val modelCreator: IModelCreator) {
open fun mapResponse(bankAccount: TypedBankAccount, response: net.dankito.banking.fints.response.client.GetTransactionsResponse): GetTransactionsResponse {
return GetTransactionsResponse(bankAccount, response.isSuccessful, mapErrorToShowToUser(response),
return GetTransactionsResponse(response.isSuccessful, mapErrorToShowToUser(response),
map(bankAccount.customer as TypedCustomer, response.retrievedData),
response.userCancelledAction, response.tanRequiredButWeWereToldToAbortIfSo)
}
@ -58,9 +58,10 @@ open class fints4kModelMapper(protected val modelCreator: IModelCreator) {
return RetrievedAccountData(
account,
retrievedData.successfullyRetrievedData,
retrievedData.balance?.toBigDecimal(),
mapTransactions(account, retrievedData.bookedTransactions),
listOf()
listOf() // TODO: map unbooked transactions
)
}

View File

@ -89,26 +89,28 @@ open class hbci4jBankingClient(
}
protected open fun tryToRetrieveAccountTransactionsForAddedAccounts(customer: TypedCustomer): AddAccountResponse {
val transactionsOfLast90DaysResponses = mutableListOf<GetTransactionsResponse>()
val balances = mutableMapOf<TypedBankAccount, BigDecimal>()
val bookedTransactions = mutableMapOf<TypedBankAccount, List<IAccountTransaction>>()
val unbookedTransactions = mutableMapOf<TypedBankAccount, List<Any>>()
var supportsRetrievingTransactionsOfLast90DaysWithoutTan = false
var userCancelledAction = false
customer.accounts.forEach { bankAccount ->
if (bankAccount.supportsRetrievingAccountTransactions) {
val response = getTransactionsOfLast90Days(bankAccount)
transactionsOfLast90DaysResponses.add(response)
bookedTransactions.put(bankAccount, response.bookedTransactions)
unbookedTransactions.put(bankAccount, response.unbookedTransactions)
balances.put(bankAccount, response.balance?.toBigDecimal() ?: BigDecimal.Zero) // TODO: really add BigDecimal.Zero if balance couldn't be retrieved?
val retrievedData = customer.accounts.map { account ->
if (account.supportsRetrievingAccountTransactions) {
val response = getTransactionsOfLast90Days(account)
if (response.isSuccessful) {
supportsRetrievingTransactionsOfLast90DaysWithoutTan = true
}
if (response.userCancelledAction) {
userCancelledAction = true
}
val supportsRetrievingTransactionsOfLast90DaysWithoutTan = transactionsOfLast90DaysResponses.firstOrNull { it.isSuccessful } != null
response.retrievedData.first()
}
else {
RetrievedAccountData(account, false, null, listOf(), listOf())
}
}
return AddAccountResponse(true, null, customer, supportsRetrievingTransactionsOfLast90DaysWithoutTan,
bookedTransactions, unbookedTransactions, balances)
retrievedData, userCancelledAction)
}
@ -146,6 +148,7 @@ open class hbci4jBankingClient(
protected open fun getTransactions(bankAccount: TypedBankAccount, parameter: GetTransactionsParameter): GetTransactionsResponse {
val connection = connect()
val retrievingDataFailed = listOf(RetrievedAccountData(bankAccount, false, null, listOf(), listOf()))
connection.handle?.let { handle ->
try {
@ -153,8 +156,8 @@ 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, "Could not connect to bank ${credentials.bankCode}: ${status.toString()}")
log.error("Could not connect to bank ${credentials.bankCode} $status: ${status.errorString}")
return GetTransactionsResponse(false, "Could not connect to bank ${credentials.bankCode}: $status", retrievingDataFailed)
}
// Auswertung des Saldo-Abrufs.
@ -163,7 +166,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, "Could not fetch balance of bank account $bankAccount: $balanceResult")
return GetTransactionsResponse(false, "Could not fetch balance of bank account $bankAccount: $balanceResult", retrievingDataFailed)
}
balance = balanceResult.entries[0].ready.value.bigDecimalValue.toBigDecimal()
@ -177,15 +180,15 @@ 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, "Could not fetch account transactions of bank account $bankAccount: $result")
return GetTransactionsResponse(false, "Could not fetch account transactions of bank account $bankAccount: $result", retrievingDataFailed)
}
return GetTransactionsResponse(bankAccount, true, null, accountTransactionMapper.mapAccountTransactions(bankAccount, result),
listOf(), balance?.toBigDecimal())
return GetTransactionsResponse(true, null, listOf(RetrievedAccountData(bankAccount, true, balance.toBigDecimal(),
accountTransactionMapper.mapAccountTransactions(bankAccount, result), listOf())))
}
catch(e: Exception) {
log.error("Could not get accounting details for bank ${credentials.bankCode}", e)
return GetTransactionsResponse(bankAccount, false, e.getInnerExceptionMessage())
return GetTransactionsResponse(false, e.getInnerExceptionMessage(), retrievingDataFailed)
}
finally {
closeConnection(connection)
@ -194,7 +197,7 @@ open class hbci4jBankingClient(
closeConnection(connection)
return GetTransactionsResponse(bankAccount, false, connection.error.getInnerExceptionMessage())
return GetTransactionsResponse(false, connection.error.getInnerExceptionMessage(), retrievingDataFailed)
}
protected open fun executeJobsForGetAccountingEntries(handle: HBCIHandler, bankAccount: TypedBankAccount, parameter: GetTransactionsParameter): Triple<HBCIJob?, HBCIJob, HBCIExecStatus> {