Updated to new BankingClient model
This commit is contained in:
parent
cd8e0a53ad
commit
234084e627
|
@ -1,17 +1,17 @@
|
|||
package net.codinux.banking.dataaccess
|
||||
|
||||
import net.codinux.banking.client.model.AccountTransaction
|
||||
import net.codinux.banking.client.model.UserAccount
|
||||
import net.codinux.banking.client.model.User
|
||||
import net.codinux.banking.dataaccess.entities.AccountTransactionEntity
|
||||
import net.codinux.banking.dataaccess.entities.BankAccountEntity
|
||||
import net.codinux.banking.dataaccess.entities.UserAccountEntity
|
||||
import net.codinux.banking.dataaccess.entities.UserEntity
|
||||
import net.codinux.banking.ui.model.AccountTransactionViewModel
|
||||
|
||||
interface BankingRepository {
|
||||
|
||||
fun getAllUserAccounts(): List<UserAccountEntity>
|
||||
fun getAllUsers(): List<UserEntity>
|
||||
|
||||
suspend fun persistUserAccount(userAccount: UserAccount): UserAccountEntity
|
||||
suspend fun persistUser(user: User): UserEntity
|
||||
|
||||
suspend fun persistTransactions(bankAccount: BankAccountEntity, transactions: List<AccountTransaction>): List<AccountTransactionEntity>
|
||||
|
||||
|
@ -20,7 +20,7 @@ interface BankingRepository {
|
|||
|
||||
fun getAllAccountTransactions(): List<AccountTransactionEntity>
|
||||
|
||||
fun getAllTransactionsOfUserAccount(userAccount: UserAccountEntity): List<AccountTransactionEntity>
|
||||
fun getAllTransactionsOfUser(user: UserEntity): List<AccountTransactionEntity>
|
||||
|
||||
fun getTransactionById(transactionId: Long): AccountTransactionEntity?
|
||||
|
||||
|
|
|
@ -1,29 +1,29 @@
|
|||
package net.codinux.banking.dataaccess
|
||||
|
||||
import net.codinux.banking.client.model.AccountTransaction
|
||||
import net.codinux.banking.client.model.UserAccount
|
||||
import net.codinux.banking.client.model.User
|
||||
import net.codinux.banking.dataaccess.entities.AccountTransactionEntity
|
||||
import net.codinux.banking.dataaccess.entities.BankAccountEntity
|
||||
import net.codinux.banking.dataaccess.entities.UserAccountEntity
|
||||
import net.codinux.banking.dataaccess.entities.UserEntity
|
||||
import net.codinux.banking.ui.model.AccountTransactionViewModel
|
||||
|
||||
class InMemoryBankingRepository(
|
||||
userAccounts: Collection<UserAccount> = emptyList(),
|
||||
users: Collection<User> = emptyList(),
|
||||
transactions: Collection<AccountTransaction> = emptyList()
|
||||
) : BankingRepository {
|
||||
|
||||
private var nextId = 0L // TODO: make thread-safe
|
||||
|
||||
private val userAccounts = userAccounts.map { map(it) }.toMutableList()
|
||||
private val users = users.map { map(it) }.toMutableList()
|
||||
|
||||
private val transactions = transactions.map { map(it) }.toMutableList()
|
||||
|
||||
|
||||
override fun getAllUserAccounts(): List<UserAccountEntity> = userAccounts.toList()
|
||||
override fun getAllUsers(): List<UserEntity> = users.toList()
|
||||
|
||||
override suspend fun persistUserAccount(userAccount: UserAccount): UserAccountEntity {
|
||||
val entity = map(userAccount) // TODO: may fix someday and add also BankAccounts and their id
|
||||
this.userAccounts.add(entity)
|
||||
override suspend fun persistUser(user: User): UserEntity {
|
||||
val entity = map(user) // TODO: may fix someday and add also BankAccounts and their id
|
||||
this.users.add(entity)
|
||||
return entity
|
||||
}
|
||||
|
||||
|
@ -37,29 +37,31 @@ class InMemoryBankingRepository(
|
|||
|
||||
override fun getAllAccountTransactions(): List<AccountTransactionEntity> = transactions.toList()
|
||||
|
||||
override fun getAllTransactionsOfUserAccount(userAccount: UserAccountEntity): List<AccountTransactionEntity> =
|
||||
getAllAccountTransactions().filter { it.userAccountId == userAccount.id }
|
||||
override fun getAllTransactionsOfUser(user: UserEntity): List<AccountTransactionEntity> =
|
||||
getAllAccountTransactions().filter { it.userId == user.id }
|
||||
|
||||
override fun getTransactionById(transactionId: Long): AccountTransactionEntity? =
|
||||
getAllAccountTransactions().firstOrNull { it.id == transactionId }
|
||||
|
||||
|
||||
private fun map(account: UserAccount) = UserAccountEntity(
|
||||
private fun map(account: User) = UserEntity(
|
||||
nextId++,
|
||||
account.bankCode, account.loginName, account.password, account.bankName, account.bic, account.customerName, account.userId,
|
||||
// TODO: may fix someday and also add BankAccounts
|
||||
emptyList(), account.selectedTanMethodId, emptyList(), account.selectedTanMediumName, emptyList(),
|
||||
account.bankingGroup, account.iconUrl, account.wrongCredentialsEntered, account.userSetDisplayName, account.displayIndex
|
||||
emptyList(), account.selectedTanMethodIdentifier, emptyList(), account.selectedTanMediumIdentifier, emptyList(),
|
||||
account.bankingGroup, account.finTsServerAddress,
|
||||
account.userSetDisplayName, account.displayIndex,
|
||||
account.iconUrl, account.wrongCredentialsEntered,
|
||||
)
|
||||
|
||||
// TODO: someday may fix and get userAccountId and bankAccountId
|
||||
private fun map(transaction: AccountTransaction, userAccountId: Long = nextId++, bankAccountId: Long = nextId++) = AccountTransactionEntity(
|
||||
private fun map(transaction: AccountTransaction, userId: Long = nextId++, bankAccountId: Long = nextId++) = AccountTransactionEntity(
|
||||
nextId++,
|
||||
userAccountId, bankAccountId,
|
||||
userId, bankAccountId,
|
||||
transaction.amount, transaction.currency, transaction.reference,
|
||||
transaction.bookingDate, transaction.valueDate,
|
||||
transaction.otherPartyName, transaction.otherPartyBankCode, transaction.otherPartyAccountId,
|
||||
transaction.bookingText
|
||||
transaction.otherPartyName, transaction.otherPartyBankId, transaction.otherPartyAccountId,
|
||||
transaction.postingText
|
||||
)
|
||||
|
||||
}
|
|
@ -6,7 +6,7 @@ import kotlinx.datetime.LocalDate
|
|||
import net.codinux.banking.client.model.*
|
||||
import net.codinux.banking.dataaccess.entities.AccountTransactionEntity
|
||||
import net.codinux.banking.dataaccess.entities.BankAccountEntity
|
||||
import net.codinux.banking.dataaccess.entities.UserAccountEntity
|
||||
import net.codinux.banking.dataaccess.entities.UserEntity
|
||||
import net.codinux.banking.ui.model.AccountTransactionViewModel
|
||||
import net.codinux.log.logger
|
||||
import kotlin.enums.EnumEntries
|
||||
|
@ -25,42 +25,46 @@ open class SqliteBankingRepository(
|
|||
|
||||
private val log by logger()
|
||||
|
||||
override fun getAllUserAccounts(): List<UserAccountEntity> {
|
||||
val bankAccounts = getAllBankAccounts().groupBy { it.userAccountId }
|
||||
|
||||
return userAccountQueries.selectAllUserAccounts { id, bankCode, loginName, password, bankName, bic, customerName, userId, selectedTanMethodId, selectedTanMediumName, bankingGroup, iconUrl, wrongCredentialsEntered, userSetDisplayName, displayIndex ->
|
||||
UserAccountEntity(id, bankCode, loginName, password, bankName, bic, customerName, userId, bankAccounts[id] ?: emptyList(), selectedTanMethodId, emptyList(), selectedTanMediumName, emptyList(),
|
||||
bankingGroup?.let { BankingGroup.valueOf(it) }, iconUrl, wrongCredentialsEntered, userSetDisplayName, displayIndex.toInt())
|
||||
override fun getAllUsers(): List<UserEntity> {
|
||||
val bankAccounts = getAllBankAccounts().groupBy { it.userId }
|
||||
|
||||
return userAccountQueries.selectAllUsers { id, bankCode, loginName, password, bankName, bic, customerName, userId, selectedTanMethodId, selectedTanMediumName, bankingGroup, iconUrl, wrongCredentialsEntered, userSetDisplayName, displayIndex ->
|
||||
UserEntity(id, bankCode, loginName, password, bankName, bic, customerName, userId, bankAccounts[id] ?: emptyList(), selectedTanMethodId, emptyList(), selectedTanMediumName, emptyList(),
|
||||
bankingGroup?.let { BankingGroup.valueOf(it) }, "", userSetDisplayName, displayIndex.toInt(), iconUrl, wrongCredentialsEntered)
|
||||
}.executeAsList()
|
||||
}
|
||||
|
||||
override suspend fun persistUserAccount(userAccount: UserAccount): UserAccountEntity {
|
||||
override suspend fun persistUser(user: User): UserEntity {
|
||||
return userAccountQueries.transactionWithResult {
|
||||
userAccountQueries.insertUserAccount(userAccount.bankCode, userAccount.loginName, userAccount.password, userAccount.bankName, userAccount.bic,
|
||||
userAccount.customerName, userAccount.userId, userAccount.selectedTanMethodId, userAccount.selectedTanMediumName,
|
||||
userAccount.bankingGroup?.name, userAccount.iconUrl, userAccount.wrongCredentialsEntered, userAccount.userSetDisplayName, userAccount.displayIndex.toLong()
|
||||
userAccountQueries.insertUser(user.bankCode, user.loginName, user.password, user.bankName, user.bic,
|
||||
user.customerName, user.userId, user.selectedTanMethodIdentifier, user.selectedTanMediumIdentifier,
|
||||
user.bankingGroup?.name, user.iconUrl, user.wrongCredentialsEntered, user.userSetDisplayName, user.displayIndex.toLong()
|
||||
)
|
||||
|
||||
val userAccountId = getLastInsertedId() // getLastInsertedId() / last_insert_rowid() has to be called in a transaction with the insert operation, otherwise it will not work
|
||||
val userId = getLastInsertedId() // getLastInsertedId() / last_insert_rowid() has to be called in a transaction with the insert operation, otherwise it will not work
|
||||
|
||||
val bankAccounts = persistBankAccounts(userAccountId, userAccount.accounts)
|
||||
val bankAccounts = persistBankAccounts(userId, user.accounts)
|
||||
|
||||
UserAccountEntity(userAccountId, userAccount, bankAccounts)
|
||||
UserEntity(userId, user, bankAccounts)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
fun getAllBankAccounts(): List<BankAccountEntity> = userAccountQueries.selectAllBankAccounts { id, userAccountId, identifier, accountHolderName, type, iban, subAccountNumber, productName, currency, accountLimit, balance, isAccountTypeSupportedByApplication, features, countDaysForWhichTransactionsAreKept, lastTransactionsRetrievalTime, retrievedTransactionsFrom, userSetDisplayName, displayIndex, hideAccount, includeInAutomaticAccountsUpdate ->
|
||||
fun getAllBankAccounts(): List<BankAccountEntity> = userAccountQueries.selectAllBankAccounts { id, userId, identifier, accountHolderName, type, iban, subAccountNumber, productName, currency, accountLimit, balance, isAccountTypeSupportedByApplication, features, serverTransactionsRetentionDays, lastTransactionsRetrievalTime, retrievedTransactionsFrom, userSetDisplayName, displayIndex, hideAccount, includeInAutomaticAccountsUpdate ->
|
||||
BankAccountEntity(
|
||||
id, userAccountId,
|
||||
identifier, accountHolderName, BankAccountType.valueOf(type),
|
||||
iban, subAccountNumber, productName, currency, accountLimit,
|
||||
id, userId,
|
||||
|
||||
identifier, subAccountNumber, iban, productName,
|
||||
accountHolderName, BankAccountType.valueOf(type),
|
||||
currency, accountLimit,
|
||||
|
||||
mapToAmount(balance),
|
||||
isAccountTypeSupportedByApplication, mapEnumSet(features, BankAccountFeatures.entries),
|
||||
|
||||
mapToInt(countDaysForWhichTransactionsAreKept),
|
||||
mapToAmount(balance),
|
||||
|
||||
mapToInt(serverTransactionsRetentionDays),
|
||||
mapToInstant(lastTransactionsRetrievalTime), mapToDate(retrievedTransactionsFrom),
|
||||
|
||||
mutableListOf(), mutableListOf(),
|
||||
|
@ -70,22 +74,22 @@ open class SqliteBankingRepository(
|
|||
)
|
||||
}.executeAsList()
|
||||
|
||||
private suspend fun persistBankAccounts(userAccountId: Long, bankAccounts: Collection<BankAccount>): List<BankAccountEntity> =
|
||||
bankAccounts.map { persistBankAccount(userAccountId, it) }
|
||||
private suspend fun persistBankAccounts(userId: Long, bankAccounts: Collection<BankAccount>): List<BankAccountEntity> =
|
||||
bankAccounts.map { persistBankAccount(userId, it) }
|
||||
|
||||
/**
|
||||
* Has to be executed in a transaction in order that getting persisted BankAccount's id works~
|
||||
*/
|
||||
private suspend fun persistBankAccount(userAccountId: Long, account: BankAccount): BankAccountEntity {
|
||||
private suspend fun persistBankAccount(userId: Long, account: BankAccount): BankAccountEntity {
|
||||
userAccountQueries.insertBankAccount(
|
||||
userAccountId,
|
||||
userId,
|
||||
account.identifier, account.accountHolderName, mapEnum(account.type),
|
||||
account.iban, account.subAccountNumber, account.productName, account.currency, account.accountLimit,
|
||||
|
||||
mapAmount(account.balance),
|
||||
account.isAccountTypeSupportedByApplication, mapEnumCollectionToString(account.features),
|
||||
|
||||
mapInt(account.countDaysForWhichTransactionsAreKept),
|
||||
mapInt(account.serverTransactionsRetentionDays),
|
||||
mapInstant(account.lastTransactionsRetrievalTime), mapDate(account.retrievedTransactionsFrom),
|
||||
|
||||
account.userSetDisplayName, mapInt(account.displayIndex),
|
||||
|
@ -95,25 +99,24 @@ open class SqliteBankingRepository(
|
|||
val accountId = getLastInsertedId()
|
||||
|
||||
val accountTransactionEntities = account.bookedTransactions.map { transaction ->
|
||||
persistTransaction(userAccountId, accountId, transaction)
|
||||
persistTransaction(userId, accountId, transaction)
|
||||
}
|
||||
|
||||
return BankAccountEntity(accountId, userAccountId, account, accountTransactionEntities)
|
||||
return BankAccountEntity(accountId, userId, account, accountTransactionEntities)
|
||||
}
|
||||
|
||||
|
||||
override fun getAllAccountTransactionsAsViewModel(): List<AccountTransactionViewModel> =
|
||||
// TODO: find a better way to express the reference value to display, sepaReference or (unparsed)reference
|
||||
accountTransactionQueries.selectAllTransactionsAsViewModel { id, userAccountId, bankAccountId, amount, currency, unparsedReference, valueDate, otherPartyName, bookingText, sepaReference, userSetDisplayName, category ->
|
||||
AccountTransactionViewModel(id, userAccountId, bankAccountId, mapToAmount(amount), currency, sepaReference ?: unparsedReference, mapToDate(valueDate), otherPartyName, bookingText, userSetDisplayName, category)
|
||||
accountTransactionQueries.selectAllTransactionsAsViewModel { id, userId, bankAccountId, amount, currency, reference, valueDate, otherPartyName, postingText, userSetDisplayName, category ->
|
||||
AccountTransactionViewModel(id, userId, bankAccountId, mapToAmount(amount), currency, reference, mapToDate(valueDate), otherPartyName, postingText, userSetDisplayName, category)
|
||||
}.executeAsList()
|
||||
|
||||
override fun getAllAccountTransactions(): List<AccountTransactionEntity> {
|
||||
return accountTransactionQueries.selectAllTransactions(::mapTransaction).executeAsList()
|
||||
}
|
||||
|
||||
override fun getAllTransactionsOfUserAccount(userAccount: UserAccountEntity): List<AccountTransactionEntity> {
|
||||
return accountTransactionQueries.selectAllTransactionsOfUserAccount(userAccount.id, ::mapTransaction).executeAsList()
|
||||
override fun getAllTransactionsOfUser(user: UserEntity): List<AccountTransactionEntity> {
|
||||
return accountTransactionQueries.selectAllTransactionsOfUser(user.id, ::mapTransaction).executeAsList()
|
||||
}
|
||||
|
||||
override fun getTransactionById(transactionId: Long): AccountTransactionEntity? =
|
||||
|
@ -123,7 +126,7 @@ open class SqliteBankingRepository(
|
|||
override suspend fun persistTransactions(bankAccount: BankAccountEntity, transactions: List<AccountTransaction>): List<AccountTransactionEntity> {
|
||||
return accountTransactionQueries.transactionWithResult {
|
||||
transactions.map { transaction ->
|
||||
persistTransaction(bankAccount.userAccountId, bankAccount.id, transaction)
|
||||
persistTransaction(bankAccount.userId, bankAccount.id, transaction)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -131,36 +134,34 @@ open class SqliteBankingRepository(
|
|||
/**
|
||||
* Has to be executed in a transaction in order that getting persisted AccountTransaction's id works~
|
||||
*/
|
||||
protected open suspend fun persistTransaction(userAccountId: Long, bankAccountId: Long, transaction: AccountTransaction): AccountTransactionEntity {
|
||||
protected open suspend fun persistTransaction(userId: Long, bankAccountId: Long, transaction: AccountTransaction): AccountTransactionEntity {
|
||||
accountTransactionQueries.insertTransaction(
|
||||
userAccountId, bankAccountId,
|
||||
userId, bankAccountId,
|
||||
|
||||
mapAmount(transaction.amount), transaction.currency, transaction.unparsedReference,
|
||||
mapAmount(transaction.amount), transaction.currency, transaction.reference,
|
||||
mapDate(transaction.bookingDate), mapDate(transaction.valueDate),
|
||||
transaction.otherPartyName, transaction.otherPartyBankCode, transaction.otherPartyAccountId,
|
||||
transaction.bookingText,
|
||||
|
||||
transaction.userSetDisplayName, null, transaction.notes, // TODO: add category to AccountTransaction
|
||||
transaction.otherPartyName, transaction.otherPartyBankId, transaction.otherPartyAccountId,
|
||||
transaction.postingText,
|
||||
|
||||
transaction.information,
|
||||
transaction.statementNumber?.toLong(), transaction.sequenceNumber?.toLong(),
|
||||
transaction.userSetDisplayName, transaction.category, transaction.notes,
|
||||
|
||||
transaction.statementNumber?.toLong(), transaction.sheetNumber?.toLong(),
|
||||
mapAmount(transaction.openingBalance), mapAmount(transaction.closingBalance),
|
||||
|
||||
transaction.endToEndReference, transaction.customerReference, transaction.mandateReference,
|
||||
transaction.creditorIdentifier, transaction.originatorsIdentificationCode,
|
||||
|
||||
transaction.compensationAmount, transaction.originalAmount,
|
||||
transaction.sepaReference,
|
||||
transaction.deviantOriginator, transaction.deviantRecipient,
|
||||
transaction.referenceWithNoSpecialType, transaction.primaNotaNumber, transaction.textKeySupplement,
|
||||
transaction.referenceWithNoSpecialType,
|
||||
|
||||
transaction.currencyType, transaction.bookingKey,
|
||||
transaction.referenceForTheAccountOwner, transaction.referenceOfTheAccountServicingInstitution,
|
||||
transaction.supplementaryDetails,
|
||||
transaction.journalNumber, transaction.textKeyAddition,
|
||||
|
||||
transaction.transactionReferenceNumber, transaction.relatedReferenceNumber
|
||||
transaction.orderReferenceNumber, transaction.referenceNumber
|
||||
)
|
||||
|
||||
return AccountTransactionEntity(getLastInsertedId(), userAccountId, bankAccountId, transaction)
|
||||
return AccountTransactionEntity(getLastInsertedId(), userId, bankAccountId, transaction)
|
||||
}
|
||||
|
||||
|
||||
|
@ -169,46 +170,59 @@ open class SqliteBankingRepository(
|
|||
|
||||
|
||||
private fun mapTransaction(
|
||||
id: Long, userAccountId: Long, bankAccountId: Long,
|
||||
amount: String, currency: String, reference: String, bookingDate: String, valueDate: String,
|
||||
otherPartyName: String?, otherPartyBankCode: String?, otherPartyAccountId: String?, bookingText: String?,
|
||||
id: Long, userId: Long, bankAccountId: Long,
|
||||
|
||||
amount: String, currency: String, reference: String?,
|
||||
bookingDate: String, valueDate: String,
|
||||
|
||||
otherPartyName: String?, otherPartyBankId: String?, otherPartyAccountId: String?,
|
||||
postingText: String?,
|
||||
|
||||
userSetDisplayName: String?, category: String?, notes: String?,
|
||||
information: String?, statementNumber: Long?, sequenceNumber: Long?,
|
||||
|
||||
statementNumber: Long?, sheetNumber: Long?,
|
||||
|
||||
openingBalance: String?, closingBalance: String?,
|
||||
|
||||
endToEndReference: String?, customerReference: String?, mandateReference: String?, creditorIdentifier: String?, originatorsIdentificationCode: String?,
|
||||
compensationAmount: String?, originalAmount: String?, sepaReference: String?, deviantOriginator: String?, deviantRecipient: String?, referenceWithNoSpecialType: String?,
|
||||
primaNotaNumber: String?, textKeySupplement: String?, currencyType: String?, bookingKey: String?, referenceForTheAccountOwner: String?, referenceOfTheAccountServicingInstitution: String?,
|
||||
supplementaryDetails: String?, transactionReferenceNumber: String?, relatedReferenceNumber: String?): AccountTransactionEntity =
|
||||
AccountTransactionEntity(
|
||||
id,
|
||||
userAccountId, bankAccountId,
|
||||
|
||||
Amount(amount), currency, reference,
|
||||
mapToDate(bookingDate), mapToDate(valueDate),
|
||||
otherPartyName, otherPartyBankCode, otherPartyAccountId,
|
||||
bookingText,
|
||||
compensationAmount: String?, originalAmount: String?, deviantOriginator: String?, deviantRecipient: String?, referenceWithNoSpecialType: String?,
|
||||
|
||||
userSetDisplayName, category, notes,
|
||||
journalNumber: String?, textKeyAddition: String?,
|
||||
|
||||
information,
|
||||
statementNumber?.toInt(), sequenceNumber?.toInt(),
|
||||
referenceForTheAccountOwner: String?, referenceOfTheAccountServicingInstitution: String?, supplementaryDetails: String?,
|
||||
|
||||
mapToAmount(openingBalance), mapToAmount(closingBalance),
|
||||
transactionReferenceNumber: String?, relatedReferenceNumber: String?
|
||||
): AccountTransactionEntity = AccountTransactionEntity(
|
||||
id,
|
||||
userId, bankAccountId,
|
||||
|
||||
endToEndReference, customerReference, mandateReference,
|
||||
creditorIdentifier, originatorsIdentificationCode,
|
||||
compensationAmount, originalAmount,
|
||||
sepaReference,
|
||||
deviantOriginator, deviantRecipient,
|
||||
referenceWithNoSpecialType, primaNotaNumber,
|
||||
textKeySupplement,
|
||||
Amount(amount), currency, reference,
|
||||
mapToDate(bookingDate), mapToDate(valueDate),
|
||||
otherPartyName, otherPartyBankId, otherPartyAccountId,
|
||||
postingText,
|
||||
|
||||
currencyType, bookingKey,
|
||||
referenceForTheAccountOwner, referenceOfTheAccountServicingInstitution,
|
||||
supplementaryDetails,
|
||||
mapToAmount(openingBalance), mapToAmount(closingBalance),
|
||||
|
||||
transactionReferenceNumber, relatedReferenceNumber
|
||||
)
|
||||
userSetDisplayName, category, notes,
|
||||
|
||||
statementNumber?.toInt(), sheetNumber?.toInt(),
|
||||
|
||||
referenceForTheAccountOwner, referenceOfTheAccountServicingInstitution,
|
||||
supplementaryDetails,
|
||||
|
||||
endToEndReference, mandateReference,
|
||||
creditorIdentifier, originatorsIdentificationCode,
|
||||
|
||||
compensationAmount, originalAmount,
|
||||
deviantOriginator, deviantRecipient,
|
||||
referenceWithNoSpecialType,
|
||||
|
||||
journalNumber, textKeyAddition,
|
||||
|
||||
transactionReferenceNumber, relatedReferenceNumber
|
||||
// TODO: add isReversal
|
||||
)
|
||||
|
||||
|
||||
@JvmName("mapAmount")
|
||||
|
|
|
@ -6,108 +6,117 @@ import net.codinux.banking.client.model.Amount
|
|||
|
||||
class AccountTransactionEntity(
|
||||
val id: Long,
|
||||
val userAccountId: Long,
|
||||
val userId: Long,
|
||||
val bankAccountId: Long,
|
||||
|
||||
amount: Amount,
|
||||
currency: String,
|
||||
reference: String,
|
||||
reference: String?,
|
||||
|
||||
bookingDate: LocalDate,
|
||||
valueDate: LocalDate,
|
||||
|
||||
otherPartyName: String? = null,
|
||||
otherPartyBankCode: String? = null,
|
||||
otherPartyBankId: String? = null,
|
||||
otherPartyAccountId: String? = null,
|
||||
|
||||
bookingText: String? = null,
|
||||
|
||||
userSetDisplayName: String? = null,
|
||||
category: String? = null,
|
||||
notes: String? = null,
|
||||
information: String? = null,
|
||||
|
||||
statementNumber: Int? = null,
|
||||
sequenceNumber: Int? = null,
|
||||
postingText: String? = null,
|
||||
|
||||
openingBalance: Amount? = null,
|
||||
closingBalance: Amount? = null,
|
||||
|
||||
endToEndReference: String? = null,
|
||||
userSetDisplayName: String? = null,
|
||||
category: String? = null,
|
||||
notes: String? = null,
|
||||
|
||||
statementNumber: Int? = null,
|
||||
sheetNumber: Int? = null,
|
||||
|
||||
customerReference: String? = null,
|
||||
bankReference: String? = null,
|
||||
furtherInformation: String? = null,
|
||||
|
||||
|
||||
endToEndReference: String? = null,
|
||||
mandateReference: String? = null,
|
||||
creditorIdentifier: String? = null,
|
||||
originatorsIdentificationCode: String? = null,
|
||||
|
||||
compensationAmount: String? = null,
|
||||
originalAmount: String? = null,
|
||||
sepaReference: String? = null,
|
||||
deviantOriginator: String? = null,
|
||||
deviantRecipient: String? = null,
|
||||
referenceWithNoSpecialType: String? = null,
|
||||
primaNotaNumber: String? = null,
|
||||
textKeySupplement: String? = null,
|
||||
|
||||
currencyType: String? = null,
|
||||
bookingKey: String? = null,
|
||||
referenceForTheAccountOwner: String? = null,
|
||||
referenceOfTheAccountServicingInstitution: String? = null,
|
||||
supplementaryDetails: String? = null,
|
||||
journalNumber: String? = null,
|
||||
textKeyAddition: String? = null,
|
||||
|
||||
transactionReferenceNumber: String? = null,
|
||||
relatedReferenceNumber: String? = null
|
||||
orderReferenceNumber: String? = null,
|
||||
referenceNumber: String? = null,
|
||||
|
||||
isReversal: Boolean = false,
|
||||
) : AccountTransaction(
|
||||
amount, currency, reference,
|
||||
bookingDate, valueDate,
|
||||
otherPartyName, otherPartyBankCode, otherPartyAccountId,
|
||||
bookingText,
|
||||
otherPartyName, otherPartyBankId, otherPartyAccountId,
|
||||
postingText,
|
||||
|
||||
information,
|
||||
statementNumber, sequenceNumber,
|
||||
openingBalance, closingBalance,
|
||||
|
||||
endToEndReference, customerReference, mandateReference,
|
||||
statementNumber, sheetNumber,
|
||||
|
||||
customerReference, bankReference, furtherInformation,
|
||||
|
||||
endToEndReference, mandateReference,
|
||||
creditorIdentifier, originatorsIdentificationCode,
|
||||
|
||||
compensationAmount, originalAmount,
|
||||
sepaReference,
|
||||
deviantOriginator, deviantRecipient,
|
||||
referenceWithNoSpecialType, primaNotaNumber,
|
||||
textKeySupplement,
|
||||
referenceWithNoSpecialType,
|
||||
|
||||
currencyType, bookingKey,
|
||||
referenceForTheAccountOwner, referenceOfTheAccountServicingInstitution,
|
||||
supplementaryDetails,
|
||||
journalNumber, textKeyAddition,
|
||||
|
||||
transactionReferenceNumber, relatedReferenceNumber,
|
||||
orderReferenceNumber, referenceNumber,
|
||||
|
||||
isReversal,
|
||||
|
||||
userSetDisplayName, category, notes
|
||||
) {
|
||||
constructor(id: Long, userAccountId: Long, bankAccountId: Long, transaction: AccountTransaction) : this(
|
||||
id, userAccountId, bankAccountId,
|
||||
transaction.amount, transaction.currency, transaction.unparsedReference, transaction.bookingDate, transaction.valueDate,
|
||||
transaction.otherPartyName, transaction.otherPartyBankCode, transaction.otherPartyAccountId, transaction.bookingText,
|
||||
constructor(id: Long, userId: Long, bankAccountId: Long, transaction: AccountTransaction) : this(
|
||||
id, userId, bankAccountId,
|
||||
transaction.amount, transaction.currency, transaction.reference,
|
||||
transaction.bookingDate, transaction.valueDate,
|
||||
|
||||
transaction.userSetDisplayName, transaction.category, transaction.notes, transaction.information,
|
||||
transaction.otherPartyName, transaction.otherPartyBankId, transaction.otherPartyAccountId,
|
||||
|
||||
transaction.postingText,
|
||||
|
||||
transaction.statementNumber, transaction.sequenceNumber,
|
||||
transaction.openingBalance, transaction.closingBalance,
|
||||
|
||||
transaction.endToEndReference, transaction.customerReference, transaction.mandateReference,
|
||||
transaction.userSetDisplayName, transaction.category, transaction.notes,
|
||||
|
||||
transaction.statementNumber, transaction.sheetNumber,
|
||||
|
||||
transaction.customerReference, transaction.bankReference,
|
||||
transaction.furtherInformation,
|
||||
|
||||
transaction.endToEndReference, transaction.mandateReference,
|
||||
transaction.creditorIdentifier, transaction.originatorsIdentificationCode,
|
||||
|
||||
transaction.compensationAmount, transaction.originalAmount,
|
||||
transaction.sepaReference,
|
||||
transaction.deviantOriginator, transaction.deviantRecipient,
|
||||
transaction.referenceWithNoSpecialType, transaction.primaNotaNumber, transaction.textKeySupplement,
|
||||
transaction.referenceWithNoSpecialType,
|
||||
|
||||
transaction.currencyType, transaction.bookingKey,
|
||||
transaction.referenceForTheAccountOwner, transaction.referenceOfTheAccountServicingInstitution,
|
||||
transaction.supplementaryDetails,
|
||||
transaction.journalNumber, transaction.textKeyAddition,
|
||||
|
||||
transaction.transactionReferenceNumber, transaction.relatedReferenceNumber
|
||||
transaction.orderReferenceNumber, transaction.referenceNumber,
|
||||
|
||||
transaction.isReversal,
|
||||
)
|
||||
|
||||
|
||||
override val identifier: String by lazy {
|
||||
"$userAccountId ${super.identifier}"
|
||||
"$userId ${super.identifier}"
|
||||
}
|
||||
|
||||
}
|
|
@ -6,28 +6,29 @@ import net.codinux.banking.client.model.*
|
|||
|
||||
class BankAccountEntity(
|
||||
val id: Long,
|
||||
val userAccountId: Long,
|
||||
val userId: Long,
|
||||
|
||||
identifier: String,
|
||||
subAccountNumber: String? = null,
|
||||
iban: String? = null,
|
||||
productName: String? = null,
|
||||
|
||||
accountHolderName: String,
|
||||
type: BankAccountType = BankAccountType.Other,
|
||||
iban: String? = null,
|
||||
subAccountNumber: String? = null,
|
||||
productName: String? = null,
|
||||
currency: String = "EUR",
|
||||
accountLimit: String? = null,
|
||||
|
||||
balance: Amount = Amount.Zero, // TODO: add a BigDecimal library
|
||||
|
||||
isAccountTypeSupportedByApplication: Boolean = true,
|
||||
features: Set<BankAccountFeatures> = emptySet(),
|
||||
|
||||
countDaysForWhichTransactionsAreKept: Int? = null,
|
||||
balance: Amount = Amount.Zero, // TODO: add a BigDecimal library
|
||||
|
||||
serverTransactionsRetentionDays: Int? = null,
|
||||
lastTransactionsRetrievalTime: Instant? = null,
|
||||
retrievedTransactionsFrom: LocalDate? = null,
|
||||
|
||||
bookedTransactions: MutableList<AccountTransactionEntity> = mutableListOf(),
|
||||
unbookedTransactions: MutableList<UnbookedAccountTransaction> = mutableListOf(),
|
||||
prebookedTransactions: MutableList<PrebookedAccountTransaction> = mutableListOf(),
|
||||
|
||||
userSetDisplayName: String? = null,
|
||||
displayIndex: Int = 0,
|
||||
|
@ -35,21 +36,39 @@ class BankAccountEntity(
|
|||
hideAccount: Boolean = false,
|
||||
includeInAutomaticAccountsUpdate: Boolean = true
|
||||
) : BankAccount(
|
||||
identifier, accountHolderName, type, iban, subAccountNumber, productName, currency, accountLimit,
|
||||
balance, isAccountTypeSupportedByApplication, features,
|
||||
lastTransactionsRetrievalTime, retrievedTransactionsFrom, countDaysForWhichTransactionsAreKept,
|
||||
bookedTransactions as MutableList<AccountTransaction>, unbookedTransactions,
|
||||
userSetDisplayName, displayIndex, hideAccount, includeInAutomaticAccountsUpdate
|
||||
identifier, subAccountNumber, iban, productName,
|
||||
|
||||
accountHolderName, type, currency, accountLimit,
|
||||
|
||||
isAccountTypeSupportedByApplication, features,
|
||||
|
||||
balance,
|
||||
|
||||
serverTransactionsRetentionDays, lastTransactionsRetrievalTime, retrievedTransactionsFrom,
|
||||
|
||||
bookedTransactions as MutableList<AccountTransaction>, prebookedTransactions,
|
||||
|
||||
userSetDisplayName, displayIndex,
|
||||
hideAccount, includeInAutomaticAccountsUpdate
|
||||
) {
|
||||
constructor(id: Long, userAccountId: Long, account: BankAccount, transactions: List<AccountTransactionEntity> = emptyList()) : this(
|
||||
id, userAccountId,
|
||||
account.identifier, account.accountHolderName, account.type, account.iban, account.subAccountNumber,
|
||||
account.productName, account.currency, account.accountLimit,
|
||||
account.balance,
|
||||
constructor(id: Long, userId: Long, account: BankAccount, transactions: List<AccountTransactionEntity> = emptyList()) : this(
|
||||
id, userId,
|
||||
account.identifier, account.subAccountNumber, account.iban, account.productName,
|
||||
|
||||
account.accountHolderName, account.type,
|
||||
account.currency, account.accountLimit,
|
||||
|
||||
account.isAccountTypeSupportedByApplication, account.features,
|
||||
account.countDaysForWhichTransactionsAreKept, account.lastTransactionsRetrievalTime, account.retrievedTransactionsFrom,
|
||||
|
||||
account.balance,
|
||||
|
||||
account.serverTransactionsRetentionDays,
|
||||
account.lastTransactionsRetrievalTime, account.retrievedTransactionsFrom,
|
||||
|
||||
transactions.toMutableList(), mutableListOf(),
|
||||
account.userSetDisplayName, account.displayIndex, account.hideAccount, account.includeInAutomaticAccountsUpdate
|
||||
|
||||
account.userSetDisplayName, account.displayIndex,
|
||||
account.hideAccount, account.includeInAutomaticAccountsUpdate
|
||||
)
|
||||
|
||||
val bookedTransactionsEntities: MutableList<AccountTransactionEntity> = bookedTransactions
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
package net.codinux.banking.dataaccess.entities
|
||||
|
||||
import net.codinux.banking.client.model.BankingGroup
|
||||
import net.codinux.banking.client.model.UserAccount
|
||||
import net.codinux.banking.client.model.User
|
||||
import net.codinux.banking.client.model.tan.TanMedium
|
||||
import net.codinux.banking.client.model.tan.TanMethod
|
||||
|
||||
class UserAccountEntity(
|
||||
class UserEntity(
|
||||
val id: Long,
|
||||
|
||||
|
||||
bankCode: String,
|
||||
loginName: String,
|
||||
password: String?,
|
||||
|
@ -16,38 +16,43 @@ class UserAccountEntity(
|
|||
bic: String,
|
||||
|
||||
customerName: String,
|
||||
userId: String = loginName,
|
||||
userId: String? = null,
|
||||
|
||||
override val accounts: List<BankAccountEntity> = emptyList(),
|
||||
|
||||
selectedTanMethodId: String? = null,
|
||||
selectedTanMethodIdentifier: String? = null,
|
||||
tanMethods: List<TanMethod> = listOf(),
|
||||
|
||||
selectedTanMediumName: String? = null,
|
||||
selectedTanMediumIdentifier: String? = null,
|
||||
tanMedia: List<TanMedium> = listOf(),
|
||||
|
||||
bankingGroup: BankingGroup? = null,
|
||||
iconUrl: String? = null,
|
||||
|
||||
wrongCredentialsEntered: Boolean = false,
|
||||
finTsServerAddress: String,
|
||||
|
||||
userSetDisplayName: String? = null,
|
||||
displayIndex: Int = 0
|
||||
) : UserAccount(bankCode, loginName, password, bankName, bic, customerName, userId, accounts, selectedTanMethodId, tanMethods, selectedTanMediumName, tanMedia, bankingGroup, iconUrl) {
|
||||
displayIndex: Int = 0,
|
||||
|
||||
iconUrl: String? = null,
|
||||
wrongCredentialsEntered: Boolean = false
|
||||
) : User(bankCode, loginName, password, bankName, bic, customerName, userId, accounts, selectedTanMethodIdentifier, tanMethods, selectedTanMediumIdentifier, tanMedia, bankingGroup, finTsServerAddress) {
|
||||
|
||||
init {
|
||||
this.wrongCredentialsEntered = wrongCredentialsEntered
|
||||
this.userSetDisplayName = userSetDisplayName
|
||||
this.displayIndex = displayIndex
|
||||
|
||||
this.iconUrl = iconUrl
|
||||
this.wrongCredentialsEntered = wrongCredentialsEntered
|
||||
}
|
||||
|
||||
|
||||
constructor(id: Long, user: UserAccount, bankAccounts: List<BankAccountEntity>) : this(
|
||||
constructor(id: Long, user: User, bankAccounts: List<BankAccountEntity>) : this(
|
||||
id,
|
||||
user.bankCode, user.loginName, user.password, user.bankName, user.bic, user.customerName, user.userId,
|
||||
bankAccounts,
|
||||
user.selectedTanMethodId, emptyList(), user.selectedTanMediumName, emptyList(),
|
||||
user.bankingGroup, user.iconUrl, user.wrongCredentialsEntered, user.userSetDisplayName, user.displayIndex
|
||||
user.selectedTanMethodIdentifier, user.tanMethods, user.selectedTanMediumIdentifier, user.tanMedia,
|
||||
user.bankingGroup, user.finTsServerAddress,
|
||||
user.userSetDisplayName, user.displayIndex,
|
||||
user.iconUrl, user.wrongCredentialsEntered,
|
||||
)
|
||||
|
||||
}
|
|
@ -1,7 +1,6 @@
|
|||
package net.codinux.banking.ui.appskeleton
|
||||
|
||||
import androidx.compose.animation.*
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
|
@ -18,13 +17,9 @@ import androidx.compose.ui.focus.FocusRequester
|
|||
import androidx.compose.ui.focus.focusRequester
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.input.key.*
|
||||
import androidx.compose.ui.layout.onGloballyPositioned
|
||||
import androidx.compose.ui.platform.LocalViewConfiguration
|
||||
import androidx.compose.ui.platform.LocalWindowInfo
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.toSize
|
||||
import bankmeister.composeapp.generated.resources.Res
|
||||
import bankmeister.composeapp.generated.resources.filter_alt
|
||||
import kotlinx.coroutines.launch
|
||||
|
@ -39,7 +34,7 @@ private val IconWidth = 48.dp
|
|||
|
||||
@Composable
|
||||
fun BottomBar(showMenuDrawer: Boolean = true) {
|
||||
val userAccounts by uiState.userAccounts.collectAsState()
|
||||
val users by uiState.users.collectAsState()
|
||||
|
||||
val transactionsFilter by uiState.transactionsFilter.collectAsState()
|
||||
|
||||
|
@ -75,7 +70,7 @@ fun BottomBar(showMenuDrawer: Boolean = true) {
|
|||
} else if (selectedAccount.bankAccount != null) {
|
||||
selectedAccount.bankAccount.displayName
|
||||
} else {
|
||||
selectedAccount.userAccount.displayName
|
||||
selectedAccount.user.displayName
|
||||
}
|
||||
|
||||
Text(title, color = color, maxLines = 1, overflow = TextOverflow.Ellipsis)
|
||||
|
@ -132,7 +127,7 @@ fun BottomBar(showMenuDrawer: Boolean = true) {
|
|||
}
|
||||
|
||||
|
||||
if (userAccounts.isNotEmpty()) {
|
||||
if (users.isNotEmpty()) {
|
||||
if (showSearchbar == false) {
|
||||
Row(Modifier.fillMaxHeight().widthIn(IconWidth, IconWidth), verticalAlignment = Alignment.CenterVertically) {
|
||||
IconButton({ showSearchbar = true }, Modifier.width(IconWidth)) {
|
||||
|
|
|
@ -54,7 +54,7 @@ private val VerticalSpacing = 8.dp
|
|||
fun SideMenuContent() {
|
||||
val drawerState = uiState.drawerState.collectAsState().value
|
||||
|
||||
val accounts = uiState.userAccounts.collectAsState().value
|
||||
val accounts = uiState.users.collectAsState().value
|
||||
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
|
||||
|
|
|
@ -9,8 +9,8 @@ import androidx.compose.runtime.mutableStateOf
|
|||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import net.codinux.banking.client.model.UserAccount
|
||||
import net.codinux.banking.client.model.UserAccountViewInfo
|
||||
import net.codinux.banking.client.model.User
|
||||
import net.codinux.banking.client.model.BankViewInfo
|
||||
import net.codinux.banking.ui.config.DI
|
||||
import net.codinux.banking.ui.model.BankInfo
|
||||
import net.dankito.banking.banklistcreator.prettifier.BankingGroupMapper
|
||||
|
@ -22,8 +22,8 @@ private val bankIconService = DI.bankIconService
|
|||
private val DefaultIconModifier: Modifier = Modifier.size(16.dp)
|
||||
|
||||
@Composable
|
||||
fun BankIcon(userAccount: UserAccount?, modifier: Modifier = Modifier, iconModifier: Modifier = DefaultIconModifier, iconResource: DrawableResource? = null) {
|
||||
val iconUrl by remember(userAccount?.bic) { mutableStateOf(userAccount?.let { bankIconService.findIconForBank(it) }) }
|
||||
fun BankIcon(user: User?, modifier: Modifier = Modifier, iconModifier: Modifier = DefaultIconModifier, iconResource: DrawableResource? = null) {
|
||||
val iconUrl by remember(user?.bic) { mutableStateOf(user?.let { bankIconService.findIconForBank(it) }) }
|
||||
|
||||
BankIcon(iconUrl, modifier, iconModifier, iconResource = iconResource)
|
||||
}
|
||||
|
@ -38,8 +38,8 @@ fun BankIcon(bank: BankInfo, modifier: Modifier = Modifier, iconModifier: Modifi
|
|||
}
|
||||
|
||||
@Composable
|
||||
fun BankIcon(userAccount: UserAccountViewInfo?, modifier: Modifier = Modifier, iconModifier: Modifier = DefaultIconModifier, iconResource: DrawableResource? = null) {
|
||||
val iconUrl = userAccount?.let { bankIconService.findIconForBank(it.bankName, it.bankingGroup) }
|
||||
fun BankIcon(user: BankViewInfo?, modifier: Modifier = Modifier, iconModifier: Modifier = DefaultIconModifier, iconResource: DrawableResource? = null) {
|
||||
val iconUrl = user?.let { bankIconService.findIconForBank(it.bankName, it.bankingGroup) }
|
||||
|
||||
BankIcon(iconUrl, modifier, iconModifier, iconResource = iconResource)
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ import androidx.compose.ui.unit.dp
|
|||
import bankmeister.composeapp.generated.resources.Res
|
||||
import bankmeister.composeapp.generated.resources.account
|
||||
import net.codinux.banking.dataaccess.entities.BankAccountEntity
|
||||
import net.codinux.banking.dataaccess.entities.UserAccountEntity
|
||||
import net.codinux.banking.dataaccess.entities.UserEntity
|
||||
import net.codinux.banking.ui.config.DI
|
||||
|
||||
private val uiState = DI.uiState
|
||||
|
@ -24,9 +24,9 @@ fun BanksList(
|
|||
textColor: Color = Color.White,
|
||||
itemModifier: Modifier = Modifier.height(48.dp).widthIn(min = 300.dp),
|
||||
itemHorizontalPadding: Dp = 8.dp,
|
||||
accountSelected: ((UserAccountEntity?, BankAccountEntity?) -> Unit)? = null
|
||||
accountSelected: ((UserEntity?, BankAccountEntity?) -> Unit)? = null
|
||||
) {
|
||||
val userAccounts = uiState.userAccounts.collectAsState()
|
||||
val users = uiState.users.collectAsState()
|
||||
|
||||
|
||||
Column(modifier) {
|
||||
|
@ -34,16 +34,16 @@ fun BanksList(
|
|||
accountSelected?.invoke(null, null)
|
||||
}
|
||||
|
||||
userAccounts.value.sortedBy { it.displayIndex }.forEach { userAccount ->
|
||||
users.value.sortedBy { it.displayIndex }.forEach { user ->
|
||||
Spacer(Modifier.fillMaxWidth().height(12.dp))
|
||||
|
||||
NavigationMenuItem(itemModifier, userAccount.displayName, textColor, iconSize, IconTextSpacing, itemHorizontalPadding, userAccount, iconResource = Res.drawable.account) {
|
||||
accountSelected?.invoke(userAccount, null)
|
||||
NavigationMenuItem(itemModifier, user.displayName, textColor, iconSize, IconTextSpacing, itemHorizontalPadding, user, iconResource = Res.drawable.account) {
|
||||
accountSelected?.invoke(user, null)
|
||||
}
|
||||
|
||||
userAccount.accounts.sortedBy { it.displayIndex }.forEach { account ->
|
||||
user.accounts.sortedBy { it.displayIndex }.forEach { account ->
|
||||
NavigationMenuItem(itemModifier, account.displayName, textColor, iconSize, IconTextSpacing, itemHorizontalPadding, bankAccount = account) {
|
||||
accountSelected?.invoke(userAccount, account)
|
||||
accountSelected?.invoke(user, account)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ import androidx.compose.ui.text.style.TextOverflow
|
|||
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.UserAccountEntity
|
||||
import net.codinux.banking.dataaccess.entities.UserEntity
|
||||
import net.codinux.banking.ui.config.Colors
|
||||
import net.codinux.banking.ui.config.DI
|
||||
import org.jetbrains.compose.resources.DrawableResource
|
||||
|
@ -37,7 +37,7 @@ fun NavigationMenuItem(
|
|||
iconSize: Dp = 24.dp,
|
||||
iconTextSpacing: Dp = 24.dp,
|
||||
horizontalPadding: Dp = 8.dp,
|
||||
userAccount: UserAccountEntity? = null,
|
||||
user: UserEntity? = null,
|
||||
bankAccount: BankAccountEntity? = null,
|
||||
iconResource: DrawableResource? = null,
|
||||
icon: (@Composable () -> Unit)? = null,
|
||||
|
@ -54,7 +54,7 @@ fun NavigationMenuItem(
|
|||
modifier = modifier
|
||||
.clickable { onClick?.invoke() }
|
||||
.let {
|
||||
if (userAccount != null && filterService.isSelected(userAccount, transactionsFilter)
|
||||
if (user != null && filterService.isSelected(user, transactionsFilter)
|
||||
|| bankAccount != null && filterService.isSelected(bankAccount, transactionsFilter)) {
|
||||
it.background(Colors.AccentAsSelectionBackground, shape = RoundedCornerShape(4.dp))
|
||||
} else {
|
||||
|
@ -68,7 +68,7 @@ fun NavigationMenuItem(
|
|||
icon()
|
||||
}
|
||||
} else {
|
||||
BankIcon(userAccount, Modifier.padding(end = iconTextSpacing), Modifier.size(iconSize), iconResource = iconResource)
|
||||
BankIcon(user, Modifier.padding(end = iconTextSpacing), Modifier.size(iconSize), iconResource = iconResource)
|
||||
}
|
||||
|
||||
Text(text, color = textColor, modifier = Modifier.weight(1f), maxLines = 1, overflow = TextOverflow.Ellipsis)
|
||||
|
@ -77,8 +77,8 @@ fun NavigationMenuItem(
|
|||
null
|
||||
} else if (bankAccount != null) {
|
||||
bankAccount.balance
|
||||
} else if (userAccount != null) {
|
||||
calculator.calculateBalanceOfUserAccount(userAccount)
|
||||
} else if (user != null) {
|
||||
calculator.calculateBalanceOfUser(user)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ import androidx.compose.ui.text.font.FontWeight
|
|||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import net.codinux.banking.client.model.Amount
|
||||
import net.codinux.banking.dataaccess.entities.UserAccountEntity
|
||||
import net.codinux.banking.dataaccess.entities.UserEntity
|
||||
import net.codinux.banking.ui.config.DI
|
||||
import net.codinux.banking.ui.forms.RoundedCornersCard
|
||||
import net.codinux.banking.ui.model.AccountTransactionViewModel
|
||||
|
@ -28,7 +28,7 @@ private val formatUtil = DI.formatUtil
|
|||
fun GroupedTransactionsListItems(
|
||||
modifier: Modifier,
|
||||
transactionsToDisplay: List<AccountTransactionViewModel>,
|
||||
userAccountsId: Map<Long, UserAccountEntity>,
|
||||
userAccountsId: Map<Long, UserEntity>,
|
||||
transactionsGrouping: TransactionsGrouping
|
||||
) {
|
||||
val groupingService = remember { TransactionsGroupingService() }
|
||||
|
@ -57,7 +57,9 @@ fun GroupedTransactionsListItems(
|
|||
RoundedCornersCard {
|
||||
Column(Modifier.background(Color.White)) { // LazyColumn inside LazyColumn is not allowed
|
||||
monthTransactions.forEachIndexed { index, transaction ->
|
||||
TransactionListItem(userAccountsId[transaction.userAccountId], transaction, index, monthTransactions.size)
|
||||
key(transaction.id) {
|
||||
TransactionListItem(userAccountsId[transaction.userId], transaction, index, monthTransactions.size)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ import androidx.compose.ui.text.style.TextOverflow
|
|||
import androidx.compose.ui.unit.DpOffset
|
||||
import androidx.compose.ui.unit.dp
|
||||
import kotlinx.coroutines.launch
|
||||
import net.codinux.banking.client.model.UserAccount
|
||||
import net.codinux.banking.client.model.User
|
||||
import net.codinux.banking.ui.composables.BankIcon
|
||||
import net.codinux.banking.ui.config.Colors
|
||||
import net.codinux.banking.ui.config.DI
|
||||
|
@ -25,7 +25,7 @@ private val uiSettings = DI.uiSettings
|
|||
private val formatUtil = DI.formatUtil
|
||||
|
||||
@Composable
|
||||
fun TransactionListItem(userAccount: UserAccount?, transaction: AccountTransactionViewModel, itemIndex: Int, countItems: Int) {
|
||||
fun TransactionListItem(user: User?, transaction: AccountTransactionViewModel, itemIndex: Int, countItems: Int) {
|
||||
val zebraStripes by uiSettings.zebraStripes.collectAsState()
|
||||
|
||||
val showBankIcons by uiSettings.showBankIcons.collectAsState()
|
||||
|
@ -48,9 +48,9 @@ fun TransactionListItem(userAccount: UserAccount?, transaction: AccountTransacti
|
|||
val transactionEntity = DI.bankingService.getTransaction(transaction.id)
|
||||
|
||||
DI.uiState.showTransferMoneyDialogData.value = ShowTransferMoneyDialogData(
|
||||
DI.uiState.userAccounts.value.firstNotNullOf { it.accounts.firstOrNull { it.id == transaction.bankAccountId } },
|
||||
DI.uiState.users.value.firstNotNullOf { it.accounts.firstOrNull { it.id == transaction.bankAccountId } },
|
||||
transaction.otherPartyName,
|
||||
transactionEntity?.otherPartyBankCode,
|
||||
transactionEntity?.otherPartyBankId,
|
||||
transactionEntity?.otherPartyAccountId,
|
||||
if (withSameData) transaction.amount else null,
|
||||
if (withSameData) transaction.reference else null
|
||||
|
@ -76,7 +76,7 @@ fun TransactionListItem(userAccount: UserAccount?, transaction: AccountTransacti
|
|||
Column(Modifier.weight(1f)) {
|
||||
Row {
|
||||
if (showBankIcons) {
|
||||
BankIcon(userAccount, Modifier.padding(end = 6.dp))
|
||||
BankIcon(user, Modifier.padding(end = 6.dp))
|
||||
}
|
||||
|
||||
Text(
|
||||
|
@ -90,7 +90,7 @@ fun TransactionListItem(userAccount: UserAccount?, transaction: AccountTransacti
|
|||
Spacer(modifier = Modifier.height(6.dp))
|
||||
|
||||
Text(
|
||||
text = transaction.reference,
|
||||
text = transaction.reference ?: "",
|
||||
Modifier.fillMaxWidth(),
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
|
|
|
@ -25,9 +25,9 @@ private val formatUtil = DI.formatUtil
|
|||
|
||||
@Composable
|
||||
fun TransactionsList(uiState: UiState, uiSettings: UiSettings, isMobile: Boolean = true) {
|
||||
val userAccounts by uiState.userAccounts.collectAsState()
|
||||
val userAccountsId by remember(userAccounts) {
|
||||
derivedStateOf { userAccounts.associateBy { it.id } }
|
||||
val users by uiState.users.collectAsState()
|
||||
val usersById by remember(users) {
|
||||
derivedStateOf { users.associateBy { it.id } }
|
||||
}
|
||||
|
||||
val transactionsFilter by uiState.transactionsFilter.collectAsState()
|
||||
|
@ -53,17 +53,19 @@ fun TransactionsList(uiState: UiState, uiSettings: UiSettings, isMobile: Boolean
|
|||
Spacer(Modifier.weight(1f))
|
||||
|
||||
if (showBalance) {
|
||||
val balance = calculator.calculateBalanceOfDisplayedTransactions(transactionsToDisplay, userAccounts, transactionsFilter)
|
||||
val balance = calculator.calculateBalanceOfDisplayedTransactions(transactionsToDisplay, users, transactionsFilter)
|
||||
Text(formatUtil.formatAmount(balance, "EUR"), color = formatUtil.getColorForAmount(balance, showColoredAmounts))
|
||||
}
|
||||
}
|
||||
|
||||
if (transactionsGrouping != TransactionsGrouping.None) {
|
||||
GroupedTransactionsListItems(transactionsListModifier, transactionsToDisplay, userAccountsId, transactionsGrouping)
|
||||
GroupedTransactionsListItems(transactionsListModifier, transactionsToDisplay, usersById, transactionsGrouping)
|
||||
} else {
|
||||
LazyColumn(transactionsListModifier, contentPadding = PaddingValues(top = 8.dp, bottom = 16.dp)) {
|
||||
itemsIndexed(transactionsToDisplay) { index, transaction ->
|
||||
TransactionListItem(userAccountsId[transaction.userAccountId], transaction, index, transactionsToDisplay.size)
|
||||
key(transaction.id) {
|
||||
TransactionListItem(usersById[transaction.userId], transaction, index, transactionsToDisplay.size)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,12 +39,12 @@ fun TransferMoneyDialog(
|
|||
data: ShowTransferMoneyDialogData,
|
||||
onDismiss: () -> Unit,
|
||||
) {
|
||||
val userAccounts = uiState.userAccounts.value
|
||||
val userAccounts = uiState.users.value
|
||||
val accountsToUserAccount = userAccounts.sortedBy { it.displayIndex }
|
||||
.flatMap { user -> user.accounts.sortedBy { it.displayIndex }.map { it to user } }.toMap()
|
||||
|
||||
val accountsSupportingTransferringMoney = userAccounts.flatMap { it.accounts }
|
||||
.filter { it.supportsAnyFeature(BankAccountFeatures.TransferMoney, BankAccountFeatures.InstantPayment) }
|
||||
.filter { it.supportsMoneyTransfer }
|
||||
|
||||
if (accountsSupportingTransferringMoney.isEmpty()) {
|
||||
uiState.applicationErrorOccurred(ErroneousAction.TransferMoney, "Keines Ihrer Konten unterstützt das Überweisen von Geld")
|
||||
|
@ -59,7 +59,7 @@ fun TransferMoneyDialog(
|
|||
var recipientAccountIdentifier by remember { mutableStateOf(data.recipientAccountIdentifier ?: "") }
|
||||
var amount by remember { mutableStateOf(data.amount?.amount ?: "") }
|
||||
var paymentReference by remember { mutableStateOf(data.reference ?: "") }
|
||||
val accountSupportsInstantTransfer by remember(senderAccount) { derivedStateOf { senderAccount.supportsAnyFeature(BankAccountFeatures.InstantPayment) } }
|
||||
val accountSupportsInstantTransfer by remember(senderAccount) { derivedStateOf { senderAccount.supportsInstantTransfer } }
|
||||
var instantTransfer by remember { mutableStateOf(false) }
|
||||
|
||||
val isRequiredDataEntered by remember(recipientName, recipientAccountIdentifier, amount) {
|
||||
|
|
|
@ -7,12 +7,12 @@ import net.codinux.banking.dataaccess.entities.AccountTransactionEntity
|
|||
|
||||
data class AccountTransactionViewModel(
|
||||
val id: Long,
|
||||
val userAccountId: Long,
|
||||
val userId: Long,
|
||||
val bankAccountId: Long,
|
||||
|
||||
val amount: Amount,
|
||||
val currency: String,
|
||||
val reference: String,
|
||||
val reference: String?,
|
||||
val valueDate: LocalDate,
|
||||
val otherPartyName: String? = null,
|
||||
|
||||
|
@ -20,8 +20,8 @@ data class AccountTransactionViewModel(
|
|||
val userSetDisplayName: String? = null,
|
||||
val category: String? = null
|
||||
) {
|
||||
constructor(entity: AccountTransactionEntity) : this(entity.id, entity.userAccountId, entity.bankAccountId, entity)
|
||||
constructor(entity: AccountTransactionEntity) : this(entity.id, entity.userId, entity.bankAccountId, entity)
|
||||
|
||||
constructor(id: Long, userAccountId: Long, bankAccountId: Long, transaction: AccountTransaction)
|
||||
: this(id, userAccountId, bankAccountId, transaction.amount, transaction.currency, transaction.reference, transaction.valueDate, transaction.otherPartyName, transaction.bookingText)
|
||||
constructor(id: Long, userId: Long, bankAccountId: Long, transaction: AccountTransaction)
|
||||
: this(id, userId, bankAccountId, transaction.amount, transaction.currency, transaction.reference, transaction.valueDate, transaction.otherPartyName, transaction.postingText)
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ package net.codinux.banking.ui.model
|
|||
|
||||
import androidx.compose.runtime.*
|
||||
import net.codinux.banking.dataaccess.entities.BankAccountEntity
|
||||
import net.codinux.banking.dataaccess.entities.UserAccountEntity
|
||||
import net.codinux.banking.dataaccess.entities.UserEntity
|
||||
|
||||
class AccountTransactionsFilter {
|
||||
|
||||
|
@ -19,11 +19,11 @@ class AccountTransactionsFilter {
|
|||
val selectedAccount: BankAccountFilter?
|
||||
get() = selectedAccounts.value.firstOrNull()
|
||||
|
||||
fun selectedAccountChanged(userAccount: UserAccountEntity?, bankAccount: BankAccountEntity?) {
|
||||
selectedAccounts.value = if (userAccount == null) {
|
||||
fun selectedAccountChanged(user: UserEntity?, bankAccount: BankAccountEntity?) {
|
||||
selectedAccounts.value = if (user == null) {
|
||||
emptyList()
|
||||
} else {
|
||||
listOf(BankAccountFilter(userAccount, bankAccount))
|
||||
listOf(BankAccountFilter(user, bankAccount))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
package net.codinux.banking.ui.model
|
||||
|
||||
import net.codinux.banking.dataaccess.entities.BankAccountEntity
|
||||
import net.codinux.banking.dataaccess.entities.UserAccountEntity
|
||||
import net.codinux.banking.dataaccess.entities.UserEntity
|
||||
|
||||
data class BankAccountFilter(
|
||||
val userAccount: UserAccountEntity,
|
||||
val user: UserEntity,
|
||||
val bankAccount: BankAccountEntity? = null
|
||||
)
|
|
@ -1,11 +1,11 @@
|
|||
package net.codinux.banking.ui.model.events
|
||||
|
||||
import net.codinux.banking.client.model.BankAccount
|
||||
import net.codinux.banking.client.model.UserAccount
|
||||
import net.codinux.banking.client.model.User
|
||||
import net.codinux.banking.ui.model.AccountTransactionViewModel
|
||||
|
||||
data class AccountTransactionsRetrievedEvent(
|
||||
val user: UserAccount,
|
||||
val user: User,
|
||||
val account: BankAccount,
|
||||
val newTransactions: List<AccountTransactionViewModel>
|
||||
)
|
|
@ -1,7 +1,7 @@
|
|||
package net.codinux.banking.ui.service
|
||||
|
||||
import net.codinux.banking.dataaccess.entities.BankAccountEntity
|
||||
import net.codinux.banking.dataaccess.entities.UserAccountEntity
|
||||
import net.codinux.banking.dataaccess.entities.UserEntity
|
||||
import net.codinux.banking.ui.model.AccountTransactionViewModel
|
||||
import net.codinux.banking.ui.model.AccountTransactionsFilter
|
||||
import net.codinux.banking.ui.model.BankAccountFilter
|
||||
|
@ -30,27 +30,27 @@ class AccountTransactionsFilterService {
|
|||
}
|
||||
|
||||
private fun matchesFilter(transaction: AccountTransactionViewModel, accountsFilter: List<BankAccountFilter>): Boolean =
|
||||
accountsFilter.any { (userAccount, bankAccount) ->
|
||||
accountsFilter.any { (user, bankAccount) ->
|
||||
if (bankAccount != null) {
|
||||
transaction.bankAccountId == bankAccount.id
|
||||
} else {
|
||||
transaction.userAccountId == userAccount.id
|
||||
transaction.userId == user.id
|
||||
}
|
||||
}
|
||||
|
||||
private fun matchesSearchTerm(transaction: AccountTransactionViewModel, searchTerm: String): Boolean =
|
||||
transaction.reference.contains(searchTerm, true)
|
||||
transaction.reference?.contains(searchTerm, true) == true
|
||||
|| (transaction.otherPartyName != null && transaction.otherPartyName.contains(searchTerm, true))
|
||||
|
||||
|
||||
fun isSelected(userAccount: UserAccountEntity, transactionsFilter: AccountTransactionsFilter): Boolean {
|
||||
fun isSelected(user: UserEntity, transactionsFilter: AccountTransactionsFilter): Boolean {
|
||||
if (transactionsFilter.showAllAccounts) {
|
||||
return false
|
||||
}
|
||||
|
||||
val filter = transactionsFilter.selectedAccount
|
||||
|
||||
return filter?.userAccount == userAccount && filter.bankAccount == null
|
||||
return filter?.user == user && filter.bankAccount == null
|
||||
}
|
||||
|
||||
fun isSelected(bankAccount: BankAccountEntity, transactionsFilter: AccountTransactionsFilter): Boolean {
|
||||
|
|
|
@ -22,7 +22,7 @@ class BankDataImporterAndExporter {
|
|||
formatAmount(transaction.amount, decimalSeparator), transaction.currency,
|
||||
transaction.valueDate.toString(), transaction.bookingDate.toString(),
|
||||
transaction.reference,
|
||||
transaction.otherPartyName, transaction.otherPartyBankCode, transaction.otherPartyAccountId
|
||||
transaction.otherPartyName, transaction.otherPartyBankId, transaction.otherPartyAccountId
|
||||
// TODO: export all columns / transaction data
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
package net.codinux.banking.ui.service
|
||||
|
||||
import net.codinux.banking.client.model.BankingGroup
|
||||
import net.codinux.banking.client.model.UserAccount
|
||||
import net.codinux.banking.client.model.User
|
||||
|
||||
class BankIconService { // TODO: extract to a common library
|
||||
|
||||
fun findIconForBank(user: UserAccount) = findIconForBank(user.bankName, user.bankingGroup)
|
||||
fun findIconForBank(user: User) = findIconForBank(user.bankName, user.bankingGroup)
|
||||
|
||||
fun findIconForBank(bankName: String, bankingGroup: BankingGroup? = null): String? = when (bankingGroup) {
|
||||
BankingGroup.Sparkasse -> "https://sparkasse.de/favicon-32x32.png"
|
||||
|
|
|
@ -15,7 +15,7 @@ import net.codinux.banking.client.service.BankingModelService
|
|||
import net.codinux.banking.dataaccess.BankingRepository
|
||||
import net.codinux.banking.dataaccess.entities.AccountTransactionEntity
|
||||
import net.codinux.banking.dataaccess.entities.BankAccountEntity
|
||||
import net.codinux.banking.dataaccess.entities.UserAccountEntity
|
||||
import net.codinux.banking.dataaccess.entities.UserEntity
|
||||
import net.codinux.banking.fints.config.FinTsClientConfiguration
|
||||
import net.codinux.banking.fints.config.FinTsClientOptions
|
||||
import net.codinux.banking.ui.IOorDefault
|
||||
|
@ -57,11 +57,11 @@ class BankingService(
|
|||
}
|
||||
|
||||
|
||||
fun getAllUserAccounts() = bankingRepository.getAllUserAccounts()
|
||||
fun getAllUsers() = bankingRepository.getAllUsers()
|
||||
|
||||
fun getAllAccountTransactions() = bankingRepository.getAllAccountTransactions()
|
||||
|
||||
fun getAllTransactionsOfUserAccount(userAccount: UserAccountEntity) = bankingRepository.getAllTransactionsOfUserAccount(userAccount)
|
||||
fun getAllTransactionsOfUser(user: UserEntity) = bankingRepository.getAllTransactionsOfUser(user)
|
||||
|
||||
fun getAllAccountTransactionsAsViewModel() = bankingRepository.getAllAccountTransactionsAsViewModel()
|
||||
|
||||
|
@ -95,15 +95,15 @@ class BankingService(
|
|||
private suspend fun handleSuccessfulGetAccountDataResponse(response: GetAccountDataResponse) {
|
||||
try {
|
||||
val newUser = response.user
|
||||
newUser.displayIndex = uiState.userAccounts.value.size
|
||||
newUser.displayIndex = uiState.users.value.size
|
||||
|
||||
val newUserEntity = bankingRepository.persistUserAccount(newUser)
|
||||
val newUserEntity = bankingRepository.persistUser(newUser)
|
||||
|
||||
log.info { "Saved user account $newUserEntity with ${newUserEntity.accounts.flatMap { it.bookedTransactionsEntities }.size} transactions" }
|
||||
|
||||
val userAccounts = uiState.userAccounts.value.toMutableList()
|
||||
userAccounts.add(newUserEntity)
|
||||
uiState.userAccounts.value = userAccounts
|
||||
val users = uiState.users.value.toMutableList()
|
||||
users.add(newUserEntity)
|
||||
uiState.users.value = users
|
||||
|
||||
updateTransactionsInUi(newUserEntity.accounts.flatMap { it.bookedTransactionsEntities })
|
||||
} catch (e: Throwable) {
|
||||
|
@ -115,15 +115,15 @@ class BankingService(
|
|||
suspend fun updateAccountTransactions() {
|
||||
val selectedAccount = uiState.transactionsFilter.value.selectedAccount
|
||||
if (selectedAccount != null) {
|
||||
updateAccountTransactions(selectedAccount.userAccount, selectedAccount.bankAccount)
|
||||
updateAccountTransactions(selectedAccount.user, selectedAccount.bankAccount)
|
||||
} else {
|
||||
uiState.userAccounts.value.forEach { user ->
|
||||
uiState.users.value.forEach { user ->
|
||||
updateAccountTransactions(user)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun updateAccountTransactions(user: UserAccountEntity, bankAccount: BankAccountEntity? = null) {
|
||||
private suspend fun updateAccountTransactions(user: UserEntity, bankAccount: BankAccountEntity? = null) {
|
||||
withContext(Dispatchers.IOorDefault) {
|
||||
try {
|
||||
val response = client.updateAccountTransactionsAsync(user, bankAccount?.let { listOf(it) })
|
||||
|
@ -138,22 +138,22 @@ class BankingService(
|
|||
}
|
||||
}
|
||||
|
||||
private suspend fun handleSuccessfulUpdateAccountTransactionsResponse(user: UserAccountEntity, responses: List<GetTransactionsResponse>) {
|
||||
private suspend fun handleSuccessfulUpdateAccountTransactionsResponse(user: UserEntity, responses: List<GetTransactionsResponse>) {
|
||||
try {
|
||||
// TODO: when user gets updated by BankingClient, also update user in database
|
||||
// val newUser = response.user
|
||||
// val newUserEntity = bankingRepository.persistUserAccount(newUser)
|
||||
// val newUserEntity = bankingRepository.persistUser(newUser)
|
||||
//
|
||||
// log.info { "Saved user account $newUserEntity with ${newUserEntity.accounts.flatMap { it.bookedTransactionsEntities }.size} transactions" }
|
||||
|
||||
val userAccountTransactions = getAllTransactionsOfUserAccount(user)
|
||||
val userTransactions = getAllTransactionsOfUser(user)
|
||||
|
||||
responses.forEach { response ->
|
||||
val account = (response.account as? BankAccountEntity) ?: user.accounts.first { it.identifier == response.account.identifier && it.subAccountNumber == response.account.subAccountNumber }
|
||||
|
||||
// TODO: update BankAccount and may updated Transactions in database
|
||||
|
||||
val existingAccountTransactions = userAccountTransactions.filter { it.bankAccountId == account.id }
|
||||
val existingAccountTransactions = userTransactions.filter { it.bankAccountId == account.id }
|
||||
|
||||
val newTransactions = modelService.findNewTransactions(response.bookedTransactions, existingAccountTransactions)
|
||||
|
||||
|
@ -182,7 +182,7 @@ class BankingService(
|
|||
}
|
||||
|
||||
|
||||
suspend fun transferMoney(user: UserAccountEntity, account: BankAccountEntity,
|
||||
suspend fun transferMoney(user: UserEntity, account: BankAccountEntity,
|
||||
recipientName: String, recipientAccountIdentifier: String, amount: Amount, currency: String,
|
||||
paymentReference: String? = null, instantTransfer: Boolean = false, recipientBankIdentifier: String? = null): Boolean {
|
||||
val response = client.transferMoneyAsync(TransferMoneyRequestForUser(
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package net.codinux.banking.ui.service
|
||||
|
||||
import net.codinux.banking.client.model.Amount
|
||||
import net.codinux.banking.client.model.UserAccount
|
||||
import net.codinux.banking.dataaccess.entities.UserAccountEntity
|
||||
import net.codinux.banking.client.model.User
|
||||
import net.codinux.banking.dataaccess.entities.UserEntity
|
||||
import net.codinux.banking.ui.extensions.toBigDecimal
|
||||
import net.codinux.banking.ui.model.AccountTransactionViewModel
|
||||
import net.codinux.banking.ui.model.AccountTransactionsFilter
|
||||
|
@ -13,8 +13,8 @@ class CalculatorService {
|
|||
// TODO: find a better solution
|
||||
Amount(transactions.sumOf { it.amount.toBigDecimal() }.toString())
|
||||
|
||||
fun calculateBalanceOfUserAccount(userAccount: UserAccount): Amount =
|
||||
sumAmounts(userAccount.accounts.map { it.balance })
|
||||
fun calculateBalanceOfUser(user: User): Amount =
|
||||
sumAmounts(user.accounts.map { it.balance })
|
||||
|
||||
fun sumAmounts(amounts: Collection<Amount>): Amount =
|
||||
// TODO: find a better solution
|
||||
|
@ -28,9 +28,9 @@ class CalculatorService {
|
|||
// TODO: find a better solution
|
||||
Amount(transactions.map { it.amount.toBigDecimal() }.filter { it < 0 }.sum().toString())
|
||||
|
||||
fun calculateBalanceOfDisplayedTransactions(transactions: Collection<AccountTransactionViewModel>, userAccounts: Collection<UserAccountEntity>, filter: AccountTransactionsFilter): Amount {
|
||||
fun calculateBalanceOfDisplayedTransactions(transactions: Collection<AccountTransactionViewModel>, users: Collection<UserEntity>, filter: AccountTransactionsFilter): Amount {
|
||||
if (filter.noFiltersApplied) {
|
||||
return sumAmounts(userAccounts.flatMap { it.accounts.map { it.balance } })
|
||||
return sumAmounts(users.flatMap { it.accounts.map { it.balance } })
|
||||
}
|
||||
|
||||
val selectedAccount = filter.selectedAccount
|
||||
|
@ -39,7 +39,7 @@ class CalculatorService {
|
|||
if (selectedAccount.bankAccount != null) {
|
||||
selectedAccount.bankAccount.balance
|
||||
} else {
|
||||
calculateBalanceOfUserAccount(selectedAccount.userAccount)
|
||||
calculateBalanceOfUser(selectedAccount.user)
|
||||
}
|
||||
} else {
|
||||
sumTransactions(transactions)
|
||||
|
|
|
@ -33,7 +33,7 @@ class RecipientFinder(private val bankFinder: BankFinder) {
|
|||
suspend fun updateData(transactions: List<AccountTransaction>) {
|
||||
availableRecipients = transactions.mapNotNull {
|
||||
if (it.otherPartyName != null && it.otherPartyAccountId != null) {
|
||||
RecipientSuggestion(it.otherPartyName!!, it.otherPartyBankCode, it.otherPartyAccountId!!)
|
||||
RecipientSuggestion(it.otherPartyName!!, it.otherPartyBankId, it.otherPartyAccountId!!)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ class RecipientFinder(private val bankFinder: BankFinder) {
|
|||
|
||||
transactionsByIban = transactions.filter { it.otherPartyAccountId != null }.groupBy { it.otherPartyAccountId!! }
|
||||
.mapValues { it.value.map {
|
||||
PaymentDataSuggestion(it.reference, Amount(it.amount.amount.replace("-", "")), it.currency, it.valueDate)
|
||||
PaymentDataSuggestion(it.reference ?: "", Amount(it.amount.amount.replace("-", "")), it.currency, it.valueDate)
|
||||
}.toSet().sortedByDescending { it.valueDate } }
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ import androidx.compose.material.DrawerValue
|
|||
import androidx.lifecycle.ViewModel
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import net.codinux.banking.dataaccess.entities.UserAccountEntity
|
||||
import net.codinux.banking.dataaccess.entities.UserEntity
|
||||
import net.codinux.banking.ui.model.*
|
||||
import net.codinux.banking.ui.model.error.ApplicationError
|
||||
import net.codinux.banking.ui.model.error.BankingClientError
|
||||
|
@ -15,7 +15,7 @@ import net.codinux.banking.ui.model.events.TransferredMoneyEvent
|
|||
|
||||
class UiState : ViewModel() {
|
||||
|
||||
val userAccounts = MutableStateFlow<List<UserAccountEntity>>(emptyList())
|
||||
val users = MutableStateFlow<List<UserEntity>>(emptyList())
|
||||
|
||||
val transactions = MutableStateFlow<List<AccountTransactionViewModel>>(emptyList())
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ CREATE TABLE IF NOT EXISTS AccountTransaction (
|
|||
|
||||
amount TEXT NOT NULL,
|
||||
currency TEXT NOT NULL,
|
||||
unparsedReference TEXT NOT NULL,
|
||||
unparsedReference TEXT,
|
||||
|
||||
bookingDate TEXT NOT NULL,
|
||||
valueDate TEXT NOT NULL,
|
||||
|
@ -21,8 +21,6 @@ CREATE TABLE IF NOT EXISTS AccountTransaction (
|
|||
category TEXT,
|
||||
notes TEXT,
|
||||
|
||||
information TEXT,
|
||||
|
||||
statementNumber INTEGER,
|
||||
sequenceNumber INTEGER,
|
||||
|
||||
|
@ -34,17 +32,16 @@ CREATE TABLE IF NOT EXISTS AccountTransaction (
|
|||
mandateReference TEXT,
|
||||
creditorIdentifier TEXT,
|
||||
originatorsIdentificationCode TEXT,
|
||||
|
||||
compensationAmount TEXT,
|
||||
originalAmount TEXT,
|
||||
sepaReference TEXT,
|
||||
deviantOriginator TEXT,
|
||||
deviantRecipient TEXT,
|
||||
referenceWithNoSpecialType TEXT,
|
||||
|
||||
primaNotaNumber TEXT,
|
||||
textKeySupplement TEXT,
|
||||
|
||||
currencyType TEXT,
|
||||
bookingKey TEXT,
|
||||
referenceForTheAccountOwner TEXT,
|
||||
referenceOfTheAccountServicingInstitution TEXT,
|
||||
supplementaryDetails TEXT,
|
||||
|
@ -65,22 +62,16 @@ INSERT INTO AccountTransaction(
|
|||
|
||||
userSetDisplayName, category, notes,
|
||||
|
||||
information,
|
||||
statementNumber, sequenceNumber,
|
||||
openingBalance, closingBalance,
|
||||
|
||||
endToEndReference, customerReference, mandateReference,
|
||||
creditorIdentifier, originatorsIdentificationCode,
|
||||
compensationAmount, originalAmount,
|
||||
sepaReference,
|
||||
deviantOriginator, deviantRecipient,
|
||||
referenceWithNoSpecialType,
|
||||
primaNotaNumber, textKeySupplement,
|
||||
|
||||
currencyType, bookingKey,
|
||||
referenceForTheAccountOwner, referenceOfTheAccountServicingInstitution,
|
||||
supplementaryDetails,
|
||||
|
||||
transactionReferenceNumber, relatedReferenceNumber
|
||||
)
|
||||
VALUES(
|
||||
|
@ -93,22 +84,16 @@ VALUES(
|
|||
|
||||
?, ?, ?,
|
||||
|
||||
?,
|
||||
?, ?,
|
||||
?, ?,
|
||||
|
||||
?, ?, ?,
|
||||
?, ?,
|
||||
?, ?,
|
||||
?,
|
||||
?, ?,
|
||||
?,
|
||||
?, ?,
|
||||
|
||||
?, ?,
|
||||
?, ?,
|
||||
?,
|
||||
|
||||
?, ?
|
||||
);
|
||||
|
||||
|
@ -118,11 +103,11 @@ SELECT AccountTransaction.*
|
|||
FROM AccountTransaction;
|
||||
|
||||
selectAllTransactionsAsViewModel:
|
||||
SELECT id, userAccountId, bankAccountId, amount, currency, unparsedReference, valueDate, otherPartyName, bookingText, sepaReference, userSetDisplayName, category
|
||||
SELECT id, userAccountId, bankAccountId, amount, currency, unparsedReference, valueDate, otherPartyName, bookingText, userSetDisplayName, category
|
||||
FROM AccountTransaction;
|
||||
|
||||
|
||||
selectAllTransactionsOfUserAccount:
|
||||
selectAllTransactionsOfUser:
|
||||
SELECT AccountTransaction.*
|
||||
FROM AccountTransaction WHERE userAccountId = ?;
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ CREATE TABLE IF NOT EXISTS UserAccount (
|
|||
bic TEXT NOT NULL,
|
||||
|
||||
customerName TEXT NOT NULL,
|
||||
userId TEXT NOT NULL,
|
||||
userId TEXT,
|
||||
|
||||
selectedTanMethodId TEXT,
|
||||
|
||||
|
@ -27,7 +27,7 @@ CREATE TABLE IF NOT EXISTS UserAccount (
|
|||
);
|
||||
|
||||
|
||||
insertUserAccount:
|
||||
insertUser:
|
||||
INSERT INTO UserAccount(
|
||||
bankCode, loginName, password,
|
||||
|
||||
|
@ -58,7 +58,7 @@ VALUES(
|
|||
);
|
||||
|
||||
|
||||
selectAllUserAccounts:
|
||||
selectAllUsers:
|
||||
SELECT UserAccount.*
|
||||
FROM UserAccount;
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ import androidx.compose.runtime.Composable
|
|||
import net.codinux.banking.client.model.BankAccountType
|
||||
import net.codinux.banking.client.model.BankAccountViewInfo
|
||||
import net.codinux.banking.client.model.BankingGroup
|
||||
import net.codinux.banking.client.model.UserAccountViewInfo
|
||||
import net.codinux.banking.client.model.BankViewInfo
|
||||
import net.codinux.banking.client.model.tan.*
|
||||
import net.codinux.banking.ui.model.TanChallengeReceived
|
||||
|
||||
|
@ -13,7 +13,7 @@ import net.codinux.banking.ui.model.TanChallengeReceived
|
|||
@Composable
|
||||
fun EnterTanDialogPreview_EnterTan() {
|
||||
val tanMethods = listOf(TanMethod("Zeig mich an", TanMethodType.AppTan, "902"))
|
||||
val user = UserAccountViewInfo("12345678", "SupiDupiNutzer", "Abzockbank", BankingGroup.Postbank)
|
||||
val user = BankViewInfo("12345678", "SupiDupiNutzer", "Abzockbank", BankingGroup.Postbank)
|
||||
val tanChallenge = TanChallenge(TanChallengeType.EnterTan, ActionRequiringTan.GetAccountInfo, "Geben Sie die TAN ein", tanMethods.first().identifier, tanMethods, user = user)
|
||||
|
||||
EnterTanDialog(TanChallengeReceived(tanChallenge) { }) { }
|
||||
|
@ -27,7 +27,7 @@ fun EnterTanDialogPreview_TanImage() {
|
|||
val tanMethod = TanMethod("photoTAN-Verfahren", TanMethodType.photoTan, "902", 6, AllowedTanFormat.Numeric)
|
||||
val tanImage = TanImage("image/png", tanImageBytes)
|
||||
|
||||
val user = UserAccountViewInfo("10010010", "Ihr krasser Login Name", "Phantasie Bank", BankingGroup.Comdirect)
|
||||
val user = 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)
|
||||
|
||||
|
@ -50,7 +50,7 @@ fun EnterTanDialogPreview_WithMultipleTanMedia() { // shows that dialog is reall
|
|||
TanMedium(TanMediumType.TanGenerator, "SparkassenCard (Debitkarte)", TanMediumStatus.Used, TanGeneratorTanMedium("5432109876"))
|
||||
)
|
||||
|
||||
val user = UserAccountViewInfo("10010010", "Ihr krasser Login Name", "Eine ganz gewöhnliche Sparkasse", BankingGroup.Sparkasse)
|
||||
val user = BankViewInfo("10010010", "Ihr krasser Login Name", "Eine ganz gewöhnliche Sparkasse", BankingGroup.Sparkasse)
|
||||
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)
|
||||
|
|
|
@ -25,14 +25,14 @@ class SqliteBankingRepositoryTest {
|
|||
@Test
|
||||
fun saveUserAccount() = runTest {
|
||||
val bankAccounts = listOf(
|
||||
BankAccount("12345", "Monika Tester", BankAccountType.CheckingAccount, balance = Amount("12.34"), retrievedTransactionsFrom = LocalDate(2024, 5, 7), features = setOf(BankAccountFeatures.RetrieveBalance, BankAccountFeatures.InstantPayment), countDaysForWhichTransactionsAreKept = 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 userAccount = UserAccount("12345678", "SupiDupiUser", "geheim", "Abzock-Bank", "ABCDDEBBXXX", "Monika Tester", accounts = bankAccounts, bankingGroup = BankingGroup.DKB).apply {
|
||||
val userAccount = User("12345678", "SupiDupiUser", "geheim", "Abzock-Bank", "ABCDDEBBXXX", "Monika Tester", accounts = bankAccounts, bankingGroup = BankingGroup.DKB, finTsServerAddress = "").apply {
|
||||
wrongCredentialsEntered = true
|
||||
displayIndex = 99
|
||||
}
|
||||
|
||||
val persisted = underTest.persistUserAccount(userAccount)
|
||||
val persisted = underTest.persistUser(userAccount)
|
||||
|
||||
assertNotNull(persisted.id)
|
||||
|
||||
|
@ -55,7 +55,7 @@ class SqliteBankingRepositoryTest {
|
|||
|
||||
val persistedBankAccount = persisted.accounts.first()
|
||||
assertNotNull(persistedBankAccount.id)
|
||||
assertEquals(persisted.id, persistedBankAccount.userAccountId)
|
||||
assertEquals(persisted.id, persistedBankAccount.userId)
|
||||
|
||||
assertEquals(bankAccounts.first().identifier, persistedBankAccount.identifier)
|
||||
assertEquals(bankAccounts.first().accountHolderName, persistedBankAccount.accountHolderName)
|
||||
|
@ -67,7 +67,7 @@ class SqliteBankingRepositoryTest {
|
|||
|
||||
assertEquals(bankAccounts.first().features, persistedBankAccount.features)
|
||||
|
||||
assertEquals(bankAccounts.first().countDaysForWhichTransactionsAreKept, persistedBankAccount.countDaysForWhichTransactionsAreKept)
|
||||
assertEquals(bankAccounts.first().serverTransactionsRetentionDays, persistedBankAccount.serverTransactionsRetentionDays)
|
||||
assertEquals(bankAccounts.first().hideAccount, persistedBankAccount.hideAccount)
|
||||
assertEquals(bankAccounts.first().includeInAutomaticAccountsUpdate, persistedBankAccount.includeInAutomaticAccountsUpdate)
|
||||
}
|
||||
|
@ -88,7 +88,7 @@ class SqliteBankingRepositoryTest {
|
|||
|
||||
assertEquals(transaction.amount, persisted.amount)
|
||||
assertEquals(transaction.currency, persisted.currency)
|
||||
assertEquals(transaction.unparsedReference, persisted.unparsedReference)
|
||||
assertEquals(transaction.reference, persisted.reference)
|
||||
assertEquals(transaction.bookingDate, persisted.bookingDate)
|
||||
assertEquals(transaction.valueDate, persisted.valueDate)
|
||||
assertEquals(transaction.otherPartyName, persisted.otherPartyName)
|
||||
|
@ -109,7 +109,7 @@ class SqliteBankingRepositoryTest {
|
|||
|
||||
assertEquals(transaction.amount, persisted.amount)
|
||||
assertEquals(transaction.currency, persisted.currency)
|
||||
assertEquals(transaction.unparsedReference, persisted.reference)
|
||||
assertEquals(transaction.reference, persisted.reference)
|
||||
assertEquals(transaction.valueDate, persisted.valueDate)
|
||||
assertEquals(transaction.otherPartyName, persisted.otherPartyName)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue