Re-added askUserForTanProcedure() so user (also that one of the library) really has a change to select a TAN procedure. As default selection otherwise gets hidden deep inside fints4java lib and if library user's enter tan dialog does not support selecting TAN procedure user would never have the choice to select her preferred procedure.

This commit is contained in:
dankl 2020-01-19 16:50:26 +01:00 committed by dankito
parent 954db89e2f
commit e5d04fc3c8
5 changed files with 55 additions and 11 deletions

View File

@ -44,6 +44,12 @@ open class fints4javaBankingClient(
protected val client = FinTsClientForCustomer(bank, customer, webClient, base64Service, threadPool, object : FinTsClientCallback { protected val client = FinTsClientForCustomer(bank, customer, webClient, base64Service, threadPool, object : FinTsClientCallback {
override fun askUserForTanProcedure(supportedTanProcedures: List<TanProcedure>, suggestedTanProcedure: TanProcedure?): TanProcedure? {
// we simply return suggestedTanProcedure as even so it's not user's preferred TAN procedure she still can select it in EnterTanDialog
return suggestedTanProcedure
}
override fun enterTan(customer: CustomerData, tanChallenge: TanChallenge): EnterTanResult { override fun enterTan(customer: CustomerData, tanChallenge: TanChallenge): EnterTanResult {
mapper.updateTanMediaAndProcedures(account, customer) mapper.updateTanMediaAndProcedures(account, customer)

View File

@ -138,6 +138,15 @@ open class FinTsClient @JvmOverloads constructor(
} }
// do not ask user for tan at this stage
var didOverwriteUserUnselectedTanProcedure = false
if (customer.isTanProcedureSelected == false && customer.supportedTanProcedures.isNotEmpty()) {
didOverwriteUserUnselectedTanProcedure = true
customer.selectedTanProcedure = customer.supportedTanProcedures.first()
}
val synchronizeCustomerResponse = synchronizeCustomerSystemId(bank, customer) val synchronizeCustomerResponse = synchronizeCustomerSystemId(bank, customer)
getTanMediaList(bank, customer, TanMedienArtVersion.Alle, TanMediumKlasse.AlleMedien) getTanMediaList(bank, customer, TanMedienArtVersion.Alle, TanMediumKlasse.AlleMedien)
@ -145,6 +154,10 @@ open class FinTsClient @JvmOverloads constructor(
// also check if retrieving account transactions of last 90 days without tan is supported (and thereby may retrieve first account transactions) // also check if retrieving account transactions of last 90 days without tan is supported (and thereby may retrieve first account transactions)
val transactionsOfLast90DaysResponse = tryGetTransactionsOfLast90DaysWithoutTan(bank, customer, false) val transactionsOfLast90DaysResponse = tryGetTransactionsOfLast90DaysWithoutTan(bank, customer, false)
if (didOverwriteUserUnselectedTanProcedure) {
customer.resetSelectedTanProcedure()
}
return AddAccountResponse(synchronizeCustomerResponse.toResponse(), bank, customer, return AddAccountResponse(synchronizeCustomerResponse.toResponse(), bank, customer,
transactionsOfLast90DaysResponse.isSuccessful, transactionsOfLast90DaysResponse.isSuccessful,
transactionsOfLast90DaysResponse.bookedTransactions, transactionsOfLast90DaysResponse.bookedTransactions,
@ -519,11 +532,21 @@ open class FinTsClient @JvmOverloads constructor(
if (customer.supportedTanProcedures.isEmpty()) { // could not retrieve supported tan procedures for user if (customer.supportedTanProcedures.isEmpty()) { // could not retrieve supported tan procedures for user
return Response(false, noTanProcedureSelected = true) return Response(false, noTanProcedureSelected = true)
} }
// we know user's supported tan procedures, now ask user which one to select
callback.askUserForTanProcedure(customer.supportedTanProcedures, selectSuggestedTanProcedure(customer))?.let {
customer.selectedTanProcedure = it
}
} }
return Response(customer.isTanProcedureSelected, noTanProcedureSelected = !!!customer.isTanProcedureSelected) return Response(customer.isTanProcedureSelected, noTanProcedureSelected = !!!customer.isTanProcedureSelected)
} }
protected open fun selectSuggestedTanProcedure(customer: CustomerData): TanProcedure? {
return customer.supportedTanProcedures.firstOrNull { it.displayName.contains("manuell", true) == false }
?: customer.supportedTanProcedures.firstOrNull()
}
protected open fun getAndHandleResponseForMessageThatMayRequiresTan(message: MessageBuilderResult, bank: BankData, protected open fun getAndHandleResponseForMessageThatMayRequiresTan(message: MessageBuilderResult, bank: BankData,
customer: CustomerData, dialogData: DialogData): Response { customer: CustomerData, dialogData: DialogData): Response {
@ -828,13 +851,6 @@ open class FinTsClient @JvmOverloads constructor(
if (response.supportedTanProceduresForUser.isNotEmpty()) { if (response.supportedTanProceduresForUser.isNotEmpty()) {
customer.supportedTanProcedures = response.supportedTanProceduresForUser.mapNotNull { findTanProcedure(it, bank) } customer.supportedTanProcedures = response.supportedTanProceduresForUser.mapNotNull { findTanProcedure(it, bank) }
if (customer.isTanProcedureSelected == false) {
(customer.supportedTanProcedures.firstOrNull { it.displayName.contains("manuell", true) == false }
?: customer.supportedTanProcedures.firstOrNull())?.let {
customer.selectedTanProcedure = it
}
}
} }
} }

View File

@ -1,18 +1,29 @@
package net.dankito.fints package net.dankito.fints
import net.dankito.fints.messages.datenelemente.implementierte.tan.TanGeneratorTanMedium import net.dankito.fints.messages.datenelemente.implementierte.tan.TanGeneratorTanMedium
import net.dankito.fints.model.CustomerData import net.dankito.fints.model.*
import net.dankito.fints.model.EnterTanGeneratorAtcResult
import net.dankito.fints.model.EnterTanResult
import net.dankito.fints.model.TanChallenge
interface FinTsClientCallback { interface FinTsClientCallback {
/**
* When user did not select a TAN procedure, this method gets called so that user selects one.
*
* As almost all FinTS messages need the selected TAN procedure, this method gets called quite early.
*
* As a simplification fints4java already suggests which TAN procedure may is the best one for user.
*
* If you do not support an enter tan dialog or if your enter tan dialog supports selecting a TAN procedure, it's
* best returning [suggestedTanProcedure] and to not show an extra select TAN procedure dialog.
*/
fun askUserForTanProcedure(supportedTanProcedures: List<TanProcedure>, suggestedTanProcedure: TanProcedure?): TanProcedure?
fun enterTan(customer: CustomerData, tanChallenge: TanChallenge): EnterTanResult fun enterTan(customer: CustomerData, tanChallenge: TanChallenge): EnterTanResult
/** /**
* This method gets called for chipTan TAN generators when the bank asks the customer to synchronize her/his TAN generator. * This method gets called for chipTan TAN generators when the bank asks the customer to synchronize her/his TAN generator.
*
* If you do not support entering TAN generator ATC, return [EnterTanGeneratorAtcResult.userDidNotEnterTan]
*/ */
fun enterTanGeneratorAtc(customer: CustomerData, tanMedium: TanGeneratorTanMedium): EnterTanGeneratorAtcResult fun enterTanGeneratorAtc(customer: CustomerData, tanMedium: TanGeneratorTanMedium): EnterTanGeneratorAtcResult

View File

@ -33,6 +33,13 @@ public class JavaShowcase {
customer.setSelectedTanProcedure(new TanProcedure("", Sicherheitsfunktion.PIN_TAN_911, TanProcedureType.ChipTanOptisch)); customer.setSelectedTanProcedure(new TanProcedure("", Sicherheitsfunktion.PIN_TAN_911, TanProcedureType.ChipTanOptisch));
FinTsClientCallback callback = new FinTsClientCallback() { FinTsClientCallback callback = new FinTsClientCallback() {
@Nullable
@Override
public TanProcedure askUserForTanProcedure(@NotNull List<? extends TanProcedure> supportedTanProcedures, @Nullable TanProcedure suggestedTanProcedure) {
return suggestedTanProcedure; // simply return suggestedTanProcedure as in most cases it's the best fitting one
}
@Nullable @Nullable
@Override @Override
public EnterTanResult enterTan(@NotNull CustomerData customer, @NotNull TanChallenge tanChallenge) { public EnterTanResult enterTan(@NotNull CustomerData customer, @NotNull TanChallenge tanChallenge) {

View File

@ -30,6 +30,10 @@ class FinTsClientTest {
private val callback = object : FinTsClientCallback { private val callback = object : FinTsClientCallback {
override fun askUserForTanProcedure(supportedTanProcedures: List<TanProcedure>, suggestedTanProcedure: TanProcedure?): TanProcedure? {
return suggestedTanProcedure // simply return suggestedTanProcedure as in most cases it's the best fitting one
}
override fun enterTan(customer: CustomerData, tanChallenge: TanChallenge): EnterTanResult { override fun enterTan(customer: CustomerData, tanChallenge: TanChallenge): EnterTanResult {
didAskUserToEnterTan.set(true) didAskUserToEnterTan.set(true)