Implemented persisting and deleting Holdings (but not updating yet)
This commit is contained in:
parent
0ff2f684ea
commit
202c9217e3
|
@ -2,8 +2,10 @@ package net.codinux.banking.dataaccess
|
|||
|
||||
import net.codinux.banking.client.model.AccountTransaction
|
||||
import net.codinux.banking.client.model.User
|
||||
import net.codinux.banking.client.model.securitiesaccount.Holding
|
||||
import net.codinux.banking.dataaccess.entities.AccountTransactionEntity
|
||||
import net.codinux.banking.dataaccess.entities.BankAccountEntity
|
||||
import net.codinux.banking.dataaccess.entities.HoldingEntity
|
||||
import net.codinux.banking.dataaccess.entities.UserEntity
|
||||
import net.codinux.banking.ui.model.AccountTransactionViewModel
|
||||
|
||||
|
@ -16,6 +18,13 @@ interface BankingRepository {
|
|||
suspend fun persistTransactions(bankAccount: BankAccountEntity, transactions: List<AccountTransaction>): List<AccountTransactionEntity>
|
||||
|
||||
|
||||
suspend fun persistHoldings(bankAccount: BankAccountEntity, holdings: List<Holding>): List<HoldingEntity>
|
||||
|
||||
suspend fun updateHoldings(holdings: List<HoldingEntity>)
|
||||
|
||||
suspend fun deleteHoldings(holdings: List<HoldingEntity>)
|
||||
|
||||
|
||||
fun getAllAccountTransactionsAsViewModel(): List<AccountTransactionViewModel>
|
||||
|
||||
fun getAllAccountTransactions(): List<AccountTransactionEntity>
|
||||
|
|
|
@ -2,8 +2,10 @@ package net.codinux.banking.dataaccess
|
|||
|
||||
import net.codinux.banking.client.model.AccountTransaction
|
||||
import net.codinux.banking.client.model.User
|
||||
import net.codinux.banking.client.model.securitiesaccount.Holding
|
||||
import net.codinux.banking.dataaccess.entities.AccountTransactionEntity
|
||||
import net.codinux.banking.dataaccess.entities.BankAccountEntity
|
||||
import net.codinux.banking.dataaccess.entities.HoldingEntity
|
||||
import net.codinux.banking.dataaccess.entities.UserEntity
|
||||
import net.codinux.banking.ui.model.AccountTransactionViewModel
|
||||
|
||||
|
@ -32,6 +34,17 @@ class InMemoryBankingRepository(
|
|||
}
|
||||
|
||||
|
||||
override suspend fun persistHoldings(bankAccount: BankAccountEntity, holdings: List<Holding>): List<HoldingEntity> = emptyList() // no-op
|
||||
|
||||
override suspend fun updateHoldings(holdings: List<HoldingEntity>) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
override suspend fun deleteHoldings(holdings: List<HoldingEntity>) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
|
||||
override fun getAllAccountTransactionsAsViewModel(): List<AccountTransactionViewModel> =
|
||||
transactions.map { AccountTransactionViewModel(it) }
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import app.cash.sqldelight.db.SqlDriver
|
|||
import kotlinx.datetime.Instant
|
||||
import kotlinx.datetime.LocalDate
|
||||
import net.codinux.banking.client.model.*
|
||||
import net.codinux.banking.client.model.securitiesaccount.Holding
|
||||
import net.codinux.banking.client.model.tan.*
|
||||
import net.codinux.banking.dataaccess.entities.*
|
||||
import net.codinux.banking.ui.model.AccountTransactionViewModel
|
||||
|
@ -29,13 +30,20 @@ open class SqliteBankingRepository(
|
|||
val bankAccounts = getAllBankAccounts().groupBy { it.userId }
|
||||
val tanMethods = getAllTanMethods().groupBy { it.userId }
|
||||
val tanMedia = getAllTanMedia().groupBy { it.userId }
|
||||
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 ->
|
||||
UserEntity(id, bankCode, loginName, password, bankName, bic, customerName, userId, bankAccounts[id] ?: emptyList(), selectedTanMethodIdentifier, tanMethods[id] ?: emptyList(), selectedTanMediumIdentifier, tanMedia[id] ?: emptyList(),
|
||||
UserEntity(id, bankCode, loginName, password, bankName, bic, customerName, userId, getAccountsOfUser(id, bankAccounts, holdings), selectedTanMethodIdentifier, tanMethods[id] ?: emptyList(), selectedTanMediumIdentifier, tanMedia[id] ?: emptyList(),
|
||||
bankingGroup?.let { BankingGroup.valueOf(it) }, serverAddress, userSetDisplayName, displayIndex.toInt(), iconUrl, wrongCredentialsEntered)
|
||||
}.executeAsList()
|
||||
}
|
||||
|
||||
protected open fun getAccountsOfUser(userId: Long, bankAccounts: Map<Long, List<BankAccountEntity>>, holdings: Map<Long, List<HoldingEntity>>): List<BankAccountEntity> {
|
||||
return bankAccounts[userId].orEmpty().onEach {
|
||||
it.holdings = holdings[it.id].orEmpty()
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun persistUser(user: User): UserEntity {
|
||||
return userQueries.transactionWithResult {
|
||||
userQueries.insertUser(user.bankCode, user.loginName, user.password, user.bankName, user.bic,
|
||||
|
@ -106,7 +114,9 @@ open class SqliteBankingRepository(
|
|||
persistTransaction(userId, accountId, transaction)
|
||||
}
|
||||
|
||||
return BankAccountEntity(accountId, userId, account, accountTransactionEntities, account.holdings)
|
||||
val holdings = account.holdings.map { holding -> persistHolding(userId, accountId, holding) }
|
||||
|
||||
return BankAccountEntity(accountId, userId, account, accountTransactionEntities, holdings)
|
||||
}
|
||||
|
||||
|
||||
|
@ -196,6 +206,50 @@ open class SqliteBankingRepository(
|
|||
}
|
||||
|
||||
|
||||
protected open fun getAllHoldings(): List<HoldingEntity> =
|
||||
accountTransactionQueries.selectAllHoldings { id, userId, 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))
|
||||
}.executeAsList()
|
||||
|
||||
override suspend fun persistHoldings(bankAccount: BankAccountEntity, holdings: List<Holding>): List<HoldingEntity> =
|
||||
accountTransactionQueries.transactionWithResult {
|
||||
holdings.map { persistHolding(bankAccount.userId, bankAccount.id, it) }
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
accountTransactionQueries.insertHolding(
|
||||
userId, bankAccountId,
|
||||
|
||||
holding.name, holding.isin, holding.wkn,
|
||||
|
||||
mapInt(holding.quantity), holding.currency,
|
||||
|
||||
mapAmount(holding.totalBalance), mapAmount(holding.marketValue),
|
||||
holding.performancePercentage?.toDouble(),
|
||||
mapAmount(holding.totalCostPrice), mapAmount(holding.averageCostPrice),
|
||||
|
||||
mapInstant(holding.pricingTime), mapDate(holding.buyingDate)
|
||||
)
|
||||
|
||||
return HoldingEntity(getLastInsertedId(), userId, bankAccountId, holding)
|
||||
}
|
||||
|
||||
override suspend fun updateHoldings(holdings: List<HoldingEntity>) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
override suspend fun deleteHoldings(holdings: List<HoldingEntity>) {
|
||||
accountTransactionQueries.transaction {
|
||||
holdings.forEach { holding ->
|
||||
accountTransactionQueries.deleteHolding(holding.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override fun getAllAccountTransactionsAsViewModel(): List<AccountTransactionViewModel> =
|
||||
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)
|
||||
|
|
|
@ -30,7 +30,7 @@ class BankAccountEntity(
|
|||
|
||||
bookedTransactions: MutableList<AccountTransactionEntity> = mutableListOf(),
|
||||
prebookedTransactions: MutableList<PrebookedAccountTransaction> = mutableListOf(),
|
||||
holdings: List<Holding> = emptyList(),
|
||||
override var holdings: List<HoldingEntity> = emptyList(),
|
||||
|
||||
userSetDisplayName: String? = null,
|
||||
displayIndex: Int = 0,
|
||||
|
@ -54,7 +54,7 @@ class BankAccountEntity(
|
|||
userSetDisplayName, displayIndex,
|
||||
hideAccount, includeInAutomaticAccountsUpdate
|
||||
) {
|
||||
constructor(id: Long, userId: Long, account: BankAccount, transactions: List<AccountTransactionEntity> = emptyList(), holdings: List<Holding> = emptyList()) : this(
|
||||
constructor(id: Long, userId: Long, account: BankAccount, transactions: List<AccountTransactionEntity> = emptyList(), holdings: List<HoldingEntity> = emptyList()) : this(
|
||||
id, userId,
|
||||
account.identifier, account.subAccountNumber, account.iban, account.productName,
|
||||
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
package net.codinux.banking.dataaccess.entities
|
||||
|
||||
import kotlinx.datetime.Instant
|
||||
import kotlinx.datetime.LocalDate
|
||||
import net.codinux.banking.client.model.Amount
|
||||
import net.codinux.banking.client.model.securitiesaccount.Holding
|
||||
|
||||
class HoldingEntity(
|
||||
val id: Long,
|
||||
val userId: Long,
|
||||
val bankAccountId: Long,
|
||||
|
||||
name: String,
|
||||
|
||||
isin: String? = null,
|
||||
wkn: String? = null,
|
||||
|
||||
quantity: Int? = null,
|
||||
currency: String? = null,
|
||||
|
||||
totalBalance: Amount? = null,
|
||||
marketValue: Amount? = null,
|
||||
|
||||
performancePercentage: Float? = null,
|
||||
|
||||
totalCostPrice: Amount? = null,
|
||||
averageCostPrice: Amount? = null,
|
||||
|
||||
pricingTime: Instant? = null,
|
||||
buyingDate: LocalDate? = null
|
||||
) : Holding(name, isin, wkn, quantity, currency, totalBalance, marketValue, performancePercentage, totalCostPrice, averageCostPrice, pricingTime, buyingDate) {
|
||||
|
||||
constructor(id: Long, userId: Long, bankAccountId: Long, holding: Holding) : this(
|
||||
id, userId, bankAccountId,
|
||||
|
||||
holding.name, holding.isin, holding.wkn,
|
||||
|
||||
holding.quantity, holding.currency,
|
||||
|
||||
holding.totalBalance, holding.marketValue,
|
||||
holding.performancePercentage,
|
||||
holding.totalCostPrice, holding.averageCostPrice,
|
||||
|
||||
holding.pricingTime, holding.buyingDate
|
||||
)
|
||||
}
|
|
@ -172,6 +172,22 @@ class BankingService(
|
|||
emptyList()
|
||||
}
|
||||
|
||||
val existingHoldingsByIsin = account.holdings.associateBy { it.identifier }
|
||||
val retrievedHoldingsByIsin = response.holdings.associateBy { it.identifier }
|
||||
|
||||
val (newHoldings, updatedRetrievedHoldings) = response.holdings.partition { existingHoldingsByIsin.keys.contains(it.identifier) == false }
|
||||
val (updatedExistingHoldings, deletedHoldings) = account.holdings.partition { retrievedHoldingsByIsin.keys.contains(it.identifier) }
|
||||
|
||||
val persistedNewHoldings = bankingRepository.persistHoldings(account, newHoldings)
|
||||
// bankingRepository.updateHoldings(updatedExistingHoldings) // TODO: map data of updatedRetrievedHoldings to updatedExistingHoldings
|
||||
bankingRepository.deleteHoldings(deletedHoldings)
|
||||
|
||||
account.holdings = account.holdings.toMutableList().apply {
|
||||
addAll(persistedNewHoldings)
|
||||
removeAll(deletedHoldings)
|
||||
}
|
||||
|
||||
|
||||
updateHoldingsInUi(response.holdings)
|
||||
|
||||
val transactionsViewModel = updateTransactionsInUi(newTransactionsEntities)
|
||||
|
|
|
@ -134,3 +134,70 @@ FROM AccountTransaction WHERE userId = ?;
|
|||
getTransactionWithId:
|
||||
SELECT AccountTransaction.*
|
||||
FROM AccountTransaction WHERE id = ?;
|
||||
|
||||
|
||||
|
||||
|
||||
CREATE TABLE IF NOT EXISTS Holding (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
|
||||
userId INTEGER NOT NULL,
|
||||
bankAccountId INTEGER NOT NULL,
|
||||
|
||||
name TEXT NOT NULL,
|
||||
isin TEXT,
|
||||
wkn TEXT,
|
||||
|
||||
quantity INTEGER ,
|
||||
currency TEXT,
|
||||
|
||||
totalBalance TEXT,
|
||||
marketValue TEXT,
|
||||
|
||||
performancePercentage REAL,
|
||||
|
||||
totalCostPrice TEXT,
|
||||
averageCostPrice TEXT,
|
||||
|
||||
pricingTime TEXT,
|
||||
buyingDate TEXT
|
||||
);
|
||||
|
||||
|
||||
insertHolding:
|
||||
INSERT INTO Holding(
|
||||
userId, bankAccountId,
|
||||
|
||||
name, isin, wkn,
|
||||
|
||||
quantity, currency,
|
||||
|
||||
totalBalance, marketValue,
|
||||
performancePercentage,
|
||||
|
||||
totalCostPrice, averageCostPrice,
|
||||
|
||||
pricingTime, buyingDate
|
||||
)
|
||||
VALUES(
|
||||
?, ?,
|
||||
|
||||
?, ?, ?,
|
||||
|
||||
?, ?,
|
||||
|
||||
?, ?,
|
||||
?,
|
||||
|
||||
?,?,
|
||||
|
||||
?, ?
|
||||
);
|
||||
|
||||
|
||||
selectAllHoldings:
|
||||
SELECT Holding.*
|
||||
FROM Holding;
|
||||
|
||||
deleteHolding:
|
||||
DELETE FROM Holding WHERE id = ?;
|
Loading…
Reference in New Issue