Implemented restoring fints4java BankingClient's data
This commit is contained in:
parent
19fcbf2823
commit
08f603a9a0
|
@ -16,7 +16,9 @@ import java.io.File
|
|||
|
||||
class MainWindow : View(messages["application.title"]) {
|
||||
|
||||
private val presenter = MainWindowPresenter(fints4javaBankingClientCreator(), BankingPersistenceJson(File("data/accounts.json")), Base64ServiceJava8(), RouterJavaFx())
|
||||
private val dataFolder = File("data")
|
||||
|
||||
private val presenter = MainWindowPresenter(fints4javaBankingClientCreator(), dataFolder, BankingPersistenceJson(File(dataFolder, "accounts.json")), Base64ServiceJava8(), RouterJavaFx())
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -20,4 +20,6 @@ interface IBankingClient {
|
|||
|
||||
fun transferMoneyAsync(data: TransferMoneyData, bankAccount: BankAccount, callback: (BankingClientResponse) -> Unit)
|
||||
|
||||
fun restoreData()
|
||||
|
||||
}
|
|
@ -25,6 +25,7 @@ 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.io.File
|
||||
import java.math.BigDecimal
|
||||
import java.util.*
|
||||
import kotlin.collections.ArrayList
|
||||
|
@ -32,6 +33,7 @@ import kotlin.collections.ArrayList
|
|||
|
||||
open class MainWindowPresenter(
|
||||
protected val bankingClientCreator: IBankingClientCreator,
|
||||
protected val dataFolder: File,
|
||||
protected val persister: IBankingPersistence,
|
||||
protected val base64Service: IBase64Service,
|
||||
protected val router: IRouter,
|
||||
|
@ -102,7 +104,15 @@ open class MainWindowPresenter(
|
|||
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)
|
||||
val newClient = bankingClientCreator.createClient(bankInfo, account.customerId, account.password,
|
||||
dataFolder, webClient, base64Service, threadPool, callback)
|
||||
|
||||
try {
|
||||
newClient.restoreData()
|
||||
} catch (e: Exception) {
|
||||
log.error("Could not deserialize account data of $account", e)
|
||||
// TODO: show error message to user
|
||||
}
|
||||
|
||||
addClientForAccount(account, newClient)
|
||||
}
|
||||
|
@ -123,7 +133,7 @@ open class MainWindowPresenter(
|
|||
// 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, webClient, base64Service, threadPool, this.callback)
|
||||
val newClient = bankingClientCreator.createClient(bankInfo, customerId, pin, dataFolder, webClient, base64Service, threadPool, this.callback)
|
||||
|
||||
newClient.addAccountAsync { response ->
|
||||
val account = response.account
|
||||
|
@ -299,16 +309,7 @@ open class MainWindowPresenter(
|
|||
|
||||
|
||||
protected open fun getClientForAccount(account: Account): IBankingClient? {
|
||||
clientsForAccounts.get(account)?.let { client ->
|
||||
// TODO: is this code still needed after updating data model is implemented?
|
||||
// account.selectedTanProcedure?.let { selectedTanProcedure ->
|
||||
// client.customer.selectedTanProcedure = fints4javaModelMapper.mapTanProcedureBack(selectedTanProcedure)
|
||||
// }
|
||||
|
||||
return client
|
||||
}
|
||||
|
||||
return null
|
||||
return clientsForAccounts.get(account)
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -45,7 +45,10 @@ class MainActivity : AppCompatActivity() {
|
|||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
presenter = MainWindowPresenter(fints4javaBankingClientCreator(), BankingPersistenceJson(File(this.filesDir, "data/accounts.json")), Base64ServiceAndroid(), RouterAndroid(this))
|
||||
val dataFolder = File(this.filesDir, "data")
|
||||
|
||||
presenter = MainWindowPresenter(fints4javaBankingClientCreator(), dataFolder,
|
||||
BankingPersistenceJson(File(dataFolder, "accounts.json")), Base64ServiceAndroid(), RouterAndroid(this))
|
||||
|
||||
initUi()
|
||||
}
|
||||
|
|
|
@ -17,14 +17,18 @@ import net.dankito.fints.model.mapper.BankDataMapper
|
|||
import net.dankito.fints.util.IBase64Service
|
||||
import net.dankito.utils.IThreadPool
|
||||
import net.dankito.utils.ThreadPool
|
||||
import net.dankito.utils.serialization.JacksonJsonSerializer
|
||||
import net.dankito.utils.web.client.IWebClient
|
||||
import net.dankito.utils.web.client.OkHttpWebClient
|
||||
import org.slf4j.LoggerFactory
|
||||
import java.io.File
|
||||
|
||||
|
||||
open class fints4javaBankingClient(
|
||||
bankInfo: BankInfo,
|
||||
customerId: String,
|
||||
pin: String,
|
||||
protected val dataFolder: File,
|
||||
webClient: IWebClient = OkHttpWebClient(),
|
||||
base64Service: IBase64Service,
|
||||
threadPool: IThreadPool = ThreadPool(),
|
||||
|
@ -32,10 +36,20 @@ open class fints4javaBankingClient(
|
|||
|
||||
) : IBankingClient {
|
||||
|
||||
companion object {
|
||||
val fints4javaClientDataFilename = "fints4javaClientData.json"
|
||||
|
||||
private val log = LoggerFactory.getLogger(fints4javaBankingClient::class.java)
|
||||
}
|
||||
|
||||
|
||||
protected val mapper = net.dankito.banking.mapper.fints4javaModelMapper()
|
||||
|
||||
protected val bankDataMapper = BankDataMapper()
|
||||
|
||||
protected val serializer = JacksonJsonSerializer()
|
||||
|
||||
|
||||
protected val bank = bankDataMapper.mapFromBankInfo(bankInfo)
|
||||
|
||||
protected val customer = CustomerData(customerId, pin)
|
||||
|
@ -74,6 +88,8 @@ open class fints4javaBankingClient(
|
|||
this.account = mapper.mapAccount(customer, bank)
|
||||
val mappedResponse = mapper.mapResponse(account, response)
|
||||
|
||||
saveData()
|
||||
|
||||
callback(mappedResponse)
|
||||
}
|
||||
}
|
||||
|
@ -89,6 +105,8 @@ open class fints4javaBankingClient(
|
|||
|
||||
val mappedResponse = mapper.mapResponse(bankAccount, response)
|
||||
|
||||
saveData()
|
||||
|
||||
callback(mappedResponse)
|
||||
}
|
||||
}
|
||||
|
@ -104,9 +122,32 @@ open class fints4javaBankingClient(
|
|||
val mappedData = BankTransferData(data.creditorName, data.creditorIban, data.creditorBic, data.amount, data.usage)
|
||||
|
||||
client.doBankTransferAsync(mappedData, account) { response ->
|
||||
saveData()
|
||||
|
||||
callback(mapper.mapResponse(response))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override fun restoreData() {
|
||||
val deserializedCustomer = serializer.deserializeObject(getFints4javaClientDataFile(), CustomerData::class.java)
|
||||
|
||||
deserializedCustomer?.let {
|
||||
mapper.updateCustomer(customer, deserializedCustomer)
|
||||
}
|
||||
}
|
||||
|
||||
protected open fun saveData() {
|
||||
try {
|
||||
serializer.serializeObject(customer, getFints4javaClientDataFile())
|
||||
} catch (e: Exception) {
|
||||
log.error("Could not save customer data for $customer", e)
|
||||
}
|
||||
}
|
||||
|
||||
protected open fun getFints4javaClientDataFile(): File {
|
||||
return File(dataFolder, "${bank.bankCode}_${customer.customerId}_$fints4javaClientDataFilename")
|
||||
}
|
||||
|
||||
}
|
|
@ -9,14 +9,23 @@ import net.dankito.fints.model.BankInfo
|
|||
import net.dankito.utils.IThreadPool
|
||||
import net.dankito.utils.web.client.IWebClient
|
||||
import net.dankito.utils.web.client.OkHttpWebClient
|
||||
import java.io.File
|
||||
|
||||
|
||||
open class fints4javaBankingClientCreator : IBankingClientCreator {
|
||||
|
||||
override fun createClient(bankInfo: BankInfo, customerId: String, pin: String, webClient: IWebClient,
|
||||
base64Service: IBase64Service, threadPool: IThreadPool, callback: BankingClientCallback): IBankingClient {
|
||||
override fun createClient(
|
||||
bankInfo: BankInfo,
|
||||
customerId: String,
|
||||
pin: String,
|
||||
dataFolder: File,
|
||||
webClient: IWebClient,
|
||||
base64Service: IBase64Service,
|
||||
threadPool: IThreadPool,
|
||||
callback: BankingClientCallback
|
||||
): IBankingClient {
|
||||
|
||||
return fints4javaBankingClient(bankInfo, customerId, pin, OkHttpWebClient(), UiCommonBase64ServiceWrapper(base64Service), threadPool, callback)
|
||||
return fints4javaBankingClient(bankInfo, customerId, pin, dataFolder, OkHttpWebClient(), UiCommonBase64ServiceWrapper(base64Service), threadPool, callback)
|
||||
}
|
||||
|
||||
}
|
|
@ -61,6 +61,10 @@ open class fints4javaModelMapper {
|
|||
}
|
||||
|
||||
|
||||
open fun mapBank(bank: BankData): Bank {
|
||||
return Bank(bank.name, bank.bankCode, bank.bic, bank.finTs3ServerAddress)
|
||||
}
|
||||
|
||||
open fun mapAccount(customer: CustomerData, bank: BankData): Account {
|
||||
val mappedBank = mapBank(bank)
|
||||
|
||||
|
@ -73,10 +77,24 @@ open class fints4javaModelMapper {
|
|||
return account
|
||||
}
|
||||
|
||||
open fun mapBank(bank: BankData): Bank {
|
||||
return Bank(bank.name, bank.bankCode, bank.bic, bank.finTs3ServerAddress)
|
||||
// TODO: move to a fints4java internal mapper
|
||||
open fun updateCustomer(customer: CustomerData, updatedCustomer: CustomerData) {
|
||||
customer.pin = updatedCustomer.pin
|
||||
customer.name = updatedCustomer.name
|
||||
|
||||
customer.supportedTanProcedures = updatedCustomer.supportedTanProcedures
|
||||
customer.selectedTanProcedure = updatedCustomer.selectedTanProcedure
|
||||
customer.tanMedia = updatedCustomer.tanMedia
|
||||
|
||||
customer.updVersion = updatedCustomer.updVersion
|
||||
customer.selectedLanguage = updatedCustomer.selectedLanguage
|
||||
customer.customerSystemId = updatedCustomer.customerSystemId
|
||||
customer.customerSystemStatus = updatedCustomer.customerSystemStatus
|
||||
|
||||
updateBankAccounts(customer, updatedCustomer.accounts)
|
||||
}
|
||||
|
||||
|
||||
open fun mapBankAccounts(account: Account, accountData: List<AccountData>): List<BankAccount> {
|
||||
return accountData.map { mapBankAccount(account, it) }
|
||||
}
|
||||
|
@ -103,6 +121,38 @@ open class fints4javaModelMapper {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: move to a fints4java internal mapper
|
||||
open fun updateBankAccounts(customer: CustomerData, updatedAccounts: List<AccountData>) {
|
||||
val accounts = customer.accounts
|
||||
|
||||
updatedAccounts.forEach { updatedAccount ->
|
||||
val matchingExistingAccount = findMatchingBankAccount(accounts, updatedAccount)
|
||||
|
||||
if (matchingExistingAccount == null) {
|
||||
customer.addAccount(updatedAccount)
|
||||
}
|
||||
else {
|
||||
updateBankAccount(matchingExistingAccount, updatedAccount)
|
||||
}
|
||||
}
|
||||
|
||||
customer.accounts.forEach { account ->
|
||||
val updatedAccount = findMatchingBankAccount(updatedAccounts, account)
|
||||
|
||||
if (updatedAccount == null) {
|
||||
customer.removeAccount(account)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
open fun updateBankAccount(account: AccountData, updatedAccount: AccountData) {
|
||||
account.allowedJobs = updatedAccount.allowedJobs
|
||||
|
||||
account.supportsRetrievingAccountTransactions = updatedAccount.supportsRetrievingAccountTransactions
|
||||
account.supportsRetrievingBalance = updatedAccount.supportsRetrievingBalance
|
||||
account.supportsTransferringMoney = updatedAccount.supportsTransferringMoney
|
||||
}
|
||||
|
||||
open fun findAccountForBankAccount(customer: CustomerData, bankAccount: BankAccount): AccountData? {
|
||||
return customer.accounts.firstOrNull { bankAccount.identifier == it.accountIdentifier }
|
||||
}
|
||||
|
@ -111,6 +161,10 @@ open class fints4javaModelMapper {
|
|||
return account.bankAccounts.firstOrNull { it.identifier == accountData.accountIdentifier }
|
||||
}
|
||||
|
||||
open fun findMatchingBankAccount(accounts: List<AccountData>, accountData: AccountData): AccountData? {
|
||||
return accounts.firstOrNull { it.accountIdentifier == accountData.accountIdentifier }
|
||||
}
|
||||
|
||||
|
||||
open fun mapTransactions(bankAccount: BankAccount, transactions: List<net.dankito.fints.model.AccountTransaction>): List<AccountTransaction> {
|
||||
return transactions.map { mapTransaction(bankAccount, it) }
|
||||
|
|
|
@ -14,6 +14,9 @@ open class TanMedium(
|
|||
) {
|
||||
|
||||
|
||||
internal constructor() : this(TanMediumKlasse.AlleMedien, TanMediumStatus.Verfuegbar)
|
||||
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
|
|
|
@ -26,7 +26,7 @@ open class AccountData(
|
|||
var triedToRetrieveTransactionsOfLast90DaysWithoutTan: Boolean = false
|
||||
) {
|
||||
|
||||
internal constructor() : this("", null, Laenderkennzeichen.Germany, "", null, "", null, null, "", null, null, listOf())
|
||||
internal constructor() : this("", null, Laenderkennzeichen.Germany, "", null, "", null, null, "", null, null, listOf()) // for object deserializers
|
||||
|
||||
override fun toString(): String {
|
||||
return "$productName $accountIdentifier $accountHolderName"
|
||||
|
|
|
@ -29,6 +29,9 @@ open class BankData(
|
|||
) {
|
||||
|
||||
|
||||
internal constructor() : this("", 0, "", "") // for object deserializers
|
||||
|
||||
|
||||
open fun resetBpdVersion() {
|
||||
bpdVersion = BPDVersion.VersionNotReceivedYet
|
||||
}
|
||||
|
|
|
@ -32,6 +32,8 @@ open class CustomerData(
|
|||
// for Java
|
||||
constructor(customerId: String, pin: String) : this(customerId, pin, customerId)
|
||||
|
||||
internal constructor() : this("", "") // for object deserializers
|
||||
|
||||
|
||||
val isTanProcedureSelected: Boolean
|
||||
get() = selectedTanProcedure != TanProcedureNotSelected
|
||||
|
@ -50,6 +52,10 @@ open class CustomerData(
|
|||
(accounts as? MutableList)?.add(account)
|
||||
}
|
||||
|
||||
open fun removeAccount(account: AccountData) {
|
||||
(accounts as? MutableList)?.remove(account)
|
||||
}
|
||||
|
||||
|
||||
override fun toString(): String {
|
||||
return customerId
|
||||
|
|
|
@ -9,6 +9,10 @@ open class TanProcedure(
|
|||
val type: TanProcedureType
|
||||
) {
|
||||
|
||||
|
||||
internal constructor() : this("", Sicherheitsfunktion.Einschritt_Verfahren, TanProcedureType.EnterTan) // for object deserializers
|
||||
|
||||
|
||||
override fun toString(): String {
|
||||
return "$displayName ($type, ${securityFunction.code})"
|
||||
}
|
||||
|
|
|
@ -6,11 +6,14 @@ open class JobParameters(
|
|||
val maxCountJobs: Int,
|
||||
val minimumCountSignatures: Int,
|
||||
val securityClass: Int?,
|
||||
segmentString: String
|
||||
segmentString: String // TODO: when serializing / deserializing we don't care for segment string -> remove it
|
||||
)
|
||||
: ReceivedSegment(segmentString) {
|
||||
|
||||
|
||||
internal constructor() : this("", 0, 0, null, "0:0:0") // for object deserializers
|
||||
|
||||
|
||||
constructor(parameters: JobParameters)
|
||||
: this(parameters.jobName, parameters.maxCountJobs, parameters.minimumCountSignatures,
|
||||
parameters.securityClass, parameters.segmentString)
|
||||
|
|
Loading…
Reference in New Issue