Updated to model changes: User has been renamed to BankAccess and bic is now nullable
This commit is contained in:
parent
41586b0148
commit
9330b72726
|
@ -13,8 +13,8 @@ import net.codinux.banking.ui.model.TanChallengeReceived
|
||||||
@Composable
|
@Composable
|
||||||
fun EnterTanDialogPreview_EnterTan() {
|
fun EnterTanDialogPreview_EnterTan() {
|
||||||
val tanMethods = listOf(TanMethod("Zeig mich an", TanMethodType.AppTan, "902"))
|
val tanMethods = listOf(TanMethod("Zeig mich an", TanMethodType.AppTan, "902"))
|
||||||
val user = BankViewInfo("12345678", "SupiDupiNutzer", "Abzockbank", BankingGroup.Postbank)
|
val bank = BankViewInfo("12345678", "SupiDupiNutzer", "Abzockbank", BankingGroup.Postbank)
|
||||||
val tanChallenge = TanChallenge(TanChallengeType.EnterTan, ActionRequiringTan.GetAccountInfo, "Geben Sie die TAN ein", tanMethods.first().identifier, tanMethods, user = user)
|
val tanChallenge = TanChallenge(TanChallengeType.EnterTan, ActionRequiringTan.GetAccountInfo, "Geben Sie die TAN ein", tanMethods.first().identifier, tanMethods, bank = bank)
|
||||||
|
|
||||||
EnterTanDialog(TanChallengeReceived(tanChallenge) { }) { }
|
EnterTanDialog(TanChallengeReceived(tanChallenge) { }) { }
|
||||||
}
|
}
|
||||||
|
@ -27,9 +27,9 @@ fun EnterTanDialogPreview_TanImage() {
|
||||||
val tanMethod = TanMethod("photoTAN-Verfahren", TanMethodType.photoTan, "902", 6, AllowedTanFormat.Numeric)
|
val tanMethod = TanMethod("photoTAN-Verfahren", TanMethodType.photoTan, "902", 6, AllowedTanFormat.Numeric)
|
||||||
val tanImage = TanImage("image/png", tanImageBytes)
|
val tanImage = TanImage("image/png", tanImageBytes)
|
||||||
|
|
||||||
val user = BankViewInfo("10010010", "Ihr krasser Login Name", "Phantasie Bank", BankingGroup.Comdirect)
|
val bank = BankViewInfo("10010010", "Ihr krasser Login Name", "Phantasie Bank", BankingGroup.Comdirect)
|
||||||
|
|
||||||
val tanChallenge = TanChallenge(TanChallengeType.Image, ActionRequiringTan.GetAccountInfo, "Geben Sie die TAN ein", tanMethod.identifier, listOf(tanMethod), null, emptyList(), tanImage, null, user)
|
val tanChallenge = TanChallenge(TanChallengeType.Image, ActionRequiringTan.GetAccountInfo, "Geben Sie die TAN ein", tanMethod.identifier, listOf(tanMethod), null, emptyList(), tanImage, null, bank)
|
||||||
|
|
||||||
EnterTanDialog(TanChallengeReceived(tanChallenge) { }) { }
|
EnterTanDialog(TanChallengeReceived(tanChallenge) { }) { }
|
||||||
}
|
}
|
||||||
|
@ -50,10 +50,10 @@ fun EnterTanDialogPreview_WithMultipleTanMedia() { // shows that dialog is reall
|
||||||
TanMedium(TanMediumType.TanGenerator, "SparkassenCard (Debitkarte)", TanMediumStatus.Used, TanGeneratorTanMedium("5432109876"))
|
TanMedium(TanMediumType.TanGenerator, "SparkassenCard (Debitkarte)", TanMediumStatus.Used, TanGeneratorTanMedium("5432109876"))
|
||||||
)
|
)
|
||||||
|
|
||||||
val user = BankViewInfo("10010010", "Ihr krasser Login Name", "Eine ganz gewöhnliche Sparkasse", BankingGroup.Sparkasse)
|
val bank = BankViewInfo("10010010", "Ihr krasser Login Name", "Eine ganz gewöhnliche Sparkasse", BankingGroup.Sparkasse)
|
||||||
val account = BankAccountViewInfo("12345678", null, BankAccountType.CheckingAccount, null, "Giro Konto")
|
val account = BankAccountViewInfo("12345678", null, BankAccountType.CheckingAccount, null, "Giro Konto")
|
||||||
|
|
||||||
val tanChallenge = TanChallenge(TanChallengeType.Image, ActionRequiringTan.GetTransactions, "Sie möchten eine \"Umsatzabfrage\" freigeben: Bitte bestätigen Sie den \"Startcode 80061030\" mit der Taste \"OK\".", "913", tanMethods, "SparkassenCard (Debitkarte)", tanMedia, tanImage, null, user, account)
|
val tanChallenge = TanChallenge(TanChallengeType.Image, ActionRequiringTan.GetTransactions, "Sie möchten eine \"Umsatzabfrage\" freigeben: Bitte bestätigen Sie den \"Startcode 80061030\" mit der Taste \"OK\".", "913", tanMethods, "SparkassenCard (Debitkarte)", tanMedia, tanImage, null, bank, account)
|
||||||
|
|
||||||
EnterTanDialog(TanChallengeReceived(tanChallenge) { }) { }
|
EnterTanDialog(TanChallengeReceived(tanChallenge) { }) { }
|
||||||
}
|
}
|
||||||
|
@ -62,8 +62,8 @@ fun EnterTanDialogPreview_WithMultipleTanMedia() { // shows that dialog is reall
|
||||||
@Composable
|
@Composable
|
||||||
fun EnterTanDialogPreview_Flickercode() {
|
fun EnterTanDialogPreview_Flickercode() {
|
||||||
val tanMethods = listOf(TanMethod("chipTAN Flickercode", TanMethodType.ChipTanFlickercode, "902"))
|
val tanMethods = listOf(TanMethod("chipTAN Flickercode", TanMethodType.ChipTanFlickercode, "902"))
|
||||||
val user = BankViewInfo("12345678", "SupiDupiNutzer", "Abzockbank", BankingGroup.Postbank)
|
val bank = BankViewInfo("12345678", "SupiDupiNutzer", "Abzockbank", BankingGroup.Postbank)
|
||||||
val tanChallenge = TanChallenge(TanChallengeType.Flickercode, ActionRequiringTan.GetAccountInfo, "Geben Sie die TAN ein", tanMethods.first().identifier, tanMethods, user = user, flickerCode = FlickerCode("", ""))
|
val tanChallenge = TanChallenge(TanChallengeType.Flickercode, ActionRequiringTan.GetAccountInfo, "Geben Sie die TAN ein", tanMethods.first().identifier, tanMethods, bank = bank, flickerCode = FlickerCode("", ""))
|
||||||
|
|
||||||
EnterTanDialog(TanChallengeReceived(tanChallenge) { }) { }
|
EnterTanDialog(TanChallengeReceived(tanChallenge) { }) { }
|
||||||
}
|
}
|
|
@ -1,19 +1,19 @@
|
||||||
package net.codinux.banking.dataaccess
|
package net.codinux.banking.dataaccess
|
||||||
|
|
||||||
import net.codinux.banking.client.model.AccountTransaction
|
import net.codinux.banking.client.model.AccountTransaction
|
||||||
import net.codinux.banking.client.model.User
|
import net.codinux.banking.client.model.BankAccess
|
||||||
import net.codinux.banking.client.model.securitiesaccount.Holding
|
import net.codinux.banking.client.model.securitiesaccount.Holding
|
||||||
import net.codinux.banking.dataaccess.entities.AccountTransactionEntity
|
import net.codinux.banking.dataaccess.entities.AccountTransactionEntity
|
||||||
import net.codinux.banking.dataaccess.entities.BankAccountEntity
|
import net.codinux.banking.dataaccess.entities.BankAccountEntity
|
||||||
import net.codinux.banking.dataaccess.entities.HoldingEntity
|
import net.codinux.banking.dataaccess.entities.HoldingEntity
|
||||||
import net.codinux.banking.dataaccess.entities.UserEntity
|
import net.codinux.banking.dataaccess.entities.BankAccessEntity
|
||||||
import net.codinux.banking.ui.model.AccountTransactionViewModel
|
import net.codinux.banking.ui.model.AccountTransactionViewModel
|
||||||
|
|
||||||
interface BankingRepository {
|
interface BankingRepository {
|
||||||
|
|
||||||
fun getAllUsers(): List<UserEntity>
|
fun getAllBanks(): List<BankAccessEntity>
|
||||||
|
|
||||||
suspend fun persistUser(user: User): UserEntity
|
suspend fun persistBank(bank: BankAccess): BankAccessEntity
|
||||||
|
|
||||||
suspend fun persistTransactions(bankAccount: BankAccountEntity, transactions: List<AccountTransaction>): List<AccountTransactionEntity>
|
suspend fun persistTransactions(bankAccount: BankAccountEntity, transactions: List<AccountTransaction>): List<AccountTransactionEntity>
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ interface BankingRepository {
|
||||||
|
|
||||||
fun getAllAccountTransactions(): List<AccountTransactionEntity>
|
fun getAllAccountTransactions(): List<AccountTransactionEntity>
|
||||||
|
|
||||||
fun getAllTransactionsOfUser(user: UserEntity): List<AccountTransactionEntity>
|
fun getAllTransactionsForBank(bank: BankAccessEntity): List<AccountTransactionEntity>
|
||||||
|
|
||||||
fun getTransactionById(transactionId: Long): AccountTransactionEntity?
|
fun getTransactionById(transactionId: Long): AccountTransactionEntity?
|
||||||
|
|
||||||
|
|
|
@ -1,31 +1,31 @@
|
||||||
package net.codinux.banking.dataaccess
|
package net.codinux.banking.dataaccess
|
||||||
|
|
||||||
import net.codinux.banking.client.model.AccountTransaction
|
import net.codinux.banking.client.model.AccountTransaction
|
||||||
import net.codinux.banking.client.model.User
|
import net.codinux.banking.client.model.BankAccess
|
||||||
import net.codinux.banking.client.model.securitiesaccount.Holding
|
import net.codinux.banking.client.model.securitiesaccount.Holding
|
||||||
import net.codinux.banking.dataaccess.entities.AccountTransactionEntity
|
import net.codinux.banking.dataaccess.entities.AccountTransactionEntity
|
||||||
import net.codinux.banking.dataaccess.entities.BankAccountEntity
|
import net.codinux.banking.dataaccess.entities.BankAccountEntity
|
||||||
import net.codinux.banking.dataaccess.entities.HoldingEntity
|
import net.codinux.banking.dataaccess.entities.HoldingEntity
|
||||||
import net.codinux.banking.dataaccess.entities.UserEntity
|
import net.codinux.banking.dataaccess.entities.BankAccessEntity
|
||||||
import net.codinux.banking.ui.model.AccountTransactionViewModel
|
import net.codinux.banking.ui.model.AccountTransactionViewModel
|
||||||
|
|
||||||
class InMemoryBankingRepository(
|
class InMemoryBankingRepository(
|
||||||
users: Collection<User> = emptyList(),
|
banks: Collection<BankAccess> = emptyList(),
|
||||||
transactions: Collection<AccountTransaction> = emptyList()
|
transactions: Collection<AccountTransaction> = emptyList()
|
||||||
) : BankingRepository {
|
) : BankingRepository {
|
||||||
|
|
||||||
private var nextId = 0L // TODO: make thread-safe
|
private var nextId = 0L // TODO: make thread-safe
|
||||||
|
|
||||||
private val users = users.map { map(it) }.toMutableList()
|
private val banks = banks.map { map(it) }.toMutableList()
|
||||||
|
|
||||||
private val transactions = transactions.map { map(it) }.toMutableList()
|
private val transactions = transactions.map { map(it) }.toMutableList()
|
||||||
|
|
||||||
|
|
||||||
override fun getAllUsers(): List<UserEntity> = users.toList()
|
override fun getAllBanks(): List<BankAccessEntity> = banks.toList()
|
||||||
|
|
||||||
override suspend fun persistUser(user: User): UserEntity {
|
override suspend fun persistBank(bank: BankAccess): BankAccessEntity {
|
||||||
val entity = map(user) // TODO: may fix someday and add also BankAccounts and their id
|
val entity = map(bank) // TODO: may fix someday and add also BankAccounts and their id
|
||||||
this.users.add(entity)
|
this.banks.add(entity)
|
||||||
return entity
|
return entity
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,27 +50,27 @@ class InMemoryBankingRepository(
|
||||||
|
|
||||||
override fun getAllAccountTransactions(): List<AccountTransactionEntity> = transactions.toList()
|
override fun getAllAccountTransactions(): List<AccountTransactionEntity> = transactions.toList()
|
||||||
|
|
||||||
override fun getAllTransactionsOfUser(user: UserEntity): List<AccountTransactionEntity> =
|
override fun getAllTransactionsForBank(bank: BankAccessEntity): List<AccountTransactionEntity> =
|
||||||
getAllAccountTransactions().filter { it.userId == user.id }
|
getAllAccountTransactions().filter { it.userId == bank.id }
|
||||||
|
|
||||||
override fun getTransactionById(transactionId: Long): AccountTransactionEntity? =
|
override fun getTransactionById(transactionId: Long): AccountTransactionEntity? =
|
||||||
getAllAccountTransactions().firstOrNull { it.id == transactionId }
|
getAllAccountTransactions().firstOrNull { it.id == transactionId }
|
||||||
|
|
||||||
|
|
||||||
private fun map(account: User) = UserEntity(
|
private fun map(bank: BankAccess) = BankAccessEntity(
|
||||||
nextId++,
|
nextId++,
|
||||||
account.bankCode, account.loginName, account.password, account.bankName, account.bic, account.customerName, account.userId,
|
bank.bankCode, bank.loginName, bank.password, bank.bankName, bank.bic, bank.customerName, bank.userId,
|
||||||
// TODO: may fix someday and also add BankAccounts
|
// TODO: may fix someday and also add BankAccounts
|
||||||
emptyList(), account.selectedTanMethodIdentifier, emptyList(), account.selectedTanMediumIdentifier, emptyList(),
|
emptyList(), bank.selectedTanMethodIdentifier, emptyList(), bank.selectedTanMediumIdentifier, emptyList(),
|
||||||
account.bankingGroup, account.serverAddress,
|
bank.bankingGroup, bank.serverAddress,
|
||||||
account.userSetDisplayName, account.displayIndex,
|
bank.userSetDisplayName, bank.displayIndex,
|
||||||
account.iconUrl, account.wrongCredentialsEntered,
|
bank.iconUrl, bank.wrongCredentialsEntered,
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO: someday may fix and get userId and bankAccountId
|
// TODO: someday may fix and get bankId and bankAccountId
|
||||||
private fun map(transaction: AccountTransaction, userId: Long = nextId++, bankAccountId: Long = nextId++) = AccountTransactionEntity(
|
private fun map(transaction: AccountTransaction, bankId: Long = nextId++, bankAccountId: Long = nextId++) = AccountTransactionEntity(
|
||||||
nextId++,
|
nextId++,
|
||||||
userId, bankAccountId,
|
bankId, bankAccountId,
|
||||||
transaction.amount, transaction.currency, transaction.reference,
|
transaction.amount, transaction.currency, transaction.reference,
|
||||||
transaction.bookingDate, transaction.valueDate,
|
transaction.bookingDate, transaction.valueDate,
|
||||||
transaction.otherPartyName, transaction.otherPartyBankId, transaction.otherPartyAccountId,
|
transaction.otherPartyName, transaction.otherPartyBankId, transaction.otherPartyAccountId,
|
||||||
|
|
|
@ -19,53 +19,53 @@ open class SqliteBankingRepository(
|
||||||
|
|
||||||
private val database = BankmeisterDb(sqlDriver)
|
private val database = BankmeisterDb(sqlDriver)
|
||||||
|
|
||||||
private val userQueries = database.userQueries
|
private val bankQueries = database.userQueries
|
||||||
|
|
||||||
private val accountTransactionQueries = database.accountTransactionQueries
|
private val accountTransactionQueries = database.accountTransactionQueries
|
||||||
|
|
||||||
private val log by logger()
|
private val log by logger()
|
||||||
|
|
||||||
|
|
||||||
override fun getAllUsers(): List<UserEntity> {
|
override fun getAllBanks(): List<BankAccessEntity> {
|
||||||
val bankAccounts = getAllBankAccounts().groupBy { it.userId }
|
val bankAccounts = getAllBankAccounts().groupBy { it.userId }
|
||||||
val tanMethods = getAllTanMethods().groupBy { it.userId }
|
val tanMethods = getAllTanMethods().groupBy { it.userId }
|
||||||
val tanMedia = getAllTanMedia().groupBy { it.userId }
|
val tanMedia = getAllTanMedia().groupBy { it.userId }
|
||||||
val holdings = getAllHoldings().groupBy { it.bankAccountId }
|
val holdings = getAllHoldings().groupBy { it.bankAccountId }
|
||||||
|
|
||||||
return userQueries.selectAllUsers { id, bankCode, loginName, password, bankName, bic, customerName, userId, selectedTanMethodIdentifier, selectedTanMediumIdentifier, bankingGroup, serverAddress, userSetDisplayName, clientData, displayIndex, iconUrl, wrongCredentialsEntered ->
|
return bankQueries.selectAllBanks { id, bankCode, loginName, password, bankName, bic, customerName, userId, selectedTanMethodIdentifier, selectedTanMediumIdentifier, bankingGroup, serverAddress, userSetDisplayName, clientData, displayIndex, iconUrl, wrongCredentialsEntered ->
|
||||||
UserEntity(id, bankCode, loginName, password, bankName, bic, customerName, userId, getAccountsOfUser(id, bankAccounts, holdings), selectedTanMethodIdentifier, tanMethods[id] ?: emptyList(), selectedTanMediumIdentifier, tanMedia[id] ?: emptyList(),
|
BankAccessEntity(id, bankCode, loginName, password, bankName, bic, customerName, userId, getAccountsOfBank(id, bankAccounts, holdings), selectedTanMethodIdentifier, tanMethods[id] ?: emptyList(), selectedTanMediumIdentifier, tanMedia[id] ?: emptyList(),
|
||||||
bankingGroup?.let { BankingGroup.valueOf(it) }, serverAddress, userSetDisplayName, displayIndex.toInt(), iconUrl, wrongCredentialsEntered)
|
bankingGroup?.let { BankingGroup.valueOf(it) }, serverAddress, userSetDisplayName, displayIndex.toInt(), iconUrl, wrongCredentialsEntered)
|
||||||
}.executeAsList()
|
}.executeAsList()
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun getAccountsOfUser(userId: Long, bankAccounts: Map<Long, List<BankAccountEntity>>, holdings: Map<Long, List<HoldingEntity>>): List<BankAccountEntity> {
|
protected open fun getAccountsOfBank(bankId: Long, bankAccounts: Map<Long, List<BankAccountEntity>>, holdings: Map<Long, List<HoldingEntity>>): List<BankAccountEntity> {
|
||||||
return bankAccounts[userId].orEmpty().onEach {
|
return bankAccounts[bankId].orEmpty().onEach {
|
||||||
it.holdings = holdings[it.id].orEmpty()
|
it.holdings = holdings[it.id].orEmpty()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun persistUser(user: User): UserEntity {
|
override suspend fun persistBank(bank: BankAccess): BankAccessEntity {
|
||||||
return userQueries.transactionWithResult {
|
return bankQueries.transactionWithResult {
|
||||||
userQueries.insertUser(user.bankCode, user.loginName, user.password, user.bankName, user.bic,
|
bankQueries.insertBank(bank.bankCode, bank.loginName, bank.password, bank.bankName, bank.bic,
|
||||||
user.customerName, user.userId, user.selectedTanMethodIdentifier, user.selectedTanMediumIdentifier,
|
bank.customerName, bank.userId, bank.selectedTanMethodIdentifier, bank.selectedTanMediumIdentifier,
|
||||||
user.bankingGroup?.name, user.serverAddress, null, user.userSetDisplayName, user.displayIndex.toLong(), user.iconUrl, user.wrongCredentialsEntered
|
bank.bankingGroup?.name, bank.serverAddress, null, bank.userSetDisplayName, bank.displayIndex.toLong(), bank.iconUrl, bank.wrongCredentialsEntered
|
||||||
)
|
)
|
||||||
|
|
||||||
val userId = getLastInsertedId() // getLastInsertedId() / last_insert_rowid() has to be called in a transaction with the insert operation, otherwise it will not work
|
val bankId = getLastInsertedId() // getLastInsertedId() / last_insert_rowid() has to be called in a transaction with the insert operation, otherwise it will not work
|
||||||
|
|
||||||
val bankAccounts = persistBankAccounts(userId, user.accounts)
|
val bankAccounts = persistBankAccounts(bankId, bank.accounts)
|
||||||
|
|
||||||
val tanMethods = persistTanMethods(userId, user.tanMethods)
|
val tanMethods = persistTanMethods(bankId, bank.tanMethods)
|
||||||
val tanMedia = persistTanMedia(userId, user.tanMedia)
|
val tanMedia = persistTanMedia(bankId, bank.tanMedia)
|
||||||
|
|
||||||
UserEntity(userId, user, bankAccounts, tanMethods, tanMedia)
|
BankAccessEntity(bankId, bank, bankAccounts, tanMethods, tanMedia)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun getAllBankAccounts(): List<BankAccountEntity> = userQueries.selectAllBankAccounts { id, userId, identifier, subAccountNumber, iban, productName, accountHolderName, type, currency, accountLimit, isAccountTypeSupportedByApplication, features, balance, serverTransactionsRetentionDays, lastAccountUpdateTime, retrievedTransactionsFrom, userSetDisplayName, displayIndex, hideAccount, includeInAutomaticAccountsUpdate ->
|
fun getAllBankAccounts(): List<BankAccountEntity> = bankQueries.selectAllBankAccounts { id, bankId, identifier, subAccountNumber, iban, productName, accountHolderName, type, currency, accountLimit, isAccountTypeSupportedByApplication, features, balance, serverTransactionsRetentionDays, lastAccountUpdateTime, retrievedTransactionsFrom, userSetDisplayName, displayIndex, hideAccount, includeInAutomaticAccountsUpdate ->
|
||||||
BankAccountEntity(
|
BankAccountEntity(
|
||||||
id, userId,
|
id, bankId,
|
||||||
|
|
||||||
identifier, subAccountNumber, iban, productName,
|
identifier, subAccountNumber, iban, productName,
|
||||||
|
|
||||||
|
@ -86,15 +86,15 @@ open class SqliteBankingRepository(
|
||||||
)
|
)
|
||||||
}.executeAsList()
|
}.executeAsList()
|
||||||
|
|
||||||
private suspend fun persistBankAccounts(userId: Long, bankAccounts: Collection<BankAccount>): List<BankAccountEntity> =
|
private suspend fun persistBankAccounts(bankId: Long, bankAccounts: Collection<BankAccount>): List<BankAccountEntity> =
|
||||||
bankAccounts.map { persistBankAccount(userId, it) }
|
bankAccounts.map { persistBankAccount(bankId, it) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Has to be executed in a transaction in order that getting persisted BankAccount's id works~
|
* Has to be executed in a transaction in order that getting persisted BankAccount's id works~
|
||||||
*/
|
*/
|
||||||
private suspend fun persistBankAccount(userId: Long, account: BankAccount): BankAccountEntity {
|
private suspend fun persistBankAccount(bankId: Long, account: BankAccount): BankAccountEntity {
|
||||||
userQueries.insertBankAccount(
|
bankQueries.insertBankAccount(
|
||||||
userId,
|
bankId,
|
||||||
account.identifier, account.accountHolderName, mapEnum(account.type),
|
account.identifier, account.accountHolderName, mapEnum(account.type),
|
||||||
account.iban, account.subAccountNumber, account.productName, account.currency, account.accountLimit,
|
account.iban, account.subAccountNumber, account.productName, account.currency, account.accountLimit,
|
||||||
|
|
||||||
|
@ -111,19 +111,19 @@ open class SqliteBankingRepository(
|
||||||
val accountId = getLastInsertedId()
|
val accountId = getLastInsertedId()
|
||||||
|
|
||||||
val accountTransactionEntities = account.bookedTransactions.map { transaction ->
|
val accountTransactionEntities = account.bookedTransactions.map { transaction ->
|
||||||
persistTransaction(userId, accountId, transaction)
|
persistTransaction(bankId, accountId, transaction)
|
||||||
}
|
}
|
||||||
|
|
||||||
val holdings = account.holdings.map { holding -> persistHolding(userId, accountId, holding) }
|
val holdings = account.holdings.map { holding -> persistHolding(bankId, accountId, holding) }
|
||||||
|
|
||||||
return BankAccountEntity(accountId, userId, account, accountTransactionEntities, holdings)
|
return BankAccountEntity(accountId, bankId, account, accountTransactionEntities, holdings)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun getAllTanMethods(): List<TanMethodEntity> = userQueries.selectAllTanMethods { id, userId, displayName, type, identifier, maxTanInputLength, allowedTanFormat ->
|
private fun getAllTanMethods(): List<TanMethodEntity> = bankQueries.selectAllTanMethods { id, bankId, displayName, type, identifier, maxTanInputLength, allowedTanFormat ->
|
||||||
TanMethodEntity(
|
TanMethodEntity(
|
||||||
id,
|
id,
|
||||||
userId,
|
bankId,
|
||||||
|
|
||||||
displayName,
|
displayName,
|
||||||
mapToEnum(type, TanMethodType.entries),
|
mapToEnum(type, TanMethodType.entries),
|
||||||
|
@ -133,12 +133,12 @@ open class SqliteBankingRepository(
|
||||||
)
|
)
|
||||||
}.executeAsList()
|
}.executeAsList()
|
||||||
|
|
||||||
private suspend fun persistTanMethods(userId: Long, tanMethods: List<TanMethod>): List<TanMethodEntity> =
|
private suspend fun persistTanMethods(bankId: Long, tanMethods: List<TanMethod>): List<TanMethodEntity> =
|
||||||
tanMethods.map { persistTanMethod(userId, it) }
|
tanMethods.map { persistTanMethod(bankId, it) }
|
||||||
|
|
||||||
private suspend fun persistTanMethod(userId: Long, tanMethod: TanMethod): TanMethodEntity {
|
private suspend fun persistTanMethod(bankId: Long, tanMethod: TanMethod): TanMethodEntity {
|
||||||
userQueries.insertTanMethod(
|
bankQueries.insertTanMethod(
|
||||||
userId,
|
bankId,
|
||||||
|
|
||||||
tanMethod.displayName,
|
tanMethod.displayName,
|
||||||
mapEnum(tanMethod.type),
|
mapEnum(tanMethod.type),
|
||||||
|
@ -149,11 +149,11 @@ open class SqliteBankingRepository(
|
||||||
|
|
||||||
val tanMethodId = getLastInsertedId()
|
val tanMethodId = getLastInsertedId()
|
||||||
|
|
||||||
return TanMethodEntity(tanMethodId, userId, tanMethod)
|
return TanMethodEntity(tanMethodId, bankId, tanMethod)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun getAllTanMedia(): List<TanMediumEntity> = userQueries.selectAllTanMedia { id, userId, type, mediumName, status, phoneNumber, concealedPhoneNumber, cardNumber, cardSequenceNumber, cardType, validFrom, validTo ->
|
private fun getAllTanMedia(): List<TanMediumEntity> = bankQueries.selectAllTanMedia { id, bankId, type, mediumName, status, phoneNumber, concealedPhoneNumber, cardNumber, cardSequenceNumber, cardType, validFrom, validTo ->
|
||||||
val mobilePhone = if (phoneNumber != null || concealedPhoneNumber != null) {
|
val mobilePhone = if (phoneNumber != null || concealedPhoneNumber != null) {
|
||||||
MobilePhoneTanMedium(phoneNumber, concealedPhoneNumber)
|
MobilePhoneTanMedium(phoneNumber, concealedPhoneNumber)
|
||||||
} else {
|
} else {
|
||||||
|
@ -168,7 +168,7 @@ open class SqliteBankingRepository(
|
||||||
|
|
||||||
TanMediumEntity(
|
TanMediumEntity(
|
||||||
id,
|
id,
|
||||||
userId,
|
bankId,
|
||||||
|
|
||||||
mapToEnum(type, TanMediumType.entries),
|
mapToEnum(type, TanMediumType.entries),
|
||||||
mediumName,
|
mediumName,
|
||||||
|
@ -179,12 +179,12 @@ open class SqliteBankingRepository(
|
||||||
)
|
)
|
||||||
}.executeAsList()
|
}.executeAsList()
|
||||||
|
|
||||||
private suspend fun persistTanMedia(userId: Long, tanMedia: List<TanMedium>): List<TanMediumEntity> =
|
private suspend fun persistTanMedia(bankId: Long, tanMedia: List<TanMedium>): List<TanMediumEntity> =
|
||||||
tanMedia.map { persistTanMedium(userId, it) }
|
tanMedia.map { persistTanMedium(bankId, it) }
|
||||||
|
|
||||||
private suspend fun persistTanMedium(userId: Long, medium: TanMedium): TanMediumEntity {
|
private suspend fun persistTanMedium(bankId: Long, medium: TanMedium): TanMediumEntity {
|
||||||
userQueries.insertTanMedium(
|
bankQueries.insertTanMedium(
|
||||||
userId,
|
bankId,
|
||||||
|
|
||||||
mapEnum(medium.type),
|
mapEnum(medium.type),
|
||||||
medium.mediumName,
|
medium.mediumName,
|
||||||
|
@ -202,13 +202,13 @@ open class SqliteBankingRepository(
|
||||||
|
|
||||||
val tanMediumId = getLastInsertedId()
|
val tanMediumId = getLastInsertedId()
|
||||||
|
|
||||||
return TanMediumEntity(tanMediumId, userId, medium)
|
return TanMediumEntity(tanMediumId, bankId, medium)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected open fun getAllHoldings(): List<HoldingEntity> =
|
protected open fun getAllHoldings(): List<HoldingEntity> =
|
||||||
accountTransactionQueries.selectAllHoldings { id, userId, bankAccountId, name, isin, wkn, quantity, currency, totalBalance, marketValue, performancePercentage, totalCostPrice, averageCostPrice, pricingTime, buyingDate ->
|
accountTransactionQueries.selectAllHoldings { id, bankId, bankAccountId, name, isin, wkn, quantity, currency, totalBalance, marketValue, performancePercentage, totalCostPrice, averageCostPrice, pricingTime, buyingDate ->
|
||||||
HoldingEntity(id, userId, bankAccountId, name, isin, wkn, mapToInt(quantity), currency, mapToAmount(totalBalance), mapToAmount(marketValue), performancePercentage?.toFloat(), mapToAmount(totalCostPrice), mapToAmount(averageCostPrice), mapToInstant(pricingTime), mapToDate(buyingDate))
|
HoldingEntity(id, bankId, bankAccountId, name, isin, wkn, mapToInt(quantity), currency, mapToAmount(totalBalance), mapToAmount(marketValue), performancePercentage?.toFloat(), mapToAmount(totalCostPrice), mapToAmount(averageCostPrice), mapToInstant(pricingTime), mapToDate(buyingDate))
|
||||||
}.executeAsList()
|
}.executeAsList()
|
||||||
|
|
||||||
override suspend fun persistHoldings(bankAccount: BankAccountEntity, holdings: List<Holding>): List<HoldingEntity> =
|
override suspend fun persistHoldings(bankAccount: BankAccountEntity, holdings: List<Holding>): List<HoldingEntity> =
|
||||||
|
@ -219,9 +219,9 @@ open class SqliteBankingRepository(
|
||||||
/**
|
/**
|
||||||
* Has to be executed in a transaction in order that getting persisted Holding's id works~
|
* Has to be executed in a transaction in order that getting persisted Holding's id works~
|
||||||
*/
|
*/
|
||||||
protected open suspend fun persistHolding(userId: Long, bankAccountId: Long, holding: Holding): HoldingEntity {
|
protected open suspend fun persistHolding(bankId: Long, bankAccountId: Long, holding: Holding): HoldingEntity {
|
||||||
accountTransactionQueries.insertHolding(
|
accountTransactionQueries.insertHolding(
|
||||||
userId, bankAccountId,
|
bankId, bankAccountId,
|
||||||
|
|
||||||
holding.name, holding.isin, holding.wkn,
|
holding.name, holding.isin, holding.wkn,
|
||||||
|
|
||||||
|
@ -234,7 +234,7 @@ open class SqliteBankingRepository(
|
||||||
mapInstant(holding.pricingTime), mapDate(holding.buyingDate)
|
mapInstant(holding.pricingTime), mapDate(holding.buyingDate)
|
||||||
)
|
)
|
||||||
|
|
||||||
return HoldingEntity(getLastInsertedId(), userId, bankAccountId, holding)
|
return HoldingEntity(getLastInsertedId(), bankId, bankAccountId, holding)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun updateHoldings(holdings: List<HoldingEntity>) {
|
override suspend fun updateHoldings(holdings: List<HoldingEntity>) {
|
||||||
|
@ -266,16 +266,16 @@ open class SqliteBankingRepository(
|
||||||
|
|
||||||
|
|
||||||
override fun getAllAccountTransactionsAsViewModel(): List<AccountTransactionViewModel> =
|
override fun getAllAccountTransactionsAsViewModel(): List<AccountTransactionViewModel> =
|
||||||
accountTransactionQueries.selectAllTransactionsAsViewModel { id, userId, bankAccountId, amount, currency, reference, valueDate, otherPartyName, postingText, userSetDisplayName, category ->
|
accountTransactionQueries.selectAllTransactionsAsViewModel { id, bankId, bankAccountId, amount, currency, reference, valueDate, otherPartyName, postingText, userSetDisplayName, category ->
|
||||||
AccountTransactionViewModel(id, userId, bankAccountId, mapToAmount(amount), currency, reference, mapToDate(valueDate), otherPartyName, postingText, userSetDisplayName, category)
|
AccountTransactionViewModel(id, bankId, bankAccountId, mapToAmount(amount), currency, reference, mapToDate(valueDate), otherPartyName, postingText, userSetDisplayName, category)
|
||||||
}.executeAsList()
|
}.executeAsList()
|
||||||
|
|
||||||
override fun getAllAccountTransactions(): List<AccountTransactionEntity> {
|
override fun getAllAccountTransactions(): List<AccountTransactionEntity> {
|
||||||
return accountTransactionQueries.selectAllTransactions(::mapTransaction).executeAsList()
|
return accountTransactionQueries.selectAllTransactions(::mapTransaction).executeAsList()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getAllTransactionsOfUser(user: UserEntity): List<AccountTransactionEntity> {
|
override fun getAllTransactionsForBank(bank: BankAccessEntity): List<AccountTransactionEntity> {
|
||||||
return accountTransactionQueries.selectAllTransactionsOfUser(user.id, ::mapTransaction).executeAsList()
|
return accountTransactionQueries.selectAllTransactionsOfUser(bank.id, ::mapTransaction).executeAsList()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getTransactionById(transactionId: Long): AccountTransactionEntity? =
|
override fun getTransactionById(transactionId: Long): AccountTransactionEntity? =
|
||||||
|
@ -293,9 +293,9 @@ open class SqliteBankingRepository(
|
||||||
/**
|
/**
|
||||||
* Has to be executed in a transaction in order that getting persisted AccountTransaction's id works~
|
* Has to be executed in a transaction in order that getting persisted AccountTransaction's id works~
|
||||||
*/
|
*/
|
||||||
protected open suspend fun persistTransaction(userId: Long, bankAccountId: Long, transaction: AccountTransaction): AccountTransactionEntity {
|
protected open suspend fun persistTransaction(bankId: Long, bankAccountId: Long, transaction: AccountTransaction): AccountTransactionEntity {
|
||||||
accountTransactionQueries.insertTransaction(
|
accountTransactionQueries.insertTransaction(
|
||||||
userId, bankAccountId,
|
bankId, bankAccountId,
|
||||||
|
|
||||||
mapAmount(transaction.amount), transaction.currency, transaction.reference,
|
mapAmount(transaction.amount), transaction.currency, transaction.reference,
|
||||||
mapDate(transaction.bookingDate), mapDate(transaction.valueDate),
|
mapDate(transaction.bookingDate), mapDate(transaction.valueDate),
|
||||||
|
@ -326,16 +326,16 @@ open class SqliteBankingRepository(
|
||||||
transaction.isReversal
|
transaction.isReversal
|
||||||
)
|
)
|
||||||
|
|
||||||
return AccountTransactionEntity(getLastInsertedId(), userId, bankAccountId, transaction)
|
return AccountTransactionEntity(getLastInsertedId(), bankId, bankAccountId, transaction)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun getLastInsertedId(): Long =
|
private fun getLastInsertedId(): Long =
|
||||||
userQueries.getLastInsertedId().executeAsOne()
|
bankQueries.getLastInsertedId().executeAsOne()
|
||||||
|
|
||||||
|
|
||||||
private fun mapTransaction(
|
private fun mapTransaction(
|
||||||
id: Long, userId: Long, bankAccountId: Long,
|
id: Long, bankId: Long, bankAccountId: Long,
|
||||||
|
|
||||||
amount: String, currency: String, reference: String?,
|
amount: String, currency: String, reference: String?,
|
||||||
bookingDate: String, valueDate: String,
|
bookingDate: String, valueDate: String,
|
||||||
|
@ -366,7 +366,7 @@ open class SqliteBankingRepository(
|
||||||
isReversal: Boolean
|
isReversal: Boolean
|
||||||
): AccountTransactionEntity = AccountTransactionEntity(
|
): AccountTransactionEntity = AccountTransactionEntity(
|
||||||
id,
|
id,
|
||||||
userId, bankAccountId,
|
bankId, bankAccountId,
|
||||||
|
|
||||||
Amount(amount), currency, reference,
|
Amount(amount), currency, reference,
|
||||||
mapToDate(bookingDate), mapToDate(valueDate),
|
mapToDate(bookingDate), mapToDate(valueDate),
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
package net.codinux.banking.dataaccess.entities
|
package net.codinux.banking.dataaccess.entities
|
||||||
|
|
||||||
|
import net.codinux.banking.client.model.BankAccess
|
||||||
import net.codinux.banking.client.model.BankingGroup
|
import net.codinux.banking.client.model.BankingGroup
|
||||||
import net.codinux.banking.client.model.User
|
|
||||||
import net.codinux.banking.client.model.tan.TanMedium
|
import net.codinux.banking.client.model.tan.TanMedium
|
||||||
import net.codinux.banking.client.model.tan.TanMethod
|
|
||||||
|
|
||||||
class UserEntity(
|
class BankAccessEntity(
|
||||||
val id: Long,
|
val id: Long,
|
||||||
|
|
||||||
bankCode: String,
|
bankCode: String,
|
||||||
|
@ -13,7 +12,7 @@ class UserEntity(
|
||||||
password: String?,
|
password: String?,
|
||||||
|
|
||||||
bankName: String,
|
bankName: String,
|
||||||
bic: String,
|
bic: String?,
|
||||||
|
|
||||||
customerName: String,
|
customerName: String,
|
||||||
userId: String? = null,
|
userId: String? = null,
|
||||||
|
@ -34,7 +33,7 @@ class UserEntity(
|
||||||
|
|
||||||
iconUrl: String? = null,
|
iconUrl: String? = null,
|
||||||
wrongCredentialsEntered: Boolean = false
|
wrongCredentialsEntered: Boolean = false
|
||||||
) : User(bankCode, loginName, password, bankName, bic, customerName, userId, accounts, selectedTanMethodIdentifier, tanMethods, selectedTanMediumIdentifier, tanMedia, bankingGroup, serverAddress) {
|
) : BankAccess(bankCode, loginName, password, bankName, bic, customerName, userId, accounts, selectedTanMethodIdentifier, tanMethods, selectedTanMediumIdentifier, tanMedia, bankingGroup, serverAddress) {
|
||||||
|
|
||||||
init {
|
init {
|
||||||
this.userSetDisplayName = userSetDisplayName
|
this.userSetDisplayName = userSetDisplayName
|
||||||
|
@ -45,14 +44,14 @@ class UserEntity(
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
constructor(id: Long, user: User, bankAccounts: List<BankAccountEntity>, tanMethods: List<TanMethodEntity>, tanMedia: List<TanMediumEntity>) : this(
|
constructor(id: Long, bank: BankAccess, bankAccounts: List<BankAccountEntity>, tanMethods: List<TanMethodEntity>, tanMedia: List<TanMediumEntity>) : this(
|
||||||
id,
|
id,
|
||||||
user.bankCode, user.loginName, user.password, user.bankName, user.bic, user.customerName, user.userId,
|
bank.bankCode, bank.loginName, bank.password, bank.bankName, bank.bic, bank.customerName, bank.userId,
|
||||||
bankAccounts,
|
bankAccounts,
|
||||||
user.selectedTanMethodIdentifier, tanMethods, user.selectedTanMediumIdentifier, tanMedia,
|
bank.selectedTanMethodIdentifier, tanMethods, bank.selectedTanMediumIdentifier, tanMedia,
|
||||||
user.bankingGroup, user.serverAddress,
|
bank.bankingGroup, bank.serverAddress,
|
||||||
user.userSetDisplayName, user.displayIndex,
|
bank.userSetDisplayName, bank.displayIndex,
|
||||||
user.iconUrl, user.wrongCredentialsEntered,
|
bank.iconUrl, bank.wrongCredentialsEntered,
|
||||||
)
|
)
|
||||||
|
|
||||||
}
|
}
|
|
@ -29,7 +29,7 @@ private val IconWidth = 48.dp
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun BottomBar(showMenuDrawer: Boolean = true) {
|
fun BottomBar(showMenuDrawer: Boolean = true) {
|
||||||
val users by uiState.users.collectAsState()
|
val banks by uiState.banks.collectAsState()
|
||||||
|
|
||||||
val transactionsFilter by uiState.transactionsFilter.collectAsState()
|
val transactionsFilter by uiState.transactionsFilter.collectAsState()
|
||||||
|
|
||||||
|
@ -65,7 +65,7 @@ fun BottomBar(showMenuDrawer: Boolean = true) {
|
||||||
} else if (selectedAccount.bankAccount != null) {
|
} else if (selectedAccount.bankAccount != null) {
|
||||||
selectedAccount.bankAccount.displayName
|
selectedAccount.bankAccount.displayName
|
||||||
} else {
|
} else {
|
||||||
selectedAccount.user.displayName
|
selectedAccount.bank.displayName
|
||||||
}
|
}
|
||||||
|
|
||||||
Text(title, color = color, maxLines = 1, overflow = TextOverflow.Ellipsis)
|
Text(title, color = color, maxLines = 1, overflow = TextOverflow.Ellipsis)
|
||||||
|
@ -122,7 +122,7 @@ fun BottomBar(showMenuDrawer: Boolean = true) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (users.isNotEmpty()) {
|
if (banks.isNotEmpty()) {
|
||||||
if (showSearchbar == false) {
|
if (showSearchbar == false) {
|
||||||
Row(Modifier.fillMaxHeight().widthIn(IconWidth, IconWidth), verticalAlignment = Alignment.CenterVertically) {
|
Row(Modifier.fillMaxHeight().widthIn(IconWidth, IconWidth), verticalAlignment = Alignment.CenterVertically) {
|
||||||
IconButton({ showSearchbar = true }, Modifier.width(IconWidth)) {
|
IconButton({ showSearchbar = true }, Modifier.width(IconWidth)) {
|
||||||
|
|
|
@ -2,7 +2,6 @@ package net.codinux.banking.ui.appskeleton
|
||||||
|
|
||||||
import androidx.compose.foundation.*
|
import androidx.compose.foundation.*
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.material.Divider
|
|
||||||
import androidx.compose.material.Icon
|
import androidx.compose.material.Icon
|
||||||
import androidx.compose.material.Text
|
import androidx.compose.material.Text
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
|
@ -55,7 +54,7 @@ private val VerticalSpacing = 8.dp
|
||||||
fun SideMenuContent() {
|
fun SideMenuContent() {
|
||||||
val drawerState = uiState.drawerState.collectAsState().value
|
val drawerState = uiState.drawerState.collectAsState().value
|
||||||
|
|
||||||
val accounts = uiState.users.collectAsState().value
|
val accounts = uiState.banks.collectAsState().value
|
||||||
|
|
||||||
val coroutineScope = rememberCoroutineScope()
|
val coroutineScope = rememberCoroutineScope()
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.vector.ImageVector
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import net.codinux.banking.client.model.User
|
import net.codinux.banking.client.model.BankAccess
|
||||||
import net.codinux.banking.client.model.BankViewInfo
|
import net.codinux.banking.client.model.BankViewInfo
|
||||||
import net.codinux.banking.ui.config.DI
|
import net.codinux.banking.ui.config.DI
|
||||||
import net.codinux.banking.ui.model.BankInfo
|
import net.codinux.banking.ui.model.BankInfo
|
||||||
|
@ -21,8 +21,8 @@ private val bankIconService = DI.bankIconService
|
||||||
private val DefaultIconModifier: Modifier = Modifier.size(16.dp)
|
private val DefaultIconModifier: Modifier = Modifier.size(16.dp)
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun BankIcon(user: User?, modifier: Modifier = Modifier, iconModifier: Modifier = DefaultIconModifier, fallbackIcon: ImageVector? = null, fallbackIconTintColor: Color? = null) {
|
fun BankIcon(bank: BankAccess?, modifier: Modifier = Modifier, iconModifier: Modifier = DefaultIconModifier, fallbackIcon: ImageVector? = null, fallbackIconTintColor: Color? = null) {
|
||||||
val iconUrl by remember(user?.bic) { mutableStateOf(user?.let { bankIconService.findIconForBank(it) }) }
|
val iconUrl by remember(bank?.bic) { mutableStateOf(bank?.let { bankIconService.findIconForBank(it) }) }
|
||||||
|
|
||||||
BankIcon(iconUrl, modifier, iconModifier, fallbackIcon = fallbackIcon, fallbackIconTintColor = fallbackIconTintColor)
|
BankIcon(iconUrl, modifier, iconModifier, fallbackIcon = fallbackIcon, fallbackIconTintColor = fallbackIconTintColor)
|
||||||
}
|
}
|
||||||
|
@ -37,8 +37,8 @@ fun BankIcon(bank: BankInfo, modifier: Modifier = Modifier, iconModifier: Modifi
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun BankIcon(user: BankViewInfo?, modifier: Modifier = Modifier, iconModifier: Modifier = DefaultIconModifier, fallbackIcon: ImageVector? = null) {
|
fun BankIcon(bank: BankViewInfo?, modifier: Modifier = Modifier, iconModifier: Modifier = DefaultIconModifier, fallbackIcon: ImageVector? = null) {
|
||||||
val iconUrl = user?.let { bankIconService.findIconForBank(it.bankName, null, it.bankingGroup) }
|
val iconUrl = bank?.let { bankIconService.findIconForBank(it.bankName, null, it.bankingGroup) }
|
||||||
|
|
||||||
BankIcon(iconUrl, modifier, iconModifier, fallbackIcon = fallbackIcon)
|
BankIcon(iconUrl, modifier, iconModifier, fallbackIcon = fallbackIcon)
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.unit.Dp
|
import androidx.compose.ui.unit.Dp
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import net.codinux.banking.dataaccess.entities.BankAccountEntity
|
import net.codinux.banking.dataaccess.entities.BankAccountEntity
|
||||||
import net.codinux.banking.dataaccess.entities.UserEntity
|
import net.codinux.banking.dataaccess.entities.BankAccessEntity
|
||||||
import net.codinux.banking.ui.config.DI
|
import net.codinux.banking.ui.config.DI
|
||||||
|
|
||||||
private val uiState = DI.uiState
|
private val uiState = DI.uiState
|
||||||
|
@ -27,9 +27,9 @@ fun BanksList(
|
||||||
textColor: Color = Color.White,
|
textColor: Color = Color.White,
|
||||||
itemModifier: Modifier = Modifier.height(48.dp).widthIn(min = 300.dp),
|
itemModifier: Modifier = Modifier.height(48.dp).widthIn(min = 300.dp),
|
||||||
itemHorizontalPadding: Dp = 8.dp,
|
itemHorizontalPadding: Dp = 8.dp,
|
||||||
accountSelected: ((UserEntity?, BankAccountEntity?) -> Unit)? = null
|
accountSelected: ((BankAccessEntity?, BankAccountEntity?) -> Unit)? = null
|
||||||
) {
|
) {
|
||||||
val users = uiState.users.collectAsState()
|
val banks = uiState.banks.collectAsState()
|
||||||
|
|
||||||
|
|
||||||
Column(modifier) {
|
Column(modifier) {
|
||||||
|
@ -37,16 +37,16 @@ fun BanksList(
|
||||||
accountSelected?.invoke(null, null)
|
accountSelected?.invoke(null, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
users.value.sortedBy { it.displayIndex }.forEach { user ->
|
banks.value.sortedBy { it.displayIndex }.forEach { bank ->
|
||||||
Spacer(Modifier.fillMaxWidth().height(12.dp))
|
Spacer(Modifier.fillMaxWidth().height(12.dp))
|
||||||
|
|
||||||
NavigationMenuItem(itemModifier, user.displayName, textColor, iconSize, IconTextSpacing, itemHorizontalPadding, user, fallbackIcon = defaultBankIcon) {
|
NavigationMenuItem(itemModifier, bank.displayName, textColor, iconSize, IconTextSpacing, itemHorizontalPadding, bank, fallbackIcon = defaultBankIcon) {
|
||||||
accountSelected?.invoke(user, null)
|
accountSelected?.invoke(bank, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
user.accounts.sortedBy { it.displayIndex }.forEach { account ->
|
bank.accounts.sortedBy { it.displayIndex }.forEach { account ->
|
||||||
NavigationMenuItem(itemModifier, account.displayName, textColor, iconSize, IconTextSpacing, itemHorizontalPadding, bankAccount = account) {
|
NavigationMenuItem(itemModifier, account.displayName, textColor, iconSize, IconTextSpacing, itemHorizontalPadding, bankAccount = account) {
|
||||||
accountSelected?.invoke(user, account)
|
accountSelected?.invoke(bank, account)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@ import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.unit.Dp
|
import androidx.compose.ui.unit.Dp
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import net.codinux.banking.dataaccess.entities.BankAccountEntity
|
import net.codinux.banking.dataaccess.entities.BankAccountEntity
|
||||||
import net.codinux.banking.dataaccess.entities.UserEntity
|
import net.codinux.banking.dataaccess.entities.BankAccessEntity
|
||||||
import net.codinux.banking.ui.config.Colors
|
import net.codinux.banking.ui.config.Colors
|
||||||
import net.codinux.banking.ui.config.DI
|
import net.codinux.banking.ui.config.DI
|
||||||
|
|
||||||
|
@ -37,7 +37,7 @@ fun NavigationMenuItem(
|
||||||
iconSize: Dp = 24.dp,
|
iconSize: Dp = 24.dp,
|
||||||
iconTextSpacing: Dp = 24.dp,
|
iconTextSpacing: Dp = 24.dp,
|
||||||
horizontalPadding: Dp = 8.dp,
|
horizontalPadding: Dp = 8.dp,
|
||||||
user: UserEntity? = null,
|
bank: BankAccessEntity? = null,
|
||||||
bankAccount: BankAccountEntity? = null,
|
bankAccount: BankAccountEntity? = null,
|
||||||
fallbackIcon: ImageVector? = null,
|
fallbackIcon: ImageVector? = null,
|
||||||
icon: (@Composable () -> Unit)? = null,
|
icon: (@Composable () -> Unit)? = null,
|
||||||
|
@ -54,7 +54,7 @@ fun NavigationMenuItem(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
.clickable { onClick?.invoke() }
|
.clickable { onClick?.invoke() }
|
||||||
.let {
|
.let {
|
||||||
if (user != null && filterService.isSelected(user, transactionsFilter)
|
if (bank != null && filterService.isSelected(bank, transactionsFilter)
|
||||||
|| bankAccount != null && filterService.isSelected(bankAccount, transactionsFilter)) {
|
|| bankAccount != null && filterService.isSelected(bankAccount, transactionsFilter)) {
|
||||||
it.background(Colors.AccentAsSelectionBackground, shape = RoundedCornerShape(4.dp))
|
it.background(Colors.AccentAsSelectionBackground, shape = RoundedCornerShape(4.dp))
|
||||||
} else {
|
} else {
|
||||||
|
@ -68,7 +68,7 @@ fun NavigationMenuItem(
|
||||||
icon()
|
icon()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
BankIcon(user, Modifier.padding(end = iconTextSpacing), Modifier.size(iconSize), fallbackIcon = fallbackIcon, fallbackIconTintColor = textColor)
|
BankIcon(bank, Modifier.padding(end = iconTextSpacing), Modifier.size(iconSize), fallbackIcon = fallbackIcon, fallbackIconTintColor = textColor)
|
||||||
}
|
}
|
||||||
|
|
||||||
Text(text, color = textColor, modifier = Modifier.weight(1f), maxLines = 1, overflow = TextOverflow.Ellipsis)
|
Text(text, color = textColor, modifier = Modifier.weight(1f), maxLines = 1, overflow = TextOverflow.Ellipsis)
|
||||||
|
@ -77,8 +77,8 @@ fun NavigationMenuItem(
|
||||||
null
|
null
|
||||||
} else if (bankAccount != null) {
|
} else if (bankAccount != null) {
|
||||||
bankAccount.balance
|
bankAccount.balance
|
||||||
} else if (user != null) {
|
} else if (bank != null) {
|
||||||
calculator.calculateBalanceOfUser(user)
|
calculator.calculateBalanceOfBankAccess(bank)
|
||||||
} else {
|
} else {
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,7 +75,7 @@ fun StateHandler(uiState: UiState, snackbarHostState: SnackbarHostState) {
|
||||||
}
|
}
|
||||||
|
|
||||||
snackbarHostState.showSnackbar(
|
snackbarHostState.showSnackbar(
|
||||||
message = "$messagePrefix für ${event.user.displayName} ${event.account.displayName}",
|
message = "$messagePrefix für ${event.bank.displayName} ${event.account.displayName}",
|
||||||
actionLabel = actionLabel,
|
actionLabel = actionLabel,
|
||||||
duration = SnackbarDuration.Long
|
duration = SnackbarDuration.Long
|
||||||
)
|
)
|
||||||
|
|
|
@ -14,7 +14,7 @@ import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import net.codinux.banking.client.model.Amount
|
import net.codinux.banking.client.model.Amount
|
||||||
import net.codinux.banking.client.model.securitiesaccount.Holding
|
import net.codinux.banking.client.model.securitiesaccount.Holding
|
||||||
import net.codinux.banking.dataaccess.entities.UserEntity
|
import net.codinux.banking.dataaccess.entities.BankAccessEntity
|
||||||
import net.codinux.banking.ui.config.Colors
|
import net.codinux.banking.ui.config.Colors
|
||||||
import net.codinux.banking.ui.config.DI
|
import net.codinux.banking.ui.config.DI
|
||||||
import net.codinux.banking.ui.forms.RoundedCornersCard
|
import net.codinux.banking.ui.forms.RoundedCornersCard
|
||||||
|
@ -31,7 +31,7 @@ fun GroupedTransactionsListItems(
|
||||||
modifier: Modifier,
|
modifier: Modifier,
|
||||||
transactionsToDisplay: List<AccountTransactionViewModel>,
|
transactionsToDisplay: List<AccountTransactionViewModel>,
|
||||||
holdingsToDisplay: List<Holding>,
|
holdingsToDisplay: List<Holding>,
|
||||||
usersById: Map<Long, UserEntity>,
|
banksById: Map<Long, BankAccessEntity>,
|
||||||
transactionsGrouping: TransactionsGrouping
|
transactionsGrouping: TransactionsGrouping
|
||||||
) {
|
) {
|
||||||
val groupingService = remember { TransactionsGroupingService() }
|
val groupingService = remember { TransactionsGroupingService() }
|
||||||
|
@ -90,7 +90,7 @@ fun GroupedTransactionsListItems(
|
||||||
Column(Modifier.background(Color.White)) { // LazyColumn inside LazyColumn is not allowed
|
Column(Modifier.background(Color.White)) { // LazyColumn inside LazyColumn is not allowed
|
||||||
monthTransactions.forEachIndexed { index, transaction ->
|
monthTransactions.forEachIndexed { index, transaction ->
|
||||||
key(transaction.id) {
|
key(transaction.id) {
|
||||||
TransactionListItem(usersById[transaction.userId], transaction, index, monthTransactions.size)
|
TransactionListItem(banksById[transaction.userId], transaction, index, monthTransactions.size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,12 +9,11 @@ import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.input.pointer.pointerInput
|
import androidx.compose.ui.input.pointer.pointerInput
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.unit.DpOffset
|
import androidx.compose.ui.unit.DpOffset
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import net.codinux.banking.client.model.User
|
import net.codinux.banking.client.model.BankAccess
|
||||||
import net.codinux.banking.ui.composables.BankIcon
|
import net.codinux.banking.ui.composables.BankIcon
|
||||||
import net.codinux.banking.ui.composables.text.ItemDivider
|
import net.codinux.banking.ui.composables.text.ItemDivider
|
||||||
import net.codinux.banking.ui.config.Colors
|
import net.codinux.banking.ui.config.Colors
|
||||||
|
@ -28,7 +27,7 @@ private val uiSettings = DI.uiSettings
|
||||||
private val formatUtil = DI.formatUtil
|
private val formatUtil = DI.formatUtil
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun TransactionListItem(user: User?, transaction: AccountTransactionViewModel, itemIndex: Int, countItems: Int) {
|
fun TransactionListItem(bank: BankAccess?, transaction: AccountTransactionViewModel, itemIndex: Int, countItems: Int) {
|
||||||
val zebraStripes by uiSettings.zebraStripes.collectAsState()
|
val zebraStripes by uiSettings.zebraStripes.collectAsState()
|
||||||
|
|
||||||
val showBankIcons by uiSettings.showBankIcons.collectAsState()
|
val showBankIcons by uiSettings.showBankIcons.collectAsState()
|
||||||
|
@ -51,7 +50,7 @@ fun TransactionListItem(user: User?, transaction: AccountTransactionViewModel, i
|
||||||
val transactionEntity = DI.bankingService.getTransaction(transaction.id)
|
val transactionEntity = DI.bankingService.getTransaction(transaction.id)
|
||||||
|
|
||||||
DI.uiState.showTransferMoneyDialogData.value = ShowTransferMoneyDialogData(
|
DI.uiState.showTransferMoneyDialogData.value = ShowTransferMoneyDialogData(
|
||||||
DI.uiState.users.value.firstNotNullOf { it.accounts.firstOrNull { it.id == transaction.bankAccountId } },
|
DI.uiState.banks.value.firstNotNullOf { it.accounts.firstOrNull { it.id == transaction.bankAccountId } },
|
||||||
transaction.otherPartyName,
|
transaction.otherPartyName,
|
||||||
transactionEntity?.otherPartyBankId,
|
transactionEntity?.otherPartyBankId,
|
||||||
transactionEntity?.otherPartyAccountId,
|
transactionEntity?.otherPartyAccountId,
|
||||||
|
@ -79,7 +78,7 @@ fun TransactionListItem(user: User?, transaction: AccountTransactionViewModel, i
|
||||||
Column(Modifier.weight(1f)) {
|
Column(Modifier.weight(1f)) {
|
||||||
Row {
|
Row {
|
||||||
if (showBankIcons) {
|
if (showBankIcons) {
|
||||||
BankIcon(user, Modifier.padding(end = 6.dp))
|
BankIcon(bank, Modifier.padding(end = 6.dp))
|
||||||
}
|
}
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
|
|
|
@ -25,9 +25,9 @@ private val formatUtil = DI.formatUtil
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun TransactionsList(uiState: UiState, uiSettings: UiSettings, isMobile: Boolean = true) {
|
fun TransactionsList(uiState: UiState, uiSettings: UiSettings, isMobile: Boolean = true) {
|
||||||
val users by uiState.users.collectAsState()
|
val banks by uiState.banks.collectAsState()
|
||||||
val usersById by remember(users) {
|
val banksById by remember(banks) {
|
||||||
derivedStateOf { users.associateBy { it.id } }
|
derivedStateOf { banks.associateBy { it.id } }
|
||||||
}
|
}
|
||||||
|
|
||||||
val transactionsFilter by uiState.transactionsFilter.collectAsState()
|
val transactionsFilter by uiState.transactionsFilter.collectAsState()
|
||||||
|
@ -59,13 +59,13 @@ fun TransactionsList(uiState: UiState, uiSettings: UiSettings, isMobile: Boolean
|
||||||
Spacer(Modifier.weight(1f))
|
Spacer(Modifier.weight(1f))
|
||||||
|
|
||||||
if (showBalance) {
|
if (showBalance) {
|
||||||
val balance = calculator.calculateBalanceOfDisplayedTransactions(transactionsToDisplay, users, transactionsFilter)
|
val balance = calculator.calculateBalanceOfDisplayedTransactions(transactionsToDisplay, banks, transactionsFilter)
|
||||||
Text(formatUtil.formatAmount(balance, "EUR"), color = formatUtil.getColorForAmount(balance, showColoredAmounts))
|
Text(formatUtil.formatAmount(balance, "EUR"), color = formatUtil.getColorForAmount(balance, showColoredAmounts))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (transactionsGrouping != TransactionsGrouping.None) {
|
if (transactionsGrouping != TransactionsGrouping.None) {
|
||||||
GroupedTransactionsListItems(transactionsListModifier, transactionsToDisplay, holdingsToDisplay, usersById, transactionsGrouping)
|
GroupedTransactionsListItems(transactionsListModifier, transactionsToDisplay, holdingsToDisplay, banksById, transactionsGrouping)
|
||||||
} else {
|
} else {
|
||||||
LazyColumn(transactionsListModifier, contentPadding = PaddingValues(top = 8.dp, bottom = 16.dp)) {
|
LazyColumn(transactionsListModifier, contentPadding = PaddingValues(top = 8.dp, bottom = 16.dp)) {
|
||||||
itemsIndexed(holdingsToDisplay) { index, holding ->
|
itemsIndexed(holdingsToDisplay) { index, holding ->
|
||||||
|
@ -76,7 +76,7 @@ fun TransactionsList(uiState: UiState, uiSettings: UiSettings, isMobile: Boolean
|
||||||
|
|
||||||
itemsIndexed(transactionsToDisplay) { index, transaction ->
|
itemsIndexed(transactionsToDisplay) { index, transaction ->
|
||||||
key(transaction.id) {
|
key(transaction.id) {
|
||||||
TransactionListItem(usersById[transaction.userId], transaction, index, transactionsToDisplay.size)
|
TransactionListItem(banksById[transaction.userId], transaction, index, transactionsToDisplay.size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,9 +94,9 @@ fun EnterTanDialog(tanChallengeReceived: TanChallengeReceived, onDismiss: () ->
|
||||||
Column(Modifier.fillMaxWidth()) {
|
Column(Modifier.fillMaxWidth()) {
|
||||||
Column(Modifier.fillMaxWidth()) {
|
Column(Modifier.fillMaxWidth()) {
|
||||||
Row {
|
Row {
|
||||||
BankIcon(challenge.user, Modifier.padding(end = 6.dp))
|
BankIcon(challenge.bank, Modifier.padding(end = 6.dp))
|
||||||
|
|
||||||
Text("${challenge.user.bankName}, Nutzer ${challenge.user.loginName}${challenge.account?.let { ", Konto ${it.productName ?: it.identifier}" } ?: ""}")
|
Text("${challenge.bank.bankName}, Nutzer ${challenge.bank.loginName}${challenge.account?.let { ", Konto ${it.productName ?: it.identifier}" } ?: ""}")
|
||||||
}
|
}
|
||||||
Text(
|
Text(
|
||||||
"TAN benötigt ${Internationalization.getTextForActionRequiringTan(challenge.forAction)}",
|
"TAN benötigt ${Internationalization.getTextForActionRequiringTan(challenge.forAction)}",
|
||||||
|
|
|
@ -38,11 +38,11 @@ fun TransferMoneyDialog(
|
||||||
data: ShowTransferMoneyDialogData,
|
data: ShowTransferMoneyDialogData,
|
||||||
onDismiss: () -> Unit,
|
onDismiss: () -> Unit,
|
||||||
) {
|
) {
|
||||||
val users = uiState.users.value
|
val banks = uiState.banks.value
|
||||||
val accountsToUser = users.sortedBy { it.displayIndex }
|
val accountsToBank = banks.sortedBy { it.displayIndex }
|
||||||
.flatMap { user -> user.accounts.sortedBy { it.displayIndex }.map { it to user } }.toMap()
|
.flatMap { bank -> bank.accounts.sortedBy { it.displayIndex }.map { it to bank } }.toMap()
|
||||||
|
|
||||||
val accountsSupportingTransferringMoney = users.flatMap { it.accounts }
|
val accountsSupportingTransferringMoney = banks.flatMap { it.accounts }
|
||||||
.filter { it.supportsMoneyTransfer }
|
.filter { it.supportsMoneyTransfer }
|
||||||
|
|
||||||
if (accountsSupportingTransferringMoney.isEmpty()) {
|
if (accountsSupportingTransferringMoney.isEmpty()) {
|
||||||
|
@ -98,7 +98,7 @@ fun TransferMoneyDialog(
|
||||||
|
|
||||||
transferMoneyJob = coroutineScope.launch(Dispatchers.IOorDefault) {
|
transferMoneyJob = coroutineScope.launch(Dispatchers.IOorDefault) {
|
||||||
val successful = bankingService.transferMoney(
|
val successful = bankingService.transferMoney(
|
||||||
accountsToUser[senderAccount]!!, senderAccount,
|
accountsToBank[senderAccount]!!, senderAccount,
|
||||||
recipientName, recipientAccountIdentifier,
|
recipientName, recipientAccountIdentifier,
|
||||||
Amount(amount), // TODO: verify entered amount is valid
|
Amount(amount), // TODO: verify entered amount is valid
|
||||||
"EUR", // TODO: add input field for currency
|
"EUR", // TODO: add input field for currency
|
||||||
|
@ -132,13 +132,13 @@ fun TransferMoneyDialog(
|
||||||
Select(
|
Select(
|
||||||
"Konto",
|
"Konto",
|
||||||
accountsSupportingTransferringMoney, senderAccount, { senderAccount = it },
|
accountsSupportingTransferringMoney, senderAccount, { senderAccount = it },
|
||||||
{ account -> "${accountsToUser[account]?.displayName} ${account.displayName}" },
|
{ account -> "${accountsToBank[account]?.displayName} ${account.displayName}" },
|
||||||
leadingIcon = { BankIcon(accountsToUser[senderAccount]) }
|
leadingIcon = { BankIcon(accountsToBank[senderAccount]) }
|
||||||
) { account ->
|
) { account ->
|
||||||
Row(Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
|
Row(Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
|
||||||
BankIcon(accountsToUser[account], Modifier.padding(end = 6.dp))
|
BankIcon(accountsToBank[account], Modifier.padding(end = 6.dp))
|
||||||
|
|
||||||
Text("${accountsToUser[account]?.displayName} ${account.displayName}")
|
Text("${accountsToBank[account]?.displayName} ${account.displayName}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ package net.codinux.banking.ui.model
|
||||||
|
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
import net.codinux.banking.dataaccess.entities.BankAccountEntity
|
import net.codinux.banking.dataaccess.entities.BankAccountEntity
|
||||||
import net.codinux.banking.dataaccess.entities.UserEntity
|
import net.codinux.banking.dataaccess.entities.BankAccessEntity
|
||||||
|
|
||||||
class AccountTransactionsFilter {
|
class AccountTransactionsFilter {
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ class AccountTransactionsFilter {
|
||||||
val selectedAccount: BankAccountFilter?
|
val selectedAccount: BankAccountFilter?
|
||||||
get() = selectedAccounts.value.firstOrNull()
|
get() = selectedAccounts.value.firstOrNull()
|
||||||
|
|
||||||
fun selectedAccountChanged(user: UserEntity?, bankAccount: BankAccountEntity?) {
|
fun selectedAccountChanged(user: BankAccessEntity?, bankAccount: BankAccountEntity?) {
|
||||||
selectedAccounts.value = if (user == null) {
|
selectedAccounts.value = if (user == null) {
|
||||||
emptyList()
|
emptyList()
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
package net.codinux.banking.ui.model
|
package net.codinux.banking.ui.model
|
||||||
|
|
||||||
import net.codinux.banking.dataaccess.entities.BankAccountEntity
|
import net.codinux.banking.dataaccess.entities.BankAccountEntity
|
||||||
import net.codinux.banking.dataaccess.entities.UserEntity
|
import net.codinux.banking.dataaccess.entities.BankAccessEntity
|
||||||
|
|
||||||
data class BankAccountFilter(
|
data class BankAccountFilter(
|
||||||
val user: UserEntity,
|
val bank: BankAccessEntity,
|
||||||
val bankAccount: BankAccountEntity? = null
|
val bankAccount: BankAccountEntity? = null
|
||||||
)
|
)
|
|
@ -1,12 +1,12 @@
|
||||||
package net.codinux.banking.ui.model.events
|
package net.codinux.banking.ui.model.events
|
||||||
|
|
||||||
import net.codinux.banking.client.model.BankAccount
|
import net.codinux.banking.client.model.BankAccount
|
||||||
import net.codinux.banking.client.model.User
|
import net.codinux.banking.client.model.BankAccess
|
||||||
import net.codinux.banking.client.model.securitiesaccount.Holding
|
import net.codinux.banking.client.model.securitiesaccount.Holding
|
||||||
import net.codinux.banking.ui.model.AccountTransactionViewModel
|
import net.codinux.banking.ui.model.AccountTransactionViewModel
|
||||||
|
|
||||||
data class AccountTransactionsRetrievedEvent(
|
data class AccountTransactionsRetrievedEvent(
|
||||||
val user: User,
|
val bank: BankAccess,
|
||||||
val account: BankAccount,
|
val account: BankAccount,
|
||||||
val newTransactions: List<AccountTransactionViewModel>,
|
val newTransactions: List<AccountTransactionViewModel>,
|
||||||
val updatedHoldings: List<Holding> = emptyList()
|
val updatedHoldings: List<Holding> = emptyList()
|
||||||
|
|
|
@ -2,7 +2,7 @@ package net.codinux.banking.ui.service
|
||||||
|
|
||||||
import net.codinux.banking.dataaccess.entities.BankAccountEntity
|
import net.codinux.banking.dataaccess.entities.BankAccountEntity
|
||||||
import net.codinux.banking.dataaccess.entities.HoldingEntity
|
import net.codinux.banking.dataaccess.entities.HoldingEntity
|
||||||
import net.codinux.banking.dataaccess.entities.UserEntity
|
import net.codinux.banking.dataaccess.entities.BankAccessEntity
|
||||||
import net.codinux.banking.ui.model.AccountTransactionViewModel
|
import net.codinux.banking.ui.model.AccountTransactionViewModel
|
||||||
import net.codinux.banking.ui.model.AccountTransactionsFilter
|
import net.codinux.banking.ui.model.AccountTransactionsFilter
|
||||||
import net.codinux.banking.ui.model.BankAccountFilter
|
import net.codinux.banking.ui.model.BankAccountFilter
|
||||||
|
@ -83,14 +83,14 @@ class AccountTransactionsFilterService {
|
||||||
|| holding.wkn?.contains(searchTerm, true) == true
|
|| holding.wkn?.contains(searchTerm, true) == true
|
||||||
|
|
||||||
|
|
||||||
fun isSelected(user: UserEntity, transactionsFilter: AccountTransactionsFilter): Boolean {
|
fun isSelected(user: BankAccessEntity, transactionsFilter: AccountTransactionsFilter): Boolean {
|
||||||
if (transactionsFilter.showAllAccounts) {
|
if (transactionsFilter.showAllAccounts) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
val filter = transactionsFilter.selectedAccount
|
val filter = transactionsFilter.selectedAccount
|
||||||
|
|
||||||
return filter?.user == user && filter.bankAccount == null
|
return filter?.bank == user && filter.bankAccount == null
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isSelected(bankAccount: BankAccountEntity, transactionsFilter: AccountTransactionsFilter): Boolean {
|
fun isSelected(bankAccount: BankAccountEntity, transactionsFilter: AccountTransactionsFilter): Boolean {
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
package net.codinux.banking.ui.service
|
package net.codinux.banking.ui.service
|
||||||
|
|
||||||
import net.codinux.banking.client.model.BankingGroup
|
import net.codinux.banking.client.model.BankingGroup
|
||||||
import net.codinux.banking.client.model.User
|
import net.codinux.banking.client.model.BankAccess
|
||||||
|
|
||||||
class BankIconService { // TODO: extract to a common library
|
class BankIconService { // TODO: extract to a common library
|
||||||
|
|
||||||
fun findIconForBank(user: User) = findIconForBank(user.bankName, user.bic, user.bankingGroup)
|
fun findIconForBank(bank: BankAccess) = findIconForBank(bank.bankName, bank.bic, bank.bankingGroup)
|
||||||
|
|
||||||
fun findIconForBank(bankName: String, bic: String? = null, bankingGroup: BankingGroup? = null): String? = when (bankingGroup) {
|
fun findIconForBank(bankName: String, bic: String? = null, bankingGroup: BankingGroup? = null): String? = when (bankingGroup) {
|
||||||
BankingGroup.Sparkasse -> "https://sparkasse.de/favicon-32x32.png"
|
BankingGroup.Sparkasse -> "https://sparkasse.de/favicon-32x32.png"
|
||||||
|
|
|
@ -45,21 +45,21 @@ class BankingService(
|
||||||
|
|
||||||
suspend fun init() {
|
suspend fun init() {
|
||||||
try {
|
try {
|
||||||
uiState.users.value = getAllUsers()
|
uiState.banks.value = getAllBanks()
|
||||||
|
|
||||||
uiState.transactions.value = getAllAccountTransactionsAsViewModel()
|
uiState.transactions.value = getAllAccountTransactionsAsViewModel()
|
||||||
uiState.holdings.value = uiState.users.value.flatMap { it.accounts }.flatMap { it.holdings }
|
uiState.holdings.value = uiState.banks.value.flatMap { it.accounts }.flatMap { it.holdings }
|
||||||
} catch (e: Throwable) {
|
} catch (e: Throwable) {
|
||||||
log.error(e) { "Could not read all user accounts and account transactions from repository" }
|
log.error(e) { "Could not read all banks and account transactions from repository" }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun getAllUsers() = bankingRepository.getAllUsers()
|
fun getAllBanks() = bankingRepository.getAllBanks()
|
||||||
|
|
||||||
fun getAllAccountTransactions() = bankingRepository.getAllAccountTransactions()
|
fun getAllAccountTransactions() = bankingRepository.getAllAccountTransactions()
|
||||||
|
|
||||||
fun getAllTransactionsOfUser(user: UserEntity) = bankingRepository.getAllTransactionsOfUser(user)
|
fun getAllTransactionsForBank(bank: BankAccessEntity) = bankingRepository.getAllTransactionsForBank(bank)
|
||||||
|
|
||||||
fun getAllAccountTransactionsAsViewModel() = bankingRepository.getAllAccountTransactionsAsViewModel()
|
fun getAllAccountTransactionsAsViewModel() = bankingRepository.getAllAccountTransactionsAsViewModel()
|
||||||
|
|
||||||
|
@ -101,21 +101,21 @@ class BankingService(
|
||||||
|
|
||||||
private suspend fun handleSuccessfulGetAccountDataResponse(response: GetAccountDataResponse) {
|
private suspend fun handleSuccessfulGetAccountDataResponse(response: GetAccountDataResponse) {
|
||||||
try {
|
try {
|
||||||
val newUser = response.user
|
val newBank = response.bank
|
||||||
newUser.displayIndex = uiState.users.value.size
|
newBank.displayIndex = uiState.banks.value.size
|
||||||
|
|
||||||
val newUserEntity = bankingRepository.persistUser(newUser)
|
val newBankEntity = bankingRepository.persistBank(newBank)
|
||||||
|
|
||||||
log.info { "Saved user account $newUserEntity with ${newUserEntity.accounts.flatMap { it.bookedTransactionsEntities }.size} transactions" }
|
log.info { "Saved bank $newBankEntity with ${newBankEntity.accounts.flatMap { it.bookedTransactionsEntities }.size} transactions" }
|
||||||
|
|
||||||
val users = uiState.users.value.toMutableList()
|
val banks = uiState.banks.value.toMutableList()
|
||||||
users.add(newUserEntity)
|
banks.add(newBankEntity)
|
||||||
uiState.users.value = users
|
uiState.banks.value = banks
|
||||||
|
|
||||||
updateTransactionsInUi(newUserEntity.accounts.flatMap { it.bookedTransactionsEntities })
|
updateTransactionsInUi(newBankEntity.accounts.flatMap { it.bookedTransactionsEntities })
|
||||||
updateHoldingsInUi(newUserEntity.accounts.flatMap { it.holdings }, emptyList())
|
updateHoldingsInUi(newBankEntity.accounts.flatMap { it.holdings }, emptyList())
|
||||||
} catch (e: Throwable) {
|
} catch (e: Throwable) {
|
||||||
log.error(e) { "Could not save user account ${response.user}" }
|
log.error(e) { "Could not save bank ${response.bank}" }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,45 +123,45 @@ class BankingService(
|
||||||
suspend fun updateAccountTransactions() {
|
suspend fun updateAccountTransactions() {
|
||||||
val selectedAccount = uiState.transactionsFilter.value.selectedAccount
|
val selectedAccount = uiState.transactionsFilter.value.selectedAccount
|
||||||
if (selectedAccount != null) {
|
if (selectedAccount != null) {
|
||||||
updateAccountTransactions(selectedAccount.user, selectedAccount.bankAccount)
|
updateAccountTransactions(selectedAccount.bank, selectedAccount.bankAccount)
|
||||||
} else {
|
} else {
|
||||||
uiState.users.value.forEach { user ->
|
uiState.banks.value.forEach { bank ->
|
||||||
updateAccountTransactions(user)
|
updateAccountTransactions(bank)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun updateAccountTransactions(user: UserEntity, bankAccount: BankAccountEntity? = null) {
|
private suspend fun updateAccountTransactions(bank: BankAccessEntity, bankAccount: BankAccountEntity? = null) {
|
||||||
withContext(Dispatchers.IOorDefault) {
|
withContext(Dispatchers.IOorDefault) {
|
||||||
try {
|
try {
|
||||||
val response = client.updateAccountTransactionsAsync(user, bankAccount?.let { listOf(it) })
|
val response = client.updateAccountTransactionsAsync(bank, bankAccount?.let { listOf(it) })
|
||||||
if (response.type == ResponseType.Success && response.data != null) {
|
if (response.type == ResponseType.Success && response.data != null) {
|
||||||
handleSuccessfulUpdateAccountTransactionsResponse(user, response.data!!)
|
handleSuccessfulUpdateAccountTransactionsResponse(bank, response.data!!)
|
||||||
} else {
|
} else {
|
||||||
handleUnsuccessfulBankingClientResponse(BankingClientAction.UpdateAccountTransactions, response)
|
handleUnsuccessfulBankingClientResponse(BankingClientAction.UpdateAccountTransactions, response)
|
||||||
}
|
}
|
||||||
} catch (e: Throwable) {
|
} catch (e: Throwable) {
|
||||||
log.error(e) { "Could not update account transactions for $user" }
|
log.error(e) { "Could not update account transactions for $bank" }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun handleSuccessfulUpdateAccountTransactionsResponse(user: UserEntity, responses: List<GetTransactionsResponse>) {
|
private suspend fun handleSuccessfulUpdateAccountTransactionsResponse(bank: BankAccessEntity, responses: List<GetTransactionsResponse>) {
|
||||||
try {
|
try {
|
||||||
// TODO: when user gets updated by BankingClient, also update user in database
|
// TODO: when bank gets updated by BankingClient, also update bank in database
|
||||||
// val newUser = response.user
|
// val newUser = response.bank
|
||||||
// val newUserEntity = bankingRepository.persistUser(newUser)
|
// val newUserEntity = bankingRepository.persistUser(newUser)
|
||||||
//
|
//
|
||||||
// log.info { "Saved user account $newUserEntity with ${newUserEntity.accounts.flatMap { it.bookedTransactionsEntities }.size} transactions" }
|
// log.info { "Saved user account $newUserEntity with ${newUserEntity.accounts.flatMap { it.bookedTransactionsEntities }.size} transactions" }
|
||||||
|
|
||||||
val userTransactions = getAllTransactionsOfUser(user)
|
val transactionsForBank = getAllTransactionsForBank(bank)
|
||||||
|
|
||||||
responses.forEach { response ->
|
responses.forEach { response ->
|
||||||
val account = (response.account as? BankAccountEntity) ?: user.accounts.first { it.identifier == response.account.identifier && it.subAccountNumber == response.account.subAccountNumber }
|
val account = (response.account as? BankAccountEntity) ?: bank.accounts.first { it.identifier == response.account.identifier && it.subAccountNumber == response.account.subAccountNumber }
|
||||||
|
|
||||||
// TODO: update BankAccount and may updated Transactions in database
|
// TODO: update BankAccount and may updated Transactions in database
|
||||||
|
|
||||||
val existingAccountTransactions = userTransactions.filter { it.bankAccountId == account.id }
|
val existingAccountTransactions = transactionsForBank.filter { it.bankAccountId == account.id }
|
||||||
|
|
||||||
val newTransactions = modelService.findNewTransactions(response.bookedTransactions, existingAccountTransactions)
|
val newTransactions = modelService.findNewTransactions(response.bookedTransactions, existingAccountTransactions)
|
||||||
|
|
||||||
|
@ -189,10 +189,10 @@ class BankingService(
|
||||||
updateHoldingsInUi(persistedNewHoldings, deletedHoldings)
|
updateHoldingsInUi(persistedNewHoldings, deletedHoldings)
|
||||||
|
|
||||||
val transactionsViewModel = updateTransactionsInUi(newTransactionsEntities)
|
val transactionsViewModel = updateTransactionsInUi(newTransactionsEntities)
|
||||||
uiState.dispatchNewTransactionsRetrieved(AccountTransactionsRetrievedEvent(user, account, transactionsViewModel, response.holdings))
|
uiState.dispatchNewTransactionsRetrieved(AccountTransactionsRetrievedEvent(bank, account, transactionsViewModel, response.holdings))
|
||||||
}
|
}
|
||||||
} catch (e: Throwable) {
|
} catch (e: Throwable) {
|
||||||
log.error(e) { "Could not save updated account transactions for user $user" }
|
log.error(e) { "Could not save updated account transactions for bank $bank" }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -235,11 +235,11 @@ class BankingService(
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
suspend fun transferMoney(user: UserEntity, account: BankAccountEntity,
|
suspend fun transferMoney(bank: BankAccessEntity, account: BankAccountEntity,
|
||||||
recipientName: String, recipientAccountIdentifier: String, amount: Amount, currency: String,
|
recipientName: String, recipientAccountIdentifier: String, amount: Amount, currency: String,
|
||||||
paymentReference: String? = null, instantTransfer: Boolean = false, recipientBankIdentifier: String? = null): Boolean {
|
paymentReference: String? = null, instantTransfer: Boolean = false, recipientBankIdentifier: String? = null): Boolean {
|
||||||
val response = client.transferMoneyAsync(TransferMoneyRequestForUser(
|
val response = client.transferMoneyAsync(TransferMoneyRequestForUser(
|
||||||
user.bankCode, user.loginName, user.password!!,
|
bank.bankCode, bank.loginName, bank.password!!,
|
||||||
BankAccountIdentifier(account.identifier, account.subAccountNumber, account.iban), // TODO: use BankingClient's one
|
BankAccountIdentifier(account.identifier, account.subAccountNumber, account.iban), // TODO: use BankingClient's one
|
||||||
recipientName, recipientAccountIdentifier, recipientBankIdentifier,
|
recipientName, recipientAccountIdentifier, recipientBankIdentifier,
|
||||||
amount, "EUR",
|
amount, "EUR",
|
||||||
|
@ -251,7 +251,7 @@ class BankingService(
|
||||||
} else if (response.type == ResponseType.Success) {
|
} else if (response.type == ResponseType.Success) {
|
||||||
uiState.dispatchTransferredMoney(TransferredMoneyEvent(recipientName, amount, currency))
|
uiState.dispatchTransferredMoney(TransferredMoneyEvent(recipientName, amount, currency))
|
||||||
|
|
||||||
updateAccountTransactions(user, account)
|
updateAccountTransactions(bank, account)
|
||||||
}
|
}
|
||||||
|
|
||||||
return response.type == ResponseType.Success
|
return response.type == ResponseType.Success
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package net.codinux.banking.ui.service
|
package net.codinux.banking.ui.service
|
||||||
|
|
||||||
import net.codinux.banking.client.model.*
|
import net.codinux.banking.client.model.*
|
||||||
import net.codinux.banking.dataaccess.entities.UserEntity
|
import net.codinux.banking.dataaccess.entities.BankAccessEntity
|
||||||
import net.codinux.banking.ui.model.AccountTransactionViewModel
|
import net.codinux.banking.ui.model.AccountTransactionViewModel
|
||||||
import net.codinux.banking.ui.model.AccountTransactionsFilter
|
import net.codinux.banking.ui.model.AccountTransactionsFilter
|
||||||
|
|
||||||
|
@ -10,8 +10,8 @@ class CalculatorService {
|
||||||
fun sumTransactions(transactions: Collection<AccountTransactionViewModel>): Amount =
|
fun sumTransactions(transactions: Collection<AccountTransactionViewModel>): Amount =
|
||||||
transactions.map { it.amount }.sum()
|
transactions.map { it.amount }.sum()
|
||||||
|
|
||||||
fun calculateBalanceOfUser(user: User): Amount =
|
fun calculateBalanceOfBankAccess(bank: BankAccess): Amount =
|
||||||
sumAmounts(user.accounts.map { it.balance })
|
sumAmounts(bank.accounts.map { it.balance })
|
||||||
|
|
||||||
fun sumAmounts(amounts: Collection<Amount>): Amount =
|
fun sumAmounts(amounts: Collection<Amount>): Amount =
|
||||||
amounts.sum()
|
amounts.sum()
|
||||||
|
@ -22,9 +22,9 @@ class CalculatorService {
|
||||||
fun sumExpenses(transactions: Collection<AccountTransactionViewModel>): Amount =
|
fun sumExpenses(transactions: Collection<AccountTransactionViewModel>): Amount =
|
||||||
sumAmounts(transactions.map { it.amount }.filter { it.isNegative })
|
sumAmounts(transactions.map { it.amount }.filter { it.isNegative })
|
||||||
|
|
||||||
fun calculateBalanceOfDisplayedTransactions(transactions: Collection<AccountTransactionViewModel>, users: Collection<UserEntity>, filter: AccountTransactionsFilter): Amount {
|
fun calculateBalanceOfDisplayedTransactions(transactions: Collection<AccountTransactionViewModel>, banks: Collection<BankAccessEntity>, filter: AccountTransactionsFilter): Amount {
|
||||||
if (filter.noFiltersApplied) {
|
if (filter.noFiltersApplied) {
|
||||||
return sumAmounts(users.flatMap { it.accounts.map { it.balance } })
|
return sumAmounts(banks.flatMap { it.accounts.map { it.balance } })
|
||||||
}
|
}
|
||||||
|
|
||||||
val selectedAccount = filter.selectedAccount
|
val selectedAccount = filter.selectedAccount
|
||||||
|
@ -33,7 +33,7 @@ class CalculatorService {
|
||||||
if (selectedAccount.bankAccount != null) {
|
if (selectedAccount.bankAccount != null) {
|
||||||
selectedAccount.bankAccount.balance
|
selectedAccount.bankAccount.balance
|
||||||
} else {
|
} else {
|
||||||
calculateBalanceOfUser(selectedAccount.user)
|
calculateBalanceOfBankAccess(selectedAccount.bank)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
sumTransactions(transactions)
|
sumTransactions(transactions)
|
||||||
|
|
|
@ -8,7 +8,7 @@ import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import net.codinux.banking.client.model.tan.EnterTanResult
|
import net.codinux.banking.client.model.tan.EnterTanResult
|
||||||
import net.codinux.banking.client.model.tan.TanChallenge
|
import net.codinux.banking.client.model.tan.TanChallenge
|
||||||
import net.codinux.banking.dataaccess.entities.HoldingEntity
|
import net.codinux.banking.dataaccess.entities.HoldingEntity
|
||||||
import net.codinux.banking.dataaccess.entities.UserEntity
|
import net.codinux.banking.dataaccess.entities.BankAccessEntity
|
||||||
import net.codinux.banking.ui.model.*
|
import net.codinux.banking.ui.model.*
|
||||||
import net.codinux.banking.ui.model.error.ApplicationError
|
import net.codinux.banking.ui.model.error.ApplicationError
|
||||||
import net.codinux.banking.ui.model.error.BankingClientError
|
import net.codinux.banking.ui.model.error.BankingClientError
|
||||||
|
@ -18,7 +18,7 @@ import net.codinux.banking.ui.model.events.TransferredMoneyEvent
|
||||||
|
|
||||||
class UiState : ViewModel() {
|
class UiState : ViewModel() {
|
||||||
|
|
||||||
val users = MutableStateFlow<List<UserEntity>>(emptyList())
|
val banks = MutableStateFlow<List<BankAccessEntity>>(emptyList())
|
||||||
|
|
||||||
val transactions = MutableStateFlow<List<AccountTransactionViewModel>>(emptyList())
|
val transactions = MutableStateFlow<List<AccountTransactionViewModel>>(emptyList())
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ CREATE TABLE IF NOT EXISTS User (
|
||||||
password TEXT,
|
password TEXT,
|
||||||
|
|
||||||
bankName TEXT NOT NULL,
|
bankName TEXT NOT NULL,
|
||||||
bic TEXT NOT NULL,
|
bic TEXT,
|
||||||
|
|
||||||
customerName TEXT NOT NULL,
|
customerName TEXT NOT NULL,
|
||||||
userId TEXT,
|
userId TEXT,
|
||||||
|
@ -31,7 +31,7 @@ CREATE TABLE IF NOT EXISTS User (
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
insertUser:
|
insertBank:
|
||||||
INSERT INTO User(
|
INSERT INTO User(
|
||||||
bankCode, loginName, password,
|
bankCode, loginName, password,
|
||||||
|
|
||||||
|
@ -72,7 +72,7 @@ VALUES(
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
selectAllUsers:
|
selectAllBanks:
|
||||||
SELECT User.*
|
SELECT User.*
|
||||||
FROM User;
|
FROM User;
|
||||||
|
|
||||||
|
|
|
@ -13,8 +13,8 @@ import net.codinux.banking.ui.model.TanChallengeReceived
|
||||||
@Composable
|
@Composable
|
||||||
fun EnterTanDialogPreview_EnterTan() {
|
fun EnterTanDialogPreview_EnterTan() {
|
||||||
val tanMethods = listOf(TanMethod("Zeig mich an", TanMethodType.AppTan, "902"))
|
val tanMethods = listOf(TanMethod("Zeig mich an", TanMethodType.AppTan, "902"))
|
||||||
val user = BankViewInfo("12345678", "SupiDupiNutzer", "Abzockbank", BankingGroup.Postbank)
|
val bank = BankViewInfo("12345678", "SupiDupiNutzer", "Abzockbank", BankingGroup.Postbank)
|
||||||
val tanChallenge = TanChallenge(TanChallengeType.EnterTan, ActionRequiringTan.GetAccountInfo, "Geben Sie die TAN ein", tanMethods.first().identifier, tanMethods, user = user)
|
val tanChallenge = TanChallenge(TanChallengeType.EnterTan, ActionRequiringTan.GetAccountInfo, "Geben Sie die TAN ein", tanMethods.first().identifier, tanMethods, bank = bank)
|
||||||
|
|
||||||
EnterTanDialog(TanChallengeReceived(tanChallenge) { }) { }
|
EnterTanDialog(TanChallengeReceived(tanChallenge) { }) { }
|
||||||
}
|
}
|
||||||
|
@ -27,9 +27,9 @@ fun EnterTanDialogPreview_TanImage() {
|
||||||
val tanMethod = TanMethod("photoTAN-Verfahren", TanMethodType.photoTan, "902", 6, AllowedTanFormat.Numeric)
|
val tanMethod = TanMethod("photoTAN-Verfahren", TanMethodType.photoTan, "902", 6, AllowedTanFormat.Numeric)
|
||||||
val tanImage = TanImage("image/png", tanImageBytes)
|
val tanImage = TanImage("image/png", tanImageBytes)
|
||||||
|
|
||||||
val user = BankViewInfo("10010010", "Ihr krasser Login Name", "Phantasie Bank", BankingGroup.Comdirect)
|
val bank = BankViewInfo("10010010", "Ihr krasser Login Name", "Phantasie Bank", BankingGroup.Comdirect)
|
||||||
|
|
||||||
val tanChallenge = TanChallenge(TanChallengeType.Image, ActionRequiringTan.GetAccountInfo, "Geben Sie die TAN ein", tanMethod.identifier, listOf(tanMethod), null, emptyList(), tanImage, null, user)
|
val tanChallenge = TanChallenge(TanChallengeType.Image, ActionRequiringTan.GetAccountInfo, "Geben Sie die TAN ein", tanMethod.identifier, listOf(tanMethod), null, emptyList(), tanImage, null, bank)
|
||||||
|
|
||||||
EnterTanDialog(TanChallengeReceived(tanChallenge) { }) { }
|
EnterTanDialog(TanChallengeReceived(tanChallenge) { }) { }
|
||||||
}
|
}
|
||||||
|
@ -50,10 +50,10 @@ fun EnterTanDialogPreview_WithMultipleTanMedia() { // shows that dialog is reall
|
||||||
TanMedium(TanMediumType.TanGenerator, "SparkassenCard (Debitkarte)", TanMediumStatus.Used, TanGeneratorTanMedium("5432109876"))
|
TanMedium(TanMediumType.TanGenerator, "SparkassenCard (Debitkarte)", TanMediumStatus.Used, TanGeneratorTanMedium("5432109876"))
|
||||||
)
|
)
|
||||||
|
|
||||||
val user = BankViewInfo("10010010", "Ihr krasser Login Name", "Eine ganz gewöhnliche Sparkasse", BankingGroup.Sparkasse)
|
val bank = BankViewInfo("10010010", "Ihr krasser Login Name", "Eine ganz gewöhnliche Sparkasse", BankingGroup.Sparkasse)
|
||||||
val account = BankAccountViewInfo("12345678", null, BankAccountType.CheckingAccount, null, "Giro Konto")
|
val account = BankAccountViewInfo("12345678", null, BankAccountType.CheckingAccount, null, "Giro Konto")
|
||||||
|
|
||||||
val tanChallenge = TanChallenge(TanChallengeType.Image, ActionRequiringTan.GetTransactions, "Sie möchten eine \"Umsatzabfrage\" freigeben: Bitte bestätigen Sie den \"Startcode 80061030\" mit der Taste \"OK\".", "913", tanMethods, "SparkassenCard (Debitkarte)", tanMedia, tanImage, null, user, account)
|
val tanChallenge = TanChallenge(TanChallengeType.Image, ActionRequiringTan.GetTransactions, "Sie möchten eine \"Umsatzabfrage\" freigeben: Bitte bestätigen Sie den \"Startcode 80061030\" mit der Taste \"OK\".", "913", tanMethods, "SparkassenCard (Debitkarte)", tanMedia, tanImage, null, bank, account)
|
||||||
|
|
||||||
EnterTanDialog(TanChallengeReceived(tanChallenge) { }) { }
|
EnterTanDialog(TanChallengeReceived(tanChallenge) { }) { }
|
||||||
}
|
}
|
|
@ -27,29 +27,29 @@ class SqliteBankingRepositoryTest {
|
||||||
val bankAccounts = listOf(
|
val bankAccounts = listOf(
|
||||||
BankAccount("12345", null, null, null, "Monika Tester", BankAccountType.CheckingAccount, balance = Amount("12.34"), retrievedTransactionsFrom = LocalDate(2024, 5, 7), features = setOf(BankAccountFeatures.RetrieveBalance, BankAccountFeatures.InstantTransfer), serverTransactionsRetentionDays = 320)
|
BankAccount("12345", null, null, null, "Monika Tester", BankAccountType.CheckingAccount, balance = Amount("12.34"), retrievedTransactionsFrom = LocalDate(2024, 5, 7), features = setOf(BankAccountFeatures.RetrieveBalance, BankAccountFeatures.InstantTransfer), serverTransactionsRetentionDays = 320)
|
||||||
)
|
)
|
||||||
val user = User("12345678", "SupiDupiUser", "geheim", "Abzock-Bank", "ABCDDEBBXXX", "Monika Tester", accounts = bankAccounts, bankingGroup = BankingGroup.DKB, serverAddress = "").apply {
|
val bank = BankAccess("12345678", "SupiDupiUser", "geheim", "Abzock-Bank", "ABCDDEBBXXX", "Monika Tester", accounts = bankAccounts, bankingGroup = BankingGroup.DKB, serverAddress = "").apply {
|
||||||
wrongCredentialsEntered = true
|
wrongCredentialsEntered = true
|
||||||
displayIndex = 99
|
displayIndex = 99
|
||||||
}
|
}
|
||||||
|
|
||||||
val persisted = underTest.persistUser(user)
|
val persisted = underTest.persistBank(bank)
|
||||||
|
|
||||||
assertNotNull(persisted.id)
|
assertNotNull(persisted.id)
|
||||||
|
|
||||||
assertEquals(user.bankCode, persisted.bankCode)
|
assertEquals(bank.domesticBankCode, persisted.domesticBankCode)
|
||||||
assertEquals(user.loginName, persisted.loginName)
|
assertEquals(bank.loginName, persisted.loginName)
|
||||||
assertEquals(user.password, persisted.password)
|
assertEquals(bank.password, persisted.password)
|
||||||
|
|
||||||
assertEquals(user.bankName, persisted.bankName)
|
assertEquals(bank.bankName, persisted.bankName)
|
||||||
assertEquals(user.bic, persisted.bic)
|
assertEquals(bank.bic, persisted.bic)
|
||||||
|
|
||||||
assertEquals(user.customerName, persisted.customerName)
|
assertEquals(bank.customerName, persisted.customerName)
|
||||||
assertEquals(user.userId, persisted.userId)
|
assertEquals(bank.userId, persisted.userId)
|
||||||
|
|
||||||
assertEquals(user.bankingGroup, persisted.bankingGroup)
|
assertEquals(bank.bankingGroup, persisted.bankingGroup)
|
||||||
|
|
||||||
assertEquals(user.wrongCredentialsEntered, persisted.wrongCredentialsEntered)
|
assertEquals(bank.wrongCredentialsEntered, persisted.wrongCredentialsEntered)
|
||||||
assertEquals(user.displayIndex, persisted.displayIndex)
|
assertEquals(bank.displayIndex, persisted.displayIndex)
|
||||||
|
|
||||||
assertEquals(1, persisted.accounts.size)
|
assertEquals(1, persisted.accounts.size)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue