From d03c0eb00386e5b1b0321212f94664bff2721015 Mon Sep 17 00:00:00 2001 From: dankl Date: Mon, 21 Oct 2019 00:47:01 +0200 Subject: [PATCH] Implemented checkIfAccountExists() which retrieves user's data and may even first account transactions without asking user for her/his tan procedure --- .../kotlin/net/dankito/fints/FinTsClient.kt | 52 +++++++++++++++-- .../net/dankito/fints/FinTsClientTest.kt | 56 +++++++++++++++++-- 2 files changed, 98 insertions(+), 10 deletions(-) diff --git a/fints4javaLib/src/main/kotlin/net/dankito/fints/FinTsClient.kt b/fints4javaLib/src/main/kotlin/net/dankito/fints/FinTsClient.kt index 6db79f05..01d3aeea 100644 --- a/fints4javaLib/src/main/kotlin/net/dankito/fints/FinTsClient.kt +++ b/fints4javaLib/src/main/kotlin/net/dankito/fints/FinTsClient.kt @@ -36,6 +36,8 @@ open class FinTsClient @JvmOverloads constructor( ) { companion object { + const val NinetyDaysAgoMilliseconds = 90 * 24 * 60 * 60 * 1000L + private val log = LoggerFactory.getLogger(FinTsClient::class.java) } @@ -109,6 +111,48 @@ open class FinTsClient @JvmOverloads constructor( } + open fun checkIfAccountExistsAsync(bank: BankData, customer: CustomerData, + callback: (FinTsClientResponse) -> Unit) { + + threadPool.runAsync { + callback(checkIfAccountExists(bank, customer)) + } + } + + open fun checkIfAccountExists(bank: BankData, customer: CustomerData): FinTsClientResponse { + + val newUserInfoResponse = getBankAndCustomerInfoForNewUser(bank, customer) + + if (newUserInfoResponse.isSuccessful == false) { // bank parameter (FinTS server address, ...) already seem to be wrong + return newUserInfoResponse + } + + + // 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) + + // 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, true) + + + if (didOverwriteUserUnselectedTanProcedure) { + customer.resetSelectedTanProcedure() + } + + return if (transactionsOfLast90DaysResponse.isSuccessful) transactionsOfLast90DaysResponse + else synchronizeCustomerResponse + } + + /** * Some banks support that according to PSD2 account transactions may be retrieved without * a TAN (= no strong customer authorization needed). @@ -117,7 +161,7 @@ open class FinTsClient @JvmOverloads constructor( callback: (GetTransactionsResponse) -> Unit) { threadPool.runAsync { - callback(tryGetTransactionsOfLast90DaysWithoutTan(bank, customer, false)) + callback(tryGetTransactionsOfLast90DaysWithoutTan(bank, customer)) } } @@ -133,12 +177,12 @@ open class FinTsClient @JvmOverloads constructor( protected open fun tryGetTransactionsOfLast90DaysWithoutTan(bank: BankData, customer: CustomerData, skipSettingCustomerFlag: Boolean): GetTransactionsResponse { - val ninetyDaysAgoMilliseconds = 90 * 24 * 60 * 60 * 1000L - val ninetyDaysAgo = Date(Date().time - ninetyDaysAgoMilliseconds) + val ninetyDaysAgo = Date(Date().time - NinetyDaysAgoMilliseconds) val response = getTransactions( GetTransactionsParameter(false, ninetyDaysAgo), bank, customer) + customer.triedToRetrieveTransactionsOfLast90DaysWithoutTan = true if (response.isSuccessful) { @@ -162,8 +206,6 @@ open class FinTsClient @JvmOverloads constructor( open fun getTransactions(parameter: GetTransactionsParameter, bank: BankData, customer: CustomerData): GetTransactionsResponse { -// synchronizeCustomerSystemIdIfNotDoneYet(bank, customer) // even though specification says this is required it can be omitted - if (customer.supportsRetrievingTransactionsOfLast90DaysWithoutTan == null && customer.triedToRetrieveTransactionsOfLast90DaysWithoutTan == false && parameter.fromDate == null) { diff --git a/fints4javaLib/src/test/kotlin/net/dankito/fints/FinTsClientTest.kt b/fints4javaLib/src/test/kotlin/net/dankito/fints/FinTsClientTest.kt index d3f40baf..7ff2ef7f 100644 --- a/fints4javaLib/src/test/kotlin/net/dankito/fints/FinTsClientTest.kt +++ b/fints4javaLib/src/test/kotlin/net/dankito/fints/FinTsClientTest.kt @@ -10,19 +10,29 @@ import net.dankito.fints.util.Java8Base64Service import org.assertj.core.api.Assertions.assertThat import org.junit.Ignore import org.junit.Test +import java.util.concurrent.atomic.AtomicBoolean @Ignore // not an automatic test, supply your settings below class FinTsClientTest { + private val didAskUserForTanProcedure = AtomicBoolean(false) + + private val didAskUserToEnterTan = AtomicBoolean(false) + + private val callback = object : FinTsClientCallback { override fun askUserForTanProcedure(supportedTanProcedures: List): TanProcedure? { + didAskUserForTanProcedure.set(true) + // TODO: if entering TAN is required select your tan procedure here return supportedTanProcedures.first() } override fun enterTan(tanChallenge: TanChallenge): String? { + didAskUserToEnterTan.set(true) + return null } @@ -41,11 +51,8 @@ class FinTsClientTest { private val BankDataAnonymous = BankData("10070000", Laenderkennzeichen.Germany, "https://fints.deutsche-bank.de/") // TODO: add your settings here: - private val Bank = BankData("", Laenderkennzeichen.Germany, "", bic = "") - private val Customer = CustomerData("", "", iban = "") - - // transfer 1 cent to yourself. Transferring money to oneself also doesn't require to enter a TAN according to PSD2 - private val BankTransferData = BankTransferData(Customer.name, Customer.iban!!, Bank.bic!!, 0.01.toBigDecimal(), "Give it to me baby") + private val Bank = BankData("", Laenderkennzeichen.Germany, "") + private val Customer = CustomerData("", "") @@ -65,6 +72,34 @@ class FinTsClientTest { } + @Test + fun checkIfAccountExists() { + + // when + val result = underTest.checkIfAccountExists(Bank, Customer) + + // then + assertThat(result.isSuccessful).isTrue() + + assertThat(didAskUserForTanProcedure).isFalse() + + assertThat(Bank.name).isNotEmpty() + assertThat(Bank.supportedJobs).isNotEmpty() // supported jobs are now known + assertThat(Bank.supportedTanProcedures).isNotEmpty() // supported tan procedures are now known + assertThat(Bank.supportedHbciVersions).isNotEmpty() // supported HBIC versions are now known + assertThat(Bank.supportedLanguages).isNotEmpty() // supported languages are now known + + assertThat(Customer.name).isNotEmpty() + assertThat(Customer.iban).isNotNull() + assertThat(Customer.supportedTanProcedures).isNotEmpty() + assertThat(Customer.selectedLanguage).isNotEqualTo(Dialogsprache.Default) // language is set now + assertThat(Customer.customerSystemId).isNotEqualTo(KundensystemStatus.SynchronizingCustomerSystemId) // customer system id is now set + assertThat(Customer.customerSystemStatus).isEqualTo(KundensystemStatusWerte.Benoetigt) // customerSystemStatus is set now + assertThat(Customer.accounts).isNotEmpty() // accounts are now known + assertThat(Customer.accounts.first().allowedJobs).isNotEmpty() // allowed jobs are now known + } + + @Test fun synchronizeCustomerSystemId() { @@ -97,6 +132,17 @@ class FinTsClientTest { @Test fun testBankTransfer() { + // given + underTest.checkIfAccountExists(Bank, Customer) + + // now BIC and IBAN should be set + assertThat(Bank.bic).describedAs("Bank's BIC should now be set").isNotNull() + assertThat(Customer.iban).describedAs("Customer's IBAN should now be set").isNotNull() + + // transfer 1 cent to yourself. Transferring money to oneself also doesn't require to enter a TAN according to PSD2 + val BankTransferData = BankTransferData(Customer.name, Customer.iban!!, Bank.bic!!, 0.01.toBigDecimal(), "Give it to me baby") + + // when val result = underTest.doBankTransfer(BankTransferData, Bank, Customer)