Added IBankingClient to abstract away fints4java in UI and implemented fints4javaBankingClient

This commit is contained in:
dankl 2020-01-02 22:39:02 +01:00 committed by dankito
parent 0d60cd2c3e
commit b7e294bcbe
12 changed files with 196 additions and 48 deletions

View File

@ -0,0 +1,23 @@
package net.dankito.banking.ui
import net.dankito.banking.ui.model.BankAccount
import net.dankito.banking.ui.model.parameters.GetTransactionsParameter
import net.dankito.banking.ui.model.parameters.TransferMoneyData
import net.dankito.banking.ui.model.responses.AddAccountResponse
import net.dankito.banking.ui.model.responses.BankingClientResponse
import net.dankito.banking.ui.model.responses.GetTransactionsResponse
interface IBankingClient {
fun addAccountAsync(callback: (AddAccountResponse) -> Unit)
fun getTransactionsAsync(
bankAccount: BankAccount,
parameter: GetTransactionsParameter,
callback: (GetTransactionsResponse) -> Unit
)
fun transferMoneyAsync(data: TransferMoneyData, callback: (BankingClientResponse) -> Unit)
}

View File

@ -0,0 +1,14 @@
package net.dankito.banking.ui.model.parameters
import java.util.*
open class GetTransactionsParameter(
val alsoRetrieveBalance: Boolean = true,
val fromDate: Date? = null,
val toDate: Date? = null
) {
constructor() : this(true, null, null) // for Java
}

View File

@ -0,0 +1,12 @@
package net.dankito.banking.ui.model.parameters
import java.math.BigDecimal
open class TransferMoneyData(
val creditorName: String,
val creditorIban: String,
val creditorBic: String,
val amount: BigDecimal,
val usage: String
)

View File

@ -48,8 +48,10 @@ android {
}
dependencies {
implementation project(':fints4javaBankingClient')
// TODO: try to get rid of this import
implementation project(':fints4javaLib')
implementation project(':BankingUiCommon')
api "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion"

View File

@ -8,7 +8,7 @@ import android.support.v7.app.AppCompatActivity
import android.support.v7.widget.Toolbar
import android.view.Menu
import androidx.navigation.findNavController
import net.dankito.banking.fints4java.android.mapper.fints4javaModelMapper
import net.dankito.banking.mapper.fints4javaModelMapper
import net.dankito.banking.fints4java.android.ui.MainWindowPresenter
import net.dankito.banking.fints4java.android.ui.dialogs.AddAccountDialog
import net.dankito.banking.fints4java.android.ui.dialogs.EnterAtcDialog
@ -110,7 +110,7 @@ class MainActivity : AppCompatActivity() {
runOnUiThread {
// TODO: don't create a fints4javaModelMapper instance here, let MainWindowPresenter do the job
EnterAtcDialog().show(fints4javaModelMapper().mapTanMedium(tanMedium), this@MainActivity, false) { enteredResult ->
EnterAtcDialog().show(net.dankito.banking.mapper.fints4javaModelMapper().mapTanMedium(tanMedium), this@MainActivity, false) { enteredResult ->
result.set(enteredResult)
tanEnteredLatch.countDown()
}

View File

@ -1,22 +1,22 @@
package net.dankito.banking.fints4java.android.ui
import net.dankito.banking.ui.IBankingClient
import net.dankito.banking.ui.model.Account
import net.dankito.banking.ui.model.AccountTransaction
import net.dankito.banking.ui.model.BankAccount
import net.dankito.banking.ui.model.parameters.TransferMoneyData
import net.dankito.banking.ui.model.responses.AddAccountResponse
import net.dankito.banking.ui.model.responses.BankingClientResponse
import net.dankito.banking.ui.model.responses.GetTransactionsResponse
import net.dankito.fints.FinTsClientCallback
import net.dankito.fints.FinTsClientForCustomer
import net.dankito.fints.banks.BankFinder
import net.dankito.fints.model.BankInfo
import net.dankito.fints.model.BankTransferData
import net.dankito.fints.model.CustomerData
import net.dankito.fints.model.GetTransactionsParameter
import net.dankito.fints.model.mapper.BankDataMapper
import net.dankito.fints.response.client.FinTsClientResponse
import net.dankito.fints.util.IBase64Service
import net.dankito.utils.IThreadPool
import net.dankito.utils.ThreadPool
import net.dankito.utils.web.client.OkHttpWebClient
import java.math.BigDecimal
import java.util.*
import kotlin.collections.ArrayList
@ -26,32 +26,32 @@ open class MainWindowPresenter(protected val base64Service: IBase64Service,
protected val callback: FinTsClientCallback
) {
companion object {
protected const val OneDayMillis = 24 * 60 * 60 * 1000
}
protected val bankFinder: BankFinder = BankFinder()
protected val threadPool: IThreadPool = ThreadPool()
protected val bankDataMapper = BankDataMapper()
protected val fints4javaModelMapper = net.dankito.banking.fints4java.android.mapper.fints4javaModelMapper()
protected val fints4javaModelMapper = net.dankito.banking.mapper.fints4javaModelMapper()
protected val accounts = mutableMapOf<Account, FinTsClientForCustomer>()
protected val accounts = mutableMapOf<Account, IBankingClient>()
protected val accountAddedListeners = mutableListOf<(Account) -> Unit>()
protected val retrievedAccountTransactionsResponseListeners = mutableListOf<(BankAccount, GetTransactionsResponse) -> Unit>()
open fun addAccountAsync(bankInfo: BankInfo, customerId: String, pin: String,
callback: (AddAccountResponse) -> Unit) {
// TODO: move BankInfo out of fints4javaLib
open fun addAccountAsync(bankInfo: BankInfo, customerId: String, pin: String, callback: (AddAccountResponse) -> Unit) {
val bank = bankDataMapper.mapFromBankInfo(bankInfo)
val customer = CustomerData(customerId, pin)
val newClient = FinTsClientForCustomer(bank, customer, this.callback, base64Service)
val newClient = net.dankito.banking.fints4javaBankingClient(bankInfo, customerId, pin, OkHttpWebClient(), base64Service, threadPool, this.callback)
newClient.addAccountAsync { response ->
val account = fints4javaModelMapper.mapAccount(customer, bank)
val mappedResponse = fints4javaModelMapper.mapResponse(account, response)
val account = response.account
if (response.isSuccessful) {
accounts.put(account, newClient)
@ -60,12 +60,12 @@ open class MainWindowPresenter(protected val base64Service: IBase64Service,
if (response.supportsRetrievingTransactionsOfLast90DaysWithoutTan) {
account.bankAccounts.forEach { bankAccount ->
retrievedAccountTransactions(bankAccount, mappedResponse)
retrievedAccountTransactions(bankAccount, response)
}
}
}
callback(mappedResponse)
callback(response)
}
}
@ -88,13 +88,11 @@ open class MainWindowPresenter(protected val base64Service: IBase64Service,
callback: (GetTransactionsResponse) -> Unit) {
getClientForAccount(bankAccount.account)?.let { client ->
client.getTransactionsAsync(GetTransactionsParameter(true, fromDate)) { response ->
client.getTransactionsAsync(bankAccount, net.dankito.banking.ui.model.parameters.GetTransactionsParameter(true, fromDate)) { response ->
val mappedResponse = fints4javaModelMapper.mapResponse(bankAccount.account, response)
retrievedAccountTransactions(bankAccount, response)
retrievedAccountTransactions(bankAccount, mappedResponse)
callback(mappedResponse)
callback(response)
}
}
}
@ -104,7 +102,7 @@ open class MainWindowPresenter(protected val base64Service: IBase64Service,
account.bankAccounts.forEach { bankAccount ->
val today = Date() // TODO: still don't know where this bug is coming from that bank returns a transaction dated at end of year
val lastRetrievedTransactionDate = bankAccount.bookedTransactions.firstOrNull { it.bookingDate <= today }?.bookingDate
val fromDate = lastRetrievedTransactionDate?.let { Date(it.time - 24 * 60 * 60 * 1000) } // on day before last received transaction
val fromDate = lastRetrievedTransactionDate?.let { Date(it.time - OneDayMillis) } // one day before last received transaction
getAccountTransactionsAsync(bankAccount, fromDate, callback)
}
@ -135,9 +133,9 @@ open class MainWindowPresenter(protected val base64Service: IBase64Service,
}
open fun transferMoneyAsync(bankAccount: BankAccount, bankTransferData: BankTransferData, callback: (FinTsClientResponse) -> Unit) {
open fun transferMoneyAsync(bankAccount: BankAccount, data: TransferMoneyData, callback: (BankingClientResponse) -> Unit) {
getClientForAccount(bankAccount.account)?.let { client ->
client.doBankTransferAsync(bankTransferData, callback)
client.transferMoneyAsync(data, callback)
}
}
@ -180,13 +178,14 @@ open class MainWindowPresenter(protected val base64Service: IBase64Service,
}
protected open fun getClientForAccount(account: Account): FinTsClientForCustomer? {
protected open fun getClientForAccount(account: Account): IBankingClient? {
accounts.get(account)?.let { client ->
account.selectedTanProcedure?.let { selectedTanProcedure ->
client.customer.selectedTanProcedure = fints4javaModelMapper.mapTanProcedureBack(selectedTanProcedure)
}
// TODO: is this code still needed after updating data model is implemented?
// account.selectedTanProcedure?.let { selectedTanProcedure ->
// client.customer.selectedTanProcedure = fints4javaModelMapper.mapTanProcedureBack(selectedTanProcedure)
// }
return client // TODO: return IBankingClient
return client
}
return null

View File

@ -14,10 +14,11 @@ import kotlinx.android.synthetic.main.dialog_bank_transfer.view.*
import net.dankito.banking.fints4java.android.R
import net.dankito.banking.fints4java.android.ui.MainWindowPresenter
import net.dankito.banking.ui.model.BankAccount
import net.dankito.banking.ui.model.parameters.TransferMoneyData
import net.dankito.banking.ui.model.responses.BankingClientResponse
import net.dankito.fints.messages.segmente.implementierte.sepa.ISepaMessageCreator
import net.dankito.fints.messages.segmente.implementierte.sepa.SepaMessageCreator
import net.dankito.fints.model.BankTransferData
import net.dankito.fints.response.client.FinTsClientResponse
import net.dankito.utils.android.extensions.asActivity
import java.math.BigDecimal
@ -109,7 +110,7 @@ open class BankTransferDialog : DialogFragment() {
protected open fun transferMoney() {
getEnteredAmount()?.let { amount -> // should only come at this stage when a valid amount has been entered
val transferData = BankTransferData(
val data = TransferMoneyData(
edtxtRemitteeName.text.toString(),
edtxtRemitteeIban.text.toString(),
edtxtRemitteeBic.text.toString(),
@ -117,15 +118,15 @@ open class BankTransferDialog : DialogFragment() {
edtxtUsage.text.toString()
)
presenter.transferMoneyAsync(bankAccount, transferData) {
presenter.transferMoneyAsync(bankAccount, data) {
context?.asActivity()?.runOnUiThread {
handleTransferMoneyResultOnUiThread(it, transferData)
handleTransferMoneyResultOnUiThread(data, it)
}
}
}
}
protected open fun handleTransferMoneyResultOnUiThread(response: FinTsClientResponse, transferData: BankTransferData) {
protected open fun handleTransferMoneyResultOnUiThread(transferData: TransferMoneyData, response: BankingClientResponse) {
context?.let { context ->
val message = if (response.isSuccessful) {
context.getString(R.string.dialog_bank_transfer_message_transfer_successful,
@ -134,7 +135,7 @@ open class BankTransferDialog : DialogFragment() {
else {
context.getString(R.string.dialog_bank_transfer_message_transfer_failed,
String.format("%.02f", transferData.amount), "", transferData.creditorName, // TODO: where to get currency from?
presenter.getErrorToShowToUser(response)
response.errorToShowToUser
)
}

View File

@ -15,7 +15,7 @@ import android.widget.Spinner
import kotlinx.android.synthetic.main.dialog_enter_tan.view.*
import kotlinx.android.synthetic.main.view_tan_image.view.*
import net.dankito.banking.fints4java.android.R
import net.dankito.banking.fints4java.android.mapper.fints4javaModelMapper
import net.dankito.banking.mapper.fints4javaModelMapper
import net.dankito.banking.fints4java.android.ui.MainWindowPresenter
import net.dankito.banking.fints4java.android.ui.adapter.TanMediumAdapter
import net.dankito.banking.fints4java.android.ui.adapter.TanProceduresAdapter
@ -96,7 +96,7 @@ open class EnterTanDialog : DialogFragment() {
spinner.onItemSelectedListener = ListItemSelectedListener(adapter) { newSelectedTanProcedure ->
if (newSelectedTanProcedure != selectedTanProcedure) {
val mappedTanProcedure = fints4javaModelMapper().mapTanProcedureBack(newSelectedTanProcedure) // TODO: move to MainWindowPresenter
val mappedTanProcedure = net.dankito.banking.mapper.fints4javaModelMapper().mapTanProcedureBack(newSelectedTanProcedure) // TODO: move to MainWindowPresenter
tanEnteredCallback(EnterTanResult.userAsksToChangeTanProcedure(mappedTanProcedure))
// TODO: find a way to update account.selectedTanProcedure afterwards

View File

@ -0,0 +1,23 @@
apply plugin: 'java-library'
apply plugin: 'kotlin'
sourceCompatibility = "1.7"
targetCompatibility = "1.7"
compileKotlin {
kotlinOptions.jvmTarget = "1.6"
}
compileTestKotlin {
kotlinOptions.jvmTarget = "1.6"
}
dependencies {
api project(':BankingUiCommon')
implementation project(':fints4javaLib')
testImplementation "junit:junit:$junitVersion"
testImplementation "org.assertj:assertj-core:$assertJVersion"
}

View File

@ -0,0 +1,70 @@
package net.dankito.banking
import net.dankito.banking.ui.IBankingClient
import net.dankito.banking.ui.model.BankAccount
import net.dankito.banking.ui.model.parameters.GetTransactionsParameter
import net.dankito.banking.ui.model.parameters.TransferMoneyData
import net.dankito.banking.ui.model.responses.AddAccountResponse
import net.dankito.banking.ui.model.responses.BankingClientResponse
import net.dankito.banking.ui.model.responses.GetTransactionsResponse
import net.dankito.fints.FinTsClientCallback
import net.dankito.fints.FinTsClientForCustomer
import net.dankito.fints.model.BankInfo
import net.dankito.fints.model.BankTransferData
import net.dankito.fints.model.CustomerData
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.web.client.IWebClient
import net.dankito.utils.web.client.OkHttpWebClient
open class fints4javaBankingClient(
bankInfo: BankInfo,
customerId: String,
pin: String,
webClient: IWebClient = OkHttpWebClient(),
base64Service: IBase64Service,
threadPool: IThreadPool = ThreadPool(),
callback: FinTsClientCallback
) : IBankingClient {
protected val mapper = net.dankito.banking.mapper.fints4javaModelMapper()
protected val bankDataMapper = BankDataMapper()
protected val bank = bankDataMapper.mapFromBankInfo(bankInfo)
protected val customer = CustomerData(customerId, pin)
protected val client = FinTsClientForCustomer(bank, customer, webClient, base64Service, threadPool, callback)
override fun addAccountAsync(callback: (AddAccountResponse) -> Unit) {
client.addAccountAsync { response ->
val account = mapper.mapAccount(customer, bank)
val mappedResponse = mapper.mapResponse(account, response)
callback(mappedResponse)
}
}
override fun getTransactionsAsync(bankAccount: BankAccount, parameter: GetTransactionsParameter, callback: (GetTransactionsResponse) -> Unit) {
client.getTransactionsAsync(net.dankito.fints.model.GetTransactionsParameter(parameter.alsoRetrieveBalance, parameter.fromDate, parameter.toDate)) { response ->
val mappedResponse = mapper.mapResponse(bankAccount, response)
callback(mappedResponse)
}
}
override fun transferMoneyAsync(data: TransferMoneyData, callback: (BankingClientResponse) -> Unit) {
val mappedData = BankTransferData(data.creditorName, data.creditorIban, data.creditorBic, data.amount, data.usage)
client.doBankTransferAsync(mappedData) { response ->
callback(mapper.mapResponse(response))
}
}
}

View File

@ -1,7 +1,8 @@
package net.dankito.banking.fints4java.android.mapper
package net.dankito.banking.mapper
import net.dankito.banking.ui.model.*
import net.dankito.banking.ui.model.responses.AddAccountResponse
import net.dankito.banking.ui.model.responses.BankingClientResponse
import net.dankito.banking.ui.model.responses.GetTransactionsResponse
import net.dankito.fints.messages.datenelemente.implementierte.signatur.Sicherheitsfunktion
import net.dankito.fints.messages.datenelemente.implementierte.tan.TanGeneratorTanMedium
@ -129,7 +130,11 @@ open class fints4javaModelMapper {
}
fun mapResponse(account: Account, response: net.dankito.fints.response.client.AddAccountResponse): AddAccountResponse {
open fun mapResponse(response: FinTsClientResponse): BankingClientResponse {
return BankingClientResponse(response.isSuccessful, mapErrorToShowToUser(response))
}
open fun mapResponse(account: Account, response: net.dankito.fints.response.client.AddAccountResponse): AddAccountResponse {
var bookedTransactions = mapOf<BankAccount, List<AccountTransaction>>()
var balances = mapOf<BankAccount, BigDecimal>()
@ -145,8 +150,7 @@ open class fints4javaModelMapper {
balances)
}
fun mapResponse(account: Account, response: net.dankito.fints.response.client.GetTransactionsResponse): GetTransactionsResponse {
val bankAccount = account.bankAccounts.first() // TODO: set bank account also on net.dankito.fints.response.client.GetTransactionsResponse
open fun mapResponse(bankAccount: BankAccount, response: net.dankito.fints.response.client.GetTransactionsResponse): GetTransactionsResponse {
return GetTransactionsResponse(response.isSuccessful, mapErrorToShowToUser(response),
mapOf(bankAccount to mapTransactions(bankAccount, response.bookedTransactions)),

View File

@ -18,13 +18,13 @@ import net.dankito.utils.web.client.OkHttpWebClient
open class FinTsClientForCustomer(
val bank: BankData,
val customer: CustomerData,
callback: FinTsClientCallback,
base64Service: IBase64Service,
webClient: IWebClient = OkHttpWebClient(),
base64Service: IBase64Service,
threadPool: IThreadPool = ThreadPool(),
callback: FinTsClientCallback,
messageBuilder: MessageBuilder = MessageBuilder(),
responseParser: ResponseParser = ResponseParser(),
mt940Parser: IAccountTransactionsParser = Mt940AccountTransactionsParser(),
threadPool: IThreadPool = ThreadPool(),
product: ProductData = ProductData("15E53C26816138699C7B6A3E8", "0.1") // TODO: get version dynamically
) {