Merged Customer and Bank
This commit is contained in:
parent
603b8ff4b7
commit
647a385f2a
|
@ -81,7 +81,7 @@ open class LuceneBankingPersistence(
|
|||
|
||||
override fun deleteAccount(customer: Customer, allCustomers: List<Customer>) {
|
||||
try {
|
||||
deleteAccountTransactions(customer.bankAccounts)
|
||||
deleteAccountTransactions(customer.accounts)
|
||||
} catch (e: Exception) {
|
||||
log.error("Could not delete account transactions of account $customer", e)
|
||||
}
|
||||
|
|
|
@ -51,7 +51,7 @@ open class AccountTransactionAdapter(protected val presenter: BankingPresenter)
|
|||
viewHolder.txtvwAmount.text = presenter.formatAmount(item.amount)
|
||||
viewHolder.txtvwAmount.setTextColorToColorResource(if (item.amount >= BigDecimal.ZERO) R.color.positiveAmount else R.color.negativeAmount)
|
||||
|
||||
val iconUrl = item.bankAccount.customer.bank.iconUrl
|
||||
val iconUrl = item.bankAccount.customer.iconUrl
|
||||
if (iconUrl != null && presenter.areAllAccountSelected) {
|
||||
viewHolder.imgvwBankIcon.visibility = View.VISIBLE
|
||||
viewHolder.imgvwBankIcon.setImageURI(Uri.parse(iconUrl))
|
||||
|
|
|
@ -32,7 +32,7 @@ open class BankAccountsAdapter(bankAccounts: List<BankAccount>) : ListAdapter<Ba
|
|||
|
||||
protected open fun setIcon(bankAccount: BankAccount, imgBankIcon: ImageView) {
|
||||
try {
|
||||
val iconUrl = bankAccount.customer.bank.iconUrl
|
||||
val iconUrl = bankAccount.customer.iconUrl
|
||||
imgBankIcon.visibility = if (iconUrl == null) View.GONE else View.VISIBLE
|
||||
imgBankIcon.setImageURI(Uri.parse(iconUrl))
|
||||
} catch (e: Exception) {
|
||||
|
|
|
@ -148,11 +148,11 @@ open class DrawerView(
|
|||
.withSecondaryIcon(GoogleMaterial.Icon.gmd_delete)
|
||||
.withSecondaryIconColor(activity, R.color.primaryTextColor_Dark)
|
||||
.withOnSecondaryIconClickedListener { closeDrawerAndEditAccount(customer) }
|
||||
.withIcon(customer.bank.iconUrl ?: "")
|
||||
.withIcon(customer.iconUrl ?: "")
|
||||
.withSelected(presenter.isSingleSelectedAccount(customer))
|
||||
.withOnDrawerItemClickListener { _, _, _ -> itemClicked { presenter.selectedAccount(customer) } }
|
||||
|
||||
if (customer.bank.iconUrl == null) {
|
||||
if (customer.iconUrl == null) {
|
||||
accountItem.withIcon(activity, FontAwesome.Icon.faw_piggy_bank, R.color.primaryTextColor_Dark)
|
||||
}
|
||||
|
||||
|
@ -161,7 +161,7 @@ open class DrawerView(
|
|||
}
|
||||
|
||||
private fun createBankAccountsDrawerItems(customer: Customer): List<IDrawerItem<*>> {
|
||||
return customer.bankAccounts.map { bankAccount ->
|
||||
return customer.accounts.map { bankAccount ->
|
||||
SecondaryDrawerItem()
|
||||
.withName(bankAccount.displayName)
|
||||
.withLevel(BankAccountLevel)
|
||||
|
|
|
@ -257,7 +257,7 @@ open class AddAccountDialog(protected val presenter: BankingPresenter) : Window(
|
|||
val account = response.customer
|
||||
|
||||
checkEnteredCredentialsResult.value = String.format(messages["add.account.dialog.error.could.not.add.account"],
|
||||
account.bank.bankCode, account.customerId, response.errorToShowToUser)
|
||||
account.bankCode, account.customerId, response.errorToShowToUser)
|
||||
|
||||
isEnteredCredentialsResultVisible.value = true
|
||||
}
|
||||
|
|
|
@ -114,7 +114,7 @@ open class TransferMoneyDialog @JvmOverloads constructor(
|
|||
cellFormat {
|
||||
text = it.displayNameIncludingBankName
|
||||
|
||||
it.customer.bank.iconUrl?.let { iconUrl ->
|
||||
it.customer.iconUrl?.let { iconUrl ->
|
||||
graphic = ImageView(iconUrl)?.apply {
|
||||
this.fitHeight = BankIconSize
|
||||
this.fitWidth = BankIconSize
|
||||
|
|
|
@ -17,13 +17,13 @@ open class AccountsAccountTreeItem(val customer: Customer) : AccountsTreeItemBas
|
|||
|
||||
graphic = createIconImageView()
|
||||
|
||||
customer.bankAccounts.forEach { bankAccount ->
|
||||
customer.accounts.forEach { bankAccount ->
|
||||
children.add(AccountsBankAccountTreeItem(bankAccount))
|
||||
}
|
||||
}
|
||||
|
||||
protected open fun createIconImageView(): Node? {
|
||||
customer.bank.iconUrl?.let {
|
||||
customer.iconUrl?.let {
|
||||
val iconImageView = ImageView(it)
|
||||
|
||||
iconImageView.fitHeight = IconSize
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
package net.dankito.banking.ui.model
|
||||
|
||||
|
||||
open class Bank @JvmOverloads constructor(
|
||||
var name: String,
|
||||
val bankCode: String,
|
||||
var bic: String,
|
||||
var finTsServerAddress: String,
|
||||
var iconUrl: String? = null
|
||||
) {
|
||||
|
||||
|
||||
internal constructor() : this("", "", "", "") // for object deserializers
|
||||
|
||||
|
||||
val displayName: String
|
||||
get() = name
|
||||
|
||||
|
||||
override fun toString(): String {
|
||||
return "$name ($bankCode)"
|
||||
}
|
||||
|
||||
}
|
|
@ -46,7 +46,7 @@ open class BankAccount @JvmOverloads constructor(
|
|||
}
|
||||
|
||||
open val displayNameIncludingBankName: String
|
||||
get() = "${customer.bank.name} ${displayName}"
|
||||
get() = "${customer.bankName} ${displayName}"
|
||||
|
||||
|
||||
open var bookedTransactions: List<AccountTransaction> = bookedAccountTransactions
|
||||
|
|
|
@ -11,16 +11,20 @@ import java.util.*
|
|||
|
||||
@JsonIdentityInfo(property = "id", generator = ObjectIdGenerators.PropertyGenerator::class) // to avoid stack overflow due to circular references
|
||||
open class Customer(
|
||||
val bank: Bank,
|
||||
val bankCode: String,
|
||||
val customerId: String,
|
||||
var password: String,
|
||||
var name: String,
|
||||
var finTsServerAddress: String,
|
||||
var bankName: String,
|
||||
var bic: String,
|
||||
var customerName: String,
|
||||
var userId: String = customerId,
|
||||
var bankAccounts: List<BankAccount> = listOf()
|
||||
var iconUrl: String? = null,
|
||||
var accounts: List<BankAccount> = listOf()
|
||||
) {
|
||||
|
||||
|
||||
internal constructor() : this(Bank(), "", "", "") // for object deserializers
|
||||
internal constructor() : this("", "", "", "", "", "", "") // for object deserializers
|
||||
|
||||
|
||||
var id: String = UUID.randomUUID().toString()
|
||||
|
@ -38,17 +42,17 @@ open class Customer(
|
|||
|
||||
|
||||
val displayName: String
|
||||
get() = bank.name
|
||||
get() = bankName
|
||||
|
||||
val balance: BigDecimal
|
||||
get() = bankAccounts.map { it.balance }.fold(BigDecimal.ZERO) { acc, e -> acc + e }
|
||||
get() = accounts.map { it.balance }.fold(BigDecimal.ZERO) { acc, e -> acc + e }
|
||||
|
||||
val transactions: List<AccountTransaction>
|
||||
get() = bankAccounts.flatMap { it.bookedTransactions }
|
||||
get() = accounts.flatMap { it.bookedTransactions }
|
||||
|
||||
|
||||
override fun toString(): String {
|
||||
return "$name ($customerId)"
|
||||
return "$customerName ($customerId)"
|
||||
}
|
||||
|
||||
}
|
|
@ -126,8 +126,7 @@ open class BankingPresenter(
|
|||
val deserializedAccounts = persister.readPersistedAccounts()
|
||||
|
||||
deserializedAccounts.forEach { customer ->
|
||||
val bank = customer.bank
|
||||
val bankInfo = BankInfo(bank.name, bank.bankCode, bank.bic, "", "", "", bank.finTsServerAddress, "FinTS V3.0", null)
|
||||
val bankInfo = BankInfo(customer.bankName, customer.bankCode, customer.bic, "", "", "", customer.finTsServerAddress, "FinTS V3.0", null)
|
||||
|
||||
val newClient = bankingClientCreator.createClient(bankInfo, customer.customerId, customer.password,
|
||||
dataFolder, threadPool, callback)
|
||||
|
@ -198,29 +197,27 @@ open class BankingPresenter(
|
|||
}
|
||||
|
||||
protected open fun findIconForBank(customer: Customer) {
|
||||
val bank = customer.bank
|
||||
|
||||
try {
|
||||
bankIconFinder.findIconForBank(bank.name)?.let { bankIconUrl ->
|
||||
val bankIconFile = saveBankIconToDisk(bank, bankIconUrl)
|
||||
bankIconFinder.findIconForBank(customer.bankName)?.let { bankIconUrl ->
|
||||
val bankIconFile = saveBankIconToDisk(customer, bankIconUrl)
|
||||
|
||||
bank.iconUrl = "file://" + bankIconFile.absolutePath // without 'file://' Android will not find it
|
||||
customer.iconUrl = "file://" + bankIconFile.absolutePath // without 'file://' Android will not find it
|
||||
|
||||
persistAccount(customer)
|
||||
|
||||
callAccountsChangedListeners()
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
log.error("Could not get icon for bank $bank", e)
|
||||
log.error("Could not get icon for bank ${customer.bankName}", e)
|
||||
}
|
||||
}
|
||||
|
||||
protected open fun saveBankIconToDisk(bank: Bank, bankIconUrl: String): File {
|
||||
protected open fun saveBankIconToDisk(customer: Customer, bankIconUrl: String): File {
|
||||
val bankIconsDir = File(dataFolder, "bank_icons")
|
||||
bankIconsDir.mkdirs()
|
||||
|
||||
val extension = getIconFileExtension(bankIconUrl)
|
||||
val bankIconFile = File(bankIconsDir, bank.bankCode + if (extension != null) (".$extension") else "")
|
||||
val bankIconFile = File(bankIconsDir, customer.bankCode + if (extension != null) (".$extension") else "")
|
||||
|
||||
URL(bankIconUrl).openConnection().getInputStream().buffered().use { iconInputStream ->
|
||||
FileOutputStream(bankIconFile).use { fileOutputStream ->
|
||||
|
@ -252,7 +249,7 @@ open class BankingPresenter(
|
|||
|
||||
open fun deleteAccount(customer: Customer) {
|
||||
val wasSelected = isSingleSelectedAccount(customer) or // either account or one of its bank accounts is currently selected
|
||||
(customer.bankAccounts.firstOrNull { isSingleSelectedBankAccount(it) } != null)
|
||||
(customer.accounts.firstOrNull { isSingleSelectedBankAccount(it) } != null)
|
||||
|
||||
bankingClientsForAccounts.remove(customer)
|
||||
|
||||
|
@ -269,7 +266,7 @@ open class BankingPresenter(
|
|||
open fun fetchAccountTransactionsAsync(customer: Customer,
|
||||
callback: (GetTransactionsResponse) -> Unit) {
|
||||
|
||||
customer.bankAccounts.forEach { bankAccount ->
|
||||
customer.accounts.forEach { bankAccount ->
|
||||
if (bankAccount.supportsRetrievingAccountTransactions) {
|
||||
fetchAccountTransactionsAsync(bankAccount, callback) // TODO: use a synchronous version of fetchAccountTransactions() so that all bank accounts get handled serially
|
||||
}
|
||||
|
@ -309,7 +306,7 @@ open class BankingPresenter(
|
|||
|
||||
protected open fun updateAccountsTransactionsAsync(abortIfTanIsRequired: Boolean = false, callback: (GetTransactionsResponse) -> Unit) {
|
||||
bankingClientsForAccounts.keys.forEach { account ->
|
||||
account.bankAccounts.forEach { bankAccount ->
|
||||
account.accounts.forEach { bankAccount ->
|
||||
if (bankAccount.supportsRetrievingAccountTransactions) {
|
||||
updateBankAccountTransactionsAsync(bankAccount, abortIfTanIsRequired, callback)
|
||||
}
|
||||
|
@ -491,7 +488,7 @@ open class BankingPresenter(
|
|||
}
|
||||
|
||||
return logEntries.map { entry ->
|
||||
MessageLogEntryDateFormat.format(entry.time) + " " + entry.customer.bank.bankCode + " " + entry.message
|
||||
MessageLogEntryDateFormat.format(entry.time) + " " + entry.customer.bankCode + " " + entry.message
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -546,7 +543,7 @@ open class BankingPresenter(
|
|||
open fun selectedAccount(customer: Customer) {
|
||||
selectedAccountType = SelectedAccountType.SingleAccount
|
||||
|
||||
setSelectedBankAccounts(customer.bankAccounts)
|
||||
setSelectedBankAccounts(customer.accounts)
|
||||
}
|
||||
|
||||
open fun selectedBankAccount(bankAccount: BankAccount) {
|
||||
|
@ -566,7 +563,7 @@ open class BankingPresenter(
|
|||
get() = bankingClientsForAccounts.keys.toList()
|
||||
|
||||
open val bankAccounts: List<BankAccount>
|
||||
get() = customers.flatMap { it.bankAccounts }
|
||||
get() = customers.flatMap { it.accounts }
|
||||
|
||||
open val allTransactions: List<AccountTransaction>
|
||||
get() = getAccountTransactionsForBankAccounts(bankAccounts)
|
||||
|
|
|
@ -67,16 +67,11 @@ open class fints4kModelMapper {
|
|||
}
|
||||
|
||||
|
||||
open fun mapBank(bank: BankData): Bank {
|
||||
return Bank(bank.name, bank.bankCode, bank.bic, bank.finTs3ServerAddress)
|
||||
}
|
||||
|
||||
open fun mapCustomer(customer: CustomerData, bank: BankData): Customer {
|
||||
val mappedBank = mapBank(bank)
|
||||
val mappedCustomer = Customer(bank.bankCode, customer.customerId, customer.pin,
|
||||
bank.finTs3ServerAddress, bank.name, bank.bic, customer.name, customer.userId)
|
||||
|
||||
val mappedCustomer = Customer(mappedBank, customer.customerId, customer.pin, customer.name, customer.userId)
|
||||
|
||||
mappedCustomer.bankAccounts = mapBankAccounts(mappedCustomer, customer.accounts)
|
||||
mappedCustomer.accounts = mapBankAccounts(mappedCustomer, customer.accounts)
|
||||
|
||||
updateTanMediaAndProcedures(mappedCustomer, customer)
|
||||
|
||||
|
@ -166,7 +161,7 @@ open class fints4kModelMapper {
|
|||
}
|
||||
|
||||
open fun findMatchingBankAccount(customer: Customer, accountData: AccountData): BankAccount? {
|
||||
return customer.bankAccounts.firstOrNull { it.identifier == accountData.accountIdentifier }
|
||||
return customer.accounts.firstOrNull { it.identifier == accountData.accountIdentifier }
|
||||
}
|
||||
|
||||
open fun findMatchingBankAccount(accounts: List<AccountData>, accountData: AccountData): AccountData? {
|
||||
|
|
|
@ -53,9 +53,8 @@ open class hbci4jBankingClient(
|
|||
|
||||
protected val credentials = AccountCredentials(bankInfo.bankCode, customerId, pin)
|
||||
|
||||
protected var bank = Bank(bankInfo.name, bankInfo.bankCode, bankInfo.bic, bankInfo.pinTanAddress ?: "")
|
||||
|
||||
protected var account = Customer(bank, customerId, pin, "")
|
||||
protected var customer = Customer(bankInfo.bankCode, customerId, pin,
|
||||
bankInfo.pinTanAddress ?: "", bankInfo.name, bankInfo.bic, "")
|
||||
|
||||
|
||||
protected val mapper = hbci4jModelMapper()
|
||||
|
@ -81,16 +80,16 @@ open class hbci4jBankingClient(
|
|||
val accounts = passport.accounts
|
||||
if (accounts == null || accounts.size == 0) {
|
||||
log.error("Keine Konten ermittelbar")
|
||||
return AddAccountResponse(false, "Keine Konten ermittelbar", account) // TODO: translate
|
||||
return AddAccountResponse(false, "Keine Konten ermittelbar", customer) // TODO: translate
|
||||
}
|
||||
|
||||
this.account.bankAccounts = mapper.mapBankAccounts(account, accounts, passport)
|
||||
this.customer.accounts = mapper.mapBankAccounts(customer, accounts, passport)
|
||||
|
||||
return tryToRetrieveAccountTransactionsForAddedAccounts(account)
|
||||
return tryToRetrieveAccountTransactionsForAddedAccounts(customer)
|
||||
}
|
||||
}
|
||||
|
||||
return AddAccountResponse(false, null, account, error = connection.error)
|
||||
return AddAccountResponse(false, null, customer, error = connection.error)
|
||||
}
|
||||
|
||||
protected open fun tryToRetrieveAccountTransactionsForAddedAccounts(customer: Customer): AddAccountResponse {
|
||||
|
@ -99,7 +98,7 @@ open class hbci4jBankingClient(
|
|||
val bookedTransactions = mutableMapOf<BankAccount, List<AccountTransaction>>()
|
||||
val unbookedTransactions = mutableMapOf<BankAccount, List<Any>>()
|
||||
|
||||
customer.bankAccounts.forEach { bankAccount ->
|
||||
customer.accounts.forEach { bankAccount ->
|
||||
if (bankAccount.supportsRetrievingAccountTransactions) {
|
||||
val response = getTransactionsOfLast90Days(bankAccount)
|
||||
transactionsOfLast90DaysResponses.add(response)
|
||||
|
@ -203,7 +202,7 @@ open class hbci4jBankingClient(
|
|||
}
|
||||
|
||||
protected open fun executeJobsForGetAccountingEntries(handle: HBCIHandler, bankAccount: BankAccount, parameter: GetTransactionsParameter): Triple<HBCIJob?, HBCIJob, HBCIExecStatus> {
|
||||
val konto = mapper.mapToKonto(bank, bankAccount)
|
||||
val konto = mapper.mapToKonto(bankAccount)
|
||||
|
||||
// 1. Auftrag fuer das Abrufen des Saldos erzeugen
|
||||
var balanceJob: HBCIJob? = null
|
||||
|
@ -265,7 +264,7 @@ open class hbci4jBankingClient(
|
|||
// TODO: implement instant payment
|
||||
val transferCashJob = handle.newJob("UebSEPA")
|
||||
|
||||
val source = mapper.mapToKonto(bank, bankAccount)
|
||||
val source = mapper.mapToKonto(bankAccount)
|
||||
val destination = mapper.mapToKonto(data)
|
||||
val amount = Value(data.amount, "EUR")
|
||||
|
||||
|
@ -292,7 +291,7 @@ open class hbci4jBankingClient(
|
|||
// In "props" koennen optional Kernel-Parameter abgelegt werden, die in der Klasse
|
||||
// org.kapott.hbci.manager.HBCIUtils (oben im Javadoc) beschrieben sind.
|
||||
val props = Properties()
|
||||
HBCIUtils.init(props, HbciCallback(credentials, account, mapper, callback))
|
||||
HBCIUtils.init(props, HbciCallback(credentials, customer, mapper, callback))
|
||||
|
||||
// In der Passport-Datei speichert HBCI4Java die Daten des Bankzugangs (Bankparameterdaten, Benutzer-Parameter, etc.).
|
||||
// Die Datei kann problemlos geloescht werden. Sie wird beim naechsten mal automatisch neu erzeugt,
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package net.dankito.banking.util
|
||||
|
||||
import net.dankito.banking.ui.model.Customer
|
||||
import net.dankito.banking.ui.model.Bank
|
||||
import net.dankito.banking.ui.model.BankAccount
|
||||
import net.dankito.banking.ui.model.BankAccountType
|
||||
import net.dankito.banking.ui.model.parameters.TransferMoneyData
|
||||
|
@ -14,12 +13,14 @@ import java.math.BigDecimal
|
|||
|
||||
open class hbci4jModelMapper {
|
||||
|
||||
open fun mapToKonto(bank: Bank, bankAccount: BankAccount): Konto {
|
||||
val konto = Konto("DE", bank.bankCode, bankAccount.identifier, bankAccount.subAccountNumber)
|
||||
open fun mapToKonto(bankAccount: BankAccount): Konto {
|
||||
val customer = bankAccount.customer
|
||||
|
||||
konto.name = bank.name
|
||||
val konto = Konto("DE", customer.bankCode, bankAccount.identifier, bankAccount.subAccountNumber)
|
||||
|
||||
konto.name = customer.bankName
|
||||
konto.iban = bankAccount.iban
|
||||
konto.bic = bank.bic
|
||||
konto.bic = customer.bic
|
||||
|
||||
return konto
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue