Renamed Customer to BankData
This commit is contained in:
parent
df1ce4fd3a
commit
60c93dedfb
|
@ -45,22 +45,22 @@ open class LuceneBankingPersistence(
|
|||
protected val fields = FieldBuilder()
|
||||
|
||||
|
||||
override fun saveOrUpdateAccountTransactions(bankAccount: TypedBankAccount, transactions: List<IAccountTransaction>) {
|
||||
override fun saveOrUpdateAccountTransactions(account: TypedBankAccount, transactions: List<IAccountTransaction>) {
|
||||
val writer = getWriter()
|
||||
|
||||
transactions.forEach { transaction ->
|
||||
writer.updateDocumentForNonNullFields(
|
||||
IdFieldName, transaction.technicalId,
|
||||
*createFieldsForAccountTransaction(bankAccount, transaction).toTypedArray()
|
||||
*createFieldsForAccountTransaction(account, transaction).toTypedArray()
|
||||
)
|
||||
}
|
||||
|
||||
writer.flushChangesToDisk()
|
||||
}
|
||||
|
||||
protected open fun createFieldsForAccountTransaction(bankAccount: TypedBankAccount, transaction: IAccountTransaction): List<IndexableField?> {
|
||||
protected open fun createFieldsForAccountTransaction(account: TypedBankAccount, transaction: IAccountTransaction): List<IndexableField?> {
|
||||
return listOf(
|
||||
fields.keywordField(BankAccountIdFieldName, bankAccount.technicalId),
|
||||
fields.keywordField(BankAccountIdFieldName, account.technicalId),
|
||||
fields.nullableFullTextSearchField(OtherPartyNameFieldName, transaction.otherPartyName, true),
|
||||
fields.fullTextSearchField(UsageFieldName, transaction.usage, true),
|
||||
fields.nullableFullTextSearchField(BookingTextFieldName, transaction.bookingText, true),
|
||||
|
@ -77,21 +77,21 @@ open class LuceneBankingPersistence(
|
|||
}
|
||||
|
||||
|
||||
override fun deleteAccount(customer: TypedCustomer, allCustomers: List<TypedCustomer>) {
|
||||
override fun deleteBank(bank: TypedBankData, allBanks: List<TypedBankData>) {
|
||||
try {
|
||||
deleteAccountTransactions(customer.accounts)
|
||||
deleteAccountTransactions(bank.accounts)
|
||||
} catch (e: Exception) {
|
||||
log.error("Could not delete account transactions of account $customer", e)
|
||||
log.error("Could not delete account transactions of account $bank", e)
|
||||
}
|
||||
|
||||
super.deleteAccount(customer, allCustomers)
|
||||
super.deleteBank(bank, allBanks)
|
||||
}
|
||||
|
||||
protected open fun deleteAccountTransactions(bankAccounts: List<TypedBankAccount>) {
|
||||
protected open fun deleteAccountTransactions(accounts: List<TypedBankAccount>) {
|
||||
val writer = getWriter()
|
||||
|
||||
val bankAccountIds = bankAccounts.map { it.technicalId }
|
||||
writer.deleteDocumentsAndFlushChangesToDisk(BankAccountIdFieldName, *bankAccountIds.toTypedArray())
|
||||
val accountIds = accounts.map { it.technicalId }
|
||||
writer.deleteDocumentsAndFlushChangesToDisk(BankAccountIdFieldName, *accountIds.toTypedArray())
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package net.dankito.banking.search
|
||||
|
||||
import net.dankito.banking.persistence.LuceneBankingPersistence
|
||||
import net.dankito.banking.ui.model.Customer
|
||||
import net.dankito.banking.ui.model.BankData
|
||||
import net.dankito.banking.ui.model.AccountTransaction
|
||||
import net.dankito.banking.ui.model.BankAccount
|
||||
import net.dankito.utils.io.FileUtils
|
||||
|
@ -37,7 +37,7 @@ class LuceneRemitteeSearcherTest {
|
|||
private val Amount = BigDecimal.valueOf(123.45)
|
||||
|
||||
|
||||
private val bankAccountMock = BankAccount(mock(Customer::class.java), "", "", null, null, "")
|
||||
private val bankAccountMock = BankAccount(mock(BankData::class.java), "", "", null, null, "")
|
||||
|
||||
|
||||
private val dateFormat = SimpleDateFormat("dd.MM.yyyy")
|
||||
|
|
|
@ -9,7 +9,7 @@ import net.dankito.banking.search.IRemitteeSearcher
|
|||
import net.dankito.banking.search.Remittee
|
||||
import net.dankito.banking.ui.model.IAccountTransaction
|
||||
import net.dankito.banking.ui.model.TypedBankAccount
|
||||
import net.dankito.banking.ui.model.TypedCustomer
|
||||
import net.dankito.banking.ui.model.TypedBankData
|
||||
import net.dankito.banking.ui.model.tan.MobilePhoneTanMedium
|
||||
import net.dankito.banking.ui.model.tan.TanGeneratorTanMedium
|
||||
import net.dankito.banking.util.persistence.doSaveUrlToFile
|
||||
|
@ -32,8 +32,8 @@ open class RoomBankingPersistence(applicationContext: Context, password: String?
|
|||
}
|
||||
|
||||
|
||||
override fun saveOrUpdateAccount(customer: TypedCustomer, allCustomers: List<TypedCustomer>) {
|
||||
(customer as? Bank)?.let { bank ->
|
||||
override fun saveOrUpdateBank(bank: TypedBankData, allBanks: List<TypedBankData>) {
|
||||
(bank as? Bank)?.let { bank ->
|
||||
bank.selectedTanMethodId = bank.selectedTanMethod?.technicalId
|
||||
|
||||
db.bankDao().saveOrUpdate(bank)
|
||||
|
@ -64,8 +64,8 @@ open class RoomBankingPersistence(applicationContext: Context, password: String?
|
|||
}
|
||||
}
|
||||
|
||||
override fun deleteAccount(customer: TypedCustomer, allCustomers: List<TypedCustomer>) {
|
||||
(customer as? Bank)?.let { bank ->
|
||||
override fun deleteBank(bank: TypedBankData, allBanks: List<TypedBankData>) {
|
||||
(bank as? Bank)?.let { bank ->
|
||||
db.accountTransactionDao().delete(bank.accounts.flatMap { it.bookedTransactions }.filterIsInstance<AccountTransaction>())
|
||||
|
||||
db.bankAccountDao().delete(bank.accounts.filterIsInstance<BankAccount>())
|
||||
|
@ -77,7 +77,7 @@ open class RoomBankingPersistence(applicationContext: Context, password: String?
|
|||
}
|
||||
}
|
||||
|
||||
override fun readPersistedAccounts(): List<TypedCustomer> {
|
||||
override fun readPersistedBanks(): List<TypedBankData> {
|
||||
val banks = db.bankDao().getAll()
|
||||
|
||||
val accounts = db.bankAccountDao().getAll()
|
||||
|
@ -92,12 +92,12 @@ open class RoomBankingPersistence(applicationContext: Context, password: String?
|
|||
bank.accounts = accounts.filter { it.bankId == bank.id }
|
||||
|
||||
bank.accounts.filterIsInstance<BankAccount>().forEach { account ->
|
||||
account.customer = bank
|
||||
account.bank = bank
|
||||
|
||||
account.bookedTransactions = transactions.filter { it.bankAccountId == account.id }
|
||||
account.bookedTransactions = transactions.filter { it.accountId == account.id }
|
||||
|
||||
account.bookedTransactions.filterIsInstance<AccountTransaction>().forEach { transaction ->
|
||||
transaction.bankAccount = account
|
||||
transaction.account = account
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -111,12 +111,12 @@ open class RoomBankingPersistence(applicationContext: Context, password: String?
|
|||
return banks
|
||||
}
|
||||
|
||||
override fun saveOrUpdateAccountTransactions(bankAccount: TypedBankAccount, transactions: List<IAccountTransaction>) {
|
||||
val accountId = (bankAccount as? BankAccount)?.id ?: bankAccount.technicalId.toLong()
|
||||
override fun saveOrUpdateAccountTransactions(account: TypedBankAccount, transactions: List<IAccountTransaction>) {
|
||||
val accountId = (account as? BankAccount)?.id ?: account.technicalId.toLong()
|
||||
|
||||
val mappedTransactions = transactions.filterIsInstance<AccountTransaction>()
|
||||
|
||||
mappedTransactions.forEach { it.bankAccountId = accountId }
|
||||
mappedTransactions.forEach { it.accountId = accountId }
|
||||
|
||||
db.accountTransactionDao().saveOrUpdate(mappedTransactions)
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ import net.dankito.utils.multiplatform.*
|
|||
@Entity
|
||||
open class AccountTransaction(
|
||||
@Ignore
|
||||
override var bankAccount: BankAccount,
|
||||
override var account: BankAccount,
|
||||
|
||||
override var amount: BigDecimal,
|
||||
override var currency: String,
|
||||
|
@ -56,15 +56,15 @@ open class AccountTransaction(
|
|||
|
||||
/* convenience constructors for languages not supporting default values */
|
||||
|
||||
constructor(bankAccount: BankAccount, otherPartyName: String?, unparsedUsage: String, amount: BigDecimal, valueDate: Date, bookingText: String?)
|
||||
: this(bankAccount, amount, "EUR", unparsedUsage, valueDate,
|
||||
constructor(account: BankAccount, otherPartyName: String?, unparsedUsage: String, amount: BigDecimal, valueDate: Date, bookingText: String?)
|
||||
: this(account, amount, "EUR", unparsedUsage, valueDate,
|
||||
otherPartyName, null, null, bookingText, valueDate)
|
||||
|
||||
|
||||
constructor(bankAccount: BankAccount, amount: BigDecimal, currency: String, unparsedUsage: String, bookingDate: Date,
|
||||
constructor(account: BankAccount, amount: BigDecimal, currency: String, unparsedUsage: String, bookingDate: Date,
|
||||
otherPartyName: String?, otherPartyBankCode: String?, otherPartyAccountId: String?,
|
||||
bookingText: String?, valueDate: Date)
|
||||
: this(bankAccount, amount, currency, unparsedUsage, bookingDate,
|
||||
: this(account, amount, currency, unparsedUsage, bookingDate,
|
||||
otherPartyName, otherPartyBankCode, otherPartyAccountId, bookingText, valueDate,
|
||||
0, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, "", "", null, null, "", null)
|
||||
|
||||
|
@ -75,7 +75,7 @@ open class AccountTransaction(
|
|||
override var technicalId: String = buildTransactionIdentifier()
|
||||
|
||||
// Room doesn't allow me to add getters and setters -> have to map it manually
|
||||
open var bankAccountId: Long = BaseDao.ObjectNotInsertedId
|
||||
open var accountId: Long = BaseDao.ObjectNotInsertedId
|
||||
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
|
|
|
@ -5,7 +5,7 @@ import androidx.room.Ignore
|
|||
import androidx.room.PrimaryKey
|
||||
import net.dankito.banking.persistence.dao.BaseDao
|
||||
import net.dankito.banking.ui.model.TypedBankAccount
|
||||
import net.dankito.banking.ui.model.TypedCustomer
|
||||
import net.dankito.banking.ui.model.TypedBankData
|
||||
import net.dankito.banking.ui.model.tan.TanMedium
|
||||
import net.dankito.banking.ui.model.tan.TanMethod
|
||||
|
||||
|
@ -44,7 +44,7 @@ open class Bank(
|
|||
|
||||
override var userSetDisplayName: String? = null,
|
||||
override var displayIndex: Int = 0
|
||||
) : TypedCustomer {
|
||||
) : TypedBankData {
|
||||
|
||||
internal constructor() : this("", "", "", "", "", "", "") // for object deserializers
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ import net.dankito.utils.multiplatform.UUID
|
|||
@Entity
|
||||
open class BankAccount(
|
||||
@Ignore
|
||||
override var customer: TypedCustomer,
|
||||
override var bank: TypedBankData,
|
||||
override var identifier: String,
|
||||
override var accountHolderName: String,
|
||||
override var iban: String?,
|
||||
|
@ -42,10 +42,10 @@ open class BankAccount(
|
|||
|
||||
/* convenience constructors for languages not supporting default values */
|
||||
|
||||
constructor(customer: TypedCustomer, productName: String?, identifier: String) : this(customer, productName, identifier, BankAccountType.Girokonto)
|
||||
constructor(bank: TypedBankData, productName: String?, identifier: String) : this(bank, productName, identifier, BankAccountType.Girokonto)
|
||||
|
||||
constructor(customer: TypedCustomer, productName: String?, identifier: String, type: BankAccountType = BankAccountType.Girokonto, balance: BigDecimal = BigDecimal.Zero)
|
||||
: this(customer, identifier, "", null, null, "", balance, "EUR", type, productName)
|
||||
constructor(bank: TypedBankData, productName: String?, identifier: String, type: BankAccountType = BankAccountType.Girokonto, balance: BigDecimal = BigDecimal.Zero)
|
||||
: this(bank, identifier, "", null, null, "", balance, "EUR", type, productName)
|
||||
|
||||
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
|
|
|
@ -2,7 +2,7 @@ package net.dankito.banking.persistence.model
|
|||
|
||||
import net.dankito.banking.ui.model.IAccountTransaction
|
||||
import net.dankito.banking.ui.model.TypedBankAccount
|
||||
import net.dankito.banking.ui.model.TypedCustomer
|
||||
import net.dankito.banking.ui.model.TypedBankData
|
||||
import net.dankito.banking.ui.model.mapper.IModelCreator
|
||||
import net.dankito.banking.ui.model.tan.AllowedTanFormat
|
||||
import net.dankito.banking.ui.model.tan.TanMethodType
|
||||
|
@ -12,18 +12,18 @@ import net.dankito.utils.multiplatform.Date
|
|||
|
||||
open class RoomModelCreator : IModelCreator {
|
||||
|
||||
override fun createCustomer(bankCode: String, customerId: String, password: String, finTsServerAddress: String, bankName: String,
|
||||
bic: String, customerName: String, userId: String, iconUrl: String?): TypedCustomer {
|
||||
override fun createBank(bankCode: String, customerId: String, password: String, finTsServerAddress: String, bankName: String,
|
||||
bic: String, customerName: String, userId: String, iconUrl: String?): TypedBankData {
|
||||
|
||||
return Bank(bankCode, customerId, password, finTsServerAddress, bankName, bic, customerName, userId, iconUrl)
|
||||
}
|
||||
|
||||
override fun createBankAccount(customer: TypedCustomer, productName: String?, identifier: String): TypedBankAccount {
|
||||
return BankAccount(customer, productName, identifier)
|
||||
override fun createAccount(bank: TypedBankData, productName: String?, identifier: String): TypedBankAccount {
|
||||
return BankAccount(bank, productName, identifier)
|
||||
}
|
||||
|
||||
override fun createTransaction(
|
||||
bankAccount: TypedBankAccount,
|
||||
account: TypedBankAccount,
|
||||
amount: BigDecimal,
|
||||
currency: String,
|
||||
unparsedUsage: String,
|
||||
|
@ -58,7 +58,7 @@ open class RoomModelCreator : IModelCreator {
|
|||
transactionReferenceNumber: String,
|
||||
relatedReferenceNumber: String?
|
||||
): IAccountTransaction {
|
||||
return AccountTransaction(bankAccount as BankAccount, amount, currency, unparsedUsage, bookingDate, otherPartyName, otherPartyBankCode, otherPartyAccountId,
|
||||
return AccountTransaction(account as BankAccount, amount, currency, unparsedUsage, bookingDate, otherPartyName, otherPartyBankCode, otherPartyAccountId,
|
||||
bookingText, valueDate, statementNumber, sequenceNumber, openingBalance, closingBalance, endToEndReference, customerReference, mandateReference,
|
||||
creditorIdentifier, originatorsIdentificationCode, compensationAmount, originalAmount, sepaUsage, deviantOriginator, deviantRecipient,
|
||||
usageWithNoSpecialType, primaNotaNumber, textKeySupplement, currencyType, bookingKey, referenceForTheAccountOwner,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package net.dankito.banking.persistence
|
||||
|
||||
import net.dankito.banking.persistence.model.CustomerEntity
|
||||
import net.dankito.banking.persistence.model.BankDataEntity
|
||||
import net.dankito.banking.ui.model.*
|
||||
import net.dankito.utils.multiplatform.File
|
||||
import net.dankito.banking.util.ISerializer
|
||||
|
@ -17,27 +17,27 @@ open class BankingPersistenceJson(
|
|||
}
|
||||
|
||||
|
||||
override fun saveOrUpdateAccount(customer: TypedCustomer, allCustomers: List<TypedCustomer>) {
|
||||
saveAllCustomers(allCustomers)
|
||||
override fun saveOrUpdateBank(bank: TypedBankData, allBanks: List<TypedBankData>) {
|
||||
saveAllBanks(allBanks)
|
||||
}
|
||||
|
||||
override fun deleteAccount(customer: TypedCustomer, allCustomers: List<TypedCustomer>) {
|
||||
saveAllCustomers(allCustomers)
|
||||
override fun deleteBank(bank: TypedBankData, allBanks: List<TypedBankData>) {
|
||||
saveAllBanks(allBanks)
|
||||
}
|
||||
|
||||
override fun readPersistedAccounts(): List<TypedCustomer> {
|
||||
return serializer.deserializeListOr(jsonFile, CustomerEntity::class).map { it as TypedCustomer }
|
||||
override fun readPersistedBanks(): List<TypedBankData> {
|
||||
return serializer.deserializeListOr(jsonFile, BankDataEntity::class).map { it as TypedBankData }
|
||||
}
|
||||
|
||||
|
||||
override fun saveOrUpdateAccountTransactions(bankAccount: TypedBankAccount, transactions: List<IAccountTransaction>) {
|
||||
override fun saveOrUpdateAccountTransactions(account: TypedBankAccount, transactions: List<IAccountTransaction>) {
|
||||
// done when called saveOrUpdateAccount()
|
||||
// TODO: or also call saveAllCustomers()?
|
||||
// TODO: or also call saveAllBanks()?
|
||||
}
|
||||
|
||||
|
||||
protected open fun saveAllCustomers(allCustomers: List<TypedCustomer>) {
|
||||
serializer.serializeObject(allCustomers, jsonFile)
|
||||
protected open fun saveAllBanks(allBanks: List<TypedBankData>) {
|
||||
serializer.serializeObject(allBanks, jsonFile)
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -2,10 +2,10 @@ package net.dankito.banking.persistence.mapper
|
|||
|
||||
import net.dankito.banking.persistence.model.AccountTransactionEntity
|
||||
import net.dankito.banking.persistence.model.BankAccountEntity
|
||||
import net.dankito.banking.persistence.model.CustomerEntity
|
||||
import net.dankito.banking.persistence.model.BankDataEntity
|
||||
import net.dankito.banking.ui.model.IAccountTransaction
|
||||
import net.dankito.banking.ui.model.TypedBankAccount
|
||||
import net.dankito.banking.ui.model.TypedCustomer
|
||||
import net.dankito.banking.ui.model.TypedBankData
|
||||
import net.dankito.banking.ui.model.mapper.IModelCreator
|
||||
import net.dankito.utils.multiplatform.BigDecimal
|
||||
import net.dankito.utils.multiplatform.Date
|
||||
|
@ -13,19 +13,19 @@ import net.dankito.utils.multiplatform.Date
|
|||
|
||||
open class EntitiesModelCreator : IModelCreator {
|
||||
|
||||
override fun createCustomer(bankCode: String, customerId: String, password: String, finTsServerAddress: String, bankName: String, bic: String,
|
||||
customerName: String, userId: String, iconUrl: String?): TypedCustomer {
|
||||
override fun createBank(bankCode: String, customerId: String, password: String, finTsServerAddress: String, bankName: String, bic: String,
|
||||
customerName: String, userId: String, iconUrl: String?): TypedBankData {
|
||||
|
||||
return CustomerEntity(bankCode, customerId, password, finTsServerAddress, bankName, bic, customerName, userId, iconUrl) as TypedCustomer
|
||||
return BankDataEntity(bankCode, customerId, password, finTsServerAddress, bankName, bic, customerName, userId, iconUrl) as TypedBankData
|
||||
}
|
||||
|
||||
|
||||
override fun createBankAccount(customer: TypedCustomer, productName: String?, identifier: String): TypedBankAccount {
|
||||
return BankAccountEntity(customer as CustomerEntity, identifier, "", null, null, "", productName = productName) as TypedBankAccount
|
||||
override fun createAccount(bank: TypedBankData, productName: String?, identifier: String): TypedBankAccount {
|
||||
return BankAccountEntity(bank as BankDataEntity, identifier, "", null, null, "", productName = productName) as TypedBankAccount
|
||||
}
|
||||
|
||||
override fun createTransaction(
|
||||
bankAccount: TypedBankAccount,
|
||||
account: TypedBankAccount,
|
||||
amount: BigDecimal,
|
||||
currency: String,
|
||||
unparsedUsage: String,
|
||||
|
@ -61,7 +61,7 @@ open class EntitiesModelCreator : IModelCreator {
|
|||
relatedReferenceNumber: String?
|
||||
) : IAccountTransaction {
|
||||
|
||||
return AccountTransactionEntity(bankAccount as BankAccountEntity, amount, currency, unparsedUsage, bookingDate,
|
||||
return AccountTransactionEntity(account as BankAccountEntity, amount, currency, unparsedUsage, bookingDate,
|
||||
otherPartyName, otherPartyBankCode, otherPartyAccountId, bookingText, valueDate, statementNumber, sequenceNumber,
|
||||
openingBalance, closingBalance, endToEndReference, customerReference, mandateReference, creditorIdentifier,
|
||||
originatorsIdentificationCode, compensationAmount, originalAmount, sepaUsage, deviantOriginator, deviantRecipient,
|
||||
|
|
|
@ -11,7 +11,7 @@ import net.dankito.utils.multiplatform.UUID
|
|||
@JsonIdentityInfo(property = "technicalId", generator = ObjectIdGenerators.PropertyGenerator::class) // to avoid stack overflow due to circular references
|
||||
// had to define all properties as 'var' 'cause MapStruct cannot handle vals
|
||||
open class AccountTransactionEntity(
|
||||
override var bankAccount: BankAccountEntity,
|
||||
override var account: BankAccountEntity,
|
||||
override var amount: BigDecimal,
|
||||
override var currency: String,
|
||||
override var unparsedUsage: String,
|
||||
|
@ -56,8 +56,8 @@ open class AccountTransactionEntity(
|
|||
-1, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, "", "", null,
|
||||
null, "", null)
|
||||
|
||||
constructor(bankAccount: BankAccountEntity, otherPartyName: String?, unparsedUsage: String, amount: BigDecimal, valueDate: Date, bookingText: String?)
|
||||
: this(bankAccount, amount, "EUR", unparsedUsage, valueDate, otherPartyName, null, null, bookingText, valueDate, 0, null, null, null,
|
||||
constructor(account: BankAccountEntity, otherPartyName: String?, unparsedUsage: String, amount: BigDecimal, valueDate: Date, bookingText: String?)
|
||||
: this(account, amount, "EUR", unparsedUsage, valueDate, otherPartyName, null, null, bookingText, valueDate, 0, null, null, null,
|
||||
null, null, null, null, null, null, null, null, null, null, null, null, null,
|
||||
null, "", "", null, null, "", null)
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ import net.dankito.utils.multiplatform.UUID
|
|||
@JsonIdentityInfo(property = "technicalId", generator = ObjectIdGenerators.PropertyGenerator::class) // to avoid stack overflow due to circular references
|
||||
// had to define all properties as 'var' 'cause MapStruct cannot handle vals (and cannot use Pozo's mapstruct-kotlin as SerializableBankAccountBuilder would fail with @Context)
|
||||
open class BankAccountEntity(
|
||||
override var customer: CustomerEntity,
|
||||
override var bank: BankDataEntity,
|
||||
override var identifier: String,
|
||||
override var accountHolderName: String,
|
||||
override var iban: String?,
|
||||
|
@ -38,7 +38,7 @@ open class BankAccountEntity(
|
|||
|
||||
) : IBankAccount<AccountTransactionEntity> {
|
||||
|
||||
internal constructor() : this(CustomerEntity(), "", "", null, null, "") // for object deserializers
|
||||
internal constructor() : this(BankDataEntity(), "", "", null, null, "") // for object deserializers
|
||||
|
||||
|
||||
override fun toString(): String {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package net.dankito.banking.persistence.model
|
||||
|
||||
import com.fasterxml.jackson.annotation.*
|
||||
import net.dankito.banking.ui.model.ICustomer
|
||||
import net.dankito.banking.ui.model.IBankData
|
||||
import net.dankito.banking.ui.model.tan.TanMedium
|
||||
import net.dankito.banking.ui.model.tan.TanMethod
|
||||
import java.util.*
|
||||
|
@ -9,7 +9,7 @@ import java.util.*
|
|||
|
||||
@JsonIdentityInfo(property = "technicalId", generator = ObjectIdGenerators.PropertyGenerator::class) // to avoid stack overflow due to circular references
|
||||
// had to define all properties as 'var' 'cause MapStruct cannot handle vals (and cannot use Pozo's mapstruct-kotlin as SerializableCustomerBuilder would fail with @Context)
|
||||
open class CustomerEntity(
|
||||
open class BankDataEntity(
|
||||
override var bankCode: String,
|
||||
override var customerId: String,
|
||||
override var password: String,
|
||||
|
@ -27,7 +27,7 @@ open class CustomerEntity(
|
|||
override var technicalId: String = UUID.randomUUID().toString(),
|
||||
override var userSetDisplayName: String? = null,
|
||||
override var displayIndex: Int = 0
|
||||
) : ICustomer<BankAccountEntity, AccountTransactionEntity> {
|
||||
) : IBankData<BankAccountEntity, AccountTransactionEntity> {
|
||||
|
||||
internal constructor() : this("", "", "", "", "", "", "") // for object deserializers
|
||||
|
|
@ -2,7 +2,7 @@ package net.dankito.banking.persistence
|
|||
|
||||
import net.dankito.banking.persistence.model.AccountTransactionEntity
|
||||
import net.dankito.banking.persistence.model.BankAccountEntity
|
||||
import net.dankito.banking.persistence.model.CustomerEntity
|
||||
import net.dankito.banking.persistence.model.BankDataEntity
|
||||
import net.dankito.banking.ui.model.*
|
||||
import net.dankito.banking.util.JacksonJsonSerializer
|
||||
import net.dankito.utils.multiplatform.BigDecimal
|
||||
|
@ -57,96 +57,96 @@ class BankingPersistenceJsonTest {
|
|||
|
||||
|
||||
@Test
|
||||
fun saveOrUpdateAccount() {
|
||||
fun saveOrUpdateBank() {
|
||||
|
||||
// given
|
||||
val customers = listOf(
|
||||
createCustomer(2),
|
||||
createCustomer(3)
|
||||
val banks = listOf(
|
||||
createBank(2),
|
||||
createBank(3)
|
||||
)
|
||||
|
||||
|
||||
// when
|
||||
underTest.saveOrUpdateAccount(customers.first() as TypedCustomer, customers.map { it as TypedCustomer })
|
||||
underTest.saveOrUpdateBank(banks.first() as TypedBankData, banks.map { it as TypedBankData })
|
||||
|
||||
|
||||
// then
|
||||
val result = serializer.deserializeListOr(file, CustomerEntity::class)
|
||||
val result = serializer.deserializeListOr(file, BankDataEntity::class)
|
||||
|
||||
assertCustomersEqual(result, customers)
|
||||
assertBanksEqual(result, banks)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun saveOrUpdateAccountWithBankAccountsAndTransactions() {
|
||||
fun saveOrUpdateBankWithAccountsAndTransactions() {
|
||||
|
||||
// given
|
||||
val customer = createCustomer(2)
|
||||
val bank = createBank(2)
|
||||
|
||||
|
||||
// when
|
||||
underTest.saveOrUpdateAccount(customer as TypedCustomer, listOf(customer).map { it as TypedCustomer })
|
||||
underTest.saveOrUpdateBank(bank as TypedBankData, listOf(bank).map { it as TypedBankData })
|
||||
|
||||
|
||||
// then
|
||||
val result = serializer.deserializeListOr(file, CustomerEntity::class)
|
||||
val result = serializer.deserializeListOr(file, BankDataEntity::class)
|
||||
|
||||
assertCustomersEqual(result, listOf(customer) as List<CustomerEntity>)
|
||||
assertBanksEqual(result, listOf(bank) as List<BankDataEntity>)
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
fun readPersistedAccounts() {
|
||||
fun readPersistedBanks() {
|
||||
|
||||
// given
|
||||
val customers = listOf(
|
||||
createCustomer(2),
|
||||
createCustomer(3)
|
||||
val banks = listOf(
|
||||
createBank(2),
|
||||
createBank(3)
|
||||
)
|
||||
|
||||
serializer.serializeObject(customers, file)
|
||||
serializer.serializeObject(banks, file)
|
||||
|
||||
|
||||
// when
|
||||
val result = underTest.readPersistedAccounts()
|
||||
val result = underTest.readPersistedBanks()
|
||||
|
||||
|
||||
// then
|
||||
assertCustomersEqual(customers, result as List<CustomerEntity>)
|
||||
assertBanksEqual(banks, result as List<BankDataEntity>)
|
||||
}
|
||||
|
||||
|
||||
private fun createCustomer(countBankAccounts: Int = 0, customerId: String = CustomerId): CustomerEntity {
|
||||
val result = CustomerEntity(BankCode, customerId, Password, FinTsServerAddress, BankName, Bic, CustomerName, UserId, IconUrl)
|
||||
private fun createBank(countAccounts: Int = 0, customerId: String = CustomerId): BankDataEntity {
|
||||
val result = BankDataEntity(BankCode, customerId, Password, FinTsServerAddress, BankName, Bic, CustomerName, UserId, IconUrl)
|
||||
|
||||
result.accounts = createBankAccounts(countBankAccounts, result)
|
||||
result.accounts = createAccounts(countAccounts, result)
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
private fun createBankAccounts(count: Int, customer: CustomerEntity): List<BankAccountEntity> {
|
||||
private fun createAccounts(count: Int, customer: BankDataEntity): List<BankAccountEntity> {
|
||||
val random = Random(System.nanoTime())
|
||||
|
||||
return IntRange(1, count).map { accountIndex ->
|
||||
createBankAccount("Account_$accountIndex", customer, random.nextInt(2, 50))
|
||||
createAccount("Account_$accountIndex", customer, random.nextInt(2, 50))
|
||||
}
|
||||
}
|
||||
|
||||
private fun createBankAccount(productName: String, customer: CustomerEntity, countTransactions: Int = 0): BankAccountEntity {
|
||||
private fun createAccount(productName: String, customer: BankDataEntity, countTransactions: Int = 0): BankAccountEntity {
|
||||
val result = BankAccountEntity(customer, customer.customerId, "AccountHolder", "DE00" + customer.bankCode + customer.customerId, null,
|
||||
customer.customerId, BigDecimal(84.25), productName = productName)
|
||||
|
||||
result.bookedTransactions = createAccountTransactions(countTransactions, result)
|
||||
result.bookedTransactions = createTransactions(countTransactions, result)
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
private fun createAccountTransactions(countTransactions: Int, account: BankAccountEntity): List<AccountTransactionEntity> {
|
||||
private fun createTransactions(countTransactions: Int, account: BankAccountEntity): List<AccountTransactionEntity> {
|
||||
return IntRange(1, countTransactions).map { transactionIndex ->
|
||||
createAccountTransaction(transactionIndex, account)
|
||||
createTransaction(transactionIndex, account)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createAccountTransaction(transactionIndex: Int, account: BankAccountEntity): AccountTransactionEntity {
|
||||
private fun createTransaction(transactionIndex: Int, account: BankAccountEntity): AccountTransactionEntity {
|
||||
return AccountTransactionEntity(account, "OtherParty_$transactionIndex", "Usage_$transactionIndex", BigDecimal(transactionIndex.toDouble()), createDate(), null)
|
||||
}
|
||||
|
||||
|
@ -155,37 +155,37 @@ class BankingPersistenceJsonTest {
|
|||
}
|
||||
|
||||
|
||||
private fun assertCustomersEqual(deserializedCustomers: List<CustomerEntity>, customers: List<CustomerEntity>) {
|
||||
assertThat(deserializedCustomers.size).isEqualTo(customers.size)
|
||||
private fun assertBanksEqual(deserializedBanks: List<BankDataEntity>, banks: List<BankDataEntity>) {
|
||||
assertThat(deserializedBanks.size).isEqualTo(banks.size)
|
||||
|
||||
deserializedCustomers.forEach { deserializedCustomer ->
|
||||
val customer = customers.firstOrNull { it.technicalId == deserializedCustomer.technicalId }
|
||||
deserializedBanks.forEach { deserializedBanks ->
|
||||
val bank = banks.firstOrNull { it.technicalId == deserializedBanks.technicalId }
|
||||
|
||||
if (customer == null) {
|
||||
Assert.fail("Could not find matching customer for deserialized customer $deserializedCustomer. customers = $customers")
|
||||
if (bank == null) {
|
||||
Assert.fail("Could not find matching bank for deserialized bank $deserializedBanks. banks = $banks")
|
||||
}
|
||||
else {
|
||||
assertCustomersEqual(deserializedCustomer, customer)
|
||||
assertBanksEqual(deserializedBanks, bank)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun assertCustomersEqual(deserializedCustomer: CustomerEntity, customer: CustomerEntity) {
|
||||
assertThat(deserializedCustomer.bankCode).isEqualTo(customer.bankCode)
|
||||
assertThat(deserializedCustomer.customerId).isEqualTo(customer.customerId)
|
||||
assertThat(deserializedCustomer.password).isEqualTo(customer.password)
|
||||
assertThat(deserializedCustomer.finTsServerAddress).isEqualTo(customer.finTsServerAddress)
|
||||
private fun assertBanksEqual(deserializedBank: BankDataEntity, bank: BankDataEntity) {
|
||||
assertThat(deserializedBank.bankCode).isEqualTo(bank.bankCode)
|
||||
assertThat(deserializedBank.customerId).isEqualTo(bank.customerId)
|
||||
assertThat(deserializedBank.password).isEqualTo(bank.password)
|
||||
assertThat(deserializedBank.finTsServerAddress).isEqualTo(bank.finTsServerAddress)
|
||||
|
||||
assertThat(deserializedCustomer.bankName).isEqualTo(customer.bankName)
|
||||
assertThat(deserializedCustomer.bic).isEqualTo(customer.bic)
|
||||
assertThat(deserializedCustomer.customerName).isEqualTo(customer.customerName)
|
||||
assertThat(deserializedCustomer.userId).isEqualTo(customer.userId)
|
||||
assertThat(deserializedCustomer.iconUrl).isEqualTo(customer.iconUrl)
|
||||
assertThat(deserializedBank.bankName).isEqualTo(bank.bankName)
|
||||
assertThat(deserializedBank.bic).isEqualTo(bank.bic)
|
||||
assertThat(deserializedBank.customerName).isEqualTo(bank.customerName)
|
||||
assertThat(deserializedBank.userId).isEqualTo(bank.userId)
|
||||
assertThat(deserializedBank.iconUrl).isEqualTo(bank.iconUrl)
|
||||
|
||||
assertBankAccountsEqual(deserializedCustomer.accounts, customer.accounts)
|
||||
assertAccountsEqual(deserializedBank.accounts, bank.accounts)
|
||||
}
|
||||
|
||||
private fun assertBankAccountsEqual(deserializedAccounts: List<BankAccountEntity>, accounts: List<BankAccountEntity>) {
|
||||
private fun assertAccountsEqual(deserializedAccounts: List<BankAccountEntity>, accounts: List<BankAccountEntity>) {
|
||||
assertThat(deserializedAccounts.size).isEqualTo(accounts.size)
|
||||
|
||||
deserializedAccounts.forEach { deserializedAccount ->
|
||||
|
@ -195,14 +195,14 @@ class BankingPersistenceJsonTest {
|
|||
Assert.fail("Could not find matching account for deserialized account $deserializedAccount. accounts = $accounts")
|
||||
}
|
||||
else {
|
||||
assertBankAccountsEqual(deserializedAccount, account)
|
||||
assertAccountsEqual(deserializedAccount, account)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun assertBankAccountsEqual(deserializedAccount: BankAccountEntity, account: BankAccountEntity) {
|
||||
private fun assertAccountsEqual(deserializedAccount: BankAccountEntity, account: BankAccountEntity) {
|
||||
// to check if MapStruct created reference correctly
|
||||
assertThat(deserializedAccount.customer.technicalId).isEqualTo(account.customer.technicalId)
|
||||
assertThat(deserializedAccount.bank.technicalId).isEqualTo(account.bank.technicalId)
|
||||
|
||||
assertThat(deserializedAccount.identifier).isEqualTo(account.identifier)
|
||||
assertThat(deserializedAccount.iban).isEqualTo(account.iban)
|
||||
|
@ -210,10 +210,10 @@ class BankingPersistenceJsonTest {
|
|||
assertThat(deserializedAccount.balance).isEqualTo(account.balance)
|
||||
assertThat(deserializedAccount.productName).isEqualTo(account.productName)
|
||||
|
||||
assertAccountTransactionsEqual(deserializedAccount.bookedTransactions, account.bookedTransactions)
|
||||
assertTransactionsEqual(deserializedAccount.bookedTransactions, account.bookedTransactions)
|
||||
}
|
||||
|
||||
private fun assertAccountTransactionsEqual(deserializedTransactions: List<AccountTransactionEntity>, transactions: List<AccountTransactionEntity>) {
|
||||
private fun assertTransactionsEqual(deserializedTransactions: List<AccountTransactionEntity>, transactions: List<AccountTransactionEntity>) {
|
||||
assertThat(deserializedTransactions.size).isEqualTo(transactions.size)
|
||||
|
||||
deserializedTransactions.forEach { deserializedTransaction ->
|
||||
|
@ -223,14 +223,14 @@ class BankingPersistenceJsonTest {
|
|||
Assert.fail("Could not find matching transaction for deserialized transaction $deserializedTransaction. transactions = $transactions")
|
||||
}
|
||||
else {
|
||||
assertAccountTransactionsEqual(deserializedTransaction, transaction)
|
||||
assertTransactionsEqual(deserializedTransaction, transaction)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun assertAccountTransactionsEqual(deserializedTransaction: AccountTransactionEntity, transaction: AccountTransactionEntity) {
|
||||
private fun assertTransactionsEqual(deserializedTransaction: AccountTransactionEntity, transaction: AccountTransactionEntity) {
|
||||
// to check if MapStruct created reference correctly
|
||||
assertThat(deserializedTransaction.bankAccount.technicalId).isEqualTo(transaction.bankAccount.technicalId)
|
||||
assertThat(deserializedTransaction.account.technicalId).isEqualTo(transaction.account.technicalId)
|
||||
|
||||
assertThat(deserializedTransaction.otherPartyName).isEqualTo(transaction.otherPartyName)
|
||||
assertThat(deserializedTransaction.unparsedUsage).isEqualTo(transaction.unparsedUsage)
|
||||
|
|
|
@ -3,7 +3,7 @@ package net.dankito.banking.ui.android
|
|||
import net.dankito.banking.ui.android.util.CurrentActivityTracker
|
||||
import net.dankito.banking.ui.IRouter
|
||||
import net.dankito.banking.ui.android.dialogs.*
|
||||
import net.dankito.banking.ui.model.TypedCustomer
|
||||
import net.dankito.banking.ui.model.TypedBankData
|
||||
import net.dankito.banking.ui.model.parameters.TransferMoneyData
|
||||
import net.dankito.banking.ui.model.tan.EnterTanGeneratorAtcResult
|
||||
import net.dankito.banking.ui.model.tan.EnterTanResult
|
||||
|
@ -20,10 +20,10 @@ open class RouterAndroid(protected val activityTracker: CurrentActivityTracker)
|
|||
}
|
||||
}
|
||||
|
||||
override fun getTanFromUserFromNonUiThread(customer: TypedCustomer, tanChallenge: TanChallenge, presenter: BankingPresenter, callback: (EnterTanResult) -> Unit) {
|
||||
override fun getTanFromUserFromNonUiThread(bank: TypedBankData, tanChallenge: TanChallenge, presenter: BankingPresenter, callback: (EnterTanResult) -> Unit) {
|
||||
activityTracker.currentOrNextActivity { activity ->
|
||||
activity.runOnUiThread {
|
||||
EnterTanDialog().show(customer, tanChallenge, activity, false) { result ->
|
||||
EnterTanDialog().show(bank, tanChallenge, activity, false) { result ->
|
||||
callback(result)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ open class AccountTransactionAdapter(protected val presenter: BankingPresenter)
|
|||
|
||||
viewHolder.txtvwAmount.showAmount(presenter, item.amount)
|
||||
|
||||
val iconUrl = item.bankAccount.customer.iconUrl
|
||||
val iconUrl = item.account.bank.iconUrl
|
||||
if (iconUrl != null && presenter.areAllAccountSelected) {
|
||||
viewHolder.imgvwBankIcon.visibility = View.VISIBLE
|
||||
viewHolder.imgvwBankIcon.setImageURI(Uri.parse(iconUrl))
|
||||
|
|
|
@ -12,7 +12,7 @@ import net.dankito.banking.ui.model.TypedBankAccount
|
|||
import net.dankito.utils.android.ui.adapter.ListAdapter
|
||||
|
||||
|
||||
open class BankAccountsAdapter(bankAccounts: List<TypedBankAccount>) : ListAdapter<TypedBankAccount>(bankAccounts) {
|
||||
open class BankAccountsAdapter(accounts: List<TypedBankAccount>) : ListAdapter<TypedBankAccount>(accounts) {
|
||||
|
||||
override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View? {
|
||||
|
||||
|
@ -30,9 +30,9 @@ open class BankAccountsAdapter(bankAccounts: List<TypedBankAccount>) : ListAdapt
|
|||
return view
|
||||
}
|
||||
|
||||
protected open fun setIcon(bankAccount: TypedBankAccount, imgBankIcon: ImageView) {
|
||||
protected open fun setIcon(account: TypedBankAccount, imgBankIcon: ImageView) {
|
||||
try {
|
||||
val iconUrl = bankAccount.customer.iconUrl
|
||||
val iconUrl = account.bank.iconUrl
|
||||
imgBankIcon.visibility = if (iconUrl == null) View.GONE else View.VISIBLE
|
||||
imgBankIcon.setImageURI(Uri.parse(iconUrl))
|
||||
} catch (e: Exception) {
|
||||
|
|
|
@ -3,13 +3,13 @@ package net.dankito.banking.ui.android.alerts
|
|||
import android.content.Context
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import net.dankito.banking.ui.android.R
|
||||
import net.dankito.banking.ui.model.TypedCustomer
|
||||
import net.dankito.banking.ui.model.TypedBankData
|
||||
import net.dankito.banking.ui.presenter.BankingPresenter
|
||||
|
||||
|
||||
open class AskDeleteAccountAlert {
|
||||
|
||||
open fun show(bank: TypedCustomer, presenter: BankingPresenter, context: Context, accountDeleted: (() -> Unit)? = null) {
|
||||
open fun show(bank: TypedBankData, presenter: BankingPresenter, context: Context, accountDeleted: (() -> Unit)? = null) {
|
||||
AlertDialog.Builder(context)
|
||||
.setTitle(context.getString(R.string.alert_ask_delete_account_title, bank.displayName))
|
||||
.setMessage(context.getString(R.string.alert_ask_delete_account_message))
|
||||
|
|
|
@ -21,7 +21,7 @@ import net.dankito.banking.ui.android.adapter.TanMediumAdapter
|
|||
import net.dankito.banking.ui.android.adapter.TanMethodsAdapter
|
||||
import net.dankito.banking.ui.android.di.BankingComponent
|
||||
import net.dankito.banking.ui.android.listener.ListItemSelectedListener
|
||||
import net.dankito.banking.ui.model.TypedCustomer
|
||||
import net.dankito.banking.ui.model.TypedBankData
|
||||
import net.dankito.banking.ui.model.responses.BankingClientResponse
|
||||
import net.dankito.banking.ui.model.tan.*
|
||||
import net.dankito.banking.ui.presenter.BankingPresenter
|
||||
|
@ -41,7 +41,7 @@ open class EnterTanDialog : DialogFragment() {
|
|||
}
|
||||
|
||||
|
||||
protected lateinit var customer: TypedCustomer
|
||||
protected lateinit var bank: TypedBankData
|
||||
|
||||
protected lateinit var tanChallenge: TanChallenge
|
||||
|
||||
|
@ -59,10 +59,10 @@ open class EnterTanDialog : DialogFragment() {
|
|||
}
|
||||
|
||||
|
||||
open fun show(customer: TypedCustomer, tanChallenge: TanChallenge, activity: AppCompatActivity,
|
||||
open fun show(bank: TypedBankData, tanChallenge: TanChallenge, activity: AppCompatActivity,
|
||||
fullscreen: Boolean = false, tanEnteredCallback: (EnterTanResult) -> Unit) {
|
||||
|
||||
this.customer = customer
|
||||
this.bank = bank
|
||||
this.tanChallenge = tanChallenge
|
||||
this.tanEnteredCallback = tanEnteredCallback
|
||||
|
||||
|
@ -97,13 +97,13 @@ open class EnterTanDialog : DialogFragment() {
|
|||
|
||||
protected open fun setupSelectTanMethodView(rootView: View) {
|
||||
val adapter = TanMethodsAdapter()
|
||||
val tanMethodsWithoutUnsupported = customer.supportedTanMethods.filterNot { it.type == TanMethodType.ChipTanUsb } // USB tan generators are not supported on Android
|
||||
val tanMethodsWithoutUnsupported = bank.supportedTanMethods.filterNot { it.type == TanMethodType.ChipTanUsb } // USB tan generators are not supported on Android
|
||||
adapter.setItems(tanMethodsWithoutUnsupported)
|
||||
|
||||
rootView.findViewById<Spinner>(R.id.spnTanMethods)?.let { spinner ->
|
||||
spinner.adapter = adapter
|
||||
|
||||
val selectedTanMethod = customer.selectedTanMethod
|
||||
val selectedTanMethod = bank.selectedTanMethod
|
||||
?: tanMethodsWithoutUnsupported.firstOrNull { it.type != TanMethodType.ChipTanManuell && it.type != TanMethodType.ChipTanUsb }
|
||||
?: tanMethodsWithoutUnsupported.firstOrNull()
|
||||
selectedTanMethod?.let { spinner.setSelection(adapter.getItems().indexOf(selectedTanMethod)) }
|
||||
|
@ -120,12 +120,12 @@ open class EnterTanDialog : DialogFragment() {
|
|||
}
|
||||
|
||||
protected open fun setupSelectTanMediumView(rootView: View) {
|
||||
val tanMediaForTanMethod = presenter.getTanMediaForTanMethod(customer, tanChallenge.tanMethod)
|
||||
val tanMediaForTanMethod = presenter.getTanMediaForTanMethod(bank, tanChallenge.tanMethod)
|
||||
|
||||
if (tanMediaForTanMethod.size > 1) {
|
||||
rootView.lytTanMedium.visibility = View.VISIBLE
|
||||
|
||||
tanMediumAdapter.setItems(customer.tanMediaSorted)
|
||||
tanMediumAdapter.setItems(bank.tanMediaSorted)
|
||||
|
||||
rootView.spnTanMedium.adapter = tanMediumAdapter
|
||||
rootView.spnTanMedium.onItemSelectedListener = ListItemSelectedListener(tanMediumAdapter) { selectedTanMedium ->
|
||||
|
|
|
@ -51,7 +51,7 @@ open class SendMessageLogDialog : DialogFragment() {
|
|||
}
|
||||
|
||||
protected open fun setupUI(rootView: View) {
|
||||
val messageLog = presenter.getMessageLogForAccounts(presenter.customers).joinToString("\r\n\r\n")
|
||||
val messageLog = presenter.getMessageLogForAccounts(presenter.allBanks).joinToString("\r\n\r\n")
|
||||
|
||||
if (messageLog.isBlank()) {
|
||||
rootView.txtvwInfoNoMessageLogEntriesYet.visibility = View.VISIBLE
|
||||
|
|
|
@ -53,7 +53,7 @@ open class TransferMoneyDialog : DialogFragment() {
|
|||
}
|
||||
|
||||
|
||||
protected lateinit var bankAccount: TypedBankAccount
|
||||
protected lateinit var account: TypedBankAccount
|
||||
|
||||
protected var preselectedValues: TransferMoneyData? = null
|
||||
|
||||
|
@ -108,16 +108,16 @@ open class TransferMoneyDialog : DialogFragment() {
|
|||
}
|
||||
|
||||
protected open fun setupUI(rootView: View) {
|
||||
val allBankAccountsSupportingTransferringMoney = presenter.bankAccountsSupportingTransferringMoney
|
||||
bankAccount = preselectedValues?.account ?: allBankAccountsSupportingTransferringMoney.first()
|
||||
val accountsSupportingTransferringMoney = presenter.accountsSupportingTransferringMoney
|
||||
account = preselectedValues?.account ?: accountsSupportingTransferringMoney.first()
|
||||
|
||||
if (allBankAccountsSupportingTransferringMoney.size > 1) {
|
||||
if (accountsSupportingTransferringMoney.size > 1) {
|
||||
rootView.lytSelectBankAccount.visibility = View.VISIBLE
|
||||
|
||||
val adapter = BankAccountsAdapter(allBankAccountsSupportingTransferringMoney)
|
||||
val adapter = BankAccountsAdapter(accountsSupportingTransferringMoney)
|
||||
rootView.spnBankAccounts.adapter = adapter
|
||||
rootView.spnBankAccounts.onItemSelectedListener = ListItemSelectedListener(adapter) { selectedBankAccount ->
|
||||
this.bankAccount = selectedBankAccount
|
||||
this.account = selectedBankAccount
|
||||
setInstantPaymentControlsVisibility(rootView)
|
||||
}
|
||||
preselectedValues?.account?.let { rootView.spnBankAccounts.setSelection(adapter.getItems().indexOf(it)) }
|
||||
|
@ -184,7 +184,7 @@ open class TransferMoneyDialog : DialogFragment() {
|
|||
|
||||
protected open fun setInstantPaymentControlsVisibility(rootView: View) {
|
||||
rootView.lytInstantPayment.visibility =
|
||||
if (bankAccount.supportsInstantPaymentMoneyTransfer) {
|
||||
if (account.supportsInstantPaymentMoneyTransfer) {
|
||||
View.VISIBLE
|
||||
}
|
||||
else {
|
||||
|
@ -295,7 +295,7 @@ open class TransferMoneyDialog : DialogFragment() {
|
|||
protected open fun transferMoney() {
|
||||
getEnteredAmount()?.let { amount -> // should only come at this stage when a valid amount has been entered
|
||||
val data = TransferMoneyData(
|
||||
bankAccount,
|
||||
account,
|
||||
inputValidator.convertToAllowedSepaCharacters(edtxtRemitteeName.text.toString()),
|
||||
edtxtRemitteeIban.text.toString().replace(" ", ""),
|
||||
remitteeBic?.replace(" ", "") ?: "", // should always be != null at this point
|
||||
|
|
|
@ -13,7 +13,7 @@ import net.dankito.banking.ui.android.alerts.AskDeleteAccountAlert
|
|||
import net.dankito.banking.ui.android.alerts.AskDismissChangesAlert
|
||||
import net.dankito.banking.ui.android.di.BankingComponent
|
||||
import net.dankito.banking.ui.android.views.FormEditText
|
||||
import net.dankito.banking.ui.model.TypedCustomer
|
||||
import net.dankito.banking.ui.model.TypedBankData
|
||||
import net.dankito.banking.ui.presenter.BankingPresenter
|
||||
import javax.inject.Inject
|
||||
|
||||
|
@ -25,7 +25,7 @@ open class BankSettingsDialog : DialogFragment() {
|
|||
}
|
||||
|
||||
|
||||
protected lateinit var bank: TypedCustomer
|
||||
protected lateinit var bank: TypedBankData
|
||||
|
||||
|
||||
@Inject
|
||||
|
@ -38,7 +38,7 @@ open class BankSettingsDialog : DialogFragment() {
|
|||
|
||||
|
||||
|
||||
fun show(bank: TypedCustomer, activity: AppCompatActivity, fullscreen: Boolean = false) {
|
||||
fun show(bank: TypedBankData, activity: AppCompatActivity, fullscreen: Boolean = false) {
|
||||
this.bank = bank
|
||||
|
||||
val style = if (fullscreen) R.style.FullscreenDialogWithStatusBar else R.style.FloatingDialog
|
||||
|
@ -108,7 +108,7 @@ open class BankSettingsDialog : DialogFragment() {
|
|||
bank.customerId = edtxtCustomerId.text
|
||||
bank.password = edtxtPassword.text
|
||||
|
||||
presenter.accountUpdated(bank)
|
||||
presenter.bankUpdated(bank)
|
||||
}
|
||||
|
||||
protected open fun askToDismissChanges() {
|
||||
|
|
|
@ -170,8 +170,8 @@ class HomeFragment : Fragment() {
|
|||
|
||||
|
||||
private fun initLogicAfterUiInitialized() {
|
||||
presenter.addAccountsChangedListener { updateMenuItemsStateAndTransactionsToDisplay() } // on account addition or deletion may menu items' state changes
|
||||
presenter.addSelectedBankAccountsChangedListener { updateMenuItemsStateAndTransactionsToDisplay() }
|
||||
presenter.addBanksChangedListener { updateMenuItemsStateAndTransactionsToDisplay() } // on account addition or deletion may menu items' state changes
|
||||
presenter.addSelectedAccountsChangedListener { updateMenuItemsStateAndTransactionsToDisplay() }
|
||||
|
||||
presenter.addRetrievedAccountTransactionsResponseListener { response ->
|
||||
handleGetTransactionsResponseOffUiThread(response)
|
||||
|
@ -183,15 +183,15 @@ class HomeFragment : Fragment() {
|
|||
|
||||
private fun updateMenuItemsStateAndTransactionsToDisplay() {
|
||||
context?.asActivity()?.runOnUiThread {
|
||||
mnitmSearchTransactions.isVisible = presenter.doSelectedBankAccountsSupportRetrievingAccountTransactions
|
||||
mnitmUpdateTransactions.isVisible = presenter.doSelectedBankAccountsSupportRetrievingAccountTransactions
|
||||
mnitmSearchTransactions.isVisible = presenter.doSelectedAccountsSupportRetrievingTransactions
|
||||
mnitmUpdateTransactions.isVisible = presenter.doSelectedAccountsSupportRetrievingTransactions
|
||||
|
||||
updateTransactionsToDisplayOnUiThread()
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateAccountsTransactions() {
|
||||
presenter.updateSelectedBankAccountTransactionsAsync { }
|
||||
presenter.updateSelectedAccountsTransactionsAsync { }
|
||||
}
|
||||
|
||||
private fun handleGetTransactionsResponseOffUiThread(response: GetTransactionsResponse) {
|
||||
|
@ -249,14 +249,14 @@ class HomeFragment : Fragment() {
|
|||
private fun updateTransactionsToDisplayOnUiThread() {
|
||||
transactionAdapter.items = presenter.searchSelectedAccountTransactions(appliedTransactionsFilter)
|
||||
|
||||
mnitmBalance.title = presenter.formatAmount(presenter.balanceOfSelectedBankAccounts)
|
||||
mnitmBalance.isVisible = presenter.doSelectedBankAccountsSupportRetrievingBalance
|
||||
mnitmBalance.title = presenter.formatAmount(presenter.balanceOfSelectedAccounts)
|
||||
mnitmBalance.isVisible = presenter.doSelectedAccountsSupportRetrievingBalance
|
||||
|
||||
lytTransactionsSummary.visibility = if (presenter.doSelectedBankAccountsSupportRetrievingBalance) View.VISIBLE else View.GONE
|
||||
lytTransactionsSummary.visibility = if (presenter.doSelectedAccountsSupportRetrievingBalance) View.VISIBLE else View.GONE
|
||||
|
||||
txtCountTransactions.text = context?.getString(R.string.fragment_home_count_transactions, transactionAdapter.items.size)
|
||||
|
||||
val sumOfDisplayedTransactions = if (appliedTransactionsFilter.isBlank()) presenter.balanceOfSelectedBankAccounts
|
||||
val sumOfDisplayedTransactions = if (appliedTransactionsFilter.isBlank()) presenter.balanceOfSelectedAccounts
|
||||
else transactionAdapter.items.map { it.amount }.sum()
|
||||
txtTransactionsBalance.showAmount(presenter, sumOfDisplayedTransactions)
|
||||
|
||||
|
@ -266,9 +266,9 @@ class HomeFragment : Fragment() {
|
|||
}
|
||||
|
||||
private fun setRecyclerViewAndNoTransactionsFetchedView() {
|
||||
val transactionsRetrievalState = presenter.selectedBankAccountsTransactionRetrievalState
|
||||
val transactionsRetrievalState = presenter.selectedAccountsTransactionRetrievalState
|
||||
val haveTransactionsBeenRetrieved = transactionsRetrievalState == TransactionsRetrievalState.RetrievedTransactions
|
||||
val noAccountsAddedYet = presenter.customers.isEmpty()
|
||||
val noAccountsAddedYet = presenter.allBanks.isEmpty()
|
||||
|
||||
rcyvwAccountTransactions.visibility = if (haveTransactionsBeenRetrieved) View.VISIBLE else View.GONE
|
||||
lytNoTransactionsFetched.visibility = if (haveTransactionsBeenRetrieved || noAccountsAddedYet) View.GONE else View.VISIBLE
|
||||
|
@ -280,7 +280,7 @@ class HomeFragment : Fragment() {
|
|||
TransactionsRetrievalState.AccountTypeNotSupported -> R.string.fragment_home_transactions_retrieval_state_account_type_not_supported
|
||||
TransactionsRetrievalState.AccountDoesNotSupportFetchingTransactions -> R.string.fragment_home_transactions_retrieval_state_account_does_not_support_retrieving_transactions
|
||||
TransactionsRetrievalState.NoTransactionsInRetrievedPeriod -> {
|
||||
val account = presenter.selectedBankAccounts.first()
|
||||
val account = presenter.selectedAccounts.first()
|
||||
account.retrievedTransactionsFromOn?.let { messageArgs.add(RetrievedTransactionsPeriodDateFormat.format(it)) }
|
||||
account.retrievedTransactionsUpTo?.let { messageArgs.add(RetrievedTransactionsPeriodDateFormat.format(it)) }
|
||||
R.string.fragment_home_transactions_retrieval_state_no_transactions_in_retrieved_period
|
||||
|
@ -292,12 +292,12 @@ class HomeFragment : Fragment() {
|
|||
}
|
||||
|
||||
private fun setFetchAllTransactionsView() {
|
||||
accountsForWhichNotAllTransactionsHaveBeenFetched = presenter.selectedBankAccountsForWhichNotAllTransactionsHaveBeenFetched
|
||||
accountsForWhichNotAllTransactionsHaveBeenFetched = presenter.selectedAccountsForWhichNotAllTransactionsHaveBeenFetched
|
||||
|
||||
var floatingActionMenuBottomMarginResourceId = R.dimen.fab_margin_bottom_without_toolbar
|
||||
|
||||
if (doNotShowFetchAllTransactionsOverlay || accountsForWhichNotAllTransactionsHaveBeenFetched.isEmpty()
|
||||
|| presenter.selectedBankAccountsTransactionRetrievalState != TransactionsRetrievalState.RetrievedTransactions) {
|
||||
|| presenter.selectedAccountsTransactionRetrievalState != TransactionsRetrievalState.RetrievedTransactions) {
|
||||
lytFetchAllTransactionsOverlay.visibility = View.GONE
|
||||
}
|
||||
else {
|
||||
|
@ -312,9 +312,9 @@ class HomeFragment : Fragment() {
|
|||
|
||||
|
||||
private fun fetchTransactions() {
|
||||
presenter.selectedBankAccounts.forEach { account ->
|
||||
presenter.selectedAccounts.forEach { account ->
|
||||
if (account.haveAllTransactionsBeenFetched) {
|
||||
presenter.updateBankAccountTransactionsAsync(account)
|
||||
presenter.updateAccountTransactionsAsync(account)
|
||||
}
|
||||
else {
|
||||
presenter.fetchAllAccountTransactionsAsync(account)
|
||||
|
|
|
@ -20,7 +20,7 @@ import com.mikepenz.materialdrawer.widget.MaterialDrawerSliderView
|
|||
import net.dankito.banking.ui.android.R
|
||||
import net.dankito.banking.ui.android.dialogs.settings.BankSettingsDialog
|
||||
import net.dankito.banking.ui.android.extensions.withIcon
|
||||
import net.dankito.banking.ui.model.TypedCustomer
|
||||
import net.dankito.banking.ui.model.TypedBankData
|
||||
import net.dankito.banking.ui.presenter.BankingPresenter
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
|
@ -32,9 +32,9 @@ open class DrawerView(
|
|||
) {
|
||||
|
||||
companion object {
|
||||
private const val AccountLevel = 2
|
||||
private const val BankLevel = 2
|
||||
|
||||
private const val BankAccountLevel = 7
|
||||
private const val AccountLevel = 7
|
||||
|
||||
private const val AccountsSectionHeaderId = 1000L
|
||||
private const val AllAccountsId = 1001L
|
||||
|
@ -60,11 +60,11 @@ open class DrawerView(
|
|||
|
||||
setDefaultDrawerItems()
|
||||
|
||||
presenter.addAccountsChangedListener {
|
||||
presenter.addBanksChangedListener {
|
||||
activity.runOnUiThread { updateDrawerItems() }
|
||||
}
|
||||
|
||||
presenter.addSelectedBankAccountsChangedListener {
|
||||
presenter.addSelectedAccountsChangedListener {
|
||||
activity.runOnUiThread { updateDrawerItems() }
|
||||
}
|
||||
|
||||
|
@ -83,16 +83,16 @@ open class DrawerView(
|
|||
PrimaryDrawerItem()
|
||||
.withName(R.string.drawer_menu_all_bank_accounts_title)
|
||||
.withIdentifier(AllAccountsId)
|
||||
.withLevel(AccountLevel)
|
||||
.withLevel(BankLevel)
|
||||
.withSelected(true)
|
||||
.withIcon(activity, GoogleMaterial.Icon.gmd_account_balance, R.color.primaryTextColor_Dark)
|
||||
.withOnDrawerItemClickListener { _, _, _ -> itemClicked { presenter.selectedAllBankAccounts() } }
|
||||
.withOnDrawerItemClickListener { _, _, _ -> itemClicked { presenter.selectedAllAccounts() } }
|
||||
,
|
||||
|
||||
PrimaryDrawerItem()
|
||||
.withName(R.string.add_account)
|
||||
.withIdentifier(AddAccountId)
|
||||
.withLevel(AccountLevel)
|
||||
.withLevel(BankLevel)
|
||||
.withIcon(activity, GoogleMaterial.Icon.gmd_add, R.color.primaryTextColor_Dark)
|
||||
.withSelectable(false)
|
||||
.withOnDrawerItemClickListener { _, _, _ -> itemClicked { presenter.showAddAccountDialog() } }
|
||||
|
@ -129,29 +129,29 @@ open class DrawerView(
|
|||
}
|
||||
|
||||
private fun createAccountsDrawerItems(): List<IDrawerItem<*>> {
|
||||
return presenter.customers.map { account ->
|
||||
return presenter.allBanks.map { account ->
|
||||
val accountItem = createAccountDrawerItem(account)
|
||||
|
||||
val bankAccountsItems = createBankAccountsDrawerItems(account).toMutableList()
|
||||
bankAccountsItems.add(0, accountItem)
|
||||
val accountsItems = createBankAccountsDrawerItems(account).toMutableList()
|
||||
accountsItems.add(0, accountItem)
|
||||
|
||||
return@map bankAccountsItems
|
||||
return@map accountsItems
|
||||
}.flatten()
|
||||
}
|
||||
|
||||
private fun createAccountDrawerItem(customer: TypedCustomer): IDrawerItem<*> {
|
||||
private fun createAccountDrawerItem(bank: TypedBankData): IDrawerItem<*> {
|
||||
|
||||
val accountItem = AccountDrawerItem()
|
||||
.withName(customer.displayName)
|
||||
.withLevel(AccountLevel)
|
||||
.withName(bank.displayName)
|
||||
.withLevel(BankLevel)
|
||||
.withSecondaryIcon(R.drawable.ic_baseline_settings_24)
|
||||
.withSecondaryIconColor(activity, R.color.primaryTextColor_Dark)
|
||||
.withOnSecondaryIconClickedListener { closeDrawerAndEditAccount(customer) }
|
||||
.withIcon(customer.iconUrl ?: "")
|
||||
.withSelected(presenter.isSingleSelectedAccount(customer))
|
||||
.withOnDrawerItemClickListener { _, _, _ -> itemClicked { presenter.selectedAccount(customer) } }
|
||||
.withOnSecondaryIconClickedListener { closeDrawerAndEditAccount(bank) }
|
||||
.withIcon(bank.iconUrl ?: "")
|
||||
.withSelected(presenter.isSingleSelectedBank(bank))
|
||||
.withOnDrawerItemClickListener { _, _, _ -> itemClicked { presenter.selectedBank(bank) } }
|
||||
|
||||
if (customer.iconUrl == null) {
|
||||
if (bank.iconUrl == null) {
|
||||
accountItem.withIcon(activity, FontAwesome.Icon.faw_piggy_bank, R.color.primaryTextColor_Dark)
|
||||
}
|
||||
|
||||
|
@ -159,13 +159,13 @@ open class DrawerView(
|
|||
return accountItem
|
||||
}
|
||||
|
||||
private fun createBankAccountsDrawerItems(customer: TypedCustomer): List<IDrawerItem<*>> {
|
||||
return customer.accounts.map { bankAccount ->
|
||||
private fun createBankAccountsDrawerItems(bank: TypedBankData): List<IDrawerItem<*>> {
|
||||
return bank.accounts.map { account ->
|
||||
SecondaryDrawerItem()
|
||||
.withName(bankAccount.displayName)
|
||||
.withLevel(BankAccountLevel)
|
||||
.withSelected(presenter.isSingleSelectedBankAccount(bankAccount))
|
||||
.withOnDrawerItemClickListener { _, _, _ -> itemClicked { presenter.selectedBankAccount(bankAccount) } }
|
||||
.withName(account.displayName)
|
||||
.withLevel(AccountLevel)
|
||||
.withSelected(presenter.isSingleSelectedAccount(account))
|
||||
.withOnDrawerItemClickListener { _, _, _ -> itemClicked { presenter.selectedAccount(account) } }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -175,14 +175,14 @@ open class DrawerView(
|
|||
return false
|
||||
}
|
||||
|
||||
private fun closeDrawerAndEditAccount(customer: TypedCustomer) {
|
||||
private fun closeDrawerAndEditAccount(bank: TypedBankData) {
|
||||
closeDrawer()
|
||||
|
||||
editAccount(customer)
|
||||
editAccount(bank)
|
||||
}
|
||||
|
||||
private fun editAccount(customer: TypedCustomer) {
|
||||
BankSettingsDialog().show(customer, activity, true)
|
||||
private fun editAccount(bank: TypedBankData) {
|
||||
BankSettingsDialog().show(bank, activity, true)
|
||||
}
|
||||
|
||||
private fun showAppVersion(navigationHeaderView: View?) {
|
||||
|
|
|
@ -35,7 +35,7 @@ open class MainActivityFloatingActionMenuButton(
|
|||
init {
|
||||
setupButtons(floatingActionMenu)
|
||||
|
||||
presenter.addAccountsChangedListener {
|
||||
presenter.addBanksChangedListener {
|
||||
fabTransferMoney.context.asActivity()?.runOnUiThread {
|
||||
checkIfThereAreAccountsThatCanTransferMoney()
|
||||
}
|
||||
|
@ -65,9 +65,9 @@ open class MainActivityFloatingActionMenuButton(
|
|||
|
||||
|
||||
protected open fun checkIfThereAreAccountsThatCanTransferMoney() {
|
||||
fabTransferMoney.isEnabled = presenter.hasBankAccountsSupportTransferringMoney
|
||||
fabTransferMoney.isEnabled = presenter.hasAccountsSupportTransferringMoney
|
||||
|
||||
fabTransferMoneyFromPdf.isEnabled = presenter.hasBankAccountsSupportTransferringMoney
|
||||
fabTransferMoneyFromPdf.isEnabled = presenter.hasAccountsSupportTransferringMoney
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ open class MainMenuBar(protected val presenter: BankingPresenter) : View() {
|
|||
|
||||
|
||||
init {
|
||||
presenter.addAccountsChangedListener {
|
||||
presenter.addBanksChangedListener {
|
||||
runLater {
|
||||
checkIfThereAreAccountsThatCanTransferMoney()
|
||||
}
|
||||
|
@ -68,7 +68,7 @@ open class MainMenuBar(protected val presenter: BankingPresenter) : View() {
|
|||
|
||||
|
||||
protected open fun checkIfThereAreAccountsThatCanTransferMoney() {
|
||||
areAccountsThatCanTransferMoneyAdded.value = presenter.hasBankAccountsSupportTransferringMoney
|
||||
areAccountsThatCanTransferMoneyAdded.value = presenter.hasAccountsSupportTransferringMoney
|
||||
}
|
||||
|
||||
protected open fun transferMoneyWithDataFromPdf() {
|
||||
|
|
|
@ -4,7 +4,7 @@ import net.dankito.banking.ui.IRouter
|
|||
import net.dankito.banking.ui.javafx.dialogs.AddAccountDialog
|
||||
import net.dankito.banking.ui.javafx.dialogs.cashtransfer.TransferMoneyDialog
|
||||
import net.dankito.banking.ui.javafx.dialogs.tan.EnterTanDialog
|
||||
import net.dankito.banking.ui.model.TypedCustomer
|
||||
import net.dankito.banking.ui.model.TypedBankData
|
||||
import net.dankito.banking.ui.model.parameters.TransferMoneyData
|
||||
import net.dankito.banking.ui.model.tan.EnterTanGeneratorAtcResult
|
||||
import net.dankito.banking.ui.model.tan.EnterTanResult
|
||||
|
@ -22,9 +22,9 @@ open class RouterJavaFx : IRouter {
|
|||
AddAccountDialog(presenter).show(messages["add.account.dialog.title"])
|
||||
}
|
||||
|
||||
override fun getTanFromUserFromNonUiThread(customer: TypedCustomer, tanChallenge: TanChallenge, presenter: BankingPresenter, callback: (EnterTanResult) -> Unit) {
|
||||
override fun getTanFromUserFromNonUiThread(bank: TypedBankData, tanChallenge: TanChallenge, presenter: BankingPresenter, callback: (EnterTanResult) -> Unit) {
|
||||
FX.runAndWait {
|
||||
EnterTanDialog(customer, tanChallenge, presenter) { result ->
|
||||
EnterTanDialog(bank, tanChallenge, presenter) { result ->
|
||||
callback(result)
|
||||
}.show(messages["enter.tan.dialog.title"])
|
||||
}
|
||||
|
|
|
@ -109,8 +109,8 @@ open class AccountTransactionsControlView(
|
|||
|
||||
|
||||
protected open fun initLogic() {
|
||||
presenter.addAccountsChangedListener { runLater { accountsChanged() } }
|
||||
presenter.addSelectedBankAccountsChangedListener { selectedBankAccountsChanged() }
|
||||
presenter.addBanksChangedListener { runLater { accountsChanged() } }
|
||||
presenter.addSelectedAccountsChangedListener { selectedBankAccountsChanged() }
|
||||
|
||||
checkIfSupportsTransferringMoneyOnUiThread()
|
||||
checkIfSupportsRetrievingAccountTransactionsOnUiThread()
|
||||
|
@ -130,13 +130,13 @@ open class AccountTransactionsControlView(
|
|||
|
||||
|
||||
protected open fun checkIfSupportsTransferringMoneyOnUiThread() {
|
||||
supportsTransferringMoney.value = presenter.hasBankAccountsSupportTransferringMoney
|
||||
supportsTransferringMoney.value = presenter.hasAccountsSupportTransferringMoney
|
||||
}
|
||||
|
||||
protected open fun checkIfSupportsRetrievingAccountTransactionsOnUiThread() {
|
||||
supportsRetrievingBalance.value = presenter.doSelectedBankAccountsSupportRetrievingBalance
|
||||
supportsRetrievingBalance.value = presenter.doSelectedAccountsSupportRetrievingBalance
|
||||
|
||||
supportsRetrievingAccountTransactions.value = presenter.doSelectedBankAccountsSupportRetrievingAccountTransactions
|
||||
supportsRetrievingAccountTransactions.value = presenter.doSelectedAccountsSupportRetrievingTransactions
|
||||
}
|
||||
|
||||
protected open fun updateAccountTransactions(processingIndicatorButton: ProcessingIndicatorButton) {
|
||||
|
|
|
@ -31,7 +31,7 @@ open class AccountTransactionsView(private val presenter: BankingPresenter) : Vi
|
|||
|
||||
|
||||
init {
|
||||
presenter.addSelectedBankAccountsChangedListener { handleSelectedBankAccountsChanged(it) }
|
||||
presenter.addSelectedAccountsChangedListener { handleSelectedBankAccountsChanged(it) }
|
||||
|
||||
presenter.addRetrievedAccountTransactionsResponseListener { response ->
|
||||
handleGetTransactionsResponseOffUiThread(response)
|
||||
|
@ -39,7 +39,7 @@ open class AccountTransactionsView(private val presenter: BankingPresenter) : Vi
|
|||
|
||||
transactionsFilter.addListener { _, _, newValue -> updateTransactionsToDisplay(newValue) }
|
||||
|
||||
handleSelectedBankAccountsChanged(presenter.selectedBankAccounts) // so that isAccountSelected and transactionsToDisplay get set
|
||||
handleSelectedBankAccountsChanged(presenter.selectedAccounts) // so that isAccountSelected and transactionsToDisplay get set
|
||||
}
|
||||
|
||||
|
||||
|
@ -135,7 +135,7 @@ open class AccountTransactionsView(private val presenter: BankingPresenter) : Vi
|
|||
transactionsToDisplay.setAll(presenter.searchSelectedAccountTransactions(filter))
|
||||
|
||||
// TODO: if transactions are filtered calculate and show balance of displayed transactions?
|
||||
balance.value = presenter.formatAmount(presenter.balanceOfSelectedBankAccounts)
|
||||
balance.value = presenter.formatAmount(presenter.balanceOfSelectedAccounts)
|
||||
}
|
||||
|
||||
protected open fun handleGetTransactionsResponseOffUiThread(response: GetTransactionsResponse) {
|
||||
|
|
|
@ -10,14 +10,14 @@ import javafx.scene.input.KeyCode
|
|||
import net.dankito.banking.ui.javafx.dialogs.JavaFxDialogService
|
||||
import net.dankito.banking.ui.javafx.model.AccountsAccountTreeItem
|
||||
import net.dankito.banking.ui.javafx.model.AccountsRootTreeItem
|
||||
import net.dankito.banking.ui.model.TypedCustomer
|
||||
import net.dankito.banking.ui.model.TypedBankData
|
||||
import net.dankito.banking.ui.presenter.BankingPresenter
|
||||
import tornadofx.*
|
||||
import tornadofx.FX.Companion.messages
|
||||
|
||||
|
||||
open class AccountsTreeView(customers: ObservableList<TypedCustomer>, protected val presenter: BankingPresenter)
|
||||
: TreeView<String>(AccountsRootTreeItem(customers)) {
|
||||
open class AccountsTreeView(banks: ObservableList<TypedBankData>, protected val presenter: BankingPresenter)
|
||||
: TreeView<String>(AccountsRootTreeItem(banks)) {
|
||||
|
||||
protected var currentMenu: ContextMenu? = null
|
||||
|
||||
|
@ -64,7 +64,7 @@ open class AccountsTreeView(customers: ObservableList<TypedCustomer>, protected
|
|||
}
|
||||
|
||||
protected open fun askIfAccountShouldBeDeleted(treeItem: AccountsAccountTreeItem) {
|
||||
val account = treeItem.customer
|
||||
val account = treeItem.bank
|
||||
|
||||
val selectedButton = JavaFxDialogService().showDialog(
|
||||
Alert.AlertType.WARNING,
|
||||
|
|
|
@ -15,11 +15,11 @@ import tornadofx.*
|
|||
|
||||
open class AccountsView(protected val presenter: BankingPresenter) : View() {
|
||||
|
||||
protected val accounts = FXCollections.observableArrayList(presenter.customers)
|
||||
protected val accounts = FXCollections.observableArrayList(presenter.allBanks)
|
||||
|
||||
|
||||
init {
|
||||
presenter.addAccountsChangedListener {
|
||||
presenter.addBanksChangedListener {
|
||||
runLater {
|
||||
accounts.setAll(it)
|
||||
}
|
||||
|
@ -69,9 +69,9 @@ open class AccountsView(protected val presenter: BankingPresenter) : View() {
|
|||
protected open fun selectedBankAccountChanged(accountTreeItem: TreeItem<String>?) {
|
||||
accountTreeItem?.let {
|
||||
when (accountTreeItem) {
|
||||
is AccountsBankAccountTreeItem -> presenter.selectedBankAccount(accountTreeItem.bankAccount)
|
||||
is AccountsAccountTreeItem -> presenter.selectedAccount(accountTreeItem.customer)
|
||||
else -> presenter.selectedAllBankAccounts()
|
||||
is AccountsBankAccountTreeItem -> presenter.selectedAccount(accountTreeItem.account)
|
||||
is AccountsAccountTreeItem -> presenter.selectedBank(accountTreeItem.bank)
|
||||
else -> presenter.selectedAllAccounts()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -256,7 +256,7 @@ open class AddAccountDialog(protected val presenter: BankingPresenter) : Window(
|
|||
handleSuccessfullyAddedAccountResultOnUiThread(response)
|
||||
}
|
||||
else {
|
||||
val account = response.customer
|
||||
val account = response.bank
|
||||
|
||||
checkEnteredCredentialsResult.value = String.format(messages["add.account.dialog.error.could.not.add.account"],
|
||||
account.bankCode, account.customerId, response.errorToShowToUser)
|
||||
|
@ -273,7 +273,7 @@ open class AddAccountDialog(protected val presenter: BankingPresenter) : Window(
|
|||
val userSelection = dialogService.showDialog(Alert.AlertType.CONFIRMATION, message, null, currentStage, ButtonType.YES, ButtonType.NO)
|
||||
|
||||
when (userSelection) {
|
||||
ButtonType.YES -> presenter.fetchAllAccountTransactionsAsync(response.customer) { }
|
||||
ButtonType.YES -> presenter.fetchAllAccountTransactionsAsync(response.bank) { }
|
||||
else -> { } // nothing to do then, simply close dialog
|
||||
}
|
||||
|
||||
|
|
|
@ -47,7 +47,7 @@ open class TransferMoneyDialog @JvmOverloads constructor(
|
|||
}
|
||||
|
||||
|
||||
protected val bankAccountsSupportingTransferringMoney = FXCollections.observableArrayList(presenter.bankAccounts.filter { it.supportsTransferringMoney })
|
||||
protected val bankAccountsSupportingTransferringMoney = FXCollections.observableArrayList(presenter.allAccounts.filter { it.supportsTransferringMoney })
|
||||
|
||||
protected val selectedBankAccount = SimpleObjectProperty<TypedBankAccount>(preselectedValues?.account ?: bankAccountsSupportingTransferringMoney.firstOrNull())
|
||||
|
||||
|
@ -114,7 +114,7 @@ open class TransferMoneyDialog @JvmOverloads constructor(
|
|||
cellFormat {
|
||||
text = it.displayName
|
||||
|
||||
it.customer.iconUrl?.let { iconUrl ->
|
||||
it.bank.iconUrl?.let { iconUrl ->
|
||||
graphic = ImageView(iconUrl)?.apply {
|
||||
this.fitHeight = BankIconSize
|
||||
this.fitWidth = BankIconSize
|
||||
|
@ -346,10 +346,10 @@ open class TransferMoneyDialog @JvmOverloads constructor(
|
|||
|
||||
protected open fun transferMoney() {
|
||||
remitteeBank.value?.let {
|
||||
val bankAccount = selectedBankAccount.value
|
||||
val account = selectedBankAccount.value
|
||||
|
||||
val data = TransferMoneyData(
|
||||
bankAccount,
|
||||
account,
|
||||
inputValidator.convertToAllowedSepaCharacters(remitteeName.value),
|
||||
remitteeIban.value.replace(" ", ""),
|
||||
remitteeBic.value.replace(" ", ""),
|
||||
|
@ -360,14 +360,14 @@ open class TransferMoneyDialog @JvmOverloads constructor(
|
|||
|
||||
presenter.transferMoneyAsync(data) {
|
||||
runLater {
|
||||
handleTransferMoneyResultOnUiThread(bankAccount, data, it)
|
||||
handleTransferMoneyResultOnUiThread(account, data, it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected open fun handleTransferMoneyResultOnUiThread(bankAccount: TypedBankAccount, transferData: TransferMoneyData, response: BankingClientResponse) {
|
||||
val currency = bankAccount.currency
|
||||
protected open fun handleTransferMoneyResultOnUiThread(account: TypedBankAccount, transferData: TransferMoneyData, response: BankingClientResponse) {
|
||||
val currency = account.currency
|
||||
|
||||
if (response.successful) {
|
||||
dialogService.showInfoMessage(String.format(messages["transfer.money.dialog.message.transfer.cash.success"],
|
||||
|
|
|
@ -10,7 +10,7 @@ import javafx.scene.text.FontWeight
|
|||
import net.dankito.banking.ui.javafx.dialogs.tan.controls.ChipTanFlickerCodeView
|
||||
import net.dankito.banking.ui.javafx.dialogs.JavaFxDialogService
|
||||
import net.dankito.banking.ui.javafx.dialogs.tan.controls.TanImageView
|
||||
import net.dankito.banking.ui.model.TypedCustomer
|
||||
import net.dankito.banking.ui.model.TypedBankData
|
||||
import net.dankito.banking.ui.model.responses.BankingClientResponse
|
||||
import net.dankito.banking.ui.model.tan.*
|
||||
import net.dankito.banking.ui.presenter.BankingPresenter
|
||||
|
@ -20,7 +20,7 @@ import tornadofx.*
|
|||
|
||||
|
||||
open class EnterTanDialog(
|
||||
protected val customer: TypedCustomer,
|
||||
protected val bank: TypedBankData,
|
||||
protected val challenge: TanChallenge,
|
||||
protected val presenter: BankingPresenter,
|
||||
protected val tanEnteredCallback: (EnterTanResult) -> Unit
|
||||
|
@ -41,11 +41,11 @@ open class EnterTanDialog(
|
|||
protected var tanImageView: TanImageView? = null
|
||||
|
||||
|
||||
protected val tanMethodsWithoutUnsupported = customer.supportedTanMethods.filterNot { it.type == TanMethodType.ChipTanUsb } // USB tan generators are not supported
|
||||
protected val tanMethodsWithoutUnsupported = bank.supportedTanMethods.filterNot { it.type == TanMethodType.ChipTanUsb } // USB tan generators are not supported
|
||||
|
||||
protected val selectedTanMethod = SimpleObjectProperty<TanMethod>(customer.selectedTanMethod ?: tanMethodsWithoutUnsupported.firstOrNull { it.displayName.contains("manuell", true) == false } ?: tanMethodsWithoutUnsupported.firstOrNull())
|
||||
protected val selectedTanMethod = SimpleObjectProperty<TanMethod>(bank.selectedTanMethod ?: tanMethodsWithoutUnsupported.firstOrNull { it.displayName.contains("manuell", true) == false } ?: tanMethodsWithoutUnsupported.firstOrNull())
|
||||
|
||||
protected val selectedTanMedium = SimpleObjectProperty<TanMedium>(customer.tanMediaSorted.firstOrNull())
|
||||
protected val selectedTanMedium = SimpleObjectProperty<TanMedium>(bank.tanMediaSorted.firstOrNull())
|
||||
|
||||
protected val enteredTan = SimpleStringProperty("")
|
||||
|
||||
|
@ -84,13 +84,13 @@ open class EnterTanDialog(
|
|||
}
|
||||
}
|
||||
|
||||
if (customer.tanMediaSorted.isNotEmpty()) {
|
||||
if (bank.tanMediaSorted.isNotEmpty()) {
|
||||
field(messages["enter.tan.dialog.select.tan.medium"]) {
|
||||
label.apply {
|
||||
font = Font.font(font.family, FontWeight.BLACK, font.size)
|
||||
}
|
||||
|
||||
combobox(selectedTanMedium, customer.tanMediaSorted) {
|
||||
combobox(selectedTanMedium, bank.tanMediaSorted) {
|
||||
cellFormat {
|
||||
text = it.displayName
|
||||
}
|
||||
|
|
|
@ -2,10 +2,10 @@ package net.dankito.banking.ui.javafx.model
|
|||
|
||||
import javafx.scene.Node
|
||||
import javafx.scene.image.ImageView
|
||||
import net.dankito.banking.ui.model.TypedCustomer
|
||||
import net.dankito.banking.ui.model.TypedBankData
|
||||
|
||||
|
||||
open class AccountsAccountTreeItem(val customer: TypedCustomer) : AccountsTreeItemBase(customer.displayName) {
|
||||
open class AccountsAccountTreeItem(val bank: TypedBankData) : AccountsTreeItemBase(bank.displayName) {
|
||||
|
||||
companion object {
|
||||
private const val IconSize = 16.0
|
||||
|
@ -17,13 +17,13 @@ open class AccountsAccountTreeItem(val customer: TypedCustomer) : AccountsTreeIt
|
|||
|
||||
graphic = createIconImageView()
|
||||
|
||||
customer.accounts.forEach { bankAccount ->
|
||||
children.add(AccountsBankAccountTreeItem(bankAccount))
|
||||
bank.accounts.forEach { account ->
|
||||
children.add(AccountsBankAccountTreeItem(account))
|
||||
}
|
||||
}
|
||||
|
||||
protected open fun createIconImageView(): Node? {
|
||||
customer.iconUrl?.let {
|
||||
bank.iconUrl?.let {
|
||||
val iconImageView = ImageView(it)
|
||||
|
||||
iconImageView.fitHeight = IconSize
|
||||
|
|
|
@ -3,4 +3,4 @@ package net.dankito.banking.ui.javafx.model
|
|||
import net.dankito.banking.ui.model.TypedBankAccount
|
||||
|
||||
|
||||
open class AccountsBankAccountTreeItem(val bankAccount: TypedBankAccount) : AccountsTreeItemBase(bankAccount.displayName)
|
||||
open class AccountsBankAccountTreeItem(val account: TypedBankAccount) : AccountsTreeItemBase(account.displayName)
|
|
@ -2,26 +2,26 @@ package net.dankito.banking.ui.javafx.model
|
|||
|
||||
import javafx.collections.ListChangeListener
|
||||
import javafx.collections.ObservableList
|
||||
import net.dankito.banking.ui.model.TypedCustomer
|
||||
import net.dankito.banking.ui.model.TypedBankData
|
||||
import tornadofx.FX.Companion.messages
|
||||
import tornadofx.get
|
||||
import tornadofx.runLater
|
||||
|
||||
|
||||
open class AccountsRootTreeItem(customers: ObservableList<TypedCustomer>) : AccountsTreeItemBase(messages["accounts.view.all.accounts"]) {
|
||||
open class AccountsRootTreeItem(banks: ObservableList<TypedBankData>) : AccountsTreeItemBase(messages["accounts.view.all.accounts"]) {
|
||||
|
||||
init {
|
||||
setAccounts(customers)
|
||||
setBanks(banks)
|
||||
|
||||
customers.addListener(ListChangeListener {
|
||||
runLater { setAccounts(customers) }
|
||||
banks.addListener(ListChangeListener {
|
||||
runLater { setBanks(banks) }
|
||||
})
|
||||
}
|
||||
|
||||
protected open fun setAccounts(customers: List<TypedCustomer>) {
|
||||
isExpanded = customers.isNotEmpty()
|
||||
protected open fun setBanks(banks: List<TypedBankData>) {
|
||||
isExpanded = banks.isNotEmpty()
|
||||
|
||||
children.setAll(customers.map { AccountsAccountTreeItem(it) })
|
||||
children.setAll(banks.map { AccountsAccountTreeItem(it) })
|
||||
}
|
||||
|
||||
}
|
|
@ -6,14 +6,14 @@ import net.dankito.utils.multiplatform.File
|
|||
|
||||
interface IBankingPersistence {
|
||||
|
||||
fun saveOrUpdateAccount(customer: TypedCustomer, allCustomers: List<TypedCustomer>)
|
||||
fun saveOrUpdateBank(bank: TypedBankData, allBanks: List<TypedBankData>)
|
||||
|
||||
fun deleteAccount(customer: TypedCustomer, allCustomers: List<TypedCustomer>)
|
||||
fun deleteBank(bank: TypedBankData, allBanks: List<TypedBankData>)
|
||||
|
||||
fun readPersistedAccounts(): List<TypedCustomer>
|
||||
fun readPersistedBanks(): List<TypedBankData>
|
||||
|
||||
|
||||
fun saveOrUpdateAccountTransactions(bankAccount: TypedBankAccount, transactions: List<IAccountTransaction>)
|
||||
fun saveOrUpdateAccountTransactions(account: TypedBankAccount, transactions: List<IAccountTransaction>)
|
||||
|
||||
fun saveUrlToFile(url: String, file: File)
|
||||
|
||||
|
|
|
@ -6,20 +6,20 @@ import net.dankito.utils.multiplatform.File
|
|||
|
||||
open class NoOpBankingPersistence : IBankingPersistence {
|
||||
|
||||
override fun saveOrUpdateAccount(customer: TypedCustomer, allCustomers: List<TypedCustomer>) {
|
||||
override fun saveOrUpdateBank(bank: TypedBankData, allBanks: List<TypedBankData>) {
|
||||
|
||||
}
|
||||
|
||||
override fun deleteAccount(customer: TypedCustomer, allCustomers: List<TypedCustomer>) {
|
||||
override fun deleteBank(bank: TypedBankData, allBanks: List<TypedBankData>) {
|
||||
|
||||
}
|
||||
|
||||
override fun readPersistedAccounts(): List<TypedCustomer> {
|
||||
override fun readPersistedBanks(): List<TypedBankData> {
|
||||
return listOf()
|
||||
}
|
||||
|
||||
|
||||
override fun saveOrUpdateAccountTransactions(bankAccount: TypedBankAccount, transactions: List<IAccountTransaction>) {
|
||||
override fun saveOrUpdateAccountTransactions(account: TypedBankAccount, transactions: List<IAccountTransaction>) {
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package net.dankito.banking.ui
|
||||
|
||||
import net.dankito.banking.ui.model.TypedCustomer
|
||||
import net.dankito.banking.ui.model.TypedBankData
|
||||
import net.dankito.banking.ui.model.tan.EnterTanGeneratorAtcResult
|
||||
import net.dankito.banking.ui.model.tan.EnterTanResult
|
||||
import net.dankito.banking.ui.model.tan.TanChallenge
|
||||
|
@ -9,7 +9,7 @@ import net.dankito.banking.ui.model.tan.TanGeneratorTanMedium
|
|||
|
||||
interface BankingClientCallback {
|
||||
|
||||
fun enterTan(customer: TypedCustomer, tanChallenge: TanChallenge, callback: (EnterTanResult) -> Unit)
|
||||
fun enterTan(bank: TypedBankData, tanChallenge: TanChallenge, callback: (EnterTanResult) -> Unit)
|
||||
|
||||
/**
|
||||
* This method gets called for chipTan TAN generators when the bank asks the customer to synchronize her/his TAN generator.
|
||||
|
|
|
@ -23,8 +23,8 @@ interface IBankingClient {
|
|||
fun transferMoneyAsync(data: TransferMoneyData, callback: (BankingClientResponse) -> Unit)
|
||||
|
||||
|
||||
fun dataChanged(customer: TypedCustomer)
|
||||
fun dataChanged(bank: TypedBankData)
|
||||
|
||||
fun deletedAccount(customer: TypedCustomer, wasLastAccountWithThisCredentials: Boolean)
|
||||
fun deletedBank(bank: TypedBankData, wasLastAccountWithThisCredentials: Boolean)
|
||||
|
||||
}
|
|
@ -1,14 +1,14 @@
|
|||
package net.dankito.banking.ui
|
||||
|
||||
import net.dankito.utils.multiplatform.File
|
||||
import net.dankito.banking.ui.model.TypedCustomer
|
||||
import net.dankito.banking.ui.model.TypedBankData
|
||||
import net.dankito.banking.util.IAsyncRunner
|
||||
|
||||
|
||||
interface IBankingClientCreator {
|
||||
|
||||
fun createClient(
|
||||
customer: TypedCustomer,
|
||||
bank: TypedBankData,
|
||||
dataFolder: File,
|
||||
asyncRunner: IAsyncRunner,
|
||||
callback: BankingClientCallback
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package net.dankito.banking.ui
|
||||
|
||||
import net.dankito.banking.ui.model.TypedCustomer
|
||||
import net.dankito.banking.ui.model.TypedBankData
|
||||
import net.dankito.banking.ui.model.parameters.TransferMoneyData
|
||||
import net.dankito.banking.ui.model.tan.EnterTanGeneratorAtcResult
|
||||
import net.dankito.banking.ui.model.tan.EnterTanResult
|
||||
|
@ -13,7 +13,7 @@ interface IRouter {
|
|||
|
||||
fun showAddAccountDialog(presenter: BankingPresenter)
|
||||
|
||||
fun getTanFromUserFromNonUiThread(customer: TypedCustomer, tanChallenge: TanChallenge, presenter: BankingPresenter, callback: (EnterTanResult) -> Unit)
|
||||
fun getTanFromUserFromNonUiThread(bank: TypedBankData, tanChallenge: TanChallenge, presenter: BankingPresenter, callback: (EnterTanResult) -> Unit)
|
||||
|
||||
fun getAtcFromUserFromNonUiThread(tanMedium: TanGeneratorTanMedium, callback: (EnterTanGeneratorAtcResult) -> Unit)
|
||||
|
||||
|
|
|
@ -2,12 +2,10 @@ package net.dankito.banking.ui.model
|
|||
|
||||
import net.dankito.utils.multiplatform.BigDecimal
|
||||
import net.dankito.utils.multiplatform.Date
|
||||
import net.dankito.utils.multiplatform.DateFormatStyle
|
||||
import net.dankito.utils.multiplatform.DateFormatter
|
||||
|
||||
|
||||
open class AccountTransaction(
|
||||
override val bankAccount: TypedBankAccount,
|
||||
override val account: TypedBankAccount,
|
||||
override val amount: BigDecimal,
|
||||
override val currency: String,
|
||||
override val unparsedUsage: String,
|
||||
|
@ -51,15 +49,15 @@ open class AccountTransaction(
|
|||
|
||||
/* convenience constructors for languages not supporting default values */
|
||||
|
||||
constructor(bankAccount: BankAccount, otherPartyName: String?, unparsedUsage: String, amount: BigDecimal, valueDate: Date, bookingText: String?)
|
||||
: this(bankAccount, amount, "EUR", unparsedUsage, valueDate,
|
||||
constructor(account: BankAccount, otherPartyName: String?, unparsedUsage: String, amount: BigDecimal, valueDate: Date, bookingText: String?)
|
||||
: this(account, amount, "EUR", unparsedUsage, valueDate,
|
||||
otherPartyName, null, null, bookingText, valueDate)
|
||||
|
||||
|
||||
constructor(bankAccount: BankAccount, amount: BigDecimal, currency: String, unparsedUsage: String, bookingDate: Date,
|
||||
constructor(account: BankAccount, amount: BigDecimal, currency: String, unparsedUsage: String, bookingDate: Date,
|
||||
otherPartyName: String?, otherPartyBankCode: String?, otherPartyAccountId: String?,
|
||||
bookingText: String?, valueDate: Date)
|
||||
: this(bankAccount, amount, currency, unparsedUsage, bookingDate,
|
||||
: this(account, amount, currency, unparsedUsage, bookingDate,
|
||||
otherPartyName, otherPartyBankCode, otherPartyAccountId, bookingText, valueDate,
|
||||
0, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, "", "", null, null, "", null)
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ import kotlin.jvm.JvmOverloads
|
|||
|
||||
|
||||
open class BankAccount @JvmOverloads constructor(
|
||||
override val customer: TypedCustomer,
|
||||
override val bank: TypedBankData,
|
||||
override var identifier: String,
|
||||
override var accountHolderName: String,
|
||||
override var iban: String?,
|
||||
|
@ -28,14 +28,14 @@ open class BankAccount @JvmOverloads constructor(
|
|||
override var unbookedTransactions: List<Any> = listOf()
|
||||
) : TypedBankAccount {
|
||||
|
||||
internal constructor() : this(Customer(), null, "") // for object deserializers
|
||||
internal constructor() : this(BankData(), null, "") // for object deserializers
|
||||
|
||||
/* convenience constructors for languages not supporting default values */
|
||||
|
||||
constructor(customer: TypedCustomer, productName: String?, identifier: String) : this(customer, productName, identifier, BankAccountType.Girokonto)
|
||||
constructor(bank: TypedBankData, productName: String?, identifier: String) : this(bank, productName, identifier, BankAccountType.Girokonto)
|
||||
|
||||
constructor(customer: TypedCustomer, productName: String?, identifier: String, type: BankAccountType = BankAccountType.Girokonto, balance: BigDecimal = BigDecimal.Zero)
|
||||
: this(customer, identifier, "", null, null, "", balance, "EUR", type, productName)
|
||||
constructor(bank: TypedBankData, productName: String?, identifier: String, type: BankAccountType = BankAccountType.Girokonto, balance: BigDecimal = BigDecimal.Zero)
|
||||
: this(bank, identifier, "", null, null, "", balance, "EUR", type, productName)
|
||||
|
||||
|
||||
override var technicalId: String = UUID.random()
|
||||
|
|
|
@ -5,7 +5,7 @@ import net.dankito.banking.ui.model.tan.TanMethod
|
|||
import net.dankito.utils.multiplatform.UUID
|
||||
|
||||
|
||||
open class Customer(
|
||||
open class BankData(
|
||||
override var bankCode: String,
|
||||
override var customerId: String,
|
||||
override var password: String,
|
||||
|
@ -16,7 +16,7 @@ open class Customer(
|
|||
override var userId: String = customerId,
|
||||
override var iconUrl: String? = null,
|
||||
override var accounts: List<TypedBankAccount> = listOf()
|
||||
) : TypedCustomer {
|
||||
) : TypedBankData {
|
||||
|
||||
|
||||
internal constructor() : this("", "", "", "", "", "", "") // for object deserializers
|
|
@ -13,7 +13,7 @@ interface IAccountTransaction {
|
|||
}
|
||||
|
||||
|
||||
val bankAccount: IBankAccount<*>
|
||||
val account: IBankAccount<*>
|
||||
val amount: BigDecimal
|
||||
val currency: String
|
||||
val unparsedUsage: String
|
||||
|
@ -62,15 +62,15 @@ interface IAccountTransaction {
|
|||
get() = otherPartyName.isNullOrBlank() == false /* && type != "ENTGELTABSCHLUSS" && type != "AUSZAHLUNG" */ // TODO
|
||||
|
||||
val canCreateMoneyTransferFrom: Boolean
|
||||
get() = otherPartyAccountId != null && bankAccount.supportsTransferringMoney
|
||||
get() = otherPartyAccountId != null && account.supportsTransferringMoney
|
||||
|
||||
val usage: String
|
||||
get() = sepaUsage ?: unparsedUsage
|
||||
|
||||
|
||||
fun buildTransactionIdentifier() : String {
|
||||
if (bankAccount != null) {
|
||||
return "${bankAccount.technicalId} ${IdDateFormat.format(bookingDate)} ${IdDateFormat.format(valueDate)} $amount $currency $unparsedUsage $otherPartyName $otherPartyBankCode $otherPartyAccountId"
|
||||
if (account != null) {
|
||||
return "${account.technicalId} ${IdDateFormat.format(bookingDate)} ${IdDateFormat.format(valueDate)} $amount $currency $unparsedUsage $otherPartyName $otherPartyBankCode $otherPartyAccountId"
|
||||
}
|
||||
else { // happens for derived classes during initialization. These have to set technicalId after initialization by themselves
|
||||
return "<uninitialized_bank_acccount> ${IdDateFormat.format(bookingDate)} ${IdDateFormat.format(valueDate)} $amount $currency $unparsedUsage $otherPartyName $otherPartyBankCode $otherPartyAccountId"
|
||||
|
@ -83,7 +83,7 @@ interface IAccountTransaction {
|
|||
if (this === other) return true
|
||||
if (other !is IAccountTransaction) return false
|
||||
|
||||
if (bankAccount != other.bankAccount) return false
|
||||
if (account != other.account) return false
|
||||
if (amount != other.amount) return false
|
||||
if (currency != other.currency) return false
|
||||
if (unparsedUsage != other.unparsedUsage) return false
|
||||
|
@ -98,7 +98,7 @@ interface IAccountTransaction {
|
|||
}
|
||||
|
||||
fun calculateHashCode(): Int {
|
||||
var result = bankAccount.hashCode()
|
||||
var result = account.hashCode()
|
||||
result = 31 * result + amount.hashCode()
|
||||
result = 31 * result + currency.hashCode()
|
||||
result = 31 * result + unparsedUsage.hashCode()
|
||||
|
|
|
@ -8,7 +8,7 @@ typealias TypedBankAccount = IBankAccount<IAccountTransaction>
|
|||
|
||||
|
||||
interface IBankAccount<TTransaction: IAccountTransaction> : OrderedDisplayable {
|
||||
val customer: ICustomer<*, *>
|
||||
val bank: IBankData<*, *>
|
||||
var identifier: String
|
||||
var accountHolderName: String
|
||||
var iban: String?
|
||||
|
|
|
@ -8,10 +8,10 @@ import net.dankito.utils.multiplatform.BigDecimal
|
|||
import net.dankito.utils.multiplatform.sum
|
||||
|
||||
|
||||
typealias TypedCustomer = ICustomer<IBankAccount<IAccountTransaction>, IAccountTransaction>
|
||||
typealias TypedBankData = IBankData<IBankAccount<IAccountTransaction>, IAccountTransaction>
|
||||
|
||||
|
||||
interface ICustomer<TAccount: IBankAccount<TAccountTransaction>, TAccountTransaction: IAccountTransaction> : OrderedDisplayable {
|
||||
interface IBankData<TAccount: IBankAccount<TAccountTransaction>, TAccountTransaction: IAccountTransaction> : OrderedDisplayable {
|
||||
|
||||
var bankCode: String
|
||||
var customerId: String
|
|
@ -6,7 +6,7 @@ import net.dankito.utils.multiplatform.Date
|
|||
open class MessageLogEntry(
|
||||
val message: String,
|
||||
val time: Date,
|
||||
val customer: TypedCustomer
|
||||
val bank: TypedBankData
|
||||
) {
|
||||
|
||||
override fun toString(): String {
|
||||
|
|
|
@ -5,8 +5,8 @@ enum class SelectedAccountType {
|
|||
|
||||
AllAccounts,
|
||||
|
||||
SingleAccount,
|
||||
SingleBank,
|
||||
|
||||
SingleBankAccount
|
||||
SingleAccount
|
||||
|
||||
}
|
|
@ -7,19 +7,19 @@ import net.dankito.utils.multiplatform.Date
|
|||
|
||||
open class DefaultModelCreator : IModelCreator {
|
||||
|
||||
override fun createCustomer(bankCode: String, customerId: String, password: String, finTsServerAddress: String, bankName: String, bic: String,
|
||||
customerName: String, userId: String, iconUrl: String?): TypedCustomer {
|
||||
override fun createBank(bankCode: String, customerId: String, password: String, finTsServerAddress: String, bankName: String, bic: String,
|
||||
customerName: String, userId: String, iconUrl: String?): TypedBankData {
|
||||
|
||||
return Customer(bankCode, customerId, password, finTsServerAddress, bankName, bic, customerName, userId, iconUrl)
|
||||
return BankData(bankCode, customerId, password, finTsServerAddress, bankName, bic, customerName, userId, iconUrl)
|
||||
}
|
||||
|
||||
|
||||
override fun createBankAccount(customer: TypedCustomer, productName: String?, identifier: String): TypedBankAccount {
|
||||
return BankAccount(customer, productName, identifier)
|
||||
override fun createAccount(bank: TypedBankData, productName: String?, identifier: String): TypedBankAccount {
|
||||
return BankAccount(bank, productName, identifier)
|
||||
}
|
||||
|
||||
override fun createTransaction(
|
||||
bankAccount: TypedBankAccount,
|
||||
account: TypedBankAccount,
|
||||
amount: BigDecimal,
|
||||
currency: String,
|
||||
unparsedUsage: String,
|
||||
|
@ -55,7 +55,7 @@ open class DefaultModelCreator : IModelCreator {
|
|||
relatedReferenceNumber: String?
|
||||
) : IAccountTransaction {
|
||||
|
||||
return AccountTransaction(bankAccount, amount, currency, unparsedUsage, bookingDate,
|
||||
return AccountTransaction(account, amount, currency, unparsedUsage, bookingDate,
|
||||
otherPartyName, otherPartyBankCode, otherPartyAccountId, bookingText, valueDate, statementNumber, sequenceNumber,
|
||||
openingBalance, closingBalance, endToEndReference, customerReference, mandateReference, creditorIdentifier,
|
||||
originatorsIdentificationCode, compensationAmount, originalAmount, sepaUsage, deviantOriginator, deviantRecipient,
|
||||
|
|
|
@ -8,15 +8,15 @@ import net.dankito.utils.multiplatform.Date
|
|||
|
||||
interface IModelCreator {
|
||||
|
||||
fun createCustomer(bankCode: String, customerId: String, password: String, finTsServerAddress: String, bankName: String, bic: String,
|
||||
customerName: String = "", userId: String = customerId, iconUrl: String? = null): TypedCustomer
|
||||
fun createBank(bankCode: String, customerId: String, password: String, finTsServerAddress: String, bankName: String, bic: String,
|
||||
customerName: String = "", userId: String = customerId, iconUrl: String? = null): TypedBankData
|
||||
|
||||
|
||||
fun createBankAccount(customer: TypedCustomer, productName: String?, identifier: String) : TypedBankAccount
|
||||
fun createAccount(bank: TypedBankData, productName: String?, identifier: String) : TypedBankAccount
|
||||
|
||||
|
||||
fun createTransaction(
|
||||
bankAccount: TypedBankAccount,
|
||||
account: TypedBankAccount,
|
||||
amount: BigDecimal,
|
||||
currency: String,
|
||||
unparsedUsage: String,
|
||||
|
|
|
@ -18,7 +18,7 @@ open class TransferMoneyData(
|
|||
|
||||
fun fromAccountTransactionWithoutAmountAndUsage(transaction: IAccountTransaction): TransferMoneyData {
|
||||
return TransferMoneyData(
|
||||
transaction.bankAccount as TypedBankAccount,
|
||||
transaction.account as TypedBankAccount,
|
||||
transaction.otherPartyName ?: "",
|
||||
transaction.otherPartyAccountId ?: "",
|
||||
transaction.otherPartyBankCode ?: "",
|
||||
|
@ -29,7 +29,7 @@ open class TransferMoneyData(
|
|||
|
||||
fun fromAccountTransaction(transaction: IAccountTransaction): TransferMoneyData {
|
||||
return TransferMoneyData(
|
||||
transaction.bankAccount as TypedBankAccount,
|
||||
transaction.account as TypedBankAccount,
|
||||
transaction.otherPartyName ?: "",
|
||||
transaction.otherPartyAccountId ?: "",
|
||||
transaction.otherPartyBankCode ?: "",
|
||||
|
|
|
@ -4,24 +4,24 @@ import net.dankito.banking.ui.model.*
|
|||
|
||||
|
||||
open class AddAccountResponse(
|
||||
open val customer: TypedCustomer,
|
||||
open val bank: TypedBankData,
|
||||
retrievedData: List<RetrievedAccountData> = listOf(),
|
||||
errorToShowToUser: String?,
|
||||
userCancelledAction: Boolean = false
|
||||
) : GetTransactionsResponse(retrievedData, errorToShowToUser, userCancelledAction) {
|
||||
|
||||
constructor(customer: TypedCustomer, errorToShowToUser: String?) : this(customer, listOf(), errorToShowToUser)
|
||||
constructor(bank: TypedBankData, errorToShowToUser: String?) : this(bank, listOf(), errorToShowToUser)
|
||||
|
||||
|
||||
override val successful: Boolean
|
||||
get() = super.successful && customer.accounts.isNotEmpty()
|
||||
get() = super.successful && bank.accounts.isNotEmpty()
|
||||
|
||||
open val supportsRetrievingTransactionsOfLast90DaysWithoutTan: Boolean
|
||||
get() = retrievedData.isNotEmpty() && retrievedData.any { it.successfullyRetrievedData }
|
||||
|
||||
|
||||
override fun toString(): String {
|
||||
return customer.toString() + " " + super.toString()
|
||||
return bank.toString() + " " + super.toString()
|
||||
}
|
||||
|
||||
}
|
|
@ -59,31 +59,31 @@ open class BankingPresenter(
|
|||
}
|
||||
|
||||
|
||||
protected val bankingClientsForAccounts = mutableMapOf<TypedCustomer, IBankingClient>()
|
||||
protected val bankingClientsForBanks = mutableMapOf<TypedBankData, IBankingClient>()
|
||||
|
||||
protected var selectedBankAccountsField = mutableListOf<TypedBankAccount>()
|
||||
protected var _selectedAccounts = mutableListOf<TypedBankAccount>()
|
||||
|
||||
protected var selectedAccountType = SelectedAccountType.AllAccounts
|
||||
|
||||
protected var saveAccountOnNextEnterTanInvocation = false
|
||||
|
||||
|
||||
protected val accountsChangedListeners = mutableListOf<(List<TypedCustomer>) -> Unit>()
|
||||
protected val banksChangedListeners = mutableListOf<(List<TypedBankData>) -> Unit>()
|
||||
|
||||
protected val retrievedAccountTransactionsResponseListeners = mutableListOf<(GetTransactionsResponse) -> Unit>()
|
||||
|
||||
protected val selectedBankAccountsChangedListeners = mutableListOf<(List<TypedBankAccount>) -> Unit>()
|
||||
protected val selectedAccountsChangedListeners = mutableListOf<(List<TypedBankAccount>) -> Unit>()
|
||||
|
||||
|
||||
protected val callback: BankingClientCallback = object : BankingClientCallback {
|
||||
|
||||
override fun enterTan(customer: TypedCustomer, tanChallenge: TanChallenge, callback: (EnterTanResult) -> Unit) {
|
||||
override fun enterTan(bank: TypedBankData, tanChallenge: TanChallenge, callback: (EnterTanResult) -> Unit) {
|
||||
if (saveAccountOnNextEnterTanInvocation) {
|
||||
persistAccountOffUiThread(customer)
|
||||
persistBankOffUiThread(bank)
|
||||
saveAccountOnNextEnterTanInvocation = false
|
||||
}
|
||||
|
||||
router.getTanFromUserFromNonUiThread(customer, tanChallenge, this@BankingPresenter) { result ->
|
||||
router.getTanFromUserFromNonUiThread(bank, tanChallenge, this@BankingPresenter) { result ->
|
||||
if (result.changeTanMethodTo != null || result.changeTanMediumTo != null) { // then either selected TAN medium or method will change -> save account on next call to enterTan() as then changes will be visible
|
||||
saveAccountOnNextEnterTanInvocation = true
|
||||
}
|
||||
|
@ -104,7 +104,7 @@ open class BankingPresenter(
|
|||
init {
|
||||
asyncRunner.runAsync {
|
||||
readAppSettings()
|
||||
readPersistedAccounts()
|
||||
readPersistedBanks()
|
||||
|
||||
updateAccountsTransactionsIfNoTanIsRequiredAsync()
|
||||
}
|
||||
|
@ -116,81 +116,81 @@ open class BankingPresenter(
|
|||
}
|
||||
|
||||
|
||||
protected open fun readPersistedAccounts() {
|
||||
protected open fun readPersistedBanks() {
|
||||
try {
|
||||
val deserializedAccounts = persister.readPersistedAccounts()
|
||||
val deserializedBanks = persister.readPersistedBanks()
|
||||
|
||||
deserializedAccounts.forEach { customer ->
|
||||
val newClient = bankingClientCreator.createClient(customer, dataFolder, asyncRunner, callback)
|
||||
deserializedBanks.forEach { bank ->
|
||||
val newClient = bankingClientCreator.createClient(bank, dataFolder, asyncRunner, callback)
|
||||
|
||||
addClientForAccount(customer, newClient)
|
||||
addClientForBank(bank, newClient)
|
||||
|
||||
customer.accounts.forEach { account ->
|
||||
bank.accounts.forEach { account ->
|
||||
if (account.haveAllTransactionsBeenFetched == false && didFetchAllTransactionsStoredOnBankServer(account, listOf())) {
|
||||
account.haveAllTransactionsBeenFetched = true // no need to save account, just delays app start-up, as even if account doesn't get saved during app run, haveAllTransactionsBeenFetched gets restored on next app run
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
callAccountsChangedListeners()
|
||||
callBanksChangedListeners()
|
||||
|
||||
selectedAllBankAccounts() // TODO: save last selected bank account(s)
|
||||
selectedAllAccounts() // TODO: save last selected bank account(s)
|
||||
} catch (e: Exception) {
|
||||
log.error(e) { "Could not deserialize persisted accounts with persister $persister" }
|
||||
log.error(e) { "Could not deserialize persisted banks with persister $persister" }
|
||||
}
|
||||
}
|
||||
|
||||
protected open fun addClientForAccount(customer: TypedCustomer, client: IBankingClient) {
|
||||
bankingClientsForAccounts.put(customer, client)
|
||||
protected open fun addClientForBank(bank: TypedBankData, client: IBankingClient) {
|
||||
bankingClientsForBanks.put(bank, client)
|
||||
}
|
||||
|
||||
|
||||
// TODO: move BankInfo out of fints4k
|
||||
open fun addAccountAsync(bankInfo: BankInfo, customerId: String, password: String, callback: (AddAccountResponse) -> Unit) {
|
||||
val customer = modelCreator.createCustomer(bankInfo.bankCode, customerId, password, bankInfo.pinTanAddress ?: "", bankInfo.name, bankInfo.bic, "")
|
||||
val bank = modelCreator.createBank(bankInfo.bankCode, customerId, password, bankInfo.pinTanAddress ?: "", bankInfo.name, bankInfo.bic, "")
|
||||
|
||||
val newClient = bankingClientCreator.createClient(customer, dataFolder, asyncRunner, this.callback)
|
||||
val newClient = bankingClientCreator.createClient(bank, dataFolder, asyncRunner, this.callback)
|
||||
|
||||
val startDate = Date()
|
||||
|
||||
newClient.addAccountAsync { response ->
|
||||
if (response.successful) {
|
||||
val account = response.customer
|
||||
account.displayIndex = customers.size
|
||||
val bank = response.bank
|
||||
bank.displayIndex = allBanks.size
|
||||
|
||||
addClientForAccount(account, newClient)
|
||||
addClientForBank(bank, newClient)
|
||||
|
||||
selectedAccount(account)
|
||||
selectedBank(bank)
|
||||
|
||||
callAccountsChangedListeners()
|
||||
callBanksChangedListeners()
|
||||
|
||||
persistAccountOffUiThread(account)
|
||||
persistBankOffUiThread(bank)
|
||||
|
||||
response.retrievedData.forEach { retrievedData ->
|
||||
retrievedAccountTransactions(GetTransactionsResponse(retrievedData), startDate, false)
|
||||
}
|
||||
|
||||
findIconForBankAsync(account)
|
||||
findIconForBankAsync(bank)
|
||||
}
|
||||
|
||||
callback(response)
|
||||
}
|
||||
}
|
||||
|
||||
protected open fun findIconForBankAsync(customer: TypedCustomer) {
|
||||
bankIconFinder.findIconForBankAsync(customer.bankName) { bankIconUrl ->
|
||||
protected open fun findIconForBankAsync(bank: TypedBankData) {
|
||||
bankIconFinder.findIconForBankAsync(bank.bankName) { bankIconUrl ->
|
||||
bankIconUrl?.let {
|
||||
try {
|
||||
handleFindIconForBankResult(customer, bankIconUrl)
|
||||
handleFindIconForBankResult(bank, bankIconUrl)
|
||||
} catch (e: Exception) {
|
||||
log.error(e) { "Could not get icon for bank ${customer.bankName}" }
|
||||
log.error(e) { "Could not get icon for bank ${bank.bankName}" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected open fun handleFindIconForBankResult(customer: TypedCustomer, bankIconUrl: String) {
|
||||
val bankIconFile = saveBankIconToDisk(customer, bankIconUrl)
|
||||
protected open fun handleFindIconForBankResult(bank: TypedBankData, bankIconUrl: String) {
|
||||
val bankIconFile = saveBankIconToDisk(bank, bankIconUrl)
|
||||
|
||||
var iconFilePath = bankIconFile.getAbsolutePath()
|
||||
|
||||
|
@ -198,19 +198,19 @@ open class BankingPresenter(
|
|||
iconFilePath = "file://" + iconFilePath // without 'file://' Android will not find it
|
||||
}
|
||||
|
||||
customer.iconUrl = iconFilePath
|
||||
bank.iconUrl = iconFilePath
|
||||
|
||||
persistAccountOffUiThread(customer)
|
||||
persistBankOffUiThread(bank)
|
||||
|
||||
callAccountsChangedListeners()
|
||||
callBanksChangedListeners()
|
||||
}
|
||||
|
||||
protected open fun saveBankIconToDisk(customer: TypedCustomer, bankIconUrl: String): File {
|
||||
protected open fun saveBankIconToDisk(bank: TypedBankData, bankIconUrl: String): File {
|
||||
val bankIconsDir = File(dataFolder, "bank_icons")
|
||||
bankIconsDir.mkdirs()
|
||||
|
||||
val extension = getIconFileExtension(bankIconUrl)
|
||||
val bankIconFile = File(bankIconsDir, customer.bankCode + if (extension != null) (".$extension") else "")
|
||||
val bankIconFile = File(bankIconsDir, bank.bankCode + if (extension != null) (".$extension") else "")
|
||||
|
||||
persister.saveUrlToFile(bankIconUrl, bankIconFile)
|
||||
|
||||
|
@ -236,45 +236,45 @@ open class BankingPresenter(
|
|||
}
|
||||
|
||||
|
||||
open fun deleteAccount(customer: TypedCustomer) {
|
||||
open fun deleteAccount(bank: TypedBankData) {
|
||||
asyncRunner.runAsync {
|
||||
deleteAccountOffUiThread(customer)
|
||||
deleteAccountOffUiThread(bank)
|
||||
}
|
||||
}
|
||||
|
||||
protected open fun deleteAccountOffUiThread(customer: TypedCustomer) {
|
||||
val wasSelected = isSingleSelectedAccount(customer) or // either account or one of its bank accounts is currently selected
|
||||
(customer.accounts.firstOrNull { isSingleSelectedBankAccount(it) } != null)
|
||||
protected open fun deleteAccountOffUiThread(bank: TypedBankData) {
|
||||
val wasSelected = isSingleSelectedBank(bank) or // either account or one of its bank accounts is currently selected
|
||||
(bank.accounts.firstOrNull { isSingleSelectedAccount(it) } != null)
|
||||
|
||||
val client = bankingClientsForAccounts.remove(customer)
|
||||
val client = bankingClientsForBanks.remove(bank)
|
||||
|
||||
val displayIndex = customer.displayIndex
|
||||
val displayIndex = bank.displayIndex
|
||||
|
||||
persister.deleteAccount(customer, customers)
|
||||
persister.deleteBank(bank, allBanks)
|
||||
|
||||
val sortedBanks = customers.sortedByDisplayIndex()
|
||||
val sortedBanks = allBanks.sortedByDisplayIndex()
|
||||
for (i in IntRange(displayIndex, sortedBanks.size - 1)) {
|
||||
val bank = sortedBanks[i]
|
||||
bank.displayIndex = i
|
||||
accountDisplayIndexUpdated(bank)
|
||||
bankDisplayIndexUpdated(bank)
|
||||
}
|
||||
|
||||
client?.deletedAccount(customer, customers.firstOrNull { it.customerId == customer.customerId && it.bankCode == customer.bankCode} == null)
|
||||
client?.deletedBank(bank, allBanks.firstOrNull { it.customerId == bank.customerId && it.bankCode == bank.bankCode} == null)
|
||||
|
||||
callAccountsChangedListeners()
|
||||
callBanksChangedListeners()
|
||||
|
||||
if (wasSelected || areAllAccountSelected) { // to update displayed account transactions as transactions of yet deleted accounts have to be removed
|
||||
selectedAllBankAccounts()
|
||||
selectedAllAccounts()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
open fun fetchAllAccountTransactionsAsync(customer: TypedCustomer,
|
||||
open fun fetchAllAccountTransactionsAsync(bank: TypedBankData,
|
||||
callback: ((GetTransactionsResponse) -> Unit)? = null) {
|
||||
|
||||
customer.accounts.forEach { bankAccount ->
|
||||
if (bankAccount.supportsRetrievingAccountTransactions) {
|
||||
fetchAllAccountTransactionsAsync(bankAccount, callback) // TODO: use a synchronous version of fetchAccountTransactions() so that all bank accounts get handled serially
|
||||
bank.accounts.forEach { account ->
|
||||
if (account.supportsRetrievingAccountTransactions) {
|
||||
fetchAllAccountTransactionsAsync(account, callback) // TODO: use a synchronous version of fetchAccountTransactions() so that all bank accounts get handled serially
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -288,10 +288,10 @@ open class BankingPresenter(
|
|||
open fun fetchAccountTransactionsAsync(account: TypedBankAccount, fromDate: Date?, abortIfTanIsRequired: Boolean = false,
|
||||
callback: ((GetTransactionsResponse) -> Unit)? = null) {
|
||||
|
||||
getBankingClientForAccount(account.customer)?.let { client ->
|
||||
getBankingClientForBank(account.bank)?.let { client ->
|
||||
val startDate = Date()
|
||||
|
||||
client.getTransactionsAsync(GetTransactionsParameter(account,true, fromDate, null, abortIfTanIsRequired, { receivedAccountsTransactionChunk(account, it) } )) { response ->
|
||||
client.getTransactionsAsync(GetTransactionsParameter(account,true, fromDate, null, abortIfTanIsRequired, { receivedAccountTransactionChunk(account, 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(response, startDate, fromDate == null)
|
||||
|
@ -310,32 +310,32 @@ open class BankingPresenter(
|
|||
updateAccountsTransactionsAsync(true) { }
|
||||
}
|
||||
|
||||
open fun updateSelectedBankAccountTransactionsAsync(callback: (GetTransactionsResponse) -> Unit) {
|
||||
updateBanksAccountsTransactionsAsync(selectedBankAccounts, false, callback)
|
||||
open fun updateSelectedAccountsTransactionsAsync(callback: (GetTransactionsResponse) -> Unit) {
|
||||
updateAccountsTransactionsAsync(selectedAccounts, false, callback)
|
||||
}
|
||||
|
||||
protected open fun updateAccountsTransactionsAsync(abortIfTanIsRequired: Boolean = false, callback: (GetTransactionsResponse) -> Unit) {
|
||||
bankingClientsForAccounts.keys.forEach { account ->
|
||||
account.accounts.forEach { bankAccount ->
|
||||
if (bankAccount.supportsRetrievingAccountTransactions) {
|
||||
updateBankAccountTransactionsAsync(bankAccount, abortIfTanIsRequired, callback)
|
||||
bankingClientsForBanks.keys.forEach { account ->
|
||||
account.accounts.forEach { account ->
|
||||
if (account.supportsRetrievingAccountTransactions) {
|
||||
updateAccountTransactionsAsync(account, abortIfTanIsRequired, callback)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected open fun updateBanksAccountsTransactionsAsync(accounts: List<TypedBankAccount>, abortIfTanIsRequired: Boolean = false, callback: (GetTransactionsResponse) -> Unit) {
|
||||
accounts.forEach { bankAccount ->
|
||||
if (bankAccount.supportsRetrievingAccountTransactions) {
|
||||
updateBankAccountTransactionsAsync(bankAccount, abortIfTanIsRequired, callback)
|
||||
protected open fun updateAccountsTransactionsAsync(accounts: List<TypedBankAccount>, abortIfTanIsRequired: Boolean = false, callback: (GetTransactionsResponse) -> Unit) {
|
||||
accounts.forEach { account ->
|
||||
if (account.supportsRetrievingAccountTransactions) {
|
||||
updateAccountTransactionsAsync(account, abortIfTanIsRequired, callback)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
open fun updateBankAccountTransactionsAsync(bankAccount: TypedBankAccount, abortIfTanIsRequired: Boolean = false, callback: ((GetTransactionsResponse) -> Unit)? = null) {
|
||||
val fromDate = bankAccount.retrievedTransactionsUpTo?.let { Date(it.millisSinceEpoch - OneDayMillis) } // one day before last received transactions
|
||||
open fun updateAccountTransactionsAsync(account: TypedBankAccount, abortIfTanIsRequired: Boolean = false, callback: ((GetTransactionsResponse) -> Unit)? = null) {
|
||||
val fromDate = account.retrievedTransactionsUpTo?.let { Date(it.millisSinceEpoch - OneDayMillis) } // one day before last received transactions
|
||||
|
||||
fetchAccountTransactionsAsync(bankAccount, fromDate, abortIfTanIsRequired, callback)
|
||||
fetchAccountTransactionsAsync(account, fromDate, abortIfTanIsRequired, callback)
|
||||
}
|
||||
|
||||
protected open fun retrievedAccountTransactions(response: GetTransactionsResponse, startDate: Date, didFetchAllTransactions: Boolean) {
|
||||
|
@ -359,7 +359,7 @@ open class BankingPresenter(
|
|||
}
|
||||
|
||||
protected open fun didFetchAllTransactionsStoredOnBankServer(account: IBankAccount<IAccountTransaction>, fetchedTransactions: Collection<IAccountTransaction>): Boolean {
|
||||
account.customer.countDaysForWhichTransactionsAreKept?.let { countDaysForWhichTransactionsAreKept ->
|
||||
account.bank.countDaysForWhichTransactionsAreKept?.let { countDaysForWhichTransactionsAreKept ->
|
||||
(account.retrievedTransactionsFromOn ?: getDateOfFirstRetrievedTransaction(account.bookedTransactions) ?: getDateOfFirstRetrievedTransaction(fetchedTransactions))?.let { retrievedTransactionsFromOn ->
|
||||
val dayOfFirstTransactionStoredOnBankServer = Date(Date.today.millisSinceEpoch - countDaysForWhichTransactionsAreKept * OneDayMillis)
|
||||
|
||||
|
@ -374,12 +374,12 @@ open class BankingPresenter(
|
|||
return transactions.map { it.valueDate }.minBy { it.millisSinceEpoch }
|
||||
}
|
||||
|
||||
protected open fun receivedAccountsTransactionChunk(bankAccount: TypedBankAccount, accountTransactionsChunk: List<IAccountTransaction>) {
|
||||
if (accountTransactionsChunk.isNotEmpty()) {
|
||||
protected open fun receivedAccountTransactionChunk(account: TypedBankAccount, transactionsChunk: List<IAccountTransaction>) {
|
||||
if (transactionsChunk.isNotEmpty()) {
|
||||
asyncRunner.runAsync { // don't block retrieving next chunk by blocked saving to db / json
|
||||
updateAccountTransactions(bankAccount, accountTransactionsChunk)
|
||||
updateAccountTransactions(account, transactionsChunk)
|
||||
|
||||
callRetrievedAccountTransactionsResponseListener(GetTransactionsResponse(RetrievedAccountData(bankAccount, true, null, accountTransactionsChunk, listOf(), null, null)))
|
||||
callRetrievedAccountTransactionsResponseListener(GetTransactionsResponse(RetrievedAccountData(account, true, null, transactionsChunk, listOf(), null, null)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -405,10 +405,10 @@ open class BankingPresenter(
|
|||
persistAccountTransactionsOffUiThread(account, newBookedTransactions)
|
||||
}
|
||||
|
||||
protected open fun updateBalance(bankAccount: TypedBankAccount, balance: BigDecimal) {
|
||||
bankAccount.balance = balance
|
||||
protected open fun updateBalance(account: TypedBankAccount, balance: BigDecimal) {
|
||||
account.balance = balance
|
||||
|
||||
persistAccountOffUiThread(bankAccount.customer)
|
||||
persistBankOffUiThread(account.bank)
|
||||
}
|
||||
|
||||
|
||||
|
@ -417,60 +417,60 @@ open class BankingPresenter(
|
|||
}
|
||||
|
||||
|
||||
open fun allAccountsUpdated() {
|
||||
customers.forEach { account ->
|
||||
accountDisplayIndexUpdated(account)
|
||||
open fun allBanksUpdated() {
|
||||
allBanks.forEach { bank ->
|
||||
bankDisplayIndexUpdated(bank)
|
||||
}
|
||||
}
|
||||
|
||||
open fun accountDisplayIndexUpdated(account: TypedCustomer) {
|
||||
persistAccountAsync(account)
|
||||
open fun bankDisplayIndexUpdated(bank: TypedBankData) {
|
||||
persistBankAsync(bank)
|
||||
|
||||
callAccountsChangedListeners()
|
||||
callBanksChangedListeners()
|
||||
}
|
||||
|
||||
open fun accountUpdated(bank: TypedCustomer) {
|
||||
persistAccountAsync(bank)
|
||||
open fun bankUpdated(bank: TypedBankData) {
|
||||
persistBankAsync(bank)
|
||||
|
||||
callAccountsChangedListeners()
|
||||
callBanksChangedListeners()
|
||||
|
||||
getBankingClientForAccount(bank)?.dataChanged(bank)
|
||||
getBankingClientForBank(bank)?.dataChanged(bank)
|
||||
}
|
||||
|
||||
open fun accountUpdated(account: TypedBankAccount) {
|
||||
persistAccountAsync(account.customer)
|
||||
persistBankAsync(account.bank)
|
||||
|
||||
callAccountsChangedListeners()
|
||||
callBanksChangedListeners()
|
||||
}
|
||||
|
||||
protected open fun persistAccountAsync(customer: ICustomer<*, *>) {
|
||||
protected open fun persistBankAsync(bank: IBankData<*, *>) {
|
||||
asyncRunner.runAsync {
|
||||
persistAccountOffUiThread(customer)
|
||||
persistBankOffUiThread(bank)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that this method only gets called off UI thread (at least for Android Room db) as otherwise it may blocks UI thread.
|
||||
*/
|
||||
protected open fun persistAccountOffUiThread(customer: ICustomer<*, *>) {
|
||||
persister.saveOrUpdateAccount(customer as TypedCustomer, customers)
|
||||
protected open fun persistBankOffUiThread(bank: IBankData<*, *>) {
|
||||
persister.saveOrUpdateBank(bank as TypedBankData, allBanks)
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that this method only gets called off UI thread (at least for Android Room db) as otherwise it may blocks UI thread.
|
||||
*/
|
||||
protected open fun persistAccountTransactionsOffUiThread(bankAccount: TypedBankAccount, bookedTransactions: List<IAccountTransaction>) {
|
||||
persister.saveOrUpdateAccountTransactions(bankAccount, bookedTransactions)
|
||||
protected open fun persistAccountTransactionsOffUiThread(account: TypedBankAccount, bookedTransactions: List<IAccountTransaction>) {
|
||||
persister.saveOrUpdateAccountTransactions(account, bookedTransactions)
|
||||
}
|
||||
|
||||
|
||||
open fun transferMoneyAsync(data: TransferMoneyData, callback: (BankingClientResponse) -> Unit) {
|
||||
val account = data.account
|
||||
|
||||
getBankingClientForAccount(account.customer)?.let { client ->
|
||||
getBankingClientForBank(account.bank)?.let { client ->
|
||||
client.transferMoneyAsync(data) { response ->
|
||||
if (response.successful) {
|
||||
updateBankAccountTransactionsAsync(account, true)
|
||||
updateAccountTransactionsAsync(account, true)
|
||||
}
|
||||
|
||||
callback(response)
|
||||
|
@ -492,7 +492,7 @@ open class BankingPresenter(
|
|||
|
||||
if (invoiceData.potentialTotalAmount != null || invoiceData.potentialIban != null) { // if at least an amount or IBAN could get extracted
|
||||
val transferMoneyData = TransferMoneyData(
|
||||
bankAccounts.first(), "",
|
||||
allAccounts.first(), "",
|
||||
invoiceData.potentialIban ?: "",
|
||||
invoiceData.potentialBic ?: "",
|
||||
invoiceData.potentialTotalAmount ?: BigDecimal.Zero, "")
|
||||
|
@ -586,7 +586,7 @@ open class BankingPresenter(
|
|||
|
||||
|
||||
open fun searchSelectedAccountTransactions(query: String): List<IAccountTransaction> {
|
||||
return searchAccountTransactions(query, selectedBankAccountsAccountTransactions)
|
||||
return searchAccountTransactions(query, selectedAccountsTransactions)
|
||||
}
|
||||
|
||||
open fun searchAccountTransactions(query: String, transactions: List<IAccountTransaction>): List<IAccountTransaction> {
|
||||
|
@ -604,13 +604,13 @@ open class BankingPresenter(
|
|||
}
|
||||
|
||||
|
||||
open fun getMessageLogForAccounts(customers: List<TypedCustomer>): List<String> {
|
||||
val logEntries = customers.flatMap {
|
||||
getBankingClientForAccount(it)?.messageLogWithoutSensitiveData ?: listOf()
|
||||
open fun getMessageLogForAccounts(banks: List<TypedBankData>): List<String> {
|
||||
val logEntries = banks.flatMap {
|
||||
getBankingClientForBank(it)?.messageLogWithoutSensitiveData ?: listOf()
|
||||
}
|
||||
|
||||
return logEntries.map { entry ->
|
||||
MessageLogEntryDateFormatter.format(entry.time) + " " + entry.customer.bankCode + " " + entry.message
|
||||
MessageLogEntryDateFormatter.format(entry.time) + " " + entry.bank.bankCode + " " + entry.message
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -628,122 +628,122 @@ open class BankingPresenter(
|
|||
}
|
||||
|
||||
|
||||
protected open fun getBankingClientForAccount(customer: ICustomer<*, *>): IBankingClient? {
|
||||
return bankingClientsForAccounts.get(customer as TypedCustomer)
|
||||
protected open fun getBankingClientForBank(bank: IBankData<*, *>): IBankingClient? {
|
||||
return bankingClientsForBanks.get(bank as TypedBankData)
|
||||
}
|
||||
|
||||
|
||||
open val selectedBankAccounts: List<TypedBankAccount>
|
||||
get() = ArrayList(selectedBankAccountsField)
|
||||
open val selectedAccounts: List<TypedBankAccount>
|
||||
get() = ArrayList(_selectedAccounts)
|
||||
|
||||
open val selectedBankAccountsAccountTransactions: List<IAccountTransaction>
|
||||
get() = getAccountTransactionsForBankAccounts(selectedBankAccounts)
|
||||
open val selectedAccountsTransactions: List<IAccountTransaction>
|
||||
get() = getTransactionsForAccounts(selectedAccounts)
|
||||
|
||||
open val balanceOfSelectedBankAccounts: BigDecimal
|
||||
get() = sumBalance(selectedBankAccounts.map { it.balance })
|
||||
open val balanceOfSelectedAccounts: BigDecimal
|
||||
get() = sumBalance(selectedAccounts.map { it.balance })
|
||||
|
||||
open val selectedBankAccountsForWhichNotAllTransactionsHaveBeenFetched: List<TypedBankAccount>
|
||||
get() = selectedBankAccounts.filter { it.haveAllTransactionsBeenFetched == false }
|
||||
open val selectedAccountsForWhichNotAllTransactionsHaveBeenFetched: List<TypedBankAccount>
|
||||
get() = selectedAccounts.filter { it.haveAllTransactionsBeenFetched == false }
|
||||
|
||||
open val selectedBankAccountsTransactionRetrievalState: TransactionsRetrievalState
|
||||
get() = getAccountsTransactionRetrievalState(selectedBankAccounts)
|
||||
open val selectedAccountsTransactionRetrievalState: TransactionsRetrievalState
|
||||
get() = getAccountsTransactionRetrievalState(selectedAccounts)
|
||||
|
||||
|
||||
open val areAllAccountSelected: Boolean
|
||||
get() = selectedAccountType == SelectedAccountType.AllAccounts
|
||||
|
||||
open fun isSingleSelectedAccount(customer: TypedCustomer): Boolean {
|
||||
open fun isSingleSelectedBank(bank: TypedBankData): Boolean {
|
||||
return selectedAccountType == SelectedAccountType.SingleBank
|
||||
&& _selectedAccounts.map { it.bank }.toSet().containsExactly(bank)
|
||||
}
|
||||
|
||||
open fun isSingleSelectedAccount(account: TypedBankAccount): Boolean {
|
||||
return selectedAccountType == SelectedAccountType.SingleAccount
|
||||
&& selectedBankAccountsField.map { it.customer }.toSet().containsExactly(customer)
|
||||
&& _selectedAccounts.containsExactly(account)
|
||||
}
|
||||
|
||||
open fun isSingleSelectedBankAccount(bankAccount: TypedBankAccount): Boolean {
|
||||
return selectedAccountType == SelectedAccountType.SingleBankAccount
|
||||
&& selectedBankAccountsField.containsExactly(bankAccount)
|
||||
}
|
||||
|
||||
open fun selectedAllBankAccounts() {
|
||||
open fun selectedAllAccounts() {
|
||||
selectedAccountType = SelectedAccountType.AllAccounts
|
||||
|
||||
setSelectedBankAccounts(bankAccounts)
|
||||
setSelectedAccounts(allAccounts)
|
||||
}
|
||||
|
||||
open fun selectedAccount(customer: TypedCustomer) {
|
||||
open fun selectedBank(bank: TypedBankData) {
|
||||
selectedAccountType = SelectedAccountType.SingleBank
|
||||
|
||||
setSelectedAccounts(bank.accounts)
|
||||
}
|
||||
|
||||
open fun selectedAccount(account: TypedBankAccount) {
|
||||
selectedAccountType = SelectedAccountType.SingleAccount
|
||||
|
||||
setSelectedBankAccounts(customer.accounts)
|
||||
setSelectedAccounts(listOf(account))
|
||||
}
|
||||
|
||||
open fun selectedBankAccount(bankAccount: TypedBankAccount) {
|
||||
selectedAccountType = SelectedAccountType.SingleBankAccount
|
||||
protected open fun setSelectedAccounts(accounts: List<TypedBankAccount>) {
|
||||
this._selectedAccounts = ArrayList(accounts) // make a copy
|
||||
|
||||
setSelectedBankAccounts(listOf(bankAccount))
|
||||
}
|
||||
|
||||
protected open fun setSelectedBankAccounts(bankAccounts: List<TypedBankAccount>) {
|
||||
this.selectedBankAccountsField = ArrayList(bankAccounts) // make a copy
|
||||
|
||||
callSelectedBankAccountsChangedListeners(selectedBankAccountsField)
|
||||
callSelectedAccountsChangedListeners(_selectedAccounts)
|
||||
}
|
||||
|
||||
|
||||
open val customers: List<TypedCustomer>
|
||||
get() = bankingClientsForAccounts.keys.toList()
|
||||
open val allBanks: List<TypedBankData>
|
||||
get() = bankingClientsForBanks.keys.toList()
|
||||
|
||||
open val bankAccounts: List<TypedBankAccount>
|
||||
get() = customers.flatMap { it.accounts }
|
||||
open val allAccounts: List<TypedBankAccount>
|
||||
get() = allBanks.flatMap { it.accounts }
|
||||
|
||||
open val allTransactions: List<IAccountTransaction>
|
||||
get() = getAccountTransactionsForBankAccounts(bankAccounts)
|
||||
get() = getTransactionsForAccounts(allAccounts)
|
||||
|
||||
open val balanceOfAllAccounts: BigDecimal
|
||||
get() = getBalanceForAccounts(customers)
|
||||
get() = getBalanceForBanks(allBanks)
|
||||
|
||||
|
||||
open val bankAccountsSupportingRetrievingAccountTransactions: List<TypedBankAccount>
|
||||
get() = bankAccounts.filter { it.supportsRetrievingAccountTransactions }
|
||||
open val accountsSupportingRetrievingAccountTransactions: List<TypedBankAccount>
|
||||
get() = allAccounts.filter { it.supportsRetrievingAccountTransactions }
|
||||
|
||||
open val hasBankAccountsSupportingRetrievingAccountTransactions: Boolean
|
||||
get() = doBankAccountsSupportRetrievingAccountTransactions(bankAccounts)
|
||||
open val hasAccountsSupportingRetrievingTransactions: Boolean
|
||||
get() = doAccountsSupportRetrievingTransactions(allAccounts)
|
||||
|
||||
open val doSelectedBankAccountsSupportRetrievingAccountTransactions: Boolean
|
||||
get() = doBankAccountsSupportRetrievingAccountTransactions(selectedBankAccounts)
|
||||
open val doSelectedAccountsSupportRetrievingTransactions: Boolean
|
||||
get() = doAccountsSupportRetrievingTransactions(selectedAccounts)
|
||||
|
||||
open fun doBankAccountsSupportRetrievingAccountTransactions(bankAccounts: List<TypedBankAccount>): Boolean {
|
||||
return bankAccounts.firstOrNull { it.supportsRetrievingAccountTransactions } != null
|
||||
open fun doAccountsSupportRetrievingTransactions(accounts: List<TypedBankAccount>): Boolean {
|
||||
return accounts.firstOrNull { it.supportsRetrievingAccountTransactions } != null
|
||||
}
|
||||
|
||||
|
||||
open val bankAccountsSupportingRetrievingBalance: List<TypedBankAccount>
|
||||
get() = bankAccounts.filter { it.supportsRetrievingBalance }
|
||||
open val accountsSupportingRetrievingBalance: List<TypedBankAccount>
|
||||
get() = allAccounts.filter { it.supportsRetrievingBalance }
|
||||
|
||||
open val hasBankAccountsSupportingRetrievingBalance: Boolean
|
||||
get() = doBankAccountsSupportRetrievingBalance(bankAccounts)
|
||||
open val hasAccountsSupportingRetrievingBalance: Boolean
|
||||
get() = doAccountsSupportRetrievingBalance(allAccounts)
|
||||
|
||||
open val doSelectedBankAccountsSupportRetrievingBalance: Boolean
|
||||
get() = doBankAccountsSupportRetrievingBalance(selectedBankAccounts)
|
||||
open val doSelectedAccountsSupportRetrievingBalance: Boolean
|
||||
get() = doAccountsSupportRetrievingBalance(selectedAccounts)
|
||||
|
||||
open fun doBankAccountsSupportRetrievingBalance(bankAccounts: List<TypedBankAccount>): Boolean {
|
||||
return bankAccounts.firstOrNull { it.supportsRetrievingBalance } != null
|
||||
open fun doAccountsSupportRetrievingBalance(accounts: List<TypedBankAccount>): Boolean {
|
||||
return accounts.firstOrNull { it.supportsRetrievingBalance } != null
|
||||
}
|
||||
|
||||
|
||||
open val bankAccountsSupportingTransferringMoney: List<TypedBankAccount>
|
||||
get() = bankAccounts.filter { it.supportsTransferringMoney }
|
||||
open val accountsSupportingTransferringMoney: List<TypedBankAccount>
|
||||
get() = allAccounts.filter { it.supportsTransferringMoney }
|
||||
|
||||
open val hasBankAccountsSupportTransferringMoney: Boolean
|
||||
get() = doBankAccountsSupportTransferringMoney(bankAccounts)
|
||||
open val hasAccountsSupportTransferringMoney: Boolean
|
||||
get() = doAccountsSupportTransferringMoney(allAccounts)
|
||||
|
||||
open val doSelectedBankAccountsSupportTransferringMoney: Boolean
|
||||
get() = doBankAccountsSupportTransferringMoney(selectedBankAccounts)
|
||||
open val doSelectedAccountsSupportTransferringMoney: Boolean
|
||||
get() = doAccountsSupportTransferringMoney(selectedAccounts)
|
||||
|
||||
open fun doBankAccountsSupportTransferringMoney(bankAccounts: List<TypedBankAccount>): Boolean {
|
||||
return bankAccounts.firstOrNull { it.supportsTransferringMoney } != null
|
||||
open fun doAccountsSupportTransferringMoney(account: List<TypedBankAccount>): Boolean {
|
||||
return account.firstOrNull { it.supportsTransferringMoney } != null
|
||||
}
|
||||
|
||||
|
||||
protected open fun getAccountTransactionsForBankAccounts(bankAccounts: Collection<TypedBankAccount>): List<IAccountTransaction> {
|
||||
return bankAccounts.flatMap { it.bookedTransactions }.sortedByDescending { it.valueDate.millisSinceEpoch } // TODO: someday add unbooked transactions
|
||||
protected open fun getTransactionsForAccounts(accounts: Collection<TypedBankAccount>): List<IAccountTransaction> {
|
||||
return accounts.flatMap { it.bookedTransactions }.sortedByDescending { it.valueDate.millisSinceEpoch } // TODO: someday add unbooked transactions
|
||||
}
|
||||
|
||||
protected open fun getAccountsTransactionRetrievalState(accounts: List<TypedBankAccount>): TransactionsRetrievalState {
|
||||
|
@ -788,8 +788,8 @@ open class BankingPresenter(
|
|||
return TransactionsRetrievalState.NeverRetrievedTransactions
|
||||
}
|
||||
|
||||
protected open fun getBalanceForAccounts(customers: Collection<TypedCustomer>): BigDecimal {
|
||||
return customers.map { it.balance }.sum()
|
||||
protected open fun getBalanceForBanks(banks: Collection<TypedBankData>): BigDecimal {
|
||||
return banks.map { it.balance }.sum()
|
||||
}
|
||||
|
||||
protected open fun sumBalance(singleBalances: Collection<BigDecimal>): BigDecimal {
|
||||
|
@ -797,7 +797,7 @@ open class BankingPresenter(
|
|||
}
|
||||
|
||||
|
||||
open fun getTanMediaForTanMethod(bank: TypedCustomer, tanMethod: TanMethod): List<TanMedium> {
|
||||
open fun getTanMediaForTanMethod(bank: TypedBankData, tanMethod: TanMethod): List<TanMedium> {
|
||||
if (ChipTanTanMethods.contains(tanMethod.type)) {
|
||||
return bank.tanMediaSorted.filterIsInstance<TanGeneratorTanMedium>()
|
||||
}
|
||||
|
@ -839,19 +839,19 @@ open class BankingPresenter(
|
|||
}
|
||||
|
||||
|
||||
open fun addAccountsChangedListener(listener: (List<TypedCustomer>) -> Unit): Boolean {
|
||||
return accountsChangedListeners.add(listener)
|
||||
open fun addBanksChangedListener(listener: (List<TypedBankData>) -> Unit): Boolean {
|
||||
return banksChangedListeners.add(listener)
|
||||
}
|
||||
|
||||
open fun removeAccountsChangedListener(listener: (List<TypedCustomer>) -> Unit): Boolean {
|
||||
return accountsChangedListeners.add(listener)
|
||||
open fun removeBanksChangedListener(listener: (List<TypedBankData>) -> Unit): Boolean {
|
||||
return banksChangedListeners.add(listener)
|
||||
}
|
||||
|
||||
protected open fun callAccountsChangedListeners() {
|
||||
val accounts = ArrayList(this.customers)
|
||||
protected open fun callBanksChangedListeners() {
|
||||
val banks = ArrayList(this.allBanks)
|
||||
|
||||
ArrayList(accountsChangedListeners).forEach {
|
||||
it(accounts) // TODO: use RxJava for this
|
||||
ArrayList(banksChangedListeners).forEach {
|
||||
it(banks) // TODO: use RxJava for this
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -871,19 +871,19 @@ open class BankingPresenter(
|
|||
}
|
||||
|
||||
|
||||
open fun addSelectedBankAccountsChangedListener(listener: (List<TypedBankAccount>) -> Unit): Boolean {
|
||||
return selectedBankAccountsChangedListeners.add(listener)
|
||||
open fun addSelectedAccountsChangedListener(listener: (List<TypedBankAccount>) -> Unit): Boolean {
|
||||
return selectedAccountsChangedListeners.add(listener)
|
||||
}
|
||||
|
||||
open fun removeSelectedBankAccountsChangedListener(listener: (List<TypedBankAccount>) -> Unit): Boolean {
|
||||
return selectedBankAccountsChangedListeners.add(listener)
|
||||
open fun removeSelectedAccountsChangedListener(listener: (List<TypedBankAccount>) -> Unit): Boolean {
|
||||
return selectedAccountsChangedListeners.add(listener)
|
||||
}
|
||||
|
||||
protected open fun callSelectedBankAccountsChangedListeners(selectedBankAccounts: List<TypedBankAccount>) {
|
||||
val selectedBankAccounts = this.selectedBankAccounts
|
||||
protected open fun callSelectedAccountsChangedListeners(selectedAccounts: List<TypedBankAccount>) {
|
||||
val accounts = ArrayList(selectedAccounts)
|
||||
|
||||
ArrayList(selectedBankAccountsChangedListeners).forEach {
|
||||
it(selectedBankAccounts) // TODO: use RxJava for this
|
||||
ArrayList(selectedAccountsChangedListeners).forEach {
|
||||
it(accounts) // TODO: use RxJava for this
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -57,10 +57,10 @@
|
|||
<attribute name="supportsTransferringMoney" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||
<attribute name="type" attributeType="String"/>
|
||||
<attribute name="userSetDisplayName" optional="YES" attributeType="String"/>
|
||||
<relationship name="customer" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="PersistedCustomer" inverseName="accounts" inverseEntity="PersistedCustomer"/>
|
||||
<relationship name="bank" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="PersistedBankData" inverseName="accounts" inverseEntity="PersistedBankData"/>
|
||||
<relationship name="transactions" toMany="YES" deletionRule="Cascade" destinationEntity="PersistedAccountTransaction" inverseName="account" inverseEntity="PersistedAccountTransaction"/>
|
||||
</entity>
|
||||
<entity name="PersistedCustomer" representedClassName="PersistedCustomer" syncable="YES" codeGenerationType="class">
|
||||
<entity name="PersistedBankData" representedClassName="PersistedBankData" syncable="YES" codeGenerationType="class">
|
||||
<attribute name="bankCode" attributeType="String"/>
|
||||
<attribute name="bankName" attributeType="String"/>
|
||||
<attribute name="bic" attributeType="String"/>
|
||||
|
@ -74,7 +74,7 @@
|
|||
<attribute name="selectedTanMethodCode" optional="YES" attributeType="String"/>
|
||||
<attribute name="userId" attributeType="String"/>
|
||||
<attribute name="userSetDisplayName" optional="YES" attributeType="String"/>
|
||||
<relationship name="accounts" toMany="YES" deletionRule="Cascade" ordered="YES" destinationEntity="PersistedBankAccount" inverseName="customer" inverseEntity="PersistedBankAccount"/>
|
||||
<relationship name="accounts" toMany="YES" deletionRule="Cascade" ordered="YES" destinationEntity="PersistedBankAccount" inverseName="bank" inverseEntity="PersistedBankAccount"/>
|
||||
<relationship name="supportedTanMethods" toMany="YES" deletionRule="Cascade" ordered="YES" destinationEntity="PersistedTanMethod"/>
|
||||
<relationship name="tanMedia" optional="YES" toMany="YES" deletionRule="Cascade" ordered="YES" destinationEntity="PersistedTanMedium"/>
|
||||
</entity>
|
||||
|
@ -92,7 +92,7 @@
|
|||
<elements>
|
||||
<element name="PersistedAccountTransaction" positionX="-36" positionY="45" width="128" height="553"/>
|
||||
<element name="PersistedBankAccount" positionX="-54" positionY="63" width="128" height="373"/>
|
||||
<element name="PersistedCustomer" positionX="-63" positionY="-18" width="128" height="283"/>
|
||||
<element name="PersistedBankData" positionX="-63" positionY="-18" width="128" height="283"/>
|
||||
<element name="PersistedTanMedium" positionX="-45" positionY="144" width="128" height="28"/>
|
||||
<element name="PersistedTanMethod" positionX="-54" positionY="135" width="128" height="118"/>
|
||||
</elements>
|
||||
|
|
|
@ -15,20 +15,20 @@ let previewImageTanChallenge = ImageTanChallenge(image: TanImage(mimeType: "imag
|
|||
let previewFlickerCodeTanChallenge = FlickerCodeTanChallenge(flickerCode: FlickerCode(challengeHHD_UC: "", parsedDataSet: "", decodingError: nil), messageToShowToUser: "", tanMethod: previewTanMethods[0])
|
||||
|
||||
|
||||
func createPreviewBanks() -> [ICustomer] {
|
||||
let bank1 = Customer(bankCode: "", customerId: "", password: "", finTsServerAddress: "", bankName: "Abzockbank", bic: "", customerName: "Marieke Musterfrau", userId: "", iconUrl: "", accounts: [])
|
||||
func createPreviewBanks() -> [IBankData] {
|
||||
let bank1 = BankData(bankCode: "", customerId: "", password: "", finTsServerAddress: "", bankName: "Abzockbank", bic: "", customerName: "Marieke Musterfrau", userId: "", iconUrl: "", accounts: [])
|
||||
|
||||
bank1.accounts = [
|
||||
BankAccount(customer: bank1, productName: "Girokonto", identifier: "1234567890"),
|
||||
BankAccount(bank: bank1, productName: "Girokonto", identifier: "1234567890"),
|
||||
|
||||
BankAccount(customer: bank1, productName: "Tagesgeld Minus", identifier: "0987654321")
|
||||
BankAccount(bank: bank1, productName: "Tagesgeld Minus", identifier: "0987654321")
|
||||
]
|
||||
|
||||
|
||||
let bank2 = Customer(bankCode: "", customerId: "", password: "", finTsServerAddress: "", bankName: "Kundenverarschebank", bic: "", customerName: "Marieke Musterfrau", userId: "", iconUrl: "", accounts: [])
|
||||
let bank2 = BankData(bankCode: "", customerId: "", password: "", finTsServerAddress: "", bankName: "Kundenverarschebank", bic: "", customerName: "Marieke Musterfrau", userId: "", iconUrl: "", accounts: [])
|
||||
|
||||
bank2.accounts = [
|
||||
BankAccount(customer: bank2, productName: "Girokonto", identifier: "1234567890")
|
||||
BankAccount(bank: bank2, productName: "Girokonto", identifier: "1234567890")
|
||||
]
|
||||
|
||||
return [ bank1, bank2 ]
|
||||
|
|
|
@ -70,7 +70,7 @@ extension KeychainPasswordItem {
|
|||
}
|
||||
|
||||
|
||||
extension Customer : Identifiable {
|
||||
extension BankData : Identifiable {
|
||||
|
||||
public var id: String { technicalId }
|
||||
|
||||
|
@ -89,11 +89,11 @@ extension AccountTransaction : Identifiable {
|
|||
}
|
||||
|
||||
|
||||
func ==(lhs: ICustomer, rhs: ICustomer) -> Bool {
|
||||
func ==(lhs: IBankData, rhs: IBankData) -> Bool {
|
||||
return lhs.technicalId == rhs.technicalId
|
||||
}
|
||||
|
||||
func !=(lhs: ICustomer, rhs: ICustomer) -> Bool {
|
||||
func !=(lhs: IBankData, rhs: IBankData) -> Bool {
|
||||
return lhs.technicalId != rhs.technicalId
|
||||
}
|
||||
|
||||
|
@ -114,7 +114,7 @@ func !=(lhs: IAccountTransaction, rhs: IAccountTransaction) -> Bool {
|
|||
}
|
||||
|
||||
|
||||
extension Array where Element == ICustomer {
|
||||
extension Array where Element == IBankData {
|
||||
|
||||
func sumBalances() -> CommonBigDecimal {
|
||||
return CommonBigDecimal(decimal_: self.map { $0.balance.decimal }.sum())
|
||||
|
|
|
@ -6,8 +6,8 @@ class AppData : ObservableObject {
|
|||
|
||||
@Inject private var presenter: BankingPresenterSwift
|
||||
|
||||
@Published var banks: [ICustomer] = []
|
||||
@Published var banksSorted: [ICustomer] = []
|
||||
@Published var banks: [IBankData] = []
|
||||
@Published var banksSorted: [IBankData] = []
|
||||
|
||||
@Published var hasAtLeastOneAccountBeenAdded: Bool = false
|
||||
|
||||
|
@ -17,14 +17,14 @@ class AppData : ObservableObject {
|
|||
init() {
|
||||
setFieldsForBanks()
|
||||
|
||||
presenter.addAccountsChangedListener { banks in
|
||||
presenter.addBanksChangedListener { banks in
|
||||
self.setFieldsForBanks()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private func setFieldsForBanks() {
|
||||
self.banks = presenter.customers
|
||||
self.banks = presenter.allBanks
|
||||
self.banksSorted = banks.sortedByDisplayIndex()
|
||||
|
||||
hasAtLeastOneAccountBeenAdded = banks.isNotEmpty
|
||||
|
|
|
@ -19,74 +19,74 @@ class CoreDataBankingPersistence: IBankingPersistence, IRemitteeSearcher {
|
|||
}
|
||||
|
||||
|
||||
func saveOrUpdateAccount(customer: ICustomer, allCustomers: [ICustomer]) {
|
||||
func saveOrUpdateBank(bank: IBankData, allBanks: [IBankData]) {
|
||||
do {
|
||||
let mapped = mapper.map(customer, context)
|
||||
let mapped = mapper.map(bank, context)
|
||||
|
||||
if customer.technicalId.isCoreDataId == false { // an unpersisted bank (but check should not be necessary)
|
||||
if bank.technicalId.isCoreDataId == false { // an unpersisted bank (but check should not be necessary)
|
||||
context.insert(mapped)
|
||||
}
|
||||
|
||||
try context.save()
|
||||
|
||||
setIds(customer, mapped)
|
||||
setIds(bank, mapped)
|
||||
} catch {
|
||||
NSLog("Could not save Customer \(customer): \(error)")
|
||||
NSLog("Could not save bank \(bank): \(error)")
|
||||
}
|
||||
}
|
||||
|
||||
private func setIds(_ customer: ICustomer, _ mappedCustomer: PersistedCustomer) {
|
||||
customer.technicalId = mappedCustomer.objectIDAsString
|
||||
private func setIds(_ bank: IBankData, _ mappedBank: PersistedBankData) {
|
||||
bank.technicalId = mappedBank.objectIDAsString
|
||||
|
||||
for account in customer.accounts {
|
||||
if let mappedAccount = mappedCustomer.accounts?.first { ($0 as! PersistedBankAccount).identifier == account.identifier} as? PersistedBankAccount {
|
||||
for account in bank.accounts {
|
||||
if let mappedAccount = mappedBank.accounts?.first { ($0 as! PersistedBankAccount).identifier == account.identifier} as? PersistedBankAccount {
|
||||
account.technicalId = mappedAccount.objectIDAsString
|
||||
}
|
||||
}
|
||||
|
||||
for tanMethod in customer.supportedTanMethods {
|
||||
if let mappedTanMethod = mappedCustomer.supportedTanMethods?.first { ($0 as! PersistedTanMethod).bankInternalMethodCode == tanMethod.bankInternalMethodCode } as? PersistedTanMethod {
|
||||
for tanMethod in bank.supportedTanMethods {
|
||||
if let mappedTanMethod = mappedBank.supportedTanMethods?.first { ($0 as! PersistedTanMethod).bankInternalMethodCode == tanMethod.bankInternalMethodCode } as? PersistedTanMethod {
|
||||
tanMethod.technicalId = mappedTanMethod.objectIDAsString
|
||||
}
|
||||
}
|
||||
|
||||
for tanMedium in customer.tanMedia {
|
||||
if let mappedTanMedium = mappedCustomer.tanMedia?.first { ($0 as! PersistedTanMedium).displayName == tanMedium.displayName } as? PersistedTanMedium {
|
||||
for tanMedium in bank.tanMedia {
|
||||
if let mappedTanMedium = mappedBank.tanMedia?.first { ($0 as! PersistedTanMedium).displayName == tanMedium.displayName } as? PersistedTanMedium {
|
||||
tanMedium.technicalId = mappedTanMedium.objectIDAsString
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func readPersistedAccounts_() -> [ICustomer] {
|
||||
var customers: [PersistedCustomer] = []
|
||||
func readPersistedBanks_() -> [IBankData] {
|
||||
var banks: [PersistedBankData] = []
|
||||
|
||||
do {
|
||||
let request: NSFetchRequest<PersistedCustomer> = PersistedCustomer.fetchRequest()
|
||||
let request: NSFetchRequest<PersistedBankData> = PersistedBankData.fetchRequest()
|
||||
request.returnsObjectsAsFaults = false
|
||||
|
||||
try customers = context.fetch(request)
|
||||
try banks = context.fetch(request)
|
||||
} catch {
|
||||
NSLog("Could not request Customers: \(error)")
|
||||
NSLog("Could not request banks: \(error)")
|
||||
}
|
||||
|
||||
return customers.map( { mapper.map($0) } )
|
||||
return banks.map( { mapper.map($0) } )
|
||||
}
|
||||
|
||||
func deleteAccount(customer: ICustomer, allCustomers: [ICustomer]) {
|
||||
func deleteBank(bank: IBankData, allBanks: [IBankData]) {
|
||||
do {
|
||||
let mapped = mapper.map(customer, context)
|
||||
let mapped = mapper.map(bank, context)
|
||||
|
||||
context.delete(mapped)
|
||||
|
||||
try context.save()
|
||||
} catch {
|
||||
NSLog("Could not delete Customer \(customer): \(error)")
|
||||
NSLog("Could not delete Bank \(bank): \(error)")
|
||||
}
|
||||
}
|
||||
|
||||
func saveOrUpdateAccountTransactions(bankAccount: IBankAccount, transactions: [IAccountTransaction]) {
|
||||
if let persistedAccount = context.objectByID(bankAccount.technicalId) as? PersistedBankAccount {
|
||||
func saveOrUpdateAccountTransactions(account: IBankAccount, transactions: [IAccountTransaction]) {
|
||||
if let persistedAccount = context.objectByID(account.technicalId) as? PersistedBankAccount {
|
||||
for transaction in transactions {
|
||||
if transaction.technicalId.isCoreDataId == false { // TODO: or also update already persisted transactions?
|
||||
do {
|
||||
|
@ -96,7 +96,7 @@ class CoreDataBankingPersistence: IBankingPersistence, IRemitteeSearcher {
|
|||
|
||||
transaction.technicalId = mappedTransaction.objectIDAsString
|
||||
} catch {
|
||||
NSLog("Could not save transaction \(transaction.buildTransactionIdentifier()) of account \(bankAccount.displayName): \(error)")
|
||||
NSLog("Could not save transaction \(transaction.buildTransactionIdentifier()) of account \(account.displayName): \(error)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -137,7 +137,7 @@ class CoreDataBankingPersistence: IBankingPersistence, IRemitteeSearcher {
|
|||
|
||||
try transactions = context.fetch(request)
|
||||
} catch {
|
||||
NSLog("Could not request Customers: \(error)")
|
||||
NSLog("Could not request banks: \(error)")
|
||||
}
|
||||
|
||||
let remittees = transactions
|
||||
|
@ -152,13 +152,13 @@ class CoreDataBankingPersistence: IBankingPersistence, IRemitteeSearcher {
|
|||
|
||||
func deleteAll() {
|
||||
do {
|
||||
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "PersistedCustomer")
|
||||
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "PersistedBankData")
|
||||
|
||||
let deleteAll = NSBatchDeleteRequest(fetchRequest: request)
|
||||
|
||||
try context.execute(deleteAll)
|
||||
} catch {
|
||||
NSLog("Could not delete all Customers: \(error)")
|
||||
NSLog("Could not delete all banks: \(error)")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,15 +6,15 @@ class EnterTanState : Identifiable {
|
|||
|
||||
let id: Foundation.UUID = UUID()
|
||||
|
||||
let customer: ICustomer
|
||||
let bank: IBankData
|
||||
|
||||
let tanChallenge: TanChallenge
|
||||
|
||||
let callback: (EnterTanResult) -> Void
|
||||
|
||||
|
||||
init(_ customer: ICustomer, _ tanChallenge: TanChallenge, _ callback: @escaping (EnterTanResult) -> Void) {
|
||||
self.customer = customer
|
||||
init(_ bank: IBankData, _ tanChallenge: TanChallenge, _ callback: @escaping (EnterTanResult) -> Void) {
|
||||
self.bank = bank
|
||||
self.tanChallenge = tanChallenge
|
||||
self.callback = callback
|
||||
}
|
||||
|
|
|
@ -5,60 +5,60 @@ import BankingUiSwift
|
|||
|
||||
class Mapper {
|
||||
|
||||
func map(_ customer: PersistedCustomer) -> ICustomer {
|
||||
let mapped = Customer(bankCode: map(customer.bankCode), customerId: map(customer.customerId), password: map(customer.password), finTsServerAddress: map(customer.finTsServerAddress), bankName: map(customer.bankName), bic: map(customer.bic), customerName: map(customer.customerName), userId: map(customer.userId), iconUrl: customer.iconUrl, accounts: [])
|
||||
func map(_ bank: PersistedBankData) -> IBankData {
|
||||
let mapped = BankData(bankCode: map(bank.bankCode), customerId: map(bank.customerId), password: map(bank.password), finTsServerAddress: map(bank.finTsServerAddress), bankName: map(bank.bankName), bic: map(bank.bic), customerName: map(bank.customerName), userId: map(bank.userId), iconUrl: bank.iconUrl, accounts: [])
|
||||
|
||||
mapped.countDaysForWhichTransactionsAreKept = mapToInt(customer.countDaysForWhichTransactionsAreKept)
|
||||
mapped.countDaysForWhichTransactionsAreKept = mapToInt(bank.countDaysForWhichTransactionsAreKept)
|
||||
|
||||
mapped.userSetDisplayName = customer.userSetDisplayName
|
||||
mapped.displayIndex = customer.displayIndex
|
||||
mapped.userSetDisplayName = bank.userSetDisplayName
|
||||
mapped.displayIndex = bank.displayIndex
|
||||
|
||||
mapped.accounts = map(mapped, customer.accounts?.array as? [PersistedBankAccount])
|
||||
mapped.accounts = map(mapped, bank.accounts?.array as? [PersistedBankAccount])
|
||||
|
||||
mapped.supportedTanMethods = map(customer.supportedTanMethods?.array as? [PersistedTanMethod])
|
||||
mapped.selectedTanMethod = mapped.supportedTanMethods.first(where: { $0.bankInternalMethodCode == customer.selectedTanMethodCode })
|
||||
mapped.supportedTanMethods = map(bank.supportedTanMethods?.array as? [PersistedTanMethod])
|
||||
mapped.selectedTanMethod = mapped.supportedTanMethods.first(where: { $0.bankInternalMethodCode == bank.selectedTanMethodCode })
|
||||
|
||||
mapped.tanMedia = map(customer.tanMedia?.array as? [PersistedTanMedium])
|
||||
mapped.tanMedia = map(bank.tanMedia?.array as? [PersistedTanMedium])
|
||||
|
||||
mapped.technicalId = customer.objectIDAsString
|
||||
mapped.technicalId = bank.objectIDAsString
|
||||
|
||||
return mapped
|
||||
}
|
||||
|
||||
func map(_ customer: ICustomer, _ context: NSManagedObjectContext) -> PersistedCustomer {
|
||||
let mapped = context.objectByID(customer.technicalId) ?? PersistedCustomer(context: context)
|
||||
func map(_ bank: IBankData, _ context: NSManagedObjectContext) -> PersistedBankData {
|
||||
let mapped = context.objectByID(bank.technicalId) ?? PersistedBankData(context: context)
|
||||
|
||||
mapped.bankCode = customer.bankCode
|
||||
mapped.customerId = customer.customerId
|
||||
mapped.password = customer.password
|
||||
mapped.finTsServerAddress = customer.finTsServerAddress
|
||||
mapped.bankName = customer.bankName
|
||||
mapped.bic = customer.bic
|
||||
mapped.customerName = customer.customerName
|
||||
mapped.userId = customer.userId
|
||||
mapped.iconUrl = customer.iconUrl
|
||||
mapped.countDaysForWhichTransactionsAreKept = mapFromInt(customer.countDaysForWhichTransactionsAreKept)
|
||||
mapped.bankCode = bank.bankCode
|
||||
mapped.customerId = bank.customerId
|
||||
mapped.password = bank.password
|
||||
mapped.finTsServerAddress = bank.finTsServerAddress
|
||||
mapped.bankName = bank.bankName
|
||||
mapped.bic = bank.bic
|
||||
mapped.customerName = bank.customerName
|
||||
mapped.userId = bank.userId
|
||||
mapped.iconUrl = bank.iconUrl
|
||||
mapped.countDaysForWhichTransactionsAreKept = mapFromInt(bank.countDaysForWhichTransactionsAreKept)
|
||||
|
||||
mapped.userSetDisplayName = customer.userSetDisplayName
|
||||
mapped.displayIndex = customer.displayIndex
|
||||
mapped.userSetDisplayName = bank.userSetDisplayName
|
||||
mapped.displayIndex = bank.displayIndex
|
||||
|
||||
mapped.accounts = NSOrderedSet(array: map(mapped, customer.accounts, context))
|
||||
mapped.accounts = NSOrderedSet(array: map(mapped, bank.accounts, context))
|
||||
|
||||
mapped.supportedTanMethods = NSOrderedSet(array: map(customer.supportedTanMethods, context))
|
||||
mapped.selectedTanMethodCode = customer.selectedTanMethod?.bankInternalMethodCode
|
||||
mapped.supportedTanMethods = NSOrderedSet(array: map(bank.supportedTanMethods, context))
|
||||
mapped.selectedTanMethodCode = bank.selectedTanMethod?.bankInternalMethodCode
|
||||
|
||||
mapped.tanMedia = NSOrderedSet(array: map(customer.tanMedia, context))
|
||||
mapped.tanMedia = NSOrderedSet(array: map(bank.tanMedia, context))
|
||||
|
||||
return mapped
|
||||
}
|
||||
|
||||
|
||||
func map(_ customer: ICustomer, _ accounts: [PersistedBankAccount]?) -> [IBankAccount] {
|
||||
return accounts?.map( { map(customer, $0) } ) ?? []
|
||||
func map(_ bank: IBankData, _ accounts: [PersistedBankAccount]?) -> [IBankAccount] {
|
||||
return accounts?.map( { map(bank, $0) } ) ?? []
|
||||
}
|
||||
|
||||
func map(_ customer: ICustomer, _ account: PersistedBankAccount) -> IBankAccount {
|
||||
let mapped = BankAccount(customer: customer, identifier: map(account.identifier), accountHolderName: map(account.accountHolderName), iban: account.iban, subAccountNumber: account.subAccountNumber, customerId: map(account.customerId), balance: map(account.balance), currency: map(account.currency), type: map(account.type), productName: account.productName, accountLimit: account.accountLimit, retrievedTransactionsFromOn: map(account.retrievedTransactionsFromOn), retrievedTransactionsUpTo: map(account.retrievedTransactionsUpTo), supportsRetrievingAccountTransactions: account.supportsRetrievingAccountTransactions, supportsRetrievingBalance: account.supportsRetrievingBalance, supportsTransferringMoney: account.supportsTransferringMoney, supportsInstantPaymentMoneyTransfer: account.supportsInstantPaymentMoneyTransfer, bookedTransactions: [], unbookedTransactions: [])
|
||||
func map(_ bank: IBankData, _ account: PersistedBankAccount) -> IBankAccount {
|
||||
let mapped = BankAccount(bank: bank, identifier: map(account.identifier), accountHolderName: map(account.accountHolderName), iban: account.iban, subAccountNumber: account.subAccountNumber, customerId: map(account.customerId), balance: map(account.balance), currency: map(account.currency), type: map(account.type), productName: account.productName, accountLimit: account.accountLimit, retrievedTransactionsFromOn: map(account.retrievedTransactionsFromOn), retrievedTransactionsUpTo: map(account.retrievedTransactionsUpTo), supportsRetrievingAccountTransactions: account.supportsRetrievingAccountTransactions, supportsRetrievingBalance: account.supportsRetrievingBalance, supportsTransferringMoney: account.supportsTransferringMoney, supportsInstantPaymentMoneyTransfer: account.supportsInstantPaymentMoneyTransfer, bookedTransactions: [], unbookedTransactions: [])
|
||||
|
||||
mapped.haveAllTransactionsBeenFetched = account.haveAllTransactionsBeenFetched
|
||||
mapped.isAccountTypeSupported = account.isAccountTypeSupported
|
||||
|
@ -73,14 +73,14 @@ class Mapper {
|
|||
return mapped
|
||||
}
|
||||
|
||||
func map(_ customer: PersistedCustomer, _ accounts: [IBankAccount], _ context: NSManagedObjectContext) -> [PersistedBankAccount] {
|
||||
return accounts.map( { map(customer, $0, context) } )
|
||||
func map(_ bank: PersistedBankData, _ accounts: [IBankAccount], _ context: NSManagedObjectContext) -> [PersistedBankAccount] {
|
||||
return accounts.map( { map(bank, $0, context) } )
|
||||
}
|
||||
|
||||
func map(_ customer: PersistedCustomer, _ account: IBankAccount, _ context: NSManagedObjectContext) -> PersistedBankAccount {
|
||||
func map(_ bank: PersistedBankData, _ account: IBankAccount, _ context: NSManagedObjectContext) -> PersistedBankAccount {
|
||||
let mapped = context.objectByID(account.technicalId) ?? PersistedBankAccount(context: context)
|
||||
|
||||
mapped.customer = customer
|
||||
mapped.bank = bank
|
||||
mapped.identifier = account.identifier
|
||||
mapped.accountHolderName = account.accountHolderName
|
||||
mapped.iban = account.iban
|
||||
|
@ -147,7 +147,7 @@ class Mapper {
|
|||
}
|
||||
|
||||
func map(_ account: IBankAccount, _ transaction: PersistedAccountTransaction) -> IAccountTransaction {
|
||||
let mapped = AccountTransaction(bankAccount: account, amount: map(transaction.amount), currency: map(transaction.currency), unparsedUsage: map(transaction.unparsedUsage), bookingDate: map(transaction.bookingDate), otherPartyName: transaction.otherPartyName, otherPartyBankCode: transaction.otherPartyBankCode, otherPartyAccountId: transaction.otherPartyAccountId, bookingText: transaction.bookingText, valueDate: map(transaction.valueDate), statementNumber: Int32(transaction.statementNumber), sequenceNumber: map(transaction.sequenceNumber), openingBalance: map(transaction.openingBalance), closingBalance: map(transaction.closingBalance), endToEndReference: transaction.endToEndReference, customerReference: transaction.customerReference, mandateReference: transaction.mandateReference, creditorIdentifier: transaction.creditorIdentifier, originatorsIdentificationCode: transaction.originatorsIdentificationCode, compensationAmount: transaction.compensationAmount, originalAmount: transaction.originalAmount, sepaUsage: transaction.sepaUsage, deviantOriginator: transaction.deviantOriginator, deviantRecipient: transaction.deviantRecipient, usageWithNoSpecialType: transaction.usageWithNoSpecialType, primaNotaNumber: transaction.primaNotaNumber, textKeySupplement: transaction.textKeySupplement, currencyType: transaction.currencyType, bookingKey: map(transaction.bookingKey), referenceForTheAccountOwner: map(transaction.referenceForTheAccountOwner), referenceOfTheAccountServicingInstitution: transaction.referenceOfTheAccountServicingInstitution, supplementaryDetails: transaction.supplementaryDetails, transactionReferenceNumber: map(transaction.transactionReferenceNumber), relatedReferenceNumber: transaction.relatedReferenceNumber)
|
||||
let mapped = AccountTransaction(account: account, amount: map(transaction.amount), currency: map(transaction.currency), unparsedUsage: map(transaction.unparsedUsage), bookingDate: map(transaction.bookingDate), otherPartyName: transaction.otherPartyName, otherPartyBankCode: transaction.otherPartyBankCode, otherPartyAccountId: transaction.otherPartyAccountId, bookingText: transaction.bookingText, valueDate: map(transaction.valueDate), statementNumber: Int32(transaction.statementNumber), sequenceNumber: map(transaction.sequenceNumber), openingBalance: map(transaction.openingBalance), closingBalance: map(transaction.closingBalance), endToEndReference: transaction.endToEndReference, customerReference: transaction.customerReference, mandateReference: transaction.mandateReference, creditorIdentifier: transaction.creditorIdentifier, originatorsIdentificationCode: transaction.originatorsIdentificationCode, compensationAmount: transaction.compensationAmount, originalAmount: transaction.originalAmount, sepaUsage: transaction.sepaUsage, deviantOriginator: transaction.deviantOriginator, deviantRecipient: transaction.deviantRecipient, usageWithNoSpecialType: transaction.usageWithNoSpecialType, primaNotaNumber: transaction.primaNotaNumber, textKeySupplement: transaction.textKeySupplement, currencyType: transaction.currencyType, bookingKey: map(transaction.bookingKey), referenceForTheAccountOwner: map(transaction.referenceForTheAccountOwner), referenceOfTheAccountServicingInstitution: transaction.referenceOfTheAccountServicingInstitution, supplementaryDetails: transaction.supplementaryDetails, transactionReferenceNumber: map(transaction.transactionReferenceNumber), relatedReferenceNumber: transaction.relatedReferenceNumber)
|
||||
|
||||
mapped.technicalId = transaction.objectIDAsString
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ extension Message {
|
|||
secondaryButton: .cancel())
|
||||
}
|
||||
|
||||
static func createAskUserToDeleteAccountMessage(_ bank: ICustomer, _ deleteAccount: @escaping (ICustomer) -> Void) -> Message {
|
||||
static func createAskUserToDeleteAccountMessage(_ bank: IBankData, _ deleteAccount: @escaping (IBankData) -> Void) -> Message {
|
||||
return Message(title: Text("Really delete account '\(bank.displayName)'?"),
|
||||
message: Text("All data for this account will be permanently deleted locally."),
|
||||
primaryButton: .destructive(Text("Delete"), action: { deleteAccount(bank) } ),
|
||||
|
|
|
@ -9,8 +9,8 @@ class SwiftUiRouter : IRouter {
|
|||
|
||||
}
|
||||
|
||||
func getTanFromUserFromNonUiThread(customer: ICustomer, tanChallenge: TanChallenge, presenter: BankingPresenter, callback: @escaping (EnterTanResult) -> Void) {
|
||||
let enterTanState = EnterTanState(customer, tanChallenge, callback)
|
||||
func getTanFromUserFromNonUiThread(bank: IBankData, tanChallenge: TanChallenge, presenter: BankingPresenter, callback: @escaping (EnterTanResult) -> Void) {
|
||||
let enterTanState = EnterTanState(bank, tanChallenge, callback)
|
||||
|
||||
SceneDelegate.navigateToView(EnterTanDialog(enterTanState))
|
||||
}
|
||||
|
|
|
@ -53,22 +53,22 @@ struct AccountTransactionsDialog: View {
|
|||
@Inject private var presenter: BankingPresenterSwift
|
||||
|
||||
|
||||
init(allBanks: [ICustomer]) {
|
||||
init(allBanks: [IBankData]) {
|
||||
self.init("All accounts", true)
|
||||
|
||||
presenter.selectedAllBankAccounts()
|
||||
presenter.selectedAllAccounts()
|
||||
}
|
||||
|
||||
init(bank: ICustomer) {
|
||||
init(bank: IBankData) {
|
||||
self.init(bank.displayName, false)
|
||||
|
||||
presenter.selectedAccount(customer: bank)
|
||||
presenter.selectedBank(bank: bank)
|
||||
}
|
||||
|
||||
init(account: IBankAccount) {
|
||||
self.init(account.displayName, false)
|
||||
|
||||
presenter.selectedBankAccount(bankAccount: account)
|
||||
presenter.selectedAccount(account: account)
|
||||
}
|
||||
|
||||
fileprivate init(_ title: String, _ showBankIcons: Bool) {
|
||||
|
@ -168,7 +168,7 @@ struct AccountTransactionsDialog: View {
|
|||
|
||||
|
||||
private func setInitialValues() {
|
||||
self.balanceOfAllTransactions = self.presenter.balanceOfSelectedBankAccounts
|
||||
self.balanceOfAllTransactions = self.presenter.balanceOfSelectedAccounts
|
||||
|
||||
self.filterTransactions("")
|
||||
|
||||
|
@ -176,10 +176,10 @@ struct AccountTransactionsDialog: View {
|
|||
}
|
||||
|
||||
private func setTransactionsView() {
|
||||
let transactionsRetrievalState = presenter.selectedBankAccountsTransactionRetrievalState
|
||||
let transactionsRetrievalState = presenter.selectedAccountsTransactionRetrievalState
|
||||
self.haveTransactionsBeenRetrievedForSelectedAccounts = transactionsRetrievalState == .retrievedtransactions
|
||||
|
||||
self.accountsForWhichNotAllTransactionsHaveBeenFetched = presenter.selectedBankAccountsForWhichNotAllTransactionsHaveBeenFetched
|
||||
self.accountsForWhichNotAllTransactionsHaveBeenFetched = presenter.selectedAccountsForWhichNotAllTransactionsHaveBeenFetched
|
||||
self.haveAllTransactionsBeenFetched = self.accountsForWhichNotAllTransactionsHaveBeenFetched.isEmpty
|
||||
self.showFetchAllTransactionsOverlay = shouldShowFetchAllTransactionsOverlay && haveTransactionsBeenRetrievedForSelectedAccounts
|
||||
|
||||
|
@ -199,10 +199,10 @@ struct AccountTransactionsDialog: View {
|
|||
|
||||
|
||||
private func updateTransactions(_ executingDone: @escaping () -> Void) {
|
||||
presenter.updateSelectedBankAccountTransactionsAsync { response in
|
||||
presenter.updateSelectedAccountsTransactionsAsync { response in
|
||||
executingDone()
|
||||
|
||||
self.balanceOfAllTransactions = self.presenter.balanceOfSelectedBankAccounts
|
||||
self.balanceOfAllTransactions = self.presenter.balanceOfSelectedAccounts
|
||||
|
||||
if response.successful {
|
||||
self.filterTransactions(self.searchText)
|
||||
|
@ -216,9 +216,9 @@ struct AccountTransactionsDialog: View {
|
|||
}
|
||||
|
||||
private func fetchTransactions() {
|
||||
for account in presenter.selectedBankAccounts {
|
||||
for account in presenter.selectedAccounts {
|
||||
if account.haveAllTransactionsBeenFetched {
|
||||
presenter.updateBankAccountTransactionsAsync(bankAccount: account, abortIfTanIsRequired: false, callback: self.handleGetTransactionsResult)
|
||||
presenter.updateAccountTransactionsAsync(account: account, abortIfTanIsRequired: false, callback: self.handleGetTransactionsResult)
|
||||
}
|
||||
else {
|
||||
presenter.fetchAllAccountTransactionsAsync(account: account, callback: self.handleGetTransactionsResult)
|
||||
|
@ -250,7 +250,7 @@ struct AccountTransactionsDialog: View {
|
|||
return "No transactions fetched yet"
|
||||
}
|
||||
else if state == .notransactionsinretrievedperiod {
|
||||
let account = presenter.selectedBankAccounts.first!
|
||||
let account = presenter.selectedAccounts.first!
|
||||
return "There haven't been any transactions in retrieved period from \(mapDate(account.retrievedTransactionsFromOn)) - \(mapDate(account.retrievedTransactionsUpTo))"
|
||||
}
|
||||
else if state == .accountdoesnotsupportfetchingtransactions {
|
||||
|
|
|
@ -99,7 +99,7 @@ struct AddAccountDialog: View {
|
|||
self.closeDialog()
|
||||
|
||||
let authenticationService = AuthenticationService()
|
||||
if self.presenter.customers.count == 1 && authenticationService.authenticationType == .unset {
|
||||
if self.presenter.allBanks.count == 1 && authenticationService.authenticationType == .unset {
|
||||
authenticationService.setAuthenticationType(.none)
|
||||
|
||||
UIAlert("Secure data?", "Secure data with?",
|
||||
|
|
|
@ -10,7 +10,7 @@ struct BankSettingsDialog: View {
|
|||
@Inject private var presenter: BankingPresenterSwift
|
||||
|
||||
|
||||
private let bank: ICustomer
|
||||
private let bank: IBankData
|
||||
|
||||
@State private var displayName: String
|
||||
|
||||
|
@ -32,7 +32,7 @@ struct BankSettingsDialog: View {
|
|||
}
|
||||
|
||||
|
||||
init(_ bank: ICustomer) {
|
||||
init(_ bank: IBankData) {
|
||||
self.bank = bank
|
||||
|
||||
_displayName = State(initialValue: bank.displayName)
|
||||
|
@ -102,7 +102,7 @@ struct BankSettingsDialog: View {
|
|||
func reorderAccounts(from source: IndexSet, to destination: Int) {
|
||||
accountsSorted = accountsSorted.reorder(from: source, to: destination)
|
||||
|
||||
presenter.accountDisplayIndexUpdated(account: bank)
|
||||
presenter.bankDisplayIndexUpdated(bank: bank)
|
||||
}
|
||||
|
||||
|
||||
|
@ -110,8 +110,8 @@ struct BankSettingsDialog: View {
|
|||
self.askUserToDeleteAccountOrSaveChangesMessage = Message.createAskUserToDeleteAccountMessage(bank, self.deleteAccount)
|
||||
}
|
||||
|
||||
func deleteAccount(bank: ICustomer) {
|
||||
presenter.deleteAccount(customer: bank)
|
||||
func deleteAccount(bank: IBankData) {
|
||||
presenter.deleteAccount(bank: bank)
|
||||
|
||||
closeDialog()
|
||||
}
|
||||
|
@ -135,7 +135,7 @@ struct BankSettingsDialog: View {
|
|||
|
||||
bank.selectedTanMethod = selectedTanMethod
|
||||
|
||||
presenter.accountUpdated(bank: bank)
|
||||
presenter.bankUpdated(bank: bank)
|
||||
}
|
||||
|
||||
closeDialog()
|
||||
|
|
|
@ -11,7 +11,7 @@ struct EnterTanDialog: View {
|
|||
|
||||
private var tanChallenge: TanChallenge
|
||||
|
||||
private var customer: ICustomer
|
||||
private var bank: IBankData
|
||||
|
||||
private var customersTanMedia: [TanMedium] = []
|
||||
|
||||
|
@ -50,9 +50,9 @@ struct EnterTanDialog: View {
|
|||
self.state = state
|
||||
|
||||
self.tanChallenge = state.tanChallenge
|
||||
self.customer = state.customer
|
||||
self.bank = state.bank
|
||||
|
||||
self.customersTanMedia = customer.tanMediaSorted
|
||||
self.customersTanMedia = bank.tanMediaSorted
|
||||
|
||||
self.showSelectTanMediumView = self.customersTanMedia.count > 1 // TODO: use isOpticalTanMethod && tanMedia.count > 1
|
||||
|
||||
|
@ -73,7 +73,7 @@ struct EnterTanDialog: View {
|
|||
var body: some View {
|
||||
Form {
|
||||
Section {
|
||||
TanMethodPicker(customer, state.tanChallenge.tanMethod) { selectedTanMethod in
|
||||
TanMethodPicker(bank, state.tanChallenge.tanMethod) { selectedTanMethod in
|
||||
self.selectedTanMethodChanged(selectedTanMethod)
|
||||
}
|
||||
|
||||
|
@ -215,7 +215,7 @@ struct EnterTanDialog: View {
|
|||
|
||||
struct EnterTanDialog_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
let customer = Customer(bankCode: "", customerId: "", password: "", finTsServerAddress: "")
|
||||
let customer = BankData(bankCode: "", customerId: "", password: "", finTsServerAddress: "")
|
||||
customer.supportedTanMethods = previewTanMethods
|
||||
|
||||
customer.tanMedia = previewTanMedia
|
||||
|
|
|
@ -58,7 +58,7 @@ struct SettingsDialog: View {
|
|||
|
||||
data.banksDisplayIndexChanged()
|
||||
|
||||
presenter.allAccountsUpdated()
|
||||
presenter.allBanksUpdated()
|
||||
}
|
||||
|
||||
func deleteBanks(at offsets: IndexSet) {
|
||||
|
@ -68,14 +68,14 @@ struct SettingsDialog: View {
|
|||
}
|
||||
}
|
||||
|
||||
func askUserToDeleteAccount(_ bankToDelete: ICustomer) {
|
||||
func askUserToDeleteAccount(_ bankToDelete: IBankData) {
|
||||
self.askToDeleteAccountMessage = Message.createAskUserToDeleteAccountMessage(bankToDelete, self.deleteAccountWithSecurityChecks)
|
||||
}
|
||||
|
||||
func deleteAccountWithSecurityChecks(_ bankToDelete: ICustomer) {
|
||||
func deleteAccountWithSecurityChecks(_ bankToDelete: IBankData) {
|
||||
// don't know why but when deleting last bank application crashes if we don't delete bank async
|
||||
DispatchQueue.main.async {
|
||||
if self.presenter.customers.count == 1 {
|
||||
if self.presenter.allBanks.count == 1 {
|
||||
self.editMode?.wrappedValue = .inactive
|
||||
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
|
||||
|
@ -88,8 +88,8 @@ struct SettingsDialog: View {
|
|||
}
|
||||
}
|
||||
|
||||
private func deleteAccount(_ bankToDelete: ICustomer) {
|
||||
self.presenter.deleteAccount(customer: bankToDelete)
|
||||
private func deleteAccount(_ bankToDelete: IBankData) {
|
||||
self.presenter.deleteAccount(bank: bankToDelete)
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -71,7 +71,7 @@ struct TransferMoneyDialog: View {
|
|||
|
||||
|
||||
init() {
|
||||
self.accountsSupportingTransferringMoney = self.presenter.bankAccounts.filter({ $0.supportsTransferringMoney })
|
||||
self.accountsSupportingTransferringMoney = self.presenter.accountsSupportingTransferringMoney
|
||||
|
||||
self.showAccounts = self.accountsSupportingTransferringMoney.count > 1
|
||||
}
|
||||
|
|
|
@ -13,12 +13,12 @@ struct IconedTitleView: View {
|
|||
private var titleFont: Font?
|
||||
|
||||
|
||||
init(_ bank: ICustomer, titleFont: Font? = nil) {
|
||||
init(_ bank: IBankData, titleFont: Font? = nil) {
|
||||
self.init(accountTitle: bank.displayName, iconUrl: bank.iconUrl, defaultIconName: Styles.AccountFallbackIcon, titleFont: titleFont)
|
||||
}
|
||||
|
||||
init(_ account: IBankAccount, titleFont: Font? = nil) {
|
||||
self.init(accountTitle: account.displayName, iconUrl: account.customer.iconUrl, defaultIconName: Styles.AccountFallbackIcon, titleFont: titleFont)
|
||||
self.init(accountTitle: account.displayName, iconUrl: account.bank.iconUrl, defaultIconName: Styles.AccountFallbackIcon, titleFont: titleFont)
|
||||
}
|
||||
|
||||
init(accountTitle: String, iconUrl: String?, defaultIconName: String, titleFont: Font? = nil) {
|
||||
|
|
|
@ -47,7 +47,7 @@ struct AccountTransactionListItem: View {
|
|||
|
||||
VStack(alignment: .trailing) {
|
||||
if areMoreThanOneBanksTransactionsDisplayed {
|
||||
IconView(iconUrl: transaction.bankAccount.customer.iconUrl, defaultIconName: Styles.AccountFallbackIcon)
|
||||
IconView(iconUrl: transaction.account.bank.iconUrl, defaultIconName: Styles.AccountFallbackIcon)
|
||||
|
||||
Spacer()
|
||||
}
|
||||
|
@ -98,6 +98,6 @@ struct AccountTransactionListItem: View {
|
|||
|
||||
struct AccountTransactionListItem_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
AccountTransactionListItem(AccountTransaction(bankAccount: previewBanks[0].accounts[0] as! BankAccount, otherPartyName: "Marieke Musterfrau", unparsedUsage: "Vielen Dank für Ihre Mühen", amount: CommonBigDecimal(double: 1234.56), valueDate: CommonDate(year: 2020, month: .march, day_: 27), bookingText: "SEPA Überweisung"), false)
|
||||
AccountTransactionListItem(AccountTransaction(account: previewBanks[0].accounts[0] as! BankAccount, otherPartyName: "Marieke Musterfrau", unparsedUsage: "Vielen Dank für Ihre Mühen", amount: CommonBigDecimal(double: 1234.56), valueDate: CommonDate(year: 2020, month: .march, day_: 27), bookingText: "SEPA Überweisung"), false)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ import BankingUiSwift
|
|||
|
||||
struct AllBanksListItem: View {
|
||||
|
||||
let banks: [ICustomer]
|
||||
let banks: [IBankData]
|
||||
|
||||
@State private var navigateToAccountTransactionsDialog = false
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ import BankingUiSwift
|
|||
|
||||
struct BankListItem : View {
|
||||
|
||||
let bank: ICustomer
|
||||
let bank: IBankData
|
||||
|
||||
@State private var navigateToAccountTransactionsDialog = false
|
||||
|
||||
|
@ -70,8 +70,8 @@ struct BankListItem : View {
|
|||
).show()
|
||||
}
|
||||
|
||||
private func deleteAccount(_ bank: ICustomer) {
|
||||
presenter.deleteAccount(customer: bank)
|
||||
private func deleteAccount(_ bank: IBankData) {
|
||||
presenter.deleteAccount(bank: bank)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ import BankingUiSwift
|
|||
|
||||
struct TanMethodPicker: View {
|
||||
|
||||
private let bank: ICustomer
|
||||
private let bank: IBankData
|
||||
|
||||
private let selectedTanMethodChanged: (TanMethod) -> Void
|
||||
|
||||
|
@ -27,7 +27,7 @@ struct TanMethodPicker: View {
|
|||
}
|
||||
|
||||
|
||||
init(_ bank: ICustomer, _ initiallySelectedTanMethod: TanMethod? = nil, selectedTanMethodChanged: @escaping (TanMethod) -> Void) {
|
||||
init(_ bank: IBankData, _ initiallySelectedTanMethod: TanMethod? = nil, selectedTanMethodChanged: @escaping (TanMethod) -> Void) {
|
||||
self.bank = bank
|
||||
|
||||
self.selectedTanMethodChanged = selectedTanMethodChanged
|
||||
|
|
|
@ -16,6 +16,7 @@ import net.dankito.banking.fints.util.PureKotlinBase64Service
|
|||
import net.dankito.banking.fints.webclient.IWebClient
|
||||
import net.dankito.banking.fints.webclient.KtorWebClient
|
||||
import net.dankito.banking.extensions.toMoney
|
||||
import net.dankito.banking.fints.model.BankData
|
||||
import net.dankito.banking.fints.response.client.FinTsClientResponse
|
||||
import net.dankito.banking.ui.model.*
|
||||
import net.dankito.banking.ui.model.MessageLogEntry
|
||||
|
@ -26,7 +27,7 @@ import net.dankito.utils.multiplatform.log.LoggerFactory
|
|||
|
||||
|
||||
open class fints4kBankingClient(
|
||||
protected val customer: TypedCustomer,
|
||||
protected val bank: TypedBankData,
|
||||
protected val modelCreator: IModelCreator,
|
||||
protected val dataFolder: File,
|
||||
protected val serializer: ISerializer,
|
||||
|
@ -48,14 +49,14 @@ open class fints4kBankingClient(
|
|||
protected var didTryToGetAccountDataFromBank = false
|
||||
|
||||
|
||||
protected val bank = restoreDataOrMapFromUiModel(customer)
|
||||
protected val fintsBank = restoreDataOrMapFromUiModel(bank)
|
||||
|
||||
|
||||
protected open val client = FinTsClientForCustomer(bank, createFinTsClientCallback(callback), webClient, base64Service)
|
||||
protected open val client = FinTsClientForCustomer(fintsBank, createFinTsClientCallback(callback), webClient, base64Service)
|
||||
|
||||
|
||||
override val messageLogWithoutSensitiveData: List<MessageLogEntry>
|
||||
get() = client.messageLogWithoutSensitiveData.map { MessageLogEntry(it.message, it.time, customer) }
|
||||
get() = client.messageLogWithoutSensitiveData.map { MessageLogEntry(it.message, it.time, bank) }
|
||||
|
||||
|
||||
override fun addAccountAsync(callback: (AddAccountResponse) -> Unit) {
|
||||
|
@ -66,8 +67,8 @@ open class fints4kBankingClient(
|
|||
|
||||
protected open fun handleAddAccountResponse(response: net.dankito.banking.fints.response.client.AddAccountResponse,
|
||||
callback: (AddAccountResponse) -> Unit) {
|
||||
mapper.mapBank(customer, bank)
|
||||
val mappedResponse = mapper.mapResponse(customer, response)
|
||||
mapper.mapBank(bank, fintsBank)
|
||||
val mappedResponse = mapper.mapResponse(bank, response)
|
||||
|
||||
saveData()
|
||||
|
||||
|
@ -76,33 +77,33 @@ open class fints4kBankingClient(
|
|||
|
||||
|
||||
override fun getTransactionsAsync(parameter: GetTransactionsParameter, callback: (GetTransactionsResponse) -> Unit) {
|
||||
val bankAccount = parameter.account
|
||||
val account = parameter.account
|
||||
|
||||
findAccountForBankAccount(bankAccount) { account, errorMessage ->
|
||||
if (account == null) {
|
||||
callback(GetTransactionsResponse(bankAccount, errorMessage ?: ""))
|
||||
findAccountForAccount(account) { accountData, errorMessage ->
|
||||
if (accountData == null) {
|
||||
callback(GetTransactionsResponse(account, errorMessage ?: ""))
|
||||
}
|
||||
else {
|
||||
val mappedParameter = GetTransactionsParameter(account, parameter.alsoRetrieveBalance, parameter.fromDate,
|
||||
val mappedParameter = GetTransactionsParameter(accountData, parameter.alsoRetrieveBalance, parameter.fromDate,
|
||||
parameter.toDate, null, parameter.abortIfTanIsRequired) {
|
||||
parameter.retrievedChunkListener?.invoke(mapper.mapTransactions(bankAccount, it))
|
||||
parameter.retrievedChunkListener?.invoke(mapper.mapTransactions(account, it))
|
||||
}
|
||||
|
||||
doGetTransactionsAsync(mappedParameter, bankAccount, callback)
|
||||
doGetTransactionsAsync(mappedParameter, account, callback)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected open fun doGetTransactionsAsync(parameter: net.dankito.banking.fints.model.GetTransactionsParameter,
|
||||
bankAccount: TypedBankAccount, callback: (GetTransactionsResponse) -> Unit) {
|
||||
account: TypedBankAccount, callback: (GetTransactionsResponse) -> Unit) {
|
||||
client.getTransactionsAsync(parameter) { response ->
|
||||
handleGetTransactionsResponse(bankAccount, response, callback)
|
||||
handleGetTransactionsResponse(account, response, callback)
|
||||
}
|
||||
}
|
||||
|
||||
protected open fun handleGetTransactionsResponse(bankAccount: TypedBankAccount, response: net.dankito.banking.fints.response.client.GetTransactionsResponse,
|
||||
protected open fun handleGetTransactionsResponse(account: TypedBankAccount, response: net.dankito.banking.fints.response.client.GetTransactionsResponse,
|
||||
callback: (GetTransactionsResponse) -> Unit) {
|
||||
val mappedResponse = mapper.mapResponse(bankAccount, response)
|
||||
val mappedResponse = mapper.mapResponse(account, response)
|
||||
|
||||
saveData()
|
||||
|
||||
|
@ -111,7 +112,7 @@ open class fints4kBankingClient(
|
|||
|
||||
|
||||
override fun transferMoneyAsync(data: TransferMoneyData, callback: (BankingClientResponse) -> Unit) {
|
||||
findAccountForBankAccount(data.account) { account, errorMessage ->
|
||||
findAccountForAccount(data.account) { account, errorMessage ->
|
||||
if (account == null) {
|
||||
callback(BankingClientResponse(false, errorMessage))
|
||||
}
|
||||
|
@ -136,19 +137,19 @@ open class fints4kBankingClient(
|
|||
}
|
||||
|
||||
|
||||
override fun dataChanged(customer: TypedCustomer) {
|
||||
mapper.mapChangesFromUiToClientModel(customer, bank)
|
||||
override fun dataChanged(bank: TypedBankData) {
|
||||
mapper.mapChangesFromUiToClientModel(bank, this.fintsBank)
|
||||
}
|
||||
|
||||
override fun deletedAccount(customer: TypedCustomer, wasLastAccountWithThisCredentials: Boolean) {
|
||||
override fun deletedBank(bank: TypedBankData, wasLastAccountWithThisCredentials: Boolean) {
|
||||
if (wasLastAccountWithThisCredentials) {
|
||||
getFints4kClientDataFile(customer).delete()
|
||||
getFints4kClientDataFile(bank).delete()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected open fun findAccountForBankAccount(bankAccount: TypedBankAccount, findAccountResult: (AccountData?, error: String?) -> Unit) {
|
||||
val mappedAccount = mapper.findAccountForBankAccount(bank, bankAccount)
|
||||
protected open fun findAccountForAccount(account: TypedBankAccount, findAccountResult: (AccountData?, error: String?) -> Unit) {
|
||||
val mappedAccount = mapper.findMatchingAccount(fintsBank, account)
|
||||
|
||||
if (mappedAccount != null) {
|
||||
findAccountResult(mappedAccount, null)
|
||||
|
@ -157,37 +158,37 @@ open class fints4kBankingClient(
|
|||
addAccountAsync { response ->
|
||||
didTryToGetAccountDataFromBank = !!! response.successful
|
||||
|
||||
findAccountResult(mapper.findAccountForBankAccount(bank, bankAccount),
|
||||
findAccountResult(mapper.findMatchingAccount(fintsBank, account),
|
||||
response.errorToShowToUser)
|
||||
}
|
||||
}
|
||||
else {
|
||||
findAccountResult(null, "Cannot find account for ${bankAccount.identifier}") // TODO: translate
|
||||
findAccountResult(null, "Cannot find account for ${account.identifier}") // TODO: translate
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected open fun restoreDataOrMapFromUiModel(customer: TypedCustomer): BankData {
|
||||
if (isNewAccount(customer)) {
|
||||
return mapToBankData(customer)
|
||||
protected open fun restoreDataOrMapFromUiModel(bank: TypedBankData): BankData {
|
||||
if (isNewAccount(bank)) {
|
||||
return mapToBankData(bank)
|
||||
}
|
||||
|
||||
return restoreData(customer) ?: mapToBankData(customer)
|
||||
return restoreData(bank) ?: mapToBankData(bank)
|
||||
}
|
||||
|
||||
protected open fun isNewAccount(customer: TypedCustomer): Boolean {
|
||||
return customer.accounts.isEmpty()
|
||||
protected open fun isNewAccount(bank: TypedBankData): Boolean {
|
||||
return bank.accounts.isEmpty()
|
||||
}
|
||||
|
||||
protected open fun mapToBankData(customer: TypedCustomer): BankData {
|
||||
return BankData(customer.bankCode, customer.customerId, customer.password, customer.finTsServerAddress, customer.bic, customer.bankName)
|
||||
protected open fun mapToBankData(bank: TypedBankData): BankData {
|
||||
return BankData(bank.bankCode, bank.customerId, bank.password, bank.finTsServerAddress, bank.bic, bank.bankName)
|
||||
}
|
||||
|
||||
protected open fun restoreData(customer: TypedCustomer): BankData? {
|
||||
protected open fun restoreData(bank: TypedBankData): BankData? {
|
||||
try {
|
||||
return serializer.deserializeObject(getFints4kClientDataFile(customer), BankData::class)
|
||||
return serializer.deserializeObject(getFints4kClientDataFile(bank), BankData::class)
|
||||
} catch (e: Exception) {
|
||||
log.warn(e) { "Could not deserialize bank data of $customer" }
|
||||
log.warn(e) { "Could not deserialize bank data of $bank" }
|
||||
}
|
||||
|
||||
return null
|
||||
|
@ -195,16 +196,16 @@ open class fints4kBankingClient(
|
|||
|
||||
protected open fun saveData() {
|
||||
try {
|
||||
val clientDataFile = getFints4kClientDataFile(bank.bankCode, bank.customerId)
|
||||
val clientDataFile = getFints4kClientDataFile(fintsBank.bankCode, fintsBank.customerId)
|
||||
|
||||
serializer.serializeObject(bank, clientDataFile)
|
||||
serializer.serializeObject(fintsBank, clientDataFile)
|
||||
} catch (e: Exception) {
|
||||
log.error("Could not save customer data for $bank", e)
|
||||
log.error("Could not save bank data for $fintsBank", e)
|
||||
}
|
||||
}
|
||||
|
||||
protected open fun getFints4kClientDataFile(customer: TypedCustomer): File {
|
||||
return getFints4kClientDataFile(customer.bankCode, customer.customerId)
|
||||
protected open fun getFints4kClientDataFile(bank: TypedBankData): File {
|
||||
return getFints4kClientDataFile(bank.bankCode, bank.customerId)
|
||||
}
|
||||
|
||||
protected open fun getFints4kClientDataFile(bankCode: String, customerId: String): File {
|
||||
|
@ -240,15 +241,15 @@ open class fints4kBankingClient(
|
|||
}
|
||||
|
||||
protected open fun handleEnterTan(bank: BankData, tanChallenge: TanChallenge, enterTanCallback: (EnterTanResult) -> Unit, clientCallback: BankingClientCallback) {
|
||||
mapper.updateTanMediaAndMethods(this@fints4kBankingClient.customer, bank)
|
||||
mapper.updateTanMediaAndMethods(this@fints4kBankingClient.bank, bank)
|
||||
|
||||
clientCallback.enterTan(this@fints4kBankingClient.customer, mapper.mapTanChallenge(tanChallenge)) { result ->
|
||||
clientCallback.enterTan(this@fints4kBankingClient.bank, mapper.mapTanChallenge(tanChallenge)) { result ->
|
||||
enterTanCallback(mapper.mapEnterTanResult(result, bank))
|
||||
}
|
||||
}
|
||||
|
||||
protected open fun handleEnterTanGeneratorAtc(bank: BankData, tanMedium: TanGeneratorTanMedium, enterAtcCallback: (EnterTanGeneratorAtcResult) -> Unit, clientCallback: BankingClientCallback) {
|
||||
mapper.updateTanMediaAndMethods(this@fints4kBankingClient.customer, bank)
|
||||
mapper.updateTanMediaAndMethods(this@fints4kBankingClient.bank, bank)
|
||||
|
||||
clientCallback.enterTanGeneratorAtc(mapper.mapTanMedium(tanMedium)) { result ->
|
||||
enterAtcCallback(mapper.mapEnterTanGeneratorAtcResult(result))
|
||||
|
|
|
@ -5,7 +5,7 @@ import net.dankito.banking.ui.IBankingClient
|
|||
import net.dankito.banking.ui.IBankingClientCreator
|
||||
import net.dankito.banking.fints.webclient.IWebClient
|
||||
import net.dankito.banking.fints.webclient.KtorWebClient
|
||||
import net.dankito.banking.ui.model.TypedCustomer
|
||||
import net.dankito.banking.ui.model.TypedBankData
|
||||
import net.dankito.banking.ui.model.mapper.IModelCreator
|
||||
import net.dankito.banking.util.IAsyncRunner
|
||||
import net.dankito.banking.util.ISerializer
|
||||
|
@ -19,13 +19,13 @@ open class fints4kBankingClientCreator(
|
|||
) : IBankingClientCreator {
|
||||
|
||||
override fun createClient(
|
||||
customer: TypedCustomer,
|
||||
bank: TypedBankData,
|
||||
dataFolder: File,
|
||||
asyncRunner: IAsyncRunner,
|
||||
callback: BankingClientCallback
|
||||
): IBankingClient {
|
||||
|
||||
return fints4kBankingClient(customer, modelCreator, dataFolder, serializer, webClient, callback = callback)
|
||||
return fints4kBankingClient(bank, modelCreator, dataFolder, serializer, webClient, callback = callback)
|
||||
}
|
||||
|
||||
}
|
|
@ -28,23 +28,23 @@ open class fints4kModelMapper(protected val modelCreator: IModelCreator) {
|
|||
return BankingClientResponse(response.successful, mapErrorToShowToUser(response), response.userCancelledAction)
|
||||
}
|
||||
|
||||
open fun mapResponse(customer: TypedCustomer, response: net.dankito.banking.fints.response.client.AddAccountResponse): AddAccountResponse {
|
||||
open fun mapResponse(bank: TypedBankData, response: net.dankito.banking.fints.response.client.AddAccountResponse): AddAccountResponse {
|
||||
|
||||
return AddAccountResponse(customer, map(customer, response.retrievedData), mapErrorToShowToUser(response), response.userCancelledAction)
|
||||
return AddAccountResponse(bank, map(bank, response.retrievedData), mapErrorToShowToUser(response), response.userCancelledAction)
|
||||
}
|
||||
|
||||
open fun mapResponse(bankAccount: TypedBankAccount, response: net.dankito.banking.fints.response.client.GetTransactionsResponse): GetTransactionsResponse {
|
||||
open fun mapResponse(account: TypedBankAccount, response: net.dankito.banking.fints.response.client.GetTransactionsResponse): GetTransactionsResponse {
|
||||
|
||||
return GetTransactionsResponse(map(bankAccount.customer as TypedCustomer, response.retrievedData),
|
||||
return GetTransactionsResponse(map(account.bank as TypedBankData, response.retrievedData),
|
||||
mapErrorToShowToUser(response), response.userCancelledAction, response.tanRequiredButWeWereToldToAbortIfSo)
|
||||
}
|
||||
|
||||
open fun map(customer: TypedCustomer, retrievedData: List<net.dankito.banking.fints.model.RetrievedAccountData>): List<RetrievedAccountData> {
|
||||
return retrievedData.mapNotNull { map(customer, it) }
|
||||
open fun map(bank: TypedBankData, retrievedData: List<net.dankito.banking.fints.model.RetrievedAccountData>): List<RetrievedAccountData> {
|
||||
return retrievedData.mapNotNull { map(bank, it) }
|
||||
}
|
||||
|
||||
open fun map(customer: TypedCustomer, retrievedData: net.dankito.banking.fints.model.RetrievedAccountData): RetrievedAccountData? {
|
||||
val account = findMatchingBankAccount(customer, retrievedData.accountData)
|
||||
open fun map(bank: TypedBankData, retrievedData: net.dankito.banking.fints.model.RetrievedAccountData): RetrievedAccountData? {
|
||||
val account = findMatchingAccount(bank, retrievedData.accountData)
|
||||
|
||||
if (account == null) {
|
||||
log.error("No matching account found for ${retrievedData.accountData}. Has there an account been added we didn't map yet?")
|
||||
|
@ -70,41 +70,41 @@ open class fints4kModelMapper(protected val modelCreator: IModelCreator) {
|
|||
}
|
||||
|
||||
|
||||
open fun mapBank(customer: TypedCustomer, bank: BankData) {
|
||||
customer.bankCode = bank.bankCode
|
||||
customer.customerId = bank.customerId
|
||||
customer.password = bank.pin
|
||||
customer.finTsServerAddress = bank.finTs3ServerAddress
|
||||
customer.bankName = bank.bankName
|
||||
customer.bic = bank.bic
|
||||
customer.customerName = bank.customerName
|
||||
customer.countDaysForWhichTransactionsAreKept = bank.countDaysForWhichTransactionsAreKept
|
||||
customer.userId = bank.userId
|
||||
open fun mapBank(bank: TypedBankData, fintsBank: BankData) {
|
||||
bank.bankCode = fintsBank.bankCode
|
||||
bank.customerId = fintsBank.customerId
|
||||
bank.password = fintsBank.pin
|
||||
bank.finTsServerAddress = fintsBank.finTs3ServerAddress
|
||||
bank.bankName = fintsBank.bankName
|
||||
bank.bic = fintsBank.bic
|
||||
bank.customerName = fintsBank.customerName
|
||||
bank.countDaysForWhichTransactionsAreKept = fintsBank.countDaysForWhichTransactionsAreKept
|
||||
bank.userId = fintsBank.userId
|
||||
|
||||
customer.accounts = mapBankAccounts(customer, bank.accounts)
|
||||
bank.accounts = mapAccounts(bank, fintsBank.accounts)
|
||||
|
||||
updateTanMediaAndMethods(customer, bank)
|
||||
updateTanMediaAndMethods(bank, fintsBank)
|
||||
}
|
||||
|
||||
/**
|
||||
* In UI only customerId, password, (bankCode,) and selected TAN method can be set
|
||||
*/
|
||||
open fun mapChangesFromUiToClientModel(customer: TypedCustomer, bank: BankData) {
|
||||
bank.customerId = customer.customerId
|
||||
bank.pin = customer.password
|
||||
open fun mapChangesFromUiToClientModel(bank: TypedBankData, fintsBank: BankData) {
|
||||
fintsBank.customerId = bank.customerId
|
||||
fintsBank.pin = bank.password
|
||||
|
||||
bank.bankCode = customer.bankCode
|
||||
fintsBank.bankCode = bank.bankCode
|
||||
|
||||
bank.selectedTanMethod = findTanMethod(bank, customer.selectedTanMethod) ?: bank.selectedTanMethod
|
||||
fintsBank.selectedTanMethod = findTanMethod(fintsBank, bank.selectedTanMethod) ?: fintsBank.selectedTanMethod
|
||||
}
|
||||
|
||||
|
||||
open fun mapBankAccounts(customer: TypedCustomer, accountData: List<AccountData>): List<TypedBankAccount> {
|
||||
open fun mapAccounts(bank: TypedBankData, accountData: List<AccountData>): List<TypedBankAccount> {
|
||||
return accountData.mapIndexed { index, account ->
|
||||
val mappedAccount = customer.accounts.firstOrNull { it.identifier == account.accountIdentifier }
|
||||
?: modelCreator.createBankAccount(customer, account.productName, account.accountIdentifier)
|
||||
val mappedAccount = bank.accounts.firstOrNull { it.identifier == account.accountIdentifier }
|
||||
?: modelCreator.createAccount(bank, account.productName, account.accountIdentifier)
|
||||
|
||||
mapBankAccount(mappedAccount, account)
|
||||
mapAccount(mappedAccount, account)
|
||||
|
||||
mappedAccount.displayIndex = index
|
||||
|
||||
|
@ -112,7 +112,7 @@ open class fints4kModelMapper(protected val modelCreator: IModelCreator) {
|
|||
}
|
||||
}
|
||||
|
||||
open fun mapBankAccount(account: TypedBankAccount, accountData: AccountData) {
|
||||
open fun mapAccount(account: TypedBankAccount, accountData: AccountData) {
|
||||
account.identifier = accountData.accountIdentifier
|
||||
account.accountHolderName = accountData.accountHolderName
|
||||
account.iban = accountData.iban
|
||||
|
@ -147,22 +147,22 @@ open class fints4kModelMapper(protected val modelCreator: IModelCreator) {
|
|||
}
|
||||
|
||||
// TODO: move to a fints4k internal mapper
|
||||
open fun updateBankAccounts(bank: BankData, updatedAccounts: List<AccountData>) {
|
||||
open fun updateAccounts(bank: BankData, updatedAccounts: List<AccountData>) {
|
||||
val accounts = bank.accounts
|
||||
|
||||
updatedAccounts.forEach { updatedAccount ->
|
||||
val matchingExistingAccount = findMatchingBankAccount(accounts, updatedAccount)
|
||||
val matchingExistingAccount = findMatchingAccount(accounts, updatedAccount)
|
||||
|
||||
if (matchingExistingAccount == null) {
|
||||
bank.addAccount(updatedAccount)
|
||||
}
|
||||
else {
|
||||
updateBankAccount(matchingExistingAccount, updatedAccount)
|
||||
updateAccount(matchingExistingAccount, updatedAccount)
|
||||
}
|
||||
}
|
||||
|
||||
bank.accounts.forEach { account ->
|
||||
val updatedAccount = findMatchingBankAccount(updatedAccounts, account)
|
||||
val updatedAccount = findMatchingAccount(updatedAccounts, account)
|
||||
|
||||
if (updatedAccount == null) {
|
||||
bank.removeAccount(account)
|
||||
|
@ -170,7 +170,7 @@ open class fints4kModelMapper(protected val modelCreator: IModelCreator) {
|
|||
}
|
||||
}
|
||||
|
||||
open fun updateBankAccount(account: AccountData, updatedAccount: AccountData) {
|
||||
open fun updateAccount(account: AccountData, updatedAccount: AccountData) {
|
||||
account.allowedJobs = updatedAccount.allowedJobs
|
||||
|
||||
AccountFeature.values().forEach { feature ->
|
||||
|
@ -178,26 +178,26 @@ open class fints4kModelMapper(protected val modelCreator: IModelCreator) {
|
|||
}
|
||||
}
|
||||
|
||||
open fun findAccountForBankAccount(bank: BankData, bankAccount: TypedBankAccount): AccountData? {
|
||||
return bank.accounts.firstOrNull { bankAccount.identifier == it.accountIdentifier }
|
||||
open fun findMatchingAccount(bank: BankData, account: TypedBankAccount): AccountData? {
|
||||
return bank.accounts.firstOrNull { account.identifier == it.accountIdentifier }
|
||||
}
|
||||
|
||||
open fun findMatchingBankAccount(customer: TypedCustomer, accountData: AccountData): TypedBankAccount? {
|
||||
return customer.accounts.firstOrNull { it.identifier == accountData.accountIdentifier }
|
||||
open fun findMatchingAccount(bank: TypedBankData, accountData: AccountData): TypedBankAccount? {
|
||||
return bank.accounts.firstOrNull { it.identifier == accountData.accountIdentifier }
|
||||
}
|
||||
|
||||
open fun findMatchingBankAccount(accounts: List<AccountData>, accountData: AccountData): AccountData? {
|
||||
open fun findMatchingAccount(accounts: List<AccountData>, accountData: AccountData): AccountData? {
|
||||
return accounts.firstOrNull { it.accountIdentifier == accountData.accountIdentifier }
|
||||
}
|
||||
|
||||
|
||||
open fun mapTransactions(bankAccount: TypedBankAccount, transactions: Collection<net.dankito.banking.fints.model.AccountTransaction>): List<IAccountTransaction> {
|
||||
return transactions.map { mapTransaction(bankAccount, it) }
|
||||
open fun mapTransactions(account: TypedBankAccount, transactions: Collection<net.dankito.banking.fints.model.AccountTransaction>): List<IAccountTransaction> {
|
||||
return transactions.map { mapTransaction(account, it) }
|
||||
}
|
||||
|
||||
open fun mapTransaction(bankAccount: TypedBankAccount, transaction: net.dankito.banking.fints.model.AccountTransaction): IAccountTransaction {
|
||||
open fun mapTransaction(account: TypedBankAccount, transaction: net.dankito.banking.fints.model.AccountTransaction): IAccountTransaction {
|
||||
return modelCreator.createTransaction(
|
||||
bankAccount,
|
||||
account,
|
||||
transaction.amount.toBigDecimal(),
|
||||
transaction.amount.currency.code,
|
||||
transaction.unparsedUsage,
|
||||
|
@ -238,20 +238,20 @@ open class fints4kModelMapper(protected val modelCreator: IModelCreator) {
|
|||
}
|
||||
|
||||
|
||||
open fun updateTanMediaAndMethods(account: TypedCustomer, bank: BankData) {
|
||||
account.supportedTanMethods = bank.tanMethodsAvailableForUser.map { tanMethod ->
|
||||
findMappedTanMethod(account, tanMethod) ?: mapTanMethod(tanMethod)
|
||||
open fun updateTanMediaAndMethods(bank: TypedBankData, fintsBank: BankData) {
|
||||
bank.supportedTanMethods = fintsBank.tanMethodsAvailableForUser.map { tanMethod ->
|
||||
findMappedTanMethod(bank, tanMethod) ?: mapTanMethod(tanMethod)
|
||||
}
|
||||
|
||||
if (bank.isTanMethodSelected) {
|
||||
account.selectedTanMethod = findMappedTanMethod(account, bank.selectedTanMethod)
|
||||
if (fintsBank.isTanMethodSelected) {
|
||||
bank.selectedTanMethod = findMappedTanMethod(bank, fintsBank.selectedTanMethod)
|
||||
}
|
||||
else {
|
||||
account.selectedTanMethod = null
|
||||
bank.selectedTanMethod = null
|
||||
}
|
||||
|
||||
account.tanMedia = bank.tanMedia.map { tanMedium ->
|
||||
findMappedTanMedium(account, tanMedium) ?: mapTanMedium(tanMedium)
|
||||
bank.tanMedia = fintsBank.tanMedia.map { tanMedium ->
|
||||
findMappedTanMedium(bank, tanMedium) ?: mapTanMedium(tanMedium)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -292,8 +292,8 @@ open class fints4kModelMapper(protected val modelCreator: IModelCreator) {
|
|||
}
|
||||
}
|
||||
|
||||
protected open fun findMappedTanMethod(customer: TypedCustomer, tanMethod: net.dankito.banking.fints.model.TanMethod): TanMethod? {
|
||||
return customer.supportedTanMethods.firstOrNull { it.bankInternalMethodCode == tanMethod.securityFunction.code }
|
||||
protected open fun findMappedTanMethod(bank: TypedBankData, tanMethod: net.dankito.banking.fints.model.TanMethod): TanMethod? {
|
||||
return bank.supportedTanMethods.firstOrNull { it.bankInternalMethodCode == tanMethod.securityFunction.code }
|
||||
}
|
||||
|
||||
protected open fun findTanMethod(bank: BankData, tanMethod: TanMethod?): net.dankito.banking.fints.model.TanMethod? {
|
||||
|
@ -304,8 +304,8 @@ open class fints4kModelMapper(protected val modelCreator: IModelCreator) {
|
|||
return bank.tanMethodsAvailableForUser.firstOrNull { it.securityFunction.code == tanMethod.bankInternalMethodCode }
|
||||
}
|
||||
|
||||
protected open fun findMappedTanMedium(customer: TypedCustomer, tanMedium: net.dankito.banking.fints.messages.datenelemente.implementierte.tan.TanMedium): TanMedium? {
|
||||
return customer.tanMedia.firstOrNull { doesMatchTanMedium(tanMedium, it) }
|
||||
protected open fun findMappedTanMedium(bank: TypedBankData, tanMedium: net.dankito.banking.fints.messages.datenelemente.implementierte.tan.TanMedium): TanMedium? {
|
||||
return bank.tanMedia.firstOrNull { doesMatchTanMedium(tanMedium, it) }
|
||||
}
|
||||
|
||||
protected open fun doesMatchTanMedium(fintsTanMedium: net.dankito.banking.fints.messages.datenelemente.implementierte.tan.TanMedium, tanMedium: TanMedium): Boolean {
|
||||
|
|
|
@ -2,7 +2,7 @@ package net.dankito.banking
|
|||
|
||||
import net.dankito.banking.model.AccountCredentials
|
||||
import net.dankito.banking.ui.BankingClientCallback
|
||||
import net.dankito.banking.ui.model.TypedCustomer
|
||||
import net.dankito.banking.ui.model.TypedBankData
|
||||
import net.dankito.banking.ui.model.tan.FlickerCodeTanChallenge
|
||||
import net.dankito.banking.ui.model.tan.ImageTanChallenge
|
||||
import net.dankito.banking.ui.model.tan.TanChallenge
|
||||
|
@ -23,7 +23,7 @@ import org.slf4j.LoggerFactory
|
|||
*/
|
||||
open class HbciCallback(
|
||||
protected val credentials: AccountCredentials,
|
||||
protected val customer: TypedCustomer,
|
||||
protected val bank: TypedBankData,
|
||||
protected val mapper: hbci4jModelMapper,
|
||||
protected val callback: BankingClientCallback
|
||||
) : AbstractHBCICallback() {
|
||||
|
@ -84,13 +84,13 @@ open class HbciCallback(
|
|||
|
||||
// ADDED: Auswaehlen welches PinTan Verfahren verwendet werden soll
|
||||
HBCICallback.NEED_PT_SECMECH -> selectTanMethod(retData.toString())?.let { selectedTanMethod ->
|
||||
customer.selectedTanMethod = selectedTanMethod
|
||||
bank.selectedTanMethod = selectedTanMethod
|
||||
retData.replace(0, retData.length, selectedTanMethod.bankInternalMethodCode)
|
||||
}
|
||||
|
||||
// chipTan or simple TAN request (iTAN, smsTAN, ...)
|
||||
HBCICallback.NEED_PT_TAN -> {
|
||||
getTanFromUser(customer, msg, retData.toString())?.let { enteredTan ->
|
||||
getTanFromUser(bank, msg, retData.toString())?.let { enteredTan ->
|
||||
retData.replace(0, retData.length, enteredTan)
|
||||
}
|
||||
}
|
||||
|
@ -99,7 +99,7 @@ open class HbciCallback(
|
|||
HBCICallback.NEED_PT_QRTAN -> { // use class QRCode to display QR code
|
||||
val qrData = retData.toString()
|
||||
val qrCode = QRCode(qrData, msg)
|
||||
val enterTanResult = callback.enterTan(customer, ImageTanChallenge(TanImage(qrCode.mimetype, qrCode.image), msg, customer.selectedTanMethod!!))
|
||||
val enterTanResult = callback.enterTan(bank, ImageTanChallenge(TanImage(qrCode.mimetype, qrCode.image), msg, bank.selectedTanMethod!!))
|
||||
enterTanResult.enteredTan?.let { enteredTan ->
|
||||
retData.replace(0, retData.length, enteredTan)
|
||||
}
|
||||
|
@ -108,7 +108,7 @@ open class HbciCallback(
|
|||
// photoTan
|
||||
HBCICallback.NEED_PT_PHOTOTAN -> { // use class MatrixCode to display photo
|
||||
val matrixCode = MatrixCode(retData.toString())
|
||||
val enterTanResult = callback.enterTan(customer, ImageTanChallenge(TanImage(matrixCode.mimetype, matrixCode.image), msg, customer.selectedTanMethod!!))
|
||||
val enterTanResult = callback.enterTan(bank, ImageTanChallenge(TanImage(matrixCode.mimetype, matrixCode.image), msg, bank.selectedTanMethod!!))
|
||||
enterTanResult.enteredTan?.let { enteredTan ->
|
||||
retData.replace(0, retData.length, enteredTan)
|
||||
}
|
||||
|
@ -171,7 +171,7 @@ open class HbciCallback(
|
|||
}
|
||||
|
||||
|
||||
open fun getTanFromUser(customer: TypedCustomer, messageToShowToUser: String, challengeHHD_UC: String): String? {
|
||||
open fun getTanFromUser(bank: TypedBankData, messageToShowToUser: String, challengeHHD_UC: String): String? {
|
||||
// Wenn per "retData" Daten uebergeben wurden, dann enthalten diese
|
||||
// den fuer chipTAN optisch zu verwendenden Flickercode.
|
||||
// Falls nicht, ist es eine TAN-Abfrage, fuer die keine weiteren
|
||||
|
@ -183,14 +183,14 @@ open class HbciCallback(
|
|||
// werden.
|
||||
|
||||
val enterTanResult = if (challengeHHD_UC.isNullOrEmpty()) {
|
||||
callback.enterTan(customer, TanChallenge(messageToShowToUser, customer.selectedTanMethod!!))
|
||||
callback.enterTan(bank, TanChallenge(messageToShowToUser, bank.selectedTanMethod!!))
|
||||
}
|
||||
else {
|
||||
// for Sparkasse messageToShowToUser started with "chipTAN optisch\nTAN-Nummer\n\n"
|
||||
val usefulMessage = messageToShowToUser.split("\n").last().trim()
|
||||
|
||||
// val parsedDataSet = FlickerCode(challengeHHD_UC).render()
|
||||
callback.enterTan(customer, FlickerCodeTanChallenge(net.dankito.banking.ui.model.tan.FlickerCode("", challengeHHD_UC), usefulMessage, customer.selectedTanMethod!!))
|
||||
callback.enterTan(bank, FlickerCodeTanChallenge(net.dankito.banking.ui.model.tan.FlickerCode("", challengeHHD_UC), usefulMessage, bank.selectedTanMethod!!))
|
||||
}
|
||||
|
||||
return enterTanResult.enteredTan
|
||||
|
@ -201,7 +201,7 @@ open class HbciCallback(
|
|||
open fun selectTanMethod(supportedTanMethodsString: String): net.dankito.banking.ui.model.tan.TanMethod? {
|
||||
val supportedTanMethods = mapper.mapTanMethods(supportedTanMethodsString)
|
||||
|
||||
customer.supportedTanMethods = supportedTanMethods
|
||||
bank.supportedTanMethods = supportedTanMethods
|
||||
|
||||
if (supportedTanMethods.isNotEmpty()) {
|
||||
// select any method, user then can select her preferred one in EnterTanDialog; try not to select 'chipTAN manuell'
|
||||
|
|
|
@ -33,7 +33,7 @@ import java.util.*
|
|||
|
||||
|
||||
open class hbci4jBankingClient(
|
||||
protected val customer: TypedCustomer,
|
||||
protected val bank: TypedBankData,
|
||||
modelCreator: IModelCreator,
|
||||
protected val dataFolder: File,
|
||||
protected val asyncRunner: IAsyncRunner = ThreadPoolAsyncRunner(ThreadPool()),
|
||||
|
@ -50,7 +50,7 @@ open class hbci4jBankingClient(
|
|||
}
|
||||
|
||||
|
||||
protected val credentials = AccountCredentials(customer)
|
||||
protected val credentials = AccountCredentials(bank)
|
||||
|
||||
|
||||
protected val mapper = hbci4jModelMapper(modelCreator)
|
||||
|
@ -76,22 +76,22 @@ open class hbci4jBankingClient(
|
|||
val accounts = passport.accounts
|
||||
if (accounts == null || accounts.size == 0) {
|
||||
log.error("Keine Konten ermittelbar")
|
||||
return AddAccountResponse(customer, "Keine Konten ermittelbar") // TODO: translate
|
||||
return AddAccountResponse(bank, "Keine Konten ermittelbar") // TODO: translate
|
||||
}
|
||||
|
||||
this.customer.accounts = mapper.mapBankAccounts(customer, accounts, passport)
|
||||
this.bank.accounts = mapper.mapAccounts(bank, accounts, passport)
|
||||
|
||||
return tryToRetrieveAccountTransactionsForAddedAccounts(customer)
|
||||
return tryToRetrieveAccountTransactionsForAddedAccounts(bank)
|
||||
}
|
||||
}
|
||||
|
||||
return AddAccountResponse(customer, connection.error?.getInnerExceptionMessage() ?: "Could not connect")
|
||||
return AddAccountResponse(bank, connection.error?.getInnerExceptionMessage() ?: "Could not connect")
|
||||
}
|
||||
|
||||
protected open fun tryToRetrieveAccountTransactionsForAddedAccounts(customer: TypedCustomer): AddAccountResponse {
|
||||
protected open fun tryToRetrieveAccountTransactionsForAddedAccounts(bank: TypedBankData): AddAccountResponse {
|
||||
var userCancelledAction = false
|
||||
|
||||
val retrievedData = customer.accounts.map { account ->
|
||||
val retrievedData = bank.accounts.map { account ->
|
||||
if (account.supportsRetrievingAccountTransactions) {
|
||||
val response = getTransactionsOfLast90Days(account)
|
||||
|
||||
|
@ -106,34 +106,34 @@ open class hbci4jBankingClient(
|
|||
}
|
||||
}
|
||||
|
||||
return AddAccountResponse(customer, retrievedData, null, userCancelledAction)
|
||||
return AddAccountResponse(bank, retrievedData, null, userCancelledAction)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* According to PSD2 for the accounting entries of the last 90 days the two-factor authorization does not have to
|
||||
* According to PSD2 for the account transactions of the last 90 days the two-factor authorization does not have to
|
||||
* be applied. It depends on the bank if they request a second factor or not.
|
||||
*
|
||||
* So we simply try to retrieve at accounting entries of the last 90 days and see if a second factor is required
|
||||
* So we simply try to retrieve at account transactions of the last 90 days and see if a second factor is required
|
||||
* or not.
|
||||
*/
|
||||
open fun getTransactionsOfLast90DaysAsync(bankAccount: TypedBankAccount, callback: (GetTransactionsResponse) -> Unit) {
|
||||
open fun getTransactionsOfLast90DaysAsync(account: TypedBankAccount, callback: (GetTransactionsResponse) -> Unit) {
|
||||
asyncRunner.runAsync {
|
||||
callback(getTransactionsOfLast90Days(bankAccount))
|
||||
callback(getTransactionsOfLast90Days(account))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* According to PSD2 for the accounting entries of the last 90 days the two-factor authorization does not have to
|
||||
* According to PSD2 for the account transactions of the last 90 days the two-factor authorization does not have to
|
||||
* be applied. It depends on the bank if they request a second factor or not.
|
||||
*
|
||||
* So we simply try to retrieve at accounting entries of the last 90 days and see if a second factor is required
|
||||
* So we simply try to retrieve at account transactions of the last 90 days and see if a second factor is required
|
||||
* or not.
|
||||
*/
|
||||
open fun getTransactionsOfLast90Days(bankAccount: TypedBankAccount): GetTransactionsResponse {
|
||||
open fun getTransactionsOfLast90Days(account: TypedBankAccount): GetTransactionsResponse {
|
||||
val ninetyDaysAgo = Date(Date.today.time - NinetyDaysInMilliseconds)
|
||||
|
||||
return getTransactions(GetTransactionsParameter(bankAccount, bankAccount.supportsRetrievingBalance, ninetyDaysAgo)) // TODO: implement abortIfTanIsRequired
|
||||
return getTransactions(GetTransactionsParameter(account, account.supportsRetrievingBalance, ninetyDaysAgo)) // TODO: implement abortIfTanIsRequired
|
||||
}
|
||||
|
||||
override fun getTransactionsAsync(parameter: GetTransactionsParameter, callback: (GetTransactionsResponse) -> Unit) {
|
||||
|
@ -148,7 +148,7 @@ open class hbci4jBankingClient(
|
|||
|
||||
connection.handle?.let { handle ->
|
||||
try {
|
||||
val (nullableBalanceJob, accountTransactionsJob, status) = executeJobsForGetAccountingEntries(handle, parameter)
|
||||
val (nullableBalanceJob, accountTransactionsJob, status) = executeJobsForGetAccountTransactions(handle, parameter)
|
||||
|
||||
// Pruefen, ob die Kommunikation mit der Bank grundsaetzlich geklappt hat
|
||||
if (!status.isOK) {
|
||||
|
@ -180,10 +180,10 @@ open class hbci4jBankingClient(
|
|||
}
|
||||
|
||||
return GetTransactionsResponse(RetrievedAccountData(account, true, balance.toBigDecimal(),
|
||||
accountTransactionMapper.mapAccountTransactions(account, result), listOf(), parameter.fromDate, parameter.toDate))
|
||||
accountTransactionMapper.mapTransactions(account, result), listOf(), parameter.fromDate, parameter.toDate))
|
||||
}
|
||||
catch(e: Exception) {
|
||||
log.error("Could not get accounting details for bank ${credentials.bankCode}", e)
|
||||
log.error("Could not get account transactions for bank ${credentials.bankCode}", e)
|
||||
return GetTransactionsResponse(account, e.getInnerExceptionMessage())
|
||||
}
|
||||
finally {
|
||||
|
@ -196,7 +196,7 @@ open class hbci4jBankingClient(
|
|||
return GetTransactionsResponse(account, connection.error?.getInnerExceptionMessage() ?: "Could not connect")
|
||||
}
|
||||
|
||||
protected open fun executeJobsForGetAccountingEntries(handle: HBCIHandler, parameter: GetTransactionsParameter): Triple<HBCIJob?, HBCIJob, HBCIExecStatus> {
|
||||
protected open fun executeJobsForGetAccountTransactions(handle: HBCIHandler, parameter: GetTransactionsParameter): Triple<HBCIJob?, HBCIJob, HBCIExecStatus> {
|
||||
val konto = mapper.mapToKonto(parameter.account)
|
||||
|
||||
// 1. Auftrag fuer das Abrufen des Saldos erzeugen
|
||||
|
@ -272,17 +272,17 @@ open class hbci4jBankingClient(
|
|||
}
|
||||
|
||||
|
||||
override fun dataChanged(customer: TypedCustomer) {
|
||||
if (customer.bankCode != credentials.bankCode || customer.customerId != credentials.customerId || customer.password != credentials.password) {
|
||||
override fun dataChanged(bank: TypedBankData) {
|
||||
if (bank.bankCode != credentials.bankCode || bank.customerId != credentials.customerId || bank.password != credentials.password) {
|
||||
getPassportFile(credentials).delete()
|
||||
}
|
||||
|
||||
credentials.bankCode = customer.bankCode
|
||||
credentials.customerId = customer.customerId
|
||||
credentials.password = customer.password
|
||||
credentials.bankCode = bank.bankCode
|
||||
credentials.customerId = bank.customerId
|
||||
credentials.password = bank.password
|
||||
}
|
||||
|
||||
override fun deletedAccount(customer: TypedCustomer, wasLastAccountWithThisCredentials: Boolean) {
|
||||
override fun deletedBank(bank: TypedBankData, wasLastAccountWithThisCredentials: Boolean) {
|
||||
getPassportFile(credentials).delete()
|
||||
}
|
||||
|
||||
|
@ -296,7 +296,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, customer, mapper, callback))
|
||||
HBCIUtils.init(props, HbciCallback(credentials, bank, 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,
|
||||
|
|
|
@ -3,7 +3,7 @@ package net.dankito.banking
|
|||
import net.dankito.banking.ui.BankingClientCallback
|
||||
import net.dankito.banking.ui.IBankingClient
|
||||
import net.dankito.banking.ui.IBankingClientCreator
|
||||
import net.dankito.banking.ui.model.TypedCustomer
|
||||
import net.dankito.banking.ui.model.TypedBankData
|
||||
import net.dankito.banking.ui.model.mapper.IModelCreator
|
||||
import net.dankito.banking.util.IAsyncRunner
|
||||
import net.dankito.utils.multiplatform.File
|
||||
|
@ -14,13 +14,13 @@ open class hbci4jBankingClientCreator(
|
|||
) : IBankingClientCreator {
|
||||
|
||||
override fun createClient(
|
||||
customer: TypedCustomer,
|
||||
bank: TypedBankData,
|
||||
dataFolder: File,
|
||||
asyncRunner: IAsyncRunner,
|
||||
callback: BankingClientCallback
|
||||
): IBankingClient {
|
||||
|
||||
return hbci4jBankingClient(customer, modelCreator, dataFolder, asyncRunner, callback)
|
||||
return hbci4jBankingClient(bank, modelCreator, dataFolder, asyncRunner, callback)
|
||||
}
|
||||
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
package net.dankito.banking.model
|
||||
|
||||
import net.dankito.banking.ui.model.TypedCustomer
|
||||
import net.dankito.banking.ui.model.TypedBankData
|
||||
|
||||
|
||||
open class AccountCredentials(
|
||||
|
@ -9,6 +9,6 @@ open class AccountCredentials(
|
|||
var password: String
|
||||
) {
|
||||
|
||||
constructor(bank: TypedCustomer) : this(bank.bankCode, bank.customerId, bank.password)
|
||||
constructor(bank: TypedBankData) : this(bank.bankCode, bank.customerId, bank.password)
|
||||
|
||||
}
|
|
@ -28,26 +28,26 @@ open class AccountTransactionMapper(
|
|||
}
|
||||
|
||||
|
||||
open fun mapAccountTransactions(bankAccount: TypedBankAccount, result: GVRKUms): List<IAccountTransaction> {
|
||||
open fun mapTransactions(account: TypedBankAccount, result: GVRKUms): List<IAccountTransaction> {
|
||||
val entries = mutableListOf<IAccountTransaction>()
|
||||
|
||||
result.dataPerDay.forEach { btag ->
|
||||
btag.lines.forEach { transaction ->
|
||||
entries.add(mapAccountingEntry(bankAccount, btag, transaction))
|
||||
entries.add(mapTransaction(account, btag, transaction))
|
||||
}
|
||||
}
|
||||
|
||||
log.debug("Retrieved ${result.flatData.size} accounting entries")
|
||||
log.debug("Retrieved ${result.flatData.size} account transactions")
|
||||
|
||||
return entries
|
||||
}
|
||||
|
||||
protected open fun mapAccountingEntry(bankAccount: TypedBankAccount, btag: GVRKUms.BTag, transaction: GVRKUms.UmsLine): IAccountTransaction {
|
||||
protected open fun mapTransaction(account: TypedBankAccount, btag: GVRKUms.BTag, transaction: GVRKUms.UmsLine): IAccountTransaction {
|
||||
val unparsedUsage = transaction.usage.joinToString("")
|
||||
val parsedUsage = Mt940Parser().getUsageParts(unparsedUsage)
|
||||
val statementAndMaySequenceNumber = btag.counter.split('/')
|
||||
|
||||
return modelCreator.createTransaction(bankAccount,
|
||||
return modelCreator.createTransaction(account,
|
||||
mapValue(transaction.value), transaction.value.curr, unparsedUsage, transaction.bdate.toDate(),
|
||||
transaction.other.name + (transaction.other.name2 ?: ""),
|
||||
transaction.other.bic ?: transaction.other.blz,
|
||||
|
|
|
@ -15,14 +15,14 @@ open class hbci4jModelMapper(
|
|||
protected val modelCreator: IModelCreator
|
||||
) {
|
||||
|
||||
open fun mapToKonto(bankAccount: TypedBankAccount): Konto {
|
||||
val customer = bankAccount.customer
|
||||
open fun mapToKonto(account: TypedBankAccount): Konto {
|
||||
val bank = account.bank
|
||||
|
||||
val konto = Konto("DE", customer.bankCode, bankAccount.identifier, bankAccount.subAccountNumber)
|
||||
val konto = Konto("DE", bank.bankCode, account.identifier, account.subAccountNumber)
|
||||
|
||||
konto.name = customer.bankName
|
||||
konto.iban = bankAccount.iban
|
||||
konto.bic = customer.bic
|
||||
konto.name = bank.bankName
|
||||
konto.iban = account.iban
|
||||
konto.bic = bank.bic
|
||||
|
||||
return konto
|
||||
}
|
||||
|
@ -42,32 +42,32 @@ open class hbci4jModelMapper(
|
|||
}
|
||||
|
||||
|
||||
open fun mapBankAccounts(customer: TypedCustomer, bankAccounts: Array<out Konto>, passport: HBCIPassport): List<TypedBankAccount> {
|
||||
return bankAccounts.map { bankAccount ->
|
||||
val iban = if (bankAccount.iban.isNullOrBlank() == false) bankAccount.iban else passport.upd.getProperty("KInfo.iban") ?: ""
|
||||
open fun mapAccounts(bank: TypedBankData, accounts: Array<out Konto>, passport: HBCIPassport): List<TypedBankAccount> {
|
||||
return accounts.map { account ->
|
||||
val iban = if (account.iban.isNullOrBlank() == false) account.iban else passport.upd.getProperty("KInfo.iban") ?: ""
|
||||
|
||||
val result = modelCreator.createBankAccount(customer, bankAccount.number,
|
||||
if (bankAccount.name2.isNullOrBlank() == false) bankAccount.name + " " + bankAccount.name2 else bankAccount.name)
|
||||
val result = modelCreator.createAccount(bank, account.number,
|
||||
if (account.name2.isNullOrBlank() == false) account.name + " " + account.name2 else account.name)
|
||||
|
||||
result.iban = iban
|
||||
result.subAccountNumber = bankAccount.subnumber
|
||||
result.customerId = bankAccount.customerid
|
||||
result.subAccountNumber = account.subnumber
|
||||
result.customerId = account.customerid
|
||||
|
||||
result.currency = bankAccount.curr
|
||||
result.type = mapBankAccountType(bankAccount)
|
||||
result.currency = account.curr
|
||||
result.type = mapBankAccountType(account)
|
||||
result.isAccountTypeSupported = result.type == BankAccountType.Girokonto || result.type == BankAccountType.Festgeldkonto
|
||||
result.accountLimit = bankAccount.limit?.value?.let { mapValue(it).toString() }
|
||||
result.accountLimit = account.limit?.value?.let { mapValue(it).toString() }
|
||||
|
||||
result.supportsRetrievingBalance = bankAccount.allowedGVs.contains("HKSAL")
|
||||
result.supportsRetrievingAccountTransactions = bankAccount.allowedGVs.contains("HKKAZ")
|
||||
result.supportsRetrievingBalance = bankAccount.allowedGVs.contains("HKCCS")
|
||||
result.supportsRetrievingBalance = account.allowedGVs.contains("HKSAL")
|
||||
result.supportsRetrievingAccountTransactions = account.allowedGVs.contains("HKKAZ")
|
||||
result.supportsRetrievingBalance = account.allowedGVs.contains("HKCCS")
|
||||
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
open fun mapBankAccountType(bankAccount: Konto): BankAccountType {
|
||||
val type = bankAccount.acctype
|
||||
open fun mapBankAccountType(account: Konto): BankAccountType {
|
||||
val type = account.acctype
|
||||
|
||||
return when {
|
||||
type.length == 1 -> BankAccountType.Girokonto
|
||||
|
|
Loading…
Reference in New Issue