Added IBankingPersistence to be able to store and deserialize added accounts and retrieved account transactions. Implemented BankingPersistenceJson not meant to be a real IBankingPersistence implementation but to get one up and running fast.
This commit is contained in:
parent
ab61064d35
commit
0c8870446e
|
@ -19,9 +19,11 @@ def title = 'Banking'
|
|||
|
||||
|
||||
dependencies {
|
||||
api project(':BankingJavaFxControls')
|
||||
implementation project(':BankingJavaFxControls')
|
||||
|
||||
api project(':fints4javaBankingClient')
|
||||
implementation project(':fints4javaBankingClient')
|
||||
|
||||
implementation project(':BankingPersistenceJson')
|
||||
|
||||
implementation "ch.qos.logback:logback-classic:$logbackVersion"
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package net.dankito.banking.javafx.dialogs.mainwindow
|
|||
|
||||
import javafx.scene.control.SplitPane
|
||||
import net.dankito.banking.fints4javaBankingClientCreator
|
||||
import net.dankito.banking.persistence.BankingPersistenceJson
|
||||
import net.dankito.banking.ui.javafx.RouterJavaFx
|
||||
import net.dankito.banking.ui.javafx.controls.AccountTransactionsView
|
||||
import net.dankito.banking.ui.javafx.controls.AccountsView
|
||||
|
@ -10,11 +11,12 @@ import net.dankito.banking.ui.javafx.util.Base64ServiceJava8
|
|||
import net.dankito.banking.ui.presenter.MainWindowPresenter
|
||||
import tornadofx.*
|
||||
import tornadofx.FX.Companion.messages
|
||||
import java.io.File
|
||||
|
||||
|
||||
class MainWindow : View(messages["application.title"]) {
|
||||
|
||||
private val presenter = MainWindowPresenter(fints4javaBankingClientCreator(), Base64ServiceJava8(), RouterJavaFx())
|
||||
private val presenter = MainWindowPresenter(fints4javaBankingClientCreator(), BankingPersistenceJson(File("data/accounts.json")), Base64ServiceJava8(), RouterJavaFx())
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ open class AccountTransactionsView(private val presenter: MainWindowPresenter) :
|
|||
|
||||
protected val balance = SimpleStringProperty("")
|
||||
|
||||
protected val transactionsToDisplay = FXCollections.observableArrayList<AccountTransaction>(presenter.allTransactions)
|
||||
protected val transactionsToDisplay = FXCollections.observableArrayList<AccountTransaction>(listOf())
|
||||
|
||||
|
||||
protected var currentMenu: ContextMenu? = null
|
||||
|
@ -37,6 +37,8 @@ open class AccountTransactionsView(private val presenter: MainWindowPresenter) :
|
|||
}
|
||||
|
||||
transactionsFilter.addListener { _, _, newValue -> updateTransactionsToDisplay(newValue) }
|
||||
|
||||
handleSelectedBankAccountsChanged(presenter.selectedBankAccounts) // so that isAccountSelected and transactionsToDisplay get set
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
package net.dankito.banking.persistence
|
||||
|
||||
import net.dankito.banking.ui.model.Account
|
||||
|
||||
|
||||
interface IBankingPersistence {
|
||||
|
||||
fun saveOrUpdateAccount(account: Account, allAccounts: List<Account>)
|
||||
|
||||
fun readPersistedAccounts(): List<Account>
|
||||
|
||||
}
|
|
@ -1,11 +1,14 @@
|
|||
package net.dankito.banking.ui.model
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIdentityInfo
|
||||
import com.fasterxml.jackson.annotation.ObjectIdGenerators
|
||||
import net.dankito.banking.ui.model.tan.TanMedium
|
||||
import net.dankito.banking.ui.model.tan.TanMediumStatus
|
||||
import net.dankito.banking.ui.model.tan.TanProcedure
|
||||
import java.math.BigDecimal
|
||||
|
||||
|
||||
@JsonIdentityInfo(generator= ObjectIdGenerators.UUIDGenerator::class) // to avoid stack overflow due to circular references // TODO: remove again, add custom domain object
|
||||
open class Account(
|
||||
val bank: Bank,
|
||||
val customerId: String,
|
||||
|
@ -15,6 +18,7 @@ open class Account(
|
|||
var bankAccounts: List<BankAccount> = listOf()
|
||||
) {
|
||||
|
||||
|
||||
internal constructor() : this(Bank(), "", "", "") // for object deserializers
|
||||
|
||||
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
package net.dankito.banking.ui.model
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIdentityInfo
|
||||
import com.fasterxml.jackson.annotation.ObjectIdGenerators
|
||||
import java.math.BigDecimal
|
||||
import java.text.DateFormat
|
||||
import java.util.*
|
||||
|
||||
|
||||
@JsonIdentityInfo(generator= ObjectIdGenerators.UUIDGenerator::class) // to avoid stack overflow due to circular references // TODO: remove again, add custom domain object
|
||||
open class AccountTransaction(
|
||||
val amount: BigDecimal,
|
||||
val bookingDate: Date,
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
package net.dankito.banking.ui.model
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIdentityInfo
|
||||
import com.fasterxml.jackson.annotation.ObjectIdGenerators
|
||||
import java.math.BigDecimal
|
||||
|
||||
|
||||
@JsonIdentityInfo(generator= ObjectIdGenerators.UUIDGenerator::class) // to avoid stack overflow due to circular references // TODO: remove again, add custom domain object
|
||||
open class BankAccount @JvmOverloads constructor(
|
||||
val account: Account,
|
||||
val identifier: String,
|
||||
|
|
|
@ -6,6 +6,10 @@ open class TanMedium(
|
|||
val status: TanMediumStatus
|
||||
) {
|
||||
|
||||
|
||||
internal constructor() : this("", TanMediumStatus.Available) // for object deserializers
|
||||
|
||||
|
||||
override fun toString(): String {
|
||||
return "$displayName $status"
|
||||
}
|
||||
|
|
|
@ -7,6 +7,10 @@ open class TanProcedure(
|
|||
val bankInternalProcedureCode: String
|
||||
) {
|
||||
|
||||
|
||||
internal constructor() : this("", TanProcedureType.EnterTan, "") // for object deserializers
|
||||
|
||||
|
||||
override fun toString(): String {
|
||||
return "$displayName ($type, ${bankInternalProcedureCode})"
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package net.dankito.banking.ui.presenter
|
||||
|
||||
import net.dankito.banking.persistence.IBankingPersistence
|
||||
import net.dankito.banking.ui.BankingClientCallback
|
||||
import net.dankito.banking.ui.IBankingClient
|
||||
import net.dankito.banking.ui.IBankingClientCreator
|
||||
|
@ -21,7 +22,9 @@ import net.dankito.fints.model.BankInfo
|
|||
import net.dankito.utils.IThreadPool
|
||||
import net.dankito.utils.ThreadPool
|
||||
import net.dankito.utils.extensions.ofMaxLength
|
||||
import net.dankito.utils.web.client.IWebClient
|
||||
import net.dankito.utils.web.client.OkHttpWebClient
|
||||
import org.slf4j.LoggerFactory
|
||||
import java.math.BigDecimal
|
||||
import java.util.*
|
||||
import kotlin.collections.ArrayList
|
||||
|
@ -29,19 +32,22 @@ import kotlin.collections.ArrayList
|
|||
|
||||
open class MainWindowPresenter(
|
||||
protected val bankingClientCreator: IBankingClientCreator,
|
||||
protected val persister: IBankingPersistence,
|
||||
protected val base64Service: IBase64Service,
|
||||
protected val router: IRouter
|
||||
protected val router: IRouter,
|
||||
protected val webClient: IWebClient = OkHttpWebClient(),
|
||||
protected val threadPool: IThreadPool = ThreadPool()
|
||||
) {
|
||||
|
||||
companion object {
|
||||
protected const val OneDayMillis = 24 * 60 * 60 * 1000
|
||||
|
||||
private val log = LoggerFactory.getLogger(MainWindowPresenter::class.java)
|
||||
}
|
||||
|
||||
|
||||
protected val bankFinder: BankFinder = BankFinder()
|
||||
|
||||
protected val threadPool: IThreadPool = ThreadPool()
|
||||
|
||||
|
||||
protected val clientsForAccounts = mutableMapOf<Account, IBankingClient>()
|
||||
|
||||
|
@ -68,19 +74,54 @@ open class MainWindowPresenter(
|
|||
}
|
||||
|
||||
|
||||
init {
|
||||
threadPool.runAsync {
|
||||
readPersistedAccounts()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected open fun readPersistedAccounts() {
|
||||
try {
|
||||
val deserializedAccounts = persister.readPersistedAccounts()
|
||||
|
||||
deserializedAccounts.forEach { account ->
|
||||
val bank = account.bank
|
||||
val bankInfo = BankInfo(bank.name, bank.bankCode, bank.bic, "", "", "", bank.finTsServerAddress, "FinTS V3.0", null)
|
||||
|
||||
val newClient = bankingClientCreator.createClient(bankInfo, account.customerId, account.password, webClient, base64Service, threadPool, callback)
|
||||
|
||||
addClientForAccount(account, newClient)
|
||||
}
|
||||
|
||||
callAccountsChangedListeners()
|
||||
|
||||
selectedAllBankAccounts() // TODO: save last selected bank account(s)
|
||||
} catch (e: Exception) {
|
||||
log.error("Could not deserialize persisted accounts with persister $persister", e)
|
||||
}
|
||||
}
|
||||
|
||||
protected open fun addClientForAccount(account: Account, client: IBankingClient) {
|
||||
clientsForAccounts.put(account, client)
|
||||
}
|
||||
|
||||
|
||||
// TODO: move BankInfo out of fints4javaLib
|
||||
open fun addAccountAsync(bankInfo: BankInfo, customerId: String, pin: String, callback: (AddAccountResponse) -> Unit) {
|
||||
|
||||
val newClient = bankingClientCreator.createClient(bankInfo, customerId, pin, OkHttpWebClient(), base64Service, threadPool, this.callback)
|
||||
val newClient = bankingClientCreator.createClient(bankInfo, customerId, pin, webClient, base64Service, threadPool, this.callback)
|
||||
|
||||
newClient.addAccountAsync { response ->
|
||||
val account = response.account
|
||||
|
||||
if (response.isSuccessful) {
|
||||
clientsForAccounts.put(account, newClient)
|
||||
addClientForAccount(account, newClient)
|
||||
|
||||
callAccountsChangedListeners()
|
||||
|
||||
persistAccount(account)
|
||||
|
||||
if (response.supportsRetrievingTransactionsOfLast90DaysWithoutTan) {
|
||||
account.bankAccounts.forEach { bankAccount ->
|
||||
retrievedAccountTransactions(bankAccount, response)
|
||||
|
@ -155,6 +196,12 @@ open class MainWindowPresenter(
|
|||
response.balances.forEach { entry ->
|
||||
entry.key.balance = entry.value
|
||||
}
|
||||
|
||||
persistAccount(bankAccount.account)
|
||||
}
|
||||
|
||||
protected open fun persistAccount(account: Account) {
|
||||
persister.saveOrUpdateAccount(account, accounts)
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -48,21 +48,23 @@ android {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
api project(':BankingUiCommon')
|
||||
implementation project(':BankingUiCommon')
|
||||
|
||||
implementation project(':fints4javaBankingClient')
|
||||
|
||||
implementation project(':BankingPersistenceJson')
|
||||
|
||||
implementation "com.github.clans:fab:$clansFloatingActionButtonVersion"
|
||||
|
||||
api "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion"
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion"
|
||||
|
||||
api "net.dankito.utils:android-utils:$androidUtilsVersion", {
|
||||
implementation "net.dankito.utils:android-utils:$androidUtilsVersion", {
|
||||
exclude group: 'org.jetbrains.kotlin', module: 'kotlin-stdlib-jdk7'
|
||||
exclude group: 'com.android.support', module: 'appcompat-v7'
|
||||
exclude group: 'com.android.support', module: 'design'
|
||||
}
|
||||
|
||||
api "org.slf4j:slf4j-android:$slf4JVersion"
|
||||
implementation "org.slf4j:slf4j-android:$slf4JVersion"
|
||||
|
||||
implementation 'com.android.support:appcompat-v7:28.0.0'
|
||||
implementation 'com.android.support:design:28.0.0'
|
||||
|
|
|
@ -18,9 +18,11 @@ import kotlinx.android.synthetic.main.action_view_account_menu_item.view.*
|
|||
import net.dankito.banking.fints4java.android.ui.views.MainActivityFloatingActionMenuButton
|
||||
import net.dankito.banking.fints4java.android.util.Base64ServiceAndroid
|
||||
import net.dankito.banking.fints4javaBankingClientCreator
|
||||
import net.dankito.banking.persistence.BankingPersistenceJson
|
||||
import net.dankito.banking.ui.model.Account
|
||||
import net.dankito.banking.ui.presenter.MainWindowPresenter
|
||||
import org.slf4j.LoggerFactory
|
||||
import java.io.File
|
||||
|
||||
|
||||
class MainActivity : AppCompatActivity() {
|
||||
|
@ -37,12 +39,14 @@ class MainActivity : AppCompatActivity() {
|
|||
private lateinit var floatingActionMenuButton: MainActivityFloatingActionMenuButton
|
||||
|
||||
|
||||
val presenter = MainWindowPresenter(fints4javaBankingClientCreator(), Base64ServiceAndroid(), RouterAndroid(this))
|
||||
lateinit var presenter: MainWindowPresenter
|
||||
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
presenter = MainWindowPresenter(fints4javaBankingClientCreator(), BankingPersistenceJson(File(this.filesDir, "data/accounts.json")), Base64ServiceAndroid(), RouterAndroid(this))
|
||||
|
||||
initUi()
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
# BankingPersistenceJson
|
||||
|
||||
A simple IBankingPersistence implementation based on Json.
|
||||
|
||||
Not meant to be a real or useful implementation. Just there to get you up and running fast.
|
||||
|
||||
Preferably use another IBankingPersistence implementation, e.g. a JPA based one.
|
|
@ -0,0 +1,20 @@
|
|||
apply plugin: 'java-library'
|
||||
apply plugin: 'kotlin'
|
||||
|
||||
apply plugin: 'kotlin-kapt'
|
||||
|
||||
|
||||
sourceCompatibility = "1.7"
|
||||
targetCompatibility = "1.7"
|
||||
|
||||
compileKotlin {
|
||||
kotlinOptions.jvmTarget = "1.6"
|
||||
}
|
||||
compileTestKotlin {
|
||||
kotlinOptions.jvmTarget = "1.6"
|
||||
}
|
||||
|
||||
|
||||
dependencies {
|
||||
implementation project(':BankingUiCommon')
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package net.dankito.banking.persistence
|
||||
|
||||
import net.dankito.banking.ui.model.Account
|
||||
import net.dankito.utils.serialization.ISerializer
|
||||
import net.dankito.utils.serialization.JacksonJsonSerializer
|
||||
import java.io.File
|
||||
|
||||
|
||||
open class BankingPersistenceJson(
|
||||
protected val jsonFile: File,
|
||||
protected val serializer: ISerializer = JacksonJsonSerializer()
|
||||
) : IBankingPersistence {
|
||||
|
||||
|
||||
init {
|
||||
jsonFile.absoluteFile.parentFile.mkdirs()
|
||||
}
|
||||
|
||||
|
||||
override fun saveOrUpdateAccount(account: Account, allAccounts: List<Account>) {
|
||||
serializer.serializeObject(allAccounts, jsonFile)
|
||||
}
|
||||
|
||||
override fun readPersistedAccounts(): List<Account> {
|
||||
return serializer.deserializeListOr(jsonFile, Account::class.java, listOf())
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue