Started UI specific model to get independent of underlying FinTS- / banking client implementation

This commit is contained in:
dankl 2019-11-03 23:06:40 +01:00 committed by dankito
parent 913d85d4a8
commit f4194f832e
17 changed files with 472 additions and 68 deletions

View File

@ -0,0 +1,34 @@
package net.dankito.banking.ui.model
import java.math.BigDecimal
open class Account(
val bank: Bank,
val customerId: String,
var pin: String,
var name: String,
var userId: String = customerId,
var bankAccounts: List<BankAccount> = listOf()
) {
internal constructor() : this(Bank(), "", "", "") // for object deserializers
var supportedTanProcedures: List<TanProcedure> = listOf()
var selectedTanProcedure: TanProcedure? = null
val balance: BigDecimal
get() = bankAccounts.map { it.balance }.fold(BigDecimal.ZERO) { acc, e -> acc + e }
val transactions: List<AccountTransaction>
get() = bankAccounts.flatMap { it.transactions }
override fun toString(): String {
return "$name ($customerId)"
}
}

View File

@ -0,0 +1,28 @@
package net.dankito.banking.ui.model
import java.math.BigDecimal
import java.text.DateFormat
import java.util.*
open class AccountTransaction(
val amount: BigDecimal,
val currency: String,
val usage: String,
val bookingDate: Date,
val otherPartyName: String?,
val otherPartyBankCode: String?,
val otherPartyAccountId: String?,
val bookingText: String?,
val bankAccount: BankAccount
) {
// for object deserializers
internal constructor() : this(0.toBigDecimal(),"", "", Date(), null, null, null, null, BankAccount())
override fun toString(): String {
return "${DateFormat.getDateInstance(DateFormat.MEDIUM).format(bookingDate)} $amount $otherPartyName: $usage"
}
}

View File

@ -0,0 +1,22 @@
package net.dankito.banking.ui.model
open class Bank(
val bankCode: String,
var finTsServerAddress: String,
var bic: String,
var name: String
) {
internal constructor() : this("", "", "", "") // for object deserializers
var iconUrl: String? = null
override fun toString(): String {
return "$name ($bankCode)"
}
}

View File

@ -0,0 +1,30 @@
package net.dankito.banking.ui.model
import java.math.BigDecimal
open class BankAccount @JvmOverloads constructor(
val account: Account,
val identifier: String,
var name: String,
var iban: String?,
var subAccountNumber: String?,
var balance: BigDecimal = BigDecimal.ZERO,
var currency: String = "EUR",
var type: BankAccountType = BankAccountType.Giro,
accountTransactions: List<AccountTransaction> = listOf()
) {
internal constructor() : this(Account(), "", "", null, null) // for object deserializers
var transactions: List<AccountTransaction> = accountTransactions
protected set
override fun toString(): String {
return "$name ($identifier)"
}
}

View File

@ -0,0 +1,8 @@
package net.dankito.banking.ui.model
enum class BankAccountType {
Giro
}

View File

@ -0,0 +1,14 @@
package net.dankito.banking.ui.model
open class TanProcedure(
val displayName: String,
val type: TanProcedureType,
val bankInternalProcedureCode: String
) {
override fun toString(): String {
return "$displayName ($type, ${bankInternalProcedureCode})"
}
}

View File

@ -0,0 +1,19 @@
package net.dankito.banking.ui.model
enum class TanProcedureType {
EnterTan,
ChipTanManuell,
ChipTanOptisch,
ChipTanQrCode,
PhotoTan,
SmsTan,
PushTan
}

View File

@ -0,0 +1,24 @@
package net.dankito.banking.ui.model.responses
import net.dankito.banking.ui.model.Account
import net.dankito.banking.ui.model.AccountTransaction
import net.dankito.banking.ui.model.BankAccount
import java.math.BigDecimal
open class AddAccountResponse(
isSuccessful: Boolean,
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()
)
: GetTransactionsResponse(isSuccessful, errorToShowToUser, bookedTransactionsOfLast90Days, unbookedTransactionsOfLast90Days, balances) {
override fun toString(): String {
return account.toString() + " " + super.toString()
}
}

View File

@ -0,0 +1,19 @@
package net.dankito.banking.ui.model.responses
open class BankingClientResponse(
val isSuccessful: Boolean,
val errorToShowToUser: String?
) {
override fun toString(): String {
return if (isSuccessful) {
"Successful"
}
else {
"Error: $errorToShowToUser"
}
}
}

View File

@ -0,0 +1,15 @@
package net.dankito.banking.ui.model.responses
import net.dankito.banking.ui.model.AccountTransaction
import net.dankito.banking.ui.model.BankAccount
import java.math.BigDecimal
open class GetTransactionsResponse(
isSuccessful: Boolean,
errorToShowToUser: String?,
val bookedTransactions: Map<BankAccount, List<AccountTransaction>> = mapOf(),
val unbookedTransactions: Map<BankAccount, List<Any>> = mapOf(),
val balances: Map<BankAccount, BigDecimal> = mapOf()
)
: BankingClientResponse(isSuccessful, errorToShowToUser)

View File

@ -0,0 +1,141 @@
package net.dankito.banking.fints4java.android.mapper
import net.dankito.banking.ui.model.*
import net.dankito.banking.ui.model.responses.AddAccountResponse
import net.dankito.banking.ui.model.responses.GetTransactionsResponse
import net.dankito.fints.messages.datenelemente.implementierte.signatur.Sicherheitsfunktion
import net.dankito.fints.model.AccountData
import net.dankito.fints.model.BankData
import net.dankito.fints.model.CustomerData
import net.dankito.fints.response.client.FinTsClientResponse
import net.dankito.fints.response.segments.AccountType
import java.math.BigDecimal
open class fints4javaModelMapper {
open fun mapAccount(customer: CustomerData, bank: BankData): Account {
val mappedBank = mapBank(bank)
val account = Account(mappedBank, customer.customerId, customer.pin, customer.name, customer.userId)
account.bankAccounts = mapBankAccounts(account, customer.accounts)
account.supportedTanProcedures = mapTanProcedures(customer.supportedTanProcedures)
return account
}
open fun mapBank(bank: BankData): Bank {
return Bank(bank.bankCode, bank.finTs3ServerAddress, bank.bic, bank.name)
}
open fun mapBankAccounts(account: Account, accountData: List<AccountData>): List<BankAccount> {
return accountData.map { mapBankAccount(account, it) }
}
open fun mapBankAccount(account: Account, accountData: AccountData): BankAccount {
return BankAccount(account, accountData.accountIdentifier, accountData.accountHolderName, accountData.iban,
accountData.subAccountAttribute, BigDecimal.ZERO, accountData.currency ?: "EUR",
mapBankAccountType(accountData.accountType))
}
open fun mapBankAccountType(type: AccountType?): BankAccountType {
return when (type) {
else -> BankAccountType.Giro
}
}
open fun mapTransactions(bankAccount: BankAccount, transactions: List<net.dankito.fints.model.AccountTransaction>): List<AccountTransaction> {
return transactions.map { mapTransaction(bankAccount, it) }
}
open fun mapTransaction(bankAccount: BankAccount, transaction: net.dankito.fints.model.AccountTransaction): AccountTransaction {
return AccountTransaction(
transaction.amount,
transaction.currency,
transaction.usage,
transaction.bookingDate,
transaction.otherPartyName,
transaction.otherPartyBankCode,
transaction.otherPartyAccountId,
transaction.bookingText,
bankAccount
)
}
open fun mapTanProcedures(tanProcedures: List<net.dankito.fints.model.TanProcedure>): List<TanProcedure> {
return tanProcedures.map { mapTanProcedure(it) }
}
open fun mapTanProcedure(tanProcedure: net.dankito.fints.model.TanProcedure): TanProcedure {
return TanProcedure(
tanProcedure.displayName,
mapTanProcedureType(tanProcedure.type),
tanProcedure.securityFunction.code
)
}
open fun mapTanProcedureType(type: net.dankito.fints.model.TanProcedureType): TanProcedureType {
return when (type) {
net.dankito.fints.model.TanProcedureType.EnterTan -> TanProcedureType.EnterTan // TODO: add ChipTanManuell
net.dankito.fints.model.TanProcedureType.ChipTan -> TanProcedureType.ChipTanOptisch
net.dankito.fints.model.TanProcedureType.ChipTanQrCode -> TanProcedureType.ChipTanQrCode
net.dankito.fints.model.TanProcedureType.PhotoTan -> TanProcedureType.PhotoTan
net.dankito.fints.model.TanProcedureType.SmsTan -> TanProcedureType.SmsTan
net.dankito.fints.model.TanProcedureType.PushTan -> TanProcedureType.PushTan
}
}
fun mapResponse(account: Account, response: net.dankito.fints.response.client.AddAccountResponse): AddAccountResponse {
var bookedTransactions = mapOf<BankAccount, List<AccountTransaction>>()
var balances = mapOf<BankAccount, BigDecimal>()
account.bankAccounts.firstOrNull()?.let { bankAccount -> // TODO: set bank account also on net.dankito.fints.response.client.GetTransactionsResponse
bookedTransactions = mapOf(bankAccount to mapTransactions(bankAccount, response.bookedTransactions))
response.balance?.let { balances = mapOf(bankAccount to it) }
}
return AddAccountResponse(response.isSuccessful, mapErrorToShowToUser(response),
account, response.supportsRetrievingTransactionsOfLast90DaysWithoutTan,
bookedTransactions,
mapOf(), // TODO: map unbooked transactions
balances)
}
fun mapResponse(account: Account, response: net.dankito.fints.response.client.GetTransactionsResponse): GetTransactionsResponse {
val bankAccount = account.bankAccounts.first() // TODO: set bank account also on net.dankito.fints.response.client.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())
}
open fun mapErrorToShowToUser(response: FinTsClientResponse): String? {
return response.exception?.localizedMessage ?: response.errorsToShowToUser.joinToString("\n")
}
open fun mapTanProcedureBack(tanProcedure: TanProcedure): net.dankito.fints.model.TanProcedure {
return net.dankito.fints.model.TanProcedure(
tanProcedure.displayName,
Sicherheitsfunktion.values().first { it.code == tanProcedure.bankInternalProcedureCode },
mapTanProcedureTypeBack(tanProcedure.type)
)
}
open fun mapTanProcedureTypeBack(type: TanProcedureType): net.dankito.fints.model.TanProcedureType {
return when (type) {
TanProcedureType.EnterTan -> net.dankito.fints.model.TanProcedureType.EnterTan
TanProcedureType.ChipTanManuell -> net.dankito.fints.model.TanProcedureType.EnterTan // TODO: add ChipTanManuell
TanProcedureType.ChipTanOptisch -> net.dankito.fints.model.TanProcedureType.ChipTan
TanProcedureType.ChipTanQrCode -> net.dankito.fints.model.TanProcedureType.ChipTanQrCode
TanProcedureType.PhotoTan -> net.dankito.fints.model.TanProcedureType.PhotoTan
TanProcedureType.SmsTan -> net.dankito.fints.model.TanProcedureType.SmsTan
TanProcedureType.PushTan -> net.dankito.fints.model.TanProcedureType.PushTan
}
}
}

View File

@ -1,14 +1,17 @@
package net.dankito.banking.fints4java.android.ui package net.dankito.banking.fints4java.android.ui
import net.dankito.banking.fints4java.android.Base64ServiceAndroid import net.dankito.banking.fints4java.android.Base64ServiceAndroid
import net.dankito.banking.ui.model.Account
import net.dankito.banking.ui.model.AccountTransaction
import net.dankito.banking.ui.model.BankAccount
import net.dankito.banking.ui.model.responses.AddAccountResponse
import net.dankito.banking.ui.model.responses.GetTransactionsResponse
import net.dankito.fints.FinTsClient import net.dankito.fints.FinTsClient
import net.dankito.fints.FinTsClientCallback import net.dankito.fints.FinTsClientCallback
import net.dankito.fints.banks.BankFinder import net.dankito.fints.banks.BankFinder
import net.dankito.fints.model.* import net.dankito.fints.model.*
import net.dankito.fints.model.mapper.BankDataMapper import net.dankito.fints.model.mapper.BankDataMapper
import net.dankito.fints.response.client.AddAccountResponse
import net.dankito.fints.response.client.FinTsClientResponse import net.dankito.fints.response.client.FinTsClientResponse
import net.dankito.fints.response.client.GetTransactionsResponse
import net.dankito.utils.IThreadPool import net.dankito.utils.IThreadPool
import net.dankito.utils.ThreadPool import net.dankito.utils.ThreadPool
import java.math.BigDecimal import java.math.BigDecimal
@ -26,18 +29,20 @@ open class MainWindowPresenter(callback: FinTsClientCallback) {
protected val bankDataMapper = BankDataMapper() protected val bankDataMapper = BankDataMapper()
protected val fints4javaModelMapper = net.dankito.banking.fints4java.android.mapper.fints4javaModelMapper()
protected val accounts = mutableMapOf<CustomerData, BankData>()
protected val bookedTransactions = mutableMapOf<CustomerData, MutableSet<AccountTransaction>>() protected val accounts = mutableMapOf<Account, Any>()
protected val unbookedTransactions = mutableMapOf<CustomerData, MutableSet<Any>>() protected val bookedTransactions = mutableMapOf<BankAccount, MutableSet<AccountTransaction>>()
protected val balances = mutableMapOf<CustomerData, BigDecimal>() protected val unbookedTransactions = mutableMapOf<BankAccount, MutableSet<Any>>()
protected val accountAddedListeners = mutableListOf<(BankData, CustomerData) -> Unit>() protected val balances = mutableMapOf<BankAccount, BigDecimal>()
protected val retrievedAccountTransactionsResponseListeners = mutableListOf<(CustomerData, GetTransactionsResponse) -> Unit>() protected val accountAddedListeners = mutableListOf<(Account) -> Unit>()
protected val retrievedAccountTransactionsResponseListeners = mutableListOf<(BankAccount, GetTransactionsResponse) -> Unit>()
open fun addAccountAsync(bankInfo: BankInfo, customerId: String, pin: String, open fun addAccountAsync(bankInfo: BankInfo, customerId: String, pin: String,
@ -47,81 +52,106 @@ open class MainWindowPresenter(callback: FinTsClientCallback) {
val customer = CustomerData(customerId, pin) val customer = CustomerData(customerId, pin)
finTsClient.addAccountAsync(bank, customer) { response -> finTsClient.addAccountAsync(bank, customer) { response ->
if (response.isSuccessful) { val account = fints4javaModelMapper.mapAccount(customer, bank)
accounts.put(customer, bank) val mappedResponse = fints4javaModelMapper.mapResponse(account, response)
callAccountAddedListeners(bank, customer) if (response.isSuccessful) {
accounts.put(account, Pair(customer, bank))
callAccountAddedListeners(account)
if (response.supportsRetrievingTransactionsOfLast90DaysWithoutTan) { if (response.supportsRetrievingTransactionsOfLast90DaysWithoutTan) {
retrievedAccountTransactions(customer, response) account.bankAccounts.forEach { bankAccount ->
retrievedAccountTransactions(bankAccount, mappedResponse)
}
} }
} }
callback(response) callback(mappedResponse)
} }
} }
open fun getAccountTransactionsAsync(bank: BankData, customer: CustomerData, open fun getAccountTransactionsAsync(account: Account,
callback: (GetTransactionsResponse) -> Unit) { callback: (GetTransactionsResponse) -> Unit) {
getAccountTransactionsAsync(bank, customer, null, callback) account.bankAccounts.forEach { bankAccount ->
getAccountTransactionsAsync(bankAccount, callback) // TODO: use a synchronous version of getAccountTransactions() so that all bank accounts get handled serially
}
} }
open fun getAccountTransactionsAsync(bank: BankData, customer: CustomerData, fromDate: Date?, open fun getAccountTransactionsAsync(bankAccount: BankAccount,
callback: (GetTransactionsResponse) -> Unit) { callback: (GetTransactionsResponse) -> Unit) {
finTsClient.getTransactionsAsync(GetTransactionsParameter(true, fromDate), bank, customer) { response -> getAccountTransactionsAsync(bankAccount, null, callback)
retrievedAccountTransactions(customer, response) }
callback(response) open fun getAccountTransactionsAsync(bankAccount: BankAccount, fromDate: Date?,
callback: (GetTransactionsResponse) -> Unit) {
getCustomerAndBankForAccount(bankAccount.account)?.let { customerBankPair ->
finTsClient.getTransactionsAsync(GetTransactionsParameter(true, fromDate),
customerBankPair.second, customerBankPair.first) { response ->
val mappedResponse = fints4javaModelMapper.mapResponse(bankAccount.account, response)
retrievedAccountTransactions(bankAccount, mappedResponse)
callback(mappedResponse)
}
} }
} }
open fun updateAccountsTransactionsAsync(callback: (GetTransactionsResponse) -> Unit) { open fun updateAccountsTransactionsAsync(callback: (GetTransactionsResponse) -> Unit) {
accounts.forEach { entry -> accounts.keys.forEach { account ->
val customer = entry.key account.bankAccounts.forEach { bankAccount ->
val today = Date() // TODO: still don't know where this bug is coming from that bank returns a transaction dated at end of year val today = Date() // TODO: still don't know where this bug is coming from that bank returns a transaction dated at end of year
val lastRetrievedTransactionDate = bookedTransactions[customer]?.firstOrNull { it.bookingDate <= today }?.bookingDate val lastRetrievedTransactionDate = bookedTransactions[bankAccount]?.firstOrNull { it.bookingDate <= today }?.bookingDate
val fromDate = lastRetrievedTransactionDate?.let { Date(it.time - 24 * 60 * 60 * 1000) } // on day before last received transaction val fromDate = lastRetrievedTransactionDate?.let { Date(it.time - 24 * 60 * 60 * 1000) } // on day before last received transaction
getAccountTransactionsAsync(entry.value, customer, fromDate, callback) getAccountTransactionsAsync(bankAccount, fromDate, callback)
}
} }
} }
protected open fun retrievedAccountTransactions(customer: CustomerData, response: GetTransactionsResponse) { protected open fun retrievedAccountTransactions(bankAccount: BankAccount, response: GetTransactionsResponse) {
if (response.isSuccessful) { if (response.isSuccessful) {
updateAccountTransactionsAndBalances(customer, response) updateAccountTransactionsAndBalances(bankAccount, response)
} }
callRetrievedAccountTransactionsResponseListener(customer, response) callRetrievedAccountTransactionsResponseListener(bankAccount, response)
} }
protected open fun updateAccountTransactionsAndBalances(customer: CustomerData, response: GetTransactionsResponse) { protected open fun updateAccountTransactionsAndBalances(bankAccount: BankAccount, response: GetTransactionsResponse) {
if (bookedTransactions.containsKey(customer) == false) { response.bookedTransactions.forEach { entry ->
bookedTransactions.put(customer, response.bookedTransactions.toMutableSet()) if (bookedTransactions.containsKey(entry.key) == false) {
bookedTransactions.put(bankAccount, entry.value.toMutableSet())
} }
else { else {
bookedTransactions[customer]?.addAll(response.bookedTransactions) // TODO: does currently not work, overwrite equals() bookedTransactions[bankAccount]?.addAll(entry.value) // TODO: does currently not work, overwrite equals()
}
} }
if (unbookedTransactions.containsKey(customer) == false) { response.unbookedTransactions.forEach { entry ->
unbookedTransactions.put(customer, response.unbookedTransactions.toMutableSet()) if (unbookedTransactions.containsKey(entry.key) == false) {
unbookedTransactions.put(bankAccount, entry.value.toMutableSet())
} }
else { else {
unbookedTransactions[customer]?.addAll(response.unbookedTransactions) unbookedTransactions[bankAccount]?.addAll(entry.value)
}
} }
response.balance?.let { response.balances.forEach { entry ->
balances[customer] = it balances[entry.key] = entry.value
} }
} }
open fun transferMoneyAsync(bankTransferData: BankTransferData, callback: (FinTsClientResponse) -> Unit) { open fun transferMoneyAsync(bankAccount: BankAccount, bankTransferData: BankTransferData, callback: (FinTsClientResponse) -> Unit) {
accounts.entries.firstOrNull()?.let { // TODO: of course not correct, but i have to think of a multi account architecture and data model anyway getCustomerAndBankForAccount(bankAccount.account)?.let { customerBankPair ->
finTsClient.doBankTransferAsync(bankTransferData, it.value, it.key, callback) finTsClient.doBankTransferAsync(
bankTransferData, customerBankPair.second, customerBankPair.first, callback)
} }
} }
@ -152,6 +182,19 @@ open class MainWindowPresenter(callback: FinTsClientCallback) {
} }
protected open fun getCustomerAndBankForAccount(account: Account): Pair<CustomerData, BankData>? {
(accounts.get(account) as? Pair<CustomerData, BankData>)?.let { customerBankPair ->
account.selectedTanProcedure?.let { selectedTanProcedure ->
customerBankPair.first.selectedTanProcedure = fints4javaModelMapper.mapTanProcedureBack(selectedTanProcedure)
}
return customerBankPair // TODO: return IBankingClient
}
return null
}
open val allTransactions: List<AccountTransaction> open val allTransactions: List<AccountTransaction>
get() = bookedTransactions.values.flatten().toList() // TODO: someday add unbooked transactions get() = bookedTransactions.values.flatten().toList() // TODO: someday add unbooked transactions
@ -159,23 +202,23 @@ open class MainWindowPresenter(callback: FinTsClientCallback) {
get() = balances.values.fold(BigDecimal.ZERO) { acc, e -> acc + e } get() = balances.values.fold(BigDecimal.ZERO) { acc, e -> acc + e }
open fun addAccountAddedListener(listener: (BankData, CustomerData) -> Unit) { open fun addAccountAddedListener(listener: (Account) -> Unit) {
accountAddedListeners.add(listener) accountAddedListeners.add(listener)
} }
protected open fun callAccountAddedListeners(bank: BankData, customer: CustomerData) { protected open fun callAccountAddedListeners(account: Account) {
ArrayList(accountAddedListeners).forEach { ArrayList(accountAddedListeners).forEach {
it(bank, customer) // TODO: use RxJava for this it(account) // TODO: use RxJava for this
} }
} }
open fun addRetrievedAccountTransactionsResponseListener(listener: (CustomerData, GetTransactionsResponse) -> Unit) { open fun addRetrievedAccountTransactionsResponseListener(listener: (BankAccount, GetTransactionsResponse) -> Unit) {
retrievedAccountTransactionsResponseListeners.add(listener) retrievedAccountTransactionsResponseListeners.add(listener)
} }
protected open fun callRetrievedAccountTransactionsResponseListener(customer: CustomerData, response: GetTransactionsResponse) { protected open fun callRetrievedAccountTransactionsResponseListener(bankAccount: BankAccount, response: GetTransactionsResponse) {
ArrayList(retrievedAccountTransactionsResponseListeners).forEach { ArrayList(retrievedAccountTransactionsResponseListeners).forEach {
it(customer, response) // TODO: use RxJava for this it(bankAccount, response) // TODO: use RxJava for this
} }
} }

View File

@ -4,7 +4,7 @@ import android.view.ContextMenu
import android.view.View import android.view.View
import net.dankito.banking.fints4java.android.R import net.dankito.banking.fints4java.android.R
import net.dankito.banking.fints4java.android.ui.adapter.viewholder.AccountTransactionViewHolder import net.dankito.banking.fints4java.android.ui.adapter.viewholder.AccountTransactionViewHolder
import net.dankito.fints.model.AccountTransaction import net.dankito.banking.ui.model.AccountTransaction
import net.dankito.utils.android.extensions.asActivity import net.dankito.utils.android.extensions.asActivity
import net.dankito.utils.android.extensions.setTextColorToColorResource import net.dankito.utils.android.extensions.setTextColorToColorResource
import net.dankito.utils.android.ui.adapter.ListRecyclerAdapter import net.dankito.utils.android.ui.adapter.ListRecyclerAdapter

View File

@ -4,7 +4,7 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.TextView import android.widget.TextView
import net.dankito.banking.fints4java.android.R import net.dankito.banking.fints4java.android.R
import net.dankito.fints.model.TanProcedure import net.dankito.banking.ui.model.TanProcedure
import net.dankito.utils.android.extensions.asActivity import net.dankito.utils.android.extensions.asActivity
import net.dankito.utils.android.ui.adapter.ListAdapter import net.dankito.utils.android.ui.adapter.ListAdapter

View File

@ -20,8 +20,8 @@ import net.dankito.banking.fints4java.android.R
import net.dankito.banking.fints4java.android.ui.MainWindowPresenter import net.dankito.banking.fints4java.android.ui.MainWindowPresenter
import net.dankito.banking.fints4java.android.ui.adapter.BankListAdapter import net.dankito.banking.fints4java.android.ui.adapter.BankListAdapter
import net.dankito.banking.fints4java.android.ui.adapter.TanProceduresAdapter import net.dankito.banking.fints4java.android.ui.adapter.TanProceduresAdapter
import net.dankito.banking.ui.model.responses.AddAccountResponse
import net.dankito.fints.model.BankInfo import net.dankito.fints.model.BankInfo
import net.dankito.fints.response.client.AddAccountResponse
import net.dankito.utils.android.extensions.asActivity import net.dankito.utils.android.extensions.asActivity
@ -100,7 +100,7 @@ open class AddAccountDialog : DialogFragment() {
} }
else { else {
AlertDialog.Builder(context) AlertDialog.Builder(context)
.setMessage(context.getString(R.string.dialog_add_account_message_could_not_add_account, (response.exception ?: response.errorsToShowToUser.joinToString("\n")))) .setMessage(context.getString(R.string.dialog_add_account_message_could_not_add_account, response.errorToShowToUser))
.setPositiveButton(android.R.string.ok) { dialog, _ -> dialog.dismiss() } .setPositiveButton(android.R.string.ok) { dialog, _ -> dialog.dismiss() }
.show() .show()
} }
@ -127,7 +127,7 @@ open class AddAccountDialog : DialogFragment() {
val view = context.asActivity()?.layoutInflater?.inflate(R.layout.view_successfully_added_account, null) val view = context.asActivity()?.layoutInflater?.inflate(R.layout.view_successfully_added_account, null)
val adapter = TanProceduresAdapter() val adapter = TanProceduresAdapter()
adapter.setItems(response.customer.supportedTanProcedures) adapter.setItems(response.account.supportedTanProcedures)
view?.findViewById<TextView>(R.id.txtSuccessfullyAddedAccountMessage)?.setText(messageId) view?.findViewById<TextView>(R.id.txtSuccessfullyAddedAccountMessage)?.setText(messageId)
@ -137,7 +137,7 @@ open class AddAccountDialog : DialogFragment() {
override fun onNothingSelected(parent: AdapterView<*>?) {} override fun onNothingSelected(parent: AdapterView<*>?) {}
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) { override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
response.customer.selectedTanProcedure = adapter.getItem(position) response.account.selectedTanProcedure = adapter.getItem(position)
} }
} }
@ -149,7 +149,7 @@ open class AddAccountDialog : DialogFragment() {
} }
protected open fun retrieveAccountTransactionsAndDismiss(response: AddAccountResponse, messageDialog: DialogInterface) { protected open fun retrieveAccountTransactionsAndDismiss(response: AddAccountResponse, messageDialog: DialogInterface) {
presenter.getAccountTransactionsAsync(response.bank, response.customer) { } // TODO: show error message if not successful. Here or in HomeFragment presenter.getAccountTransactionsAsync(response.account) { }
messageDialog.dismiss() messageDialog.dismiss()
} }

View File

@ -13,6 +13,7 @@ import kotlinx.android.synthetic.main.dialog_bank_transfer.*
import kotlinx.android.synthetic.main.dialog_bank_transfer.view.* import kotlinx.android.synthetic.main.dialog_bank_transfer.view.*
import net.dankito.banking.fints4java.android.R import net.dankito.banking.fints4java.android.R
import net.dankito.banking.fints4java.android.ui.MainWindowPresenter import net.dankito.banking.fints4java.android.ui.MainWindowPresenter
import net.dankito.banking.ui.model.BankAccount
import net.dankito.fints.messages.segmente.implementierte.sepa.ISepaMessageCreator import net.dankito.fints.messages.segmente.implementierte.sepa.ISepaMessageCreator
import net.dankito.fints.messages.segmente.implementierte.sepa.SepaMessageCreator import net.dankito.fints.messages.segmente.implementierte.sepa.SepaMessageCreator
import net.dankito.fints.model.BankTransferData import net.dankito.fints.model.BankTransferData
@ -30,17 +31,20 @@ open class BankTransferDialog : DialogFragment() {
protected lateinit var presenter: MainWindowPresenter protected lateinit var presenter: MainWindowPresenter
protected lateinit var bankAccount: BankAccount
protected var preselectedValues: BankTransferData? = null protected var preselectedValues: BankTransferData? = null
protected val sepaMessageCreator: ISepaMessageCreator = SepaMessageCreator() protected val sepaMessageCreator: ISepaMessageCreator = SepaMessageCreator()
open fun show(activity: AppCompatActivity, presenter: MainWindowPresenter, fullscreen: Boolean = false) { open fun show(activity: AppCompatActivity, presenter: MainWindowPresenter, bankAccount: BankAccount, fullscreen: Boolean = false) {
show(activity, presenter, null, fullscreen) show(activity, presenter, bankAccount, null, fullscreen)
} }
open fun show(activity: AppCompatActivity, presenter: MainWindowPresenter, preselectedValues: BankTransferData?, fullscreen: Boolean = false) { open fun show(activity: AppCompatActivity, presenter: MainWindowPresenter, bankAccount: BankAccount, preselectedValues: BankTransferData?, fullscreen: Boolean = false) {
this.presenter = presenter this.presenter = presenter
this.bankAccount = bankAccount
this.preselectedValues = preselectedValues this.preselectedValues = preselectedValues
val style = if(fullscreen) R.style.FullscreenDialogWithStatusBar else R.style.Dialog val style = if(fullscreen) R.style.FullscreenDialogWithStatusBar else R.style.Dialog
@ -113,7 +117,7 @@ open class BankTransferDialog : DialogFragment() {
edtxtUsage.text.toString() edtxtUsage.text.toString()
) )
presenter.transferMoneyAsync(transferData) { presenter.transferMoneyAsync(bankAccount, transferData) {
context?.asActivity()?.runOnUiThread { context?.asActivity()?.runOnUiThread {
handleTransferMoneyResultOnUiThread(it, transferData) handleTransferMoneyResultOnUiThread(it, transferData)
} }

View File

@ -18,8 +18,9 @@ import net.dankito.banking.fints4java.android.R
import net.dankito.banking.fints4java.android.ui.MainWindowPresenter import net.dankito.banking.fints4java.android.ui.MainWindowPresenter
import net.dankito.banking.fints4java.android.ui.adapter.AccountTransactionAdapter import net.dankito.banking.fints4java.android.ui.adapter.AccountTransactionAdapter
import net.dankito.banking.fints4java.android.ui.dialogs.BankTransferDialog import net.dankito.banking.fints4java.android.ui.dialogs.BankTransferDialog
import net.dankito.banking.ui.model.AccountTransaction
import net.dankito.banking.ui.model.responses.GetTransactionsResponse
import net.dankito.fints.model.BankTransferData import net.dankito.fints.model.BankTransferData
import net.dankito.fints.response.client.GetTransactionsResponse
import net.dankito.utils.android.extensions.asActivity import net.dankito.utils.android.extensions.asActivity
import java.math.BigDecimal import java.math.BigDecimal
@ -159,7 +160,7 @@ class HomeFragment : Fragment() {
mnitmBalance.isVisible = true mnitmBalance.isVisible = true
} else { } else {
AlertDialog.Builder(activity) // TODO: may show account name in message AlertDialog.Builder(activity) // TODO: may show account name in message
.setMessage(activity.getString(R.string.fragment_home_could_not_retrieve_account_transactions, response.exception ?: response.errorsToShowToUser.joinToString("\n"))) .setMessage(activity.getString(R.string.fragment_home_could_not_retrieve_account_transactions, response.errorToShowToUser))
.setPositiveButton(android.R.string.ok) { dialog, _ -> dialog.dismiss() } .setPositiveButton(android.R.string.ok) { dialog, _ -> dialog.dismiss() }
.show() .show()
} }
@ -169,13 +170,15 @@ class HomeFragment : Fragment() {
private fun showBankTransferDialog() { private fun showBankTransferDialog() {
transactionAdapter.selectedTransaction?.let { selectedTransaction ->
(context as? AppCompatActivity)?.let { activity -> (context as? AppCompatActivity)?.let { activity ->
BankTransferDialog().show(activity, presenter, mapPreselectedValues()) BankTransferDialog().show(activity, presenter, selectedTransaction.bankAccount, mapPreselectedValues(selectedTransaction))
}
} }
} }
private fun mapPreselectedValues(): BankTransferData? { private fun mapPreselectedValues(selectedTransaction: AccountTransaction?): BankTransferData? {
transactionAdapter.selectedTransaction?.let { selectedTransaction -> selectedTransaction?.let {
return BankTransferData( return BankTransferData(
selectedTransaction.otherPartyName ?: "", selectedTransaction.otherPartyName ?: "",
selectedTransaction.otherPartyAccountId ?: "", selectedTransaction.otherPartyAccountId ?: "",