Made bookedTransactions, unbookedTransactions and balance flat as we call getTransactions() bank account by bank account

This commit is contained in:
dankito 2020-05-25 19:05:56 +02:00
parent d94dad345c
commit 40af21137c
8 changed files with 57 additions and 58 deletions

View File

@ -133,7 +133,7 @@ class HomeFragment : Fragment() {
presenter.addAccountsChangedListener { updateMenuItemsStateAndTransactionsToDisplay() } // on account addition or deletion may menu items' state changes
presenter.addSelectedBankAccountsChangedListener { updateMenuItemsStateAndTransactionsToDisplay() }
presenter.addRetrievedAccountTransactionsResponseListener { _, response ->
presenter.addRetrievedAccountTransactionsResponseListener { response ->
handleGetTransactionsResponse(response)
}

View File

@ -32,7 +32,7 @@ open class AccountTransactionsView(private val presenter: BankingPresenter) : Vi
init {
presenter.addSelectedBankAccountsChangedListener { handleSelectedBankAccountsChanged(it) }
presenter.addRetrievedAccountTransactionsResponseListener { _, response ->
presenter.addRetrievedAccountTransactionsResponseListener { response ->
handleGetTransactionsResponseOffUiThread(response)
}

View File

@ -11,13 +11,13 @@ open class AddAccountResponse(
errorToShowToUser: String?,
val account: Account,
val supportsRetrievingTransactionsOfLast90DaysWithoutTan: Boolean = false,
bookedTransactionsOfLast90Days: Map<BankAccount, List<AccountTransaction>> = mapOf(),
unbookedTransactionsOfLast90Days: Map<BankAccount, List<Any>> = mapOf(),
balances: Map<BankAccount, BigDecimal> = mapOf(),
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
)
: GetTransactionsResponse(isSuccessful, errorToShowToUser, bookedTransactionsOfLast90Days, unbookedTransactionsOfLast90Days, balances, error, userCancelledAction) {
: BankingClientResponse(isSuccessful, errorToShowToUser, error, userCancelledAction) {
override fun toString(): String {
return account.toString() + " " + super.toString()

View File

@ -6,11 +6,12 @@ import java.math.BigDecimal
open class GetTransactionsResponse(
val bankAccount: BankAccount,
isSuccessful: Boolean,
errorToShowToUser: String?,
val bookedTransactions: Map<BankAccount, List<AccountTransaction>> = mapOf(),
val unbookedTransactions: Map<BankAccount, List<Any>> = mapOf(),
val balances: Map<BankAccount, BigDecimal> = mapOf(),
val bookedTransactions: List<AccountTransaction> = listOf(),
val unbookedTransactions: List<Any> = listOf(),
val balance: BigDecimal? = null,
error: Exception? = null,
userCancelledAction: Boolean = false,
val tanRequiredButWeWereToldToAbortIfSo: Boolean = false

View File

@ -67,7 +67,7 @@ open class BankingPresenter(
protected val accountsChangedListeners = mutableListOf<(List<Account>) -> Unit>()
protected val retrievedAccountTransactionsResponseListeners = mutableListOf<(BankAccount, GetTransactionsResponse) -> Unit>()
protected val retrievedAccountTransactionsResponseListeners = mutableListOf<(GetTransactionsResponse) -> Unit>()
protected val selectedBankAccountsChangedListeners = mutableListOf<(List<BankAccount>) -> Unit>()
@ -167,8 +167,12 @@ open class BankingPresenter(
persistAccount(account)
if (response.supportsRetrievingTransactionsOfLast90DaysWithoutTan) {
response.bookedTransactions.keys.forEach { bankAccount ->
retrievedAccountTransactions(bankAccount, startDate, response)
response.bookedTransactionsOfLast90Days.keys.forEach { bankAccount ->
retrievedAccountTransactions(startDate, GetTransactionsResponse(bankAccount, true, null,
response.bookedTransactionsOfLast90Days[bankAccount] ?: listOf(),
response.unbookedTransactionsOfLast90Days[bankAccount] ?: listOf(),
response.balances[bankAccount])
)
}
}
@ -279,7 +283,7 @@ open class BankingPresenter(
client.getTransactionsAsync(bankAccount, GetTransactionsParameter(true, fromDate, null, abortIfTanIsRequired, { receivedAccountsTransactionChunk(bankAccount, it) } )) { response ->
if (response.tanRequiredButWeWereToldToAbortIfSo == false) { // don't call retrievedAccountTransactions() if aborted due to TAN required but we told client to abort if so
retrievedAccountTransactions(bankAccount, startDate, response)
retrievedAccountTransactions(startDate, response)
}
callback(response)
@ -311,40 +315,38 @@ open class BankingPresenter(
fetchAccountTransactionsAsync(bankAccount, fromDate, abortIfTanIsRequired, callback)
}
protected open fun retrievedAccountTransactions(bankAccount: BankAccount, startDate: Date, response: GetTransactionsResponse) {
protected open fun retrievedAccountTransactions(startDate: Date, response: GetTransactionsResponse) {
if (response.isSuccessful) {
bankAccount.lastRetrievedTransactionsTimestamp = startDate
response.bankAccount.lastRetrievedTransactionsTimestamp = startDate
updateAccountTransactionsAndBalances(bankAccount, response)
updateAccountTransactionsAndBalances(response)
}
callRetrievedAccountTransactionsResponseListener(bankAccount, response)
callRetrievedAccountTransactionsResponseListener(response)
}
protected open fun receivedAccountsTransactionChunk(bankAccount: BankAccount, accountTransactionsChunk: List<AccountTransaction>) {
if (accountTransactionsChunk.isNotEmpty()) {
bankAccount.addBookedTransactions(accountTransactionsChunk)
callRetrievedAccountTransactionsResponseListener(bankAccount, GetTransactionsResponse(true, null, mapOf(bankAccount to accountTransactionsChunk)))
callRetrievedAccountTransactionsResponseListener(GetTransactionsResponse(bankAccount, true, null, accountTransactionsChunk))
}
}
protected open fun updateAccountTransactionsAndBalances(bankAccount: BankAccount, response: GetTransactionsResponse) {
protected open fun updateAccountTransactionsAndBalances(response: GetTransactionsResponse) {
response.bookedTransactions.forEach { entry ->
entry.key.addBookedTransactions(entry.value)
}
val bankAccount = response.bankAccount
response.unbookedTransactions.forEach { entry ->
entry.key.addUnbookedTransactions(entry.value)
}
bankAccount.addBookedTransactions(response.bookedTransactions)
response.balances.forEach { entry ->
entry.key.balance = entry.value
bankAccount.addUnbookedTransactions(response.unbookedTransactions)
response.balance?.let {
bankAccount.balance = it
}
persistAccount(bankAccount.account) // only needed because of balance
persistAccountTransactions(response.bookedTransactions, response.unbookedTransactions)
persistAccountTransactions(bankAccount, response.bookedTransactions, response.unbookedTransactions)
}
open fun formatAmount(amount: BigDecimal): String {
@ -356,10 +358,8 @@ open class BankingPresenter(
persister.saveOrUpdateAccount(account, accounts)
}
protected open fun persistAccountTransactions(bookedTransactions: Map<BankAccount, List<AccountTransaction>>, unbookedTransactions: Map<BankAccount, List<Any>>) {
bookedTransactions.forEach {
persister.saveOrUpdateAccountTransactions(it.key, it.value)
}
protected open fun persistAccountTransactions(bankAccount: BankAccount, bookedTransactions: List<AccountTransaction>, unbookedTransactions: List<Any>) {
persister.saveOrUpdateAccountTransactions(bankAccount, bookedTransactions)
// TODO: someday also persist unbooked transactions
}
@ -618,17 +618,17 @@ open class BankingPresenter(
}
open fun addRetrievedAccountTransactionsResponseListener(listener: (BankAccount, GetTransactionsResponse) -> Unit): Boolean {
open fun addRetrievedAccountTransactionsResponseListener(listener: (GetTransactionsResponse) -> Unit): Boolean {
return retrievedAccountTransactionsResponseListeners.add(listener)
}
open fun removeRetrievedAccountTransactionsResponseListener(listener: (BankAccount, GetTransactionsResponse) -> Unit): Boolean {
open fun removeRetrievedAccountTransactionsResponseListener(listener: (GetTransactionsResponse) -> Unit): Boolean {
return retrievedAccountTransactionsResponseListeners.add(listener)
}
protected open fun callRetrievedAccountTransactionsResponseListener(bankAccount: BankAccount, response: GetTransactionsResponse) {
protected open fun callRetrievedAccountTransactionsResponseListener(response: GetTransactionsResponse) {
ArrayList(retrievedAccountTransactionsResponseListeners).forEach {
it(bankAccount, response) // TODO: use RxJava for this
it(response) // TODO: use RxJava for this
}
}

View File

@ -103,7 +103,7 @@ open class fints4kBankingClient(
val account = mapper.findAccountForBankAccount(customer, bankAccount)
if (account == null) {
callback(GetTransactionsResponse(false, "Cannot find account for ${bankAccount.identifier}")) // TODO: translate
callback(GetTransactionsResponse(bankAccount, false, "Cannot find account for ${bankAccount.identifier}")) // TODO: translate
}
else {
client.getTransactionsAsync(GetTransactionsParameter(parameter.alsoRetrieveBalance, parameter.fromDate, parameter.toDate, null, parameter.abortIfTanIsRequired,

View File

@ -49,10 +49,10 @@ open class fints4kModelMapper {
open fun mapResponse(bankAccount: BankAccount, response: net.dankito.banking.fints.response.client.GetTransactionsResponse): GetTransactionsResponse {
return GetTransactionsResponse(response.isSuccessful, mapErrorToShowToUser(response),
mapOf(bankAccount to mapTransactions(bankAccount, response.bookedTransactions)),
mapOf(), // TODO: map unbooked transactions
response.balance?.let { mapOf(bankAccount to it) } ?: mapOf(),
return GetTransactionsResponse(bankAccount, response.isSuccessful, mapErrorToShowToUser(response),
mapTransactions(bankAccount, response.bookedTransactions),
listOf(), // TODO: map unbooked transactions
response.balance,
response.exception, response.userCancelledAction, response.tanRequiredButWeWereToldToAbortIfSo)
}
@ -268,6 +268,7 @@ open class fints4kModelMapper {
}
open fun mapTanMedium(tanMedium: net.dankito.banking.fints.messages.datenelemente.implementierte.tan.TanMedium): TanMedium {
// TODO: irgendwas ging hier schief
if (tanMedium is net.dankito.banking.fints.messages.datenelemente.implementierte.tan.TanGeneratorTanMedium) {
return mapTanMedium(tanMedium)
}

View File

@ -86,18 +86,14 @@ open class hbci4jBankingClient(
this.account.bankAccounts = mapper.mapBankAccounts(account, accounts, passport)
val transactionsOfLast90DaysResponse = tryToRetrieveAccountTransactionsForAddedAccounts(account)
return AddAccountResponse(true, null, account, transactionsOfLast90DaysResponse.isSuccessful,
transactionsOfLast90DaysResponse.bookedTransactions, transactionsOfLast90DaysResponse.unbookedTransactions,
transactionsOfLast90DaysResponse.balances)
return tryToRetrieveAccountTransactionsForAddedAccounts(account)
}
}
return AddAccountResponse(false, null, account, error = connection.error)
}
protected open fun tryToRetrieveAccountTransactionsForAddedAccounts(account: Account): GetTransactionsResponse {
protected open fun tryToRetrieveAccountTransactionsForAddedAccounts(account: Account): AddAccountResponse {
val transactionsOfLast90DaysResponses = mutableListOf<GetTransactionsResponse>()
val balances = mutableMapOf<BankAccount, BigDecimal>()
val bookedTransactions = mutableMapOf<BankAccount, List<AccountTransaction>>()
@ -108,15 +104,16 @@ open class hbci4jBankingClient(
val response = getTransactionsOfLast90Days(bankAccount)
transactionsOfLast90DaysResponses.add(response)
response.bookedTransactions[bankAccount]?.let { bookedTransactions.put(bankAccount, it) }
response.unbookedTransactions[bankAccount]?.let { unbookedTransactions.put(bankAccount, it) }
response.balances[bankAccount]?.let { balances.put(bankAccount, it) }
bookedTransactions.put(bankAccount, response.bookedTransactions)
unbookedTransactions.put(bankAccount, response.unbookedTransactions)
balances.put(bankAccount, response.balance ?: BigDecimal.ZERO) // TODO: really add BigDecimal.Zero if balance couldn't be retrieved?
}
}
val supportsRetrievingTransactionsOfLast90DaysWithoutTan = transactionsOfLast90DaysResponses.firstOrNull { it.isSuccessful } != null
return GetTransactionsResponse(supportsRetrievingTransactionsOfLast90DaysWithoutTan, null, bookedTransactions, unbookedTransactions, balances)
return AddAccountResponse(true, null, account, supportsRetrievingTransactionsOfLast90DaysWithoutTan,
bookedTransactions, unbookedTransactions, balances)
}
@ -162,7 +159,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(false, null, error = Exception("Could not connect to bank ${credentials.bankCode}: ${status.toString()}"))
return GetTransactionsResponse(bankAccount, false, null, error = Exception("Could not connect to bank ${credentials.bankCode}: ${status.toString()}"))
}
// Auswertung des Saldo-Abrufs.
@ -171,7 +168,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(false, null, error = Exception("Could not fetch balance of bank account $bankAccount: $balanceResult"))
return GetTransactionsResponse(bankAccount, false, null, error = Exception("Could not fetch balance of bank account $bankAccount: $balanceResult"))
}
balance = balanceResult.entries[0].ready.value.bigDecimalValue
@ -185,15 +182,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(false, null, error = Exception("Could not fetch account transactions of bank account $bankAccount: $result"))
return GetTransactionsResponse(bankAccount, false, null, error = Exception("Could not fetch account transactions of bank account $bankAccount: $result"))
}
return GetTransactionsResponse(true, null, mapOf(bankAccount to accountTransactionMapper.mapAccountTransactions(bankAccount, result)),
mapOf(), mapOf(bankAccount to balance))
return GetTransactionsResponse(bankAccount, true, null, accountTransactionMapper.mapAccountTransactions(bankAccount, result),
listOf(), balance)
}
catch(e: Exception) {
log.error("Could not get accounting details for bank ${credentials.bankCode}", e)
return GetTransactionsResponse(false, null, error = e)
return GetTransactionsResponse(bankAccount, false, null, error = e)
}
finally {
closeConnection(connection)
@ -202,7 +199,7 @@ open class hbci4jBankingClient(
closeConnection(connection)
return GetTransactionsResponse(false, null, error = connection.error)
return GetTransactionsResponse(bankAccount, false, null, error = connection.error)
}
protected open fun executeJobsForGetAccountingEntries(handle: HBCIHandler, bankAccount: BankAccount, parameter: GetTransactionsParameter): Triple<HBCIJob?, HBCIJob, HBCIExecStatus> {