Compare commits

..

3 Commits

4 changed files with 48 additions and 15 deletions

View File

@ -21,7 +21,7 @@ open class TanChallenge(
* As [availableTanMethods] also contains selected TanMethod, we didn't want to duplicate this object. Use
* [selectedTanMethod] to get selected TanMethod or iterate over [availableTanMethods] and filter selected one by this id.
*/
open val selectedTanMethodId: String,
open val selectedTanMethodIdentifier: String,
/**
* When adding an account, frontend has no UserAccount object in BankingClientCallback to know which TanMethods are
* available for user.
@ -38,7 +38,7 @@ open class TanChallenge(
* As [availableTanMedia] also contains selected TanMedium, we didn't want to duplicate this object. Use
* [selectedTanMedium] to get selected TanMedium or iterate over [availableTanMedia] and filter selected one by this medium name.
*/
open val selectedTanMediumName: String? = null,
open val selectedTanMediumIdentifier: String? = null,
open val availableTanMedia: List<TanMedium> = emptyList(),
open val tanImage: TanImage? = null,
@ -56,11 +56,11 @@ open class TanChallenge(
@get:JsonIgnore
open val selectedTanMethod: TanMethod
get() = availableTanMethods.first { it.identifier == selectedTanMethodId }
get() = availableTanMethods.first { it.identifier == selectedTanMethodIdentifier }
@get:JsonIgnore
open val selectedTanMedium: TanMedium?
get() = availableTanMedia.firstOrNull { it.mediumName == selectedTanMediumName }
get() = availableTanMedia.firstOrNull { it.mediumName == selectedTanMediumIdentifier }
/**

View File

@ -292,11 +292,11 @@ open class FinTs4kMapper {
val action = mapActionRequiringTan(challenge.forAction)
val tanMethods = challenge.bank.tanMethodsAvailableForUser.map { mapTanMethod(it) }
val selectedTanMethodId = challenge.tanMethod.securityFunction.code
val selectedTanMethodIdentifier = challenge.tanMethod.securityFunction.code
val tanMedia = challenge.bank.tanMedia.map { mapTanMedium(it) }
// TanMedium has not natural id in FinTS model so we have to create our own one
val selectedTanMediumName = challenge.bank.selectedTanMedium?.let { selected -> tanMedia.firstOrNull { it == selected } }?.identifier
val selectedTanMediumIdentifier = challenge.bank.selectedTanMedium?.let { selected -> tanMedia.firstOrNull { it == selected } }?.identifier
val bank = mapToBankViewInfo(challenge.bank)
val account = challenge.account?.let { mapToBankAccountViewInfo(it) }
@ -304,7 +304,7 @@ open class FinTs4kMapper {
val tanImage = if (challenge is ImageTanChallenge) mapTanImage(challenge.image) else null
val flickerCode = if (challenge is FlickerCodeTanChallenge) mapFlickerCode(challenge.flickerCode) else null
return object : TanChallenge(type, action, challenge.messageToShowToUser, selectedTanMethodId, tanMethods, selectedTanMediumName, tanMedia, tanImage, flickerCode, bank, account, challenge.tanExpirationTime, challenge.challengeCreationTimestamp) {
return object : TanChallenge(type, action, challenge.messageToShowToUser, selectedTanMethodIdentifier, tanMethods, selectedTanMediumIdentifier, tanMedia, tanImage, flickerCode, bank, account, challenge.tanExpirationTime, challenge.challengeCreationTimestamp) {
override fun addTanExpiredCallback(callback: () -> Unit) {
challenge.addTanExpiredCallback(callback)
}

View File

@ -82,7 +82,10 @@ class ShowUsage {
This fetches the booked account transactions of the last 90 days. In most cases no TAN is required for this.
You can also specify options e.g. which transactions should be retrieved:
#### GetAccountData parameter
You can also specify options e.g. which transactions you would like to retrieve:
```kotlin
val options = GetAccountDataOptions(
@ -95,20 +98,40 @@ val options = GetAccountDataOptions(
val response = client.getAccountData(options)
```
Retrieving transactions older than 90 days requires a TAN, so add TAN handling in Client Callback:
#### TAN handling
Retrieving transactions older than 90 days or sometimes even log in 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 ...
val tan: String? = null // if a TAN is required, read TAN from command line, add a UI, ...
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
})
```
E.g. TAN handling on the command line:
```kotlin
println("Enter password for $bankCode:")
val password = readln() // as an alternative for hard coding password; of course can also be done for bankCode and login name
val client = FinTs4kBankingClientForUser(bankCode, loginName, password, SimpleBankingClientCallback { tanChallenge, callback ->
println("A TAN is required for ${tanChallenge.forAction}. Selected TAN method is '${tanChallenge.selectedTanMethod.displayName}'. Messsage of your credit institute:")
println(tanChallenge.messageToShowToUser)
println("Get TAN from your TAN app etc., enter it and press Enter (or press Enter without an input to abort process):")
val tan: String? = readlnOrNull().takeUnless { it.isNullOrBlank() } // map empty input to null to abort process
callback.invoke(EnterTanResult(tan))
})
```
#### Error handling
Add some error handling by checking `response.error`:
```kotlin
response.error?.let{ error ->
println("Could not fetch account data: ${error.internalError ?: error.errorMessagesFromBank.joinToString()}")
println("Could not fetch account data: ${error.type} ${error.internalError ?: error.errorMessagesFromBank.joinToString()}")
}
```

View File

@ -42,9 +42,16 @@ class ShowUsage {
}
fun getAccountDataFullExample() {
println("Enter password for $bankCode:")
val password = readln() // as an alternative for hard coding password; of course can also be done for bankCode and login name
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
println("A TAN is required for ${tanChallenge.forAction}. Selected TAN method is '${tanChallenge.selectedTanMethod.displayName}'. Messsage of your credit institute:")
println(tanChallenge.messageToShowToUser)
println("Get TAN from your TAN app etc., enter it and press Enter (or press Enter without an input to abort process):")
val tan: String? = readlnOrNull().takeUnless { it.isNullOrBlank() } // map empty input to null to abort process
callback.invoke(EnterTanResult(tan))
})
val options = GetAccountDataOptions(
@ -57,7 +64,7 @@ class ShowUsage {
val response = client.getAccountData(options)
response.error?.let{ error ->
println("Could not fetch account data: ${error.internalError ?: error.errorMessagesFromBank.joinToString()}")
println("Could not fetch account data: ${error.type} ${error.internalError ?: error.errorMessagesFromBank.joinToString()}")
}
printReceivedData(response)
@ -65,7 +72,10 @@ class ShowUsage {
fun updateAccountTransactions() {
val client = FinTs4kBankingClientForUser(bankCode, loginName, password, SimpleBankingClientCallback())
val client = FinTs4kBankingClientForUser(bankCode, loginName, password, SimpleBankingClientCallback { tanChallenge, callback ->
val tan: String? = readlnOrNull() // if a TAN is required, read TAN from command line, add a UI, ...
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
})
// simulate account transactions we retrieved last time
val today = Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault()).date