2024-08-22 15:07:02 +00:00
# Banking Client
Library to abstract over different banking client implementations like [fints4k ](https://git.dankito.net/codinux/fints4k ).
It's primary purpose is to abstract away the different implementation details and to create a common model that can be
used in all projects directly or indirectly referencing it - Web Service, Middleware, Native Apps, HTML Apps - so that
not each project has the implement to model again.
## Setup
### Gradle:
```
plugins {
kotlin("jvm") version "2.0.10" // or kotlin("multiplatform"), depending on your requirements
}
repositories {
mavenCentral()
maven {
setUrl("https://maven.dankito.net/api/packages/codinux/maven")
}
}
dependencies {
implementation("net.codinux.banking.client:fints4k-banking-client:0.5.0")
}
```
## Usage
2024-08-22 16:23:44 +00:00
For the full example source code see [ShowUsage ](SampleApp/src/main/kotlin/net/codinux/banking/client/fints4k/example/ShowUsage.kt ).
2024-08-22 15:07:02 +00:00
### Get AccountData
Retrieves data like accounts, balance and booked transactions (Konten, Saldo und Kontoumsätze).
2024-08-22 16:23:44 +00:00
Simple example:
2024-08-22 15:07:02 +00:00
```kotlin
class ShowUsage {
private val bankCode = "" // Bankleitzahl deiner Bank
private val loginName = "" // Online-Banking Login Name mit dem du dich beim Online-Banking deiner Bank anmeldest
private val password = "" // Online-Banking Password mit dem du dich beim Online-Banking deiner Bank anmeldest
fun getAccountData() {
2024-09-03 20:53:26 +00:00
val client = FinTs4kBankingClient(SimpleBankingClientCallback())
2024-08-22 15:07:02 +00:00
2024-09-03 20:53:26 +00:00
val response = client.getAccountData(bankCode, loginName, password) // that's all
2024-08-22 16:23:44 +00:00
2024-09-03 20:53:26 +00:00
printReceivedData(response) // now print retrieved data (save it to database, display it in UI, ...)
2024-08-22 16:23:44 +00:00
}
private fun printReceivedData(response: Response< GetAccountDataResponse > ) {
2024-08-22 15:07:02 +00:00
response.data?.let { data ->
2024-08-27 21:53:15 +00:00
val user = data.user
println("Kunde: ${user.customerName} ${user.accounts.size} Konten @ ${user.bic} ${user.bankName}")
2024-08-22 15:07:02 +00:00
println()
println("Konten:")
2024-08-27 21:53:15 +00:00
user.accounts.sortedBy { it.type }.forEach { account ->
2024-08-22 15:07:02 +00:00
println("${account.identifier} ${account.productName} ${account.balance} ${account.currency}")
}
println()
println("Umsätze:")
data.bookedTransactions.forEach { transaction ->
println("${transaction.valueDate} ${transaction.amount} ${transaction.currency} ${transaction.otherPartyName ?: ""} - ${transaction.reference}")
}
}
}
}
```
This fetches the booked account transactions of the last 90 days. In most cases no TAN is required for this.
2024-08-22 16:23:44 +00:00
You can also specify options e.g. which transactions should be retrieved:
```kotlin
val options = GetAccountDataOptions(
retrieveBalance = true, // retrieve balance (Saldo / Kontostand) yes or no
retrieveTransactions = RetrieveTransactions.AccordingToRetrieveFromAndTo, // so that fromDate and toDate below determine of which time period transactions (Umsätze) should be retrieved; defaults to OfLast90Days which in most cases doesn't require a TAN
retrieveTransactionsFrom = LocalDate(2023, 1, 1),
retrieveTransactionsTo = LocalDate(2023, 12, 31),
abortIfTanIsRequired = false // e.g. for command line application when entering TAN is either not possible or a TAN procedure is used that cannot be handled via a break point (e.g. showing a TAN image or flicker code)
)
val response = client.getAccountData(options)
```
2024-09-03 20:53:26 +00:00
Retrieving transactions older than 90 days requires a TAN, so add TAN handling in Client Callback:
```kotlin
val client = FinTs4kBankingClientForUser(bankCode, loginName, password, SimpleBankingClientCallback { tanChallenge, callback ->
val tan: String? = null // if a TAN is required, add a UI or ...
callback.invoke(EnterTanResult(tan)) // ... set a break point here, get TAN e.g. from your TAN app, set tan variable in debugger view and resume debugger
})
```
2024-08-22 15:07:02 +00:00
Add some error handling by checking `response.error` :
```kotlin
response.error?.let{ error ->
println("Could not fetch account data: ${error.internalError ?: error.errorMessagesFromBank.joinToString()}")
}
2024-09-03 20:53:26 +00:00
```
### Update Account Transactions
2024-09-11 21:21:06 +00:00
The data model saves when it retrieved account transactions the last time (in `BankAccount.lastAccountUpdateTime` ).
2024-09-03 20:53:26 +00:00
So you only need to call `FinTs4kBankingClient.updateAccountTransactions()` to retrieve all transactions starting from
2024-09-11 21:21:06 +00:00
`BankAccount.lastAccountUpdateTime` .
2024-09-03 20:53:26 +00:00
But as we can only specify from which day on account transactions should be retrieved, response may contain some transactions
2024-09-11 21:21:06 +00:00
from the day of `lastAccountUpdateTime` that we already have locally. To filter out these you can use
2024-09-03 20:53:26 +00:00
`BankingModelService().findNewTransactions(retrieveTransactions, existingTransactions)` :
```kotlin
fun updateAccountTransactions() {
val client = FinTs4kBankingClientForUser(bankCode, loginName, password, SimpleBankingClientCallback())
// simulate account transactions we retrieved last time
val today = Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault()).date
val lastCallToBankServer = client.getAccountData(GetAccountDataOptions(RetrieveTransactions.AccordingToRetrieveFromAndTo, retrieveTransactionsFrom = today.minusDays(90), retrieveTransactionsTo = today.minusDays(30)))
if (lastCallToBankServer.data != null) { // now update account transactions
val existingTransactions = lastCallToBankServer.data!!.bookedTransactions
val updateTransactionsResponse = client.updateAccountTransactions()
if (updateTransactionsResponse.data != null) {
val retrievedTransactions = updateTransactionsResponse.data!!.flatMap { it.bookedTransactions }
val newTransactions = BankingModelService().findNewTransactions(retrievedTransactions, existingTransactions)
// `retrievedTransactions` may contain transactions we already have locally, `newTransactions` only
// transactions that are not in `existingTransactions`
}
}
}
2024-08-22 15:07:02 +00:00
```