diff --git a/BankingUiCommon/src/main/java/net/dankito/banking/ui/BankingClientCallback.kt b/BankingUiCommon/src/main/java/net/dankito/banking/ui/BankingClientCallback.kt new file mode 100644 index 00000000..9bbb5999 --- /dev/null +++ b/BankingUiCommon/src/main/java/net/dankito/banking/ui/BankingClientCallback.kt @@ -0,0 +1,19 @@ +package net.dankito.banking.ui + +import net.dankito.banking.ui.model.Account +import net.dankito.banking.ui.model.tan.EnterTanGeneratorAtcResult +import net.dankito.banking.ui.model.tan.EnterTanResult +import net.dankito.banking.ui.model.tan.TanChallenge +import net.dankito.banking.ui.model.tan.TanGeneratorTanMedium + + +interface BankingClientCallback { + + fun enterTan(account: Account, tanChallenge: TanChallenge): EnterTanResult + + /** + * This method gets called for chipTan TAN generators when the bank asks the customer to synchronize her/his TAN generator. + */ + fun enterTanGeneratorAtc(tanMedium: TanGeneratorTanMedium): EnterTanGeneratorAtcResult + +} \ No newline at end of file diff --git a/BankingUiCommon/src/main/java/net/dankito/banking/ui/model/Account.kt b/BankingUiCommon/src/main/java/net/dankito/banking/ui/model/Account.kt index 29c92cd9..48449745 100644 --- a/BankingUiCommon/src/main/java/net/dankito/banking/ui/model/Account.kt +++ b/BankingUiCommon/src/main/java/net/dankito/banking/ui/model/Account.kt @@ -1,5 +1,7 @@ package net.dankito.banking.ui.model +import net.dankito.banking.ui.model.tan.TanMedium +import net.dankito.banking.ui.model.tan.TanProcedure import java.math.BigDecimal diff --git a/BankingUiCommon/src/main/java/net/dankito/banking/ui/model/tan/EnterTanGeneratorAtcResult.kt b/BankingUiCommon/src/main/java/net/dankito/banking/ui/model/tan/EnterTanGeneratorAtcResult.kt new file mode 100644 index 00000000..5c65ec3e --- /dev/null +++ b/BankingUiCommon/src/main/java/net/dankito/banking/ui/model/tan/EnterTanGeneratorAtcResult.kt @@ -0,0 +1,30 @@ +package net.dankito.banking.ui.model.tan + + +open class EnterTanGeneratorAtcResult protected constructor( + val tan: String?, + val atc: Int? +) { + + companion object { + + fun userEnteredAtc(enteredTan: String, enteredAtc: Int): EnterTanGeneratorAtcResult { + return EnterTanGeneratorAtcResult(enteredTan, enteredAtc) + } + + fun userDidNotEnterTan(): EnterTanGeneratorAtcResult { + return EnterTanGeneratorAtcResult(null, null) + } + + } + + + val hasAtcBeenEntered: Boolean + get() = tan != null && atc != null + + + override fun toString(): String { + return "TAN: $tan, ATC: $atc" + } + +} \ No newline at end of file diff --git a/BankingUiCommon/src/main/java/net/dankito/banking/ui/model/tan/EnterTanResult.kt b/BankingUiCommon/src/main/java/net/dankito/banking/ui/model/tan/EnterTanResult.kt new file mode 100644 index 00000000..a70bf849 --- /dev/null +++ b/BankingUiCommon/src/main/java/net/dankito/banking/ui/model/tan/EnterTanResult.kt @@ -0,0 +1,45 @@ +package net.dankito.banking.ui.model.tan + +import net.dankito.banking.ui.model.responses.BankingClientResponse + + +open class EnterTanResult protected constructor( + val enteredTan: String?, + val changeTanProcedureTo: TanProcedure? = null, + val changeTanMediumTo: TanMedium? = null, + val changeTanMediumResultCallback: ((BankingClientResponse) -> Unit)? = null +) { + + companion object { + + fun userEnteredTan(enteredTan: String): EnterTanResult { + return EnterTanResult(enteredTan) + } + + fun userDidNotEnterTan(): EnterTanResult { + return EnterTanResult(null) + } + + fun userAsksToChangeTanProcedure(changeTanProcedureTo: TanProcedure): EnterTanResult { + return EnterTanResult(null, changeTanProcedureTo) + } + + fun userAsksToChangeTanMedium(changeTanMediumTo: TanMedium, changeTanMediumResultCallback: ((BankingClientResponse) -> Unit)?): EnterTanResult { + return EnterTanResult(null, null, changeTanMediumTo, changeTanMediumResultCallback) + } + + } + + override fun toString(): String { + if (changeTanProcedureTo != null) { + return "User asks to change TAN procedure to $changeTanProcedureTo" + } + + if (changeTanMediumTo != null) { + return "User asks to change TAN medium to $changeTanMediumTo" + } + + return "enteredTan = $enteredTan" + } + +} \ No newline at end of file diff --git a/BankingUiCommon/src/main/java/net/dankito/banking/ui/model/tan/FlickerCode.kt b/BankingUiCommon/src/main/java/net/dankito/banking/ui/model/tan/FlickerCode.kt new file mode 100644 index 00000000..b4784c7a --- /dev/null +++ b/BankingUiCommon/src/main/java/net/dankito/banking/ui/model/tan/FlickerCode.kt @@ -0,0 +1,22 @@ +package net.dankito.banking.ui.model.tan + + +open class FlickerCode( + val challengeHHD_UC: String, + val parsedDataSet: String, + val decodingError: Exception? = null +) { + + val decodingSuccessful: Boolean + get() = decodingError == null + + + override fun toString(): String { + if (decodingSuccessful == false) { + return "Decoding error: $decodingError" + } + + return "Parsed $challengeHHD_UC to $parsedDataSet" + } + +} \ No newline at end of file diff --git a/BankingUiCommon/src/main/java/net/dankito/banking/ui/model/tan/FlickerCodeTanChallenge.kt b/BankingUiCommon/src/main/java/net/dankito/banking/ui/model/tan/FlickerCodeTanChallenge.kt new file mode 100644 index 00000000..b7e9a0d9 --- /dev/null +++ b/BankingUiCommon/src/main/java/net/dankito/banking/ui/model/tan/FlickerCodeTanChallenge.kt @@ -0,0 +1,15 @@ +package net.dankito.banking.ui.model.tan + + +open class FlickerCodeTanChallenge( + val flickerCode: FlickerCode, + messageToShowToUser: String, + tanProcedure: TanProcedure + +) : TanChallenge(messageToShowToUser, tanProcedure) { + + override fun toString(): String { + return "$tanProcedure $flickerCode: $messageToShowToUser" + } + +} \ No newline at end of file diff --git a/BankingUiCommon/src/main/java/net/dankito/banking/ui/model/tan/ImageTanChallenge.kt b/BankingUiCommon/src/main/java/net/dankito/banking/ui/model/tan/ImageTanChallenge.kt new file mode 100644 index 00000000..b1efab66 --- /dev/null +++ b/BankingUiCommon/src/main/java/net/dankito/banking/ui/model/tan/ImageTanChallenge.kt @@ -0,0 +1,15 @@ +package net.dankito.banking.ui.model.tan + + +open class ImageTanChallenge( + val image: TanImage, + messageToShowToUser: String, + tanProcedure: TanProcedure + + ) : TanChallenge(messageToShowToUser, tanProcedure) { + + override fun toString(): String { + return "$tanProcedure $image: $messageToShowToUser" + } + +} \ No newline at end of file diff --git a/BankingUiCommon/src/main/java/net/dankito/banking/ui/model/tan/TanChallenge.kt b/BankingUiCommon/src/main/java/net/dankito/banking/ui/model/tan/TanChallenge.kt new file mode 100644 index 00000000..014af9f1 --- /dev/null +++ b/BankingUiCommon/src/main/java/net/dankito/banking/ui/model/tan/TanChallenge.kt @@ -0,0 +1,13 @@ +package net.dankito.banking.ui.model.tan + + +open class TanChallenge( + val messageToShowToUser: String, + val tanProcedure: TanProcedure +) { + + override fun toString(): String { + return "$tanProcedure: $messageToShowToUser" + } + +} \ No newline at end of file diff --git a/BankingUiCommon/src/main/java/net/dankito/banking/ui/model/tan/TanGeneratorTanMedium.kt b/BankingUiCommon/src/main/java/net/dankito/banking/ui/model/tan/TanGeneratorTanMedium.kt new file mode 100644 index 00000000..bea5ee67 --- /dev/null +++ b/BankingUiCommon/src/main/java/net/dankito/banking/ui/model/tan/TanGeneratorTanMedium.kt @@ -0,0 +1,15 @@ +package net.dankito.banking.ui.model.tan + + +open class TanGeneratorTanMedium( + displayName: String, + status: TanMediumStatus, + val cardNumber: String + +) : TanMedium(displayName, status) { + + override fun toString(): String { + return "$displayName $status" + } + +} \ No newline at end of file diff --git a/BankingUiCommon/src/main/java/net/dankito/banking/ui/model/tan/TanImage.kt b/BankingUiCommon/src/main/java/net/dankito/banking/ui/model/tan/TanImage.kt new file mode 100644 index 00000000..98998ad9 --- /dev/null +++ b/BankingUiCommon/src/main/java/net/dankito/banking/ui/model/tan/TanImage.kt @@ -0,0 +1,22 @@ +package net.dankito.banking.ui.model.tan + + +open class TanImage( + val mimeType: String, + val imageBytes: ByteArray, + val decodingError: Exception? = null +) { + + val decodingSuccessful: Boolean + get() = decodingError == null + + + override fun toString(): String { + if (decodingSuccessful == false) { + return "Decoding error: $decodingError" + } + + return "$mimeType ${imageBytes.size} bytes" + } + +} \ No newline at end of file diff --git a/BankingUiCommon/src/main/java/net/dankito/banking/ui/model/TanMedium.kt b/BankingUiCommon/src/main/java/net/dankito/banking/ui/model/tan/TanMedium.kt similarity index 58% rename from BankingUiCommon/src/main/java/net/dankito/banking/ui/model/TanMedium.kt rename to BankingUiCommon/src/main/java/net/dankito/banking/ui/model/tan/TanMedium.kt index a2135ef1..3186b1d2 100644 --- a/BankingUiCommon/src/main/java/net/dankito/banking/ui/model/TanMedium.kt +++ b/BankingUiCommon/src/main/java/net/dankito/banking/ui/model/tan/TanMedium.kt @@ -1,10 +1,9 @@ -package net.dankito.banking.ui.model +package net.dankito.banking.ui.model.tan open class TanMedium( val displayName: String, - val status: TanMediumStatus, - val originalObject: Any + val status: TanMediumStatus ) { override fun toString(): String { diff --git a/BankingUiCommon/src/main/java/net/dankito/banking/ui/model/TanMediumStatus.kt b/BankingUiCommon/src/main/java/net/dankito/banking/ui/model/tan/TanMediumStatus.kt similarity index 58% rename from BankingUiCommon/src/main/java/net/dankito/banking/ui/model/TanMediumStatus.kt rename to BankingUiCommon/src/main/java/net/dankito/banking/ui/model/tan/TanMediumStatus.kt index 4a385061..f1679c41 100644 --- a/BankingUiCommon/src/main/java/net/dankito/banking/ui/model/TanMediumStatus.kt +++ b/BankingUiCommon/src/main/java/net/dankito/banking/ui/model/tan/TanMediumStatus.kt @@ -1,4 +1,4 @@ -package net.dankito.banking.ui.model +package net.dankito.banking.ui.model.tan enum class TanMediumStatus { diff --git a/BankingUiCommon/src/main/java/net/dankito/banking/ui/model/TanProcedure.kt b/BankingUiCommon/src/main/java/net/dankito/banking/ui/model/tan/TanProcedure.kt similarity index 85% rename from BankingUiCommon/src/main/java/net/dankito/banking/ui/model/TanProcedure.kt rename to BankingUiCommon/src/main/java/net/dankito/banking/ui/model/tan/TanProcedure.kt index b0060bad..224868db 100644 --- a/BankingUiCommon/src/main/java/net/dankito/banking/ui/model/TanProcedure.kt +++ b/BankingUiCommon/src/main/java/net/dankito/banking/ui/model/tan/TanProcedure.kt @@ -1,4 +1,4 @@ -package net.dankito.banking.ui.model +package net.dankito.banking.ui.model.tan open class TanProcedure( diff --git a/BankingUiCommon/src/main/java/net/dankito/banking/ui/model/TanProcedureType.kt b/BankingUiCommon/src/main/java/net/dankito/banking/ui/model/tan/TanProcedureType.kt similarity index 78% rename from BankingUiCommon/src/main/java/net/dankito/banking/ui/model/TanProcedureType.kt rename to BankingUiCommon/src/main/java/net/dankito/banking/ui/model/tan/TanProcedureType.kt index 527ef040..cff49031 100644 --- a/BankingUiCommon/src/main/java/net/dankito/banking/ui/model/TanProcedureType.kt +++ b/BankingUiCommon/src/main/java/net/dankito/banking/ui/model/tan/TanProcedureType.kt @@ -1,4 +1,4 @@ -package net.dankito.banking.ui.model +package net.dankito.banking.ui.model.tan enum class TanProcedureType { diff --git a/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/MainActivity.kt b/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/MainActivity.kt index f616c539..36200ad1 100644 --- a/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/MainActivity.kt +++ b/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/MainActivity.kt @@ -8,17 +8,17 @@ import android.support.v7.app.AppCompatActivity import android.support.v7.widget.Toolbar import android.view.Menu import androidx.navigation.findNavController -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 import net.dankito.banking.fints4java.android.ui.dialogs.EnterTanDialog -import net.dankito.fints.FinTsClientCallback -import net.dankito.fints.messages.datenelemente.implementierte.tan.TanGeneratorTanMedium -import net.dankito.fints.model.CustomerData -import net.dankito.fints.model.EnterTanGeneratorAtcResult -import net.dankito.fints.model.EnterTanResult -import net.dankito.fints.model.TanChallenge +import net.dankito.banking.mapper.fints4javaModelMapper +import net.dankito.banking.ui.BankingClientCallback +import net.dankito.banking.ui.model.Account +import net.dankito.banking.ui.model.tan.EnterTanGeneratorAtcResult +import net.dankito.banking.ui.model.tan.EnterTanResult +import net.dankito.banking.ui.model.tan.TanChallenge +import net.dankito.banking.ui.model.tan.TanGeneratorTanMedium import java.util.concurrent.CountDownLatch import java.util.concurrent.atomic.AtomicReference @@ -27,14 +27,14 @@ class MainActivity : AppCompatActivity() { // private lateinit var appBarConfiguration: AppBarConfiguration - val presenter = MainWindowPresenter(Base64ServiceAndroid(), object : FinTsClientCallback { + val presenter = MainWindowPresenter(Base64ServiceAndroid(), object : BankingClientCallback { - override fun enterTan(customer: CustomerData, tanChallenge: TanChallenge): EnterTanResult { - return getTanFromUserOffUiThread(customer, tanChallenge) + override fun enterTan(account: Account, tanChallenge: TanChallenge): EnterTanResult { + return getTanFromUserOffUiThread(account, tanChallenge) } - override fun enterTanGeneratorAtc(customer: CustomerData, tanMedium: TanGeneratorTanMedium): EnterTanGeneratorAtcResult { - return getAtcFromUserOffUiThread(customer, tanMedium) + override fun enterTanGeneratorAtc(tanMedium: TanGeneratorTanMedium): EnterTanGeneratorAtcResult { + return getAtcFromUserOffUiThread(tanMedium) } }) @@ -86,12 +86,10 @@ class MainActivity : AppCompatActivity() { // return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp() // } - private fun getTanFromUserOffUiThread(customer: CustomerData, tanChallenge: TanChallenge): EnterTanResult { + private fun getTanFromUserOffUiThread(account: Account, tanChallenge: TanChallenge): EnterTanResult { val enteredTan = AtomicReference(null) val tanEnteredLatch = CountDownLatch(1) - val account = presenter.getAccountForCustomer(customer) - runOnUiThread { EnterTanDialog().show(account, tanChallenge, presenter, this@MainActivity, false) { enteredTan.set(it) @@ -104,13 +102,13 @@ class MainActivity : AppCompatActivity() { return enteredTan.get() } - private fun getAtcFromUserOffUiThread(customer: CustomerData, tanMedium: TanGeneratorTanMedium): EnterTanGeneratorAtcResult { + private fun getAtcFromUserOffUiThread(tanMedium: TanGeneratorTanMedium): EnterTanGeneratorAtcResult { val result = AtomicReference(null) val tanEnteredLatch = CountDownLatch(1) runOnUiThread { // TODO: don't create a fints4javaModelMapper instance here, let MainWindowPresenter do the job - EnterAtcDialog().show(net.dankito.banking.mapper.fints4javaModelMapper().mapTanMedium(tanMedium), this@MainActivity, false) { enteredResult -> + EnterAtcDialog().show(tanMedium, this@MainActivity, false) { enteredResult -> result.set(enteredResult) tanEnteredLatch.countDown() } diff --git a/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/MainWindowPresenter.kt b/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/MainWindowPresenter.kt index 3964e41c..1b2f2185 100644 --- a/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/MainWindowPresenter.kt +++ b/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/MainWindowPresenter.kt @@ -1,6 +1,7 @@ package net.dankito.banking.fints4java.android.ui import net.dankito.banking.ui.IBankingClient +import net.dankito.banking.ui.BankingClientCallback import net.dankito.banking.ui.model.Account import net.dankito.banking.ui.model.AccountTransaction import net.dankito.banking.ui.model.BankAccount @@ -8,11 +9,8 @@ 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.banks.BankFinder import net.dankito.fints.model.BankInfo -import net.dankito.fints.model.CustomerData -import net.dankito.fints.response.client.FinTsClientResponse import net.dankito.fints.util.IBase64Service import net.dankito.utils.IThreadPool import net.dankito.utils.ThreadPool @@ -23,7 +21,7 @@ import kotlin.collections.ArrayList open class MainWindowPresenter(protected val base64Service: IBase64Service, - protected val callback: FinTsClientCallback + protected val callback: BankingClientCallback ) { companion object { @@ -35,10 +33,8 @@ open class MainWindowPresenter(protected val base64Service: IBase64Service, protected val threadPool: IThreadPool = ThreadPool() - protected val fints4javaModelMapper = net.dankito.banking.mapper.fints4javaModelMapper() - - protected val accounts = mutableMapOf() + protected val clientsForAccounts = mutableMapOf() protected val accountAddedListeners = mutableListOf<(Account) -> Unit>() @@ -54,7 +50,7 @@ open class MainWindowPresenter(protected val base64Service: IBase64Service, val account = response.account if (response.isSuccessful) { - accounts.put(account, newClient) + clientsForAccounts.put(account, newClient) callAccountAddedListeners(account) @@ -98,7 +94,7 @@ open class MainWindowPresenter(protected val base64Service: IBase64Service, } open fun updateAccountsTransactionsAsync(callback: (GetTransactionsResponse) -> Unit) { - accounts.keys.forEach { account -> + clientsForAccounts.keys.forEach { account -> 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 @@ -179,7 +175,7 @@ open class MainWindowPresenter(protected val base64Service: IBase64Service, protected open fun getClientForAccount(account: Account): IBankingClient? { - accounts.get(account)?.let { client -> + clientsForAccounts.get(account)?.let { client -> // TODO: is this code still needed after updating data model is implemented? // account.selectedTanProcedure?.let { selectedTanProcedure -> // client.customer.selectedTanProcedure = fints4javaModelMapper.mapTanProcedureBack(selectedTanProcedure) @@ -192,20 +188,14 @@ open class MainWindowPresenter(protected val base64Service: IBase64Service, } - open fun getErrorToShowToUser(response: FinTsClientResponse): String? { - return fints4javaModelMapper.mapErrorToShowToUser(response) - } - + open val accounts: List + get() = clientsForAccounts.keys.toList() open val allTransactions: List - get() = accounts.keys.flatMap { it.transactions }.sortedByDescending { it.bookingDate } // TODO: someday add unbooked transactions + get() = clientsForAccounts.keys.flatMap { it.transactions }.sortedByDescending { it.bookingDate } // TODO: someday add unbooked transactions open val balanceOfAllAccounts: BigDecimal - get() = accounts.keys.map { it.balance }.fold(BigDecimal.ZERO) { acc, e -> acc + e } - - open fun getAccountForCustomer(customer: CustomerData): Account { // TODO: remove as presenter should not be aware of fints4java objects - return accounts.keys.first { it.customerId == customer.customerId } - } + get() = clientsForAccounts.keys.map { it.balance }.fold(BigDecimal.ZERO) { acc, e -> acc + e } open fun addAccountAddedListener(listener: (Account) -> Unit) { diff --git a/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/adapter/TanMediumAdapter.kt b/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/adapter/TanMediumAdapter.kt index 37fa7051..a7da8551 100644 --- a/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/adapter/TanMediumAdapter.kt +++ b/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/adapter/TanMediumAdapter.kt @@ -4,7 +4,7 @@ import android.view.View import android.view.ViewGroup import android.widget.TextView import net.dankito.banking.fints4java.android.R -import net.dankito.banking.ui.model.TanMedium +import net.dankito.banking.ui.model.tan.TanMedium import net.dankito.utils.android.extensions.asActivity import net.dankito.utils.android.ui.adapter.ListAdapter diff --git a/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/adapter/TanProceduresAdapter.kt b/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/adapter/TanProceduresAdapter.kt index 374bbef4..6816b0ad 100644 --- a/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/adapter/TanProceduresAdapter.kt +++ b/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/adapter/TanProceduresAdapter.kt @@ -4,7 +4,7 @@ import android.view.View import android.view.ViewGroup import android.widget.TextView import net.dankito.banking.fints4java.android.R -import net.dankito.banking.ui.model.TanProcedure +import net.dankito.banking.ui.model.tan.TanProcedure import net.dankito.utils.android.extensions.asActivity import net.dankito.utils.android.ui.adapter.ListAdapter diff --git a/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/dialogs/BankTransferDialog.kt b/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/dialogs/BankTransferDialog.kt index 47807e4e..6308261d 100644 --- a/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/dialogs/BankTransferDialog.kt +++ b/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/dialogs/BankTransferDialog.kt @@ -18,7 +18,6 @@ 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.utils.android.extensions.asActivity import java.math.BigDecimal @@ -34,7 +33,7 @@ open class BankTransferDialog : DialogFragment() { protected lateinit var bankAccount: BankAccount - protected var preselectedValues: BankTransferData? = null + protected var preselectedValues: TransferMoneyData? = null protected val sepaMessageCreator: ISepaMessageCreator = SepaMessageCreator() @@ -43,7 +42,7 @@ open class BankTransferDialog : DialogFragment() { show(activity, presenter, bankAccount, null, fullscreen) } - open fun show(activity: AppCompatActivity, presenter: MainWindowPresenter, bankAccount: BankAccount, preselectedValues: BankTransferData?, fullscreen: Boolean = false) { + open fun show(activity: AppCompatActivity, presenter: MainWindowPresenter, bankAccount: BankAccount, preselectedValues: TransferMoneyData?, fullscreen: Boolean = false) { this.presenter = presenter this.bankAccount = bankAccount this.preselectedValues = preselectedValues @@ -92,7 +91,7 @@ open class BankTransferDialog : DialogFragment() { } } - protected open fun focusEditTextAccordingToPreselectedValues(rootView: View, data: BankTransferData) { + protected open fun focusEditTextAccordingToPreselectedValues(rootView: View, data: TransferMoneyData) { if (data.creditorName.trim().isNotEmpty()) { if (data.creditorIban.trim().isNotEmpty()) { if (data.creditorBic.trim().isNotEmpty()) { diff --git a/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/dialogs/EnterAtcDialog.kt b/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/dialogs/EnterAtcDialog.kt index bd6e7797..a94ccb39 100644 --- a/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/dialogs/EnterAtcDialog.kt +++ b/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/dialogs/EnterAtcDialog.kt @@ -10,8 +10,8 @@ import android.view.View import android.view.ViewGroup import kotlinx.android.synthetic.main.dialog_enter_atc.view.* import net.dankito.banking.fints4java.android.R -import net.dankito.banking.ui.model.TanMedium -import net.dankito.fints.model.EnterTanGeneratorAtcResult +import net.dankito.banking.ui.model.tan.EnterTanGeneratorAtcResult +import net.dankito.banking.ui.model.tan.TanMedium open class EnterAtcDialog : DialogFragment() { diff --git a/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/dialogs/EnterTanDialog.kt b/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/dialogs/EnterTanDialog.kt index 1a64c68e..bf7f38e0 100644 --- a/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/dialogs/EnterTanDialog.kt +++ b/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/dialogs/EnterTanDialog.kt @@ -15,17 +15,13 @@ 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.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 import net.dankito.banking.fints4java.android.ui.listener.ListItemSelectedListener import net.dankito.banking.ui.model.Account -import net.dankito.banking.ui.model.TanMedium -import net.dankito.banking.ui.model.TanMediumStatus -import net.dankito.fints.messages.datenelemente.implementierte.tan.TanGeneratorTanMedium -import net.dankito.fints.model.* -import net.dankito.fints.response.client.FinTsClientResponse +import net.dankito.banking.ui.model.responses.BankingClientResponse +import net.dankito.banking.ui.model.tan.* open class EnterTanDialog : DialogFragment() { @@ -96,8 +92,7 @@ open class EnterTanDialog : DialogFragment() { spinner.onItemSelectedListener = ListItemSelectedListener(adapter) { newSelectedTanProcedure -> if (newSelectedTanProcedure != selectedTanProcedure) { - val mappedTanProcedure = net.dankito.banking.mapper.fints4javaModelMapper().mapTanProcedureBack(newSelectedTanProcedure) // TODO: move to MainWindowPresenter - tanEnteredCallback(EnterTanResult.userAsksToChangeTanProcedure(mappedTanProcedure)) + tanEnteredCallback(EnterTanResult.userAsksToChangeTanProcedure(newSelectedTanProcedure)) // TODO: find a way to update account.selectedTanProcedure afterwards dismiss() @@ -114,7 +109,7 @@ open class EnterTanDialog : DialogFragment() { rootView.spnTanMedium.adapter = tanMediumAdapter rootView.spnTanMedium.onItemSelectedListener = ListItemSelectedListener(tanMediumAdapter) { selectedTanMedium -> if (selectedTanMedium.status != TanMediumStatus.Used) { - (selectedTanMedium.originalObject as? TanGeneratorTanMedium)?.let { tanGeneratorTanMedium -> + (selectedTanMedium as? TanGeneratorTanMedium)?.let { tanGeneratorTanMedium -> tanEnteredCallback(EnterTanResult.userAsksToChangeTanMedium(tanGeneratorTanMedium) { response -> handleChangeTanMediumResponse(selectedTanMedium, response) }) @@ -132,16 +127,16 @@ open class EnterTanDialog : DialogFragment() { setupSelectTanMediumView(rootView) } - if (tanChallenge is FlickercodeTanChallenge) { + if (tanChallenge is FlickerCodeTanChallenge) { val flickerCodeView = rootView.flickerCodeView flickerCodeView.visibility = View.VISIBLE - val flickercode = (tanChallenge as FlickercodeTanChallenge).flickercode + val flickercode = (tanChallenge as FlickerCodeTanChallenge).flickerCode if (flickercode.decodingSuccessful) { flickerCodeView.setCode(flickercode) } else { - showDecodingTanChallengeFailedErrorDelayed(flickercode.error) + showDecodingTanChallengeFailedErrorDelayed(flickercode.decodingError) } } else if (tanChallenge is ImageTanChallenge) { @@ -153,7 +148,7 @@ open class EnterTanDialog : DialogFragment() { rootView.imgTanImageView.setImageBitmap(bitmap) } else { - showDecodingTanChallengeFailedErrorDelayed(decodedImage.error) + showDecodingTanChallengeFailedErrorDelayed(decodedImage.decodingError) } } @@ -182,7 +177,7 @@ open class EnterTanDialog : DialogFragment() { } - protected open fun handleChangeTanMediumResponse(newUsedTanMedium: TanMedium, response: FinTsClientResponse) { + protected open fun handleChangeTanMediumResponse(newUsedTanMedium: TanMedium, response: BankingClientResponse) { activity?.let { activity -> activity.runOnUiThread { handleChangeTanMediumResponseOnUiThread(activity, newUsedTanMedium, response) @@ -190,7 +185,7 @@ open class EnterTanDialog : DialogFragment() { } } - protected open fun handleChangeTanMediumResponseOnUiThread(context: Context, newUsedTanMedium: TanMedium, response: FinTsClientResponse) { + protected open fun handleChangeTanMediumResponseOnUiThread(context: Context, newUsedTanMedium: TanMedium, response: BankingClientResponse) { if (response.isSuccessful) { AlertDialog.Builder(context) .setMessage(context.getString(R.string.dialog_enter_tan_tan_medium_successfully_changed, newUsedTanMedium.displayName)) @@ -202,7 +197,7 @@ open class EnterTanDialog : DialogFragment() { } else { AlertDialog.Builder(context) - .setMessage(context.getString(R.string.dialog_enter_tan_error_changing_tan_medium, newUsedTanMedium.displayName, presenter.getErrorToShowToUser(response))) + .setMessage(context.getString(R.string.dialog_enter_tan_error_changing_tan_medium, newUsedTanMedium.displayName, response.errorToShowToUser)) .setPositiveButton(android.R.string.ok) { dialog, _ -> dialog.dismiss() } .show() } diff --git a/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/home/HomeFragment.kt b/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/home/HomeFragment.kt index 74cc89fa..6698d202 100644 --- a/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/home/HomeFragment.kt +++ b/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/home/HomeFragment.kt @@ -19,8 +19,8 @@ import net.dankito.banking.fints4java.android.ui.MainWindowPresenter import net.dankito.banking.fints4java.android.ui.adapter.AccountTransactionAdapter import net.dankito.banking.fints4java.android.ui.dialogs.BankTransferDialog import net.dankito.banking.ui.model.AccountTransaction +import net.dankito.banking.ui.model.parameters.TransferMoneyData import net.dankito.banking.ui.model.responses.GetTransactionsResponse -import net.dankito.fints.model.BankTransferData import net.dankito.utils.android.extensions.asActivity import java.math.BigDecimal @@ -177,9 +177,9 @@ class HomeFragment : Fragment() { } } - private fun mapPreselectedValues(selectedTransaction: AccountTransaction?): BankTransferData? { + private fun mapPreselectedValues(selectedTransaction: AccountTransaction?): TransferMoneyData? { selectedTransaction?.let { - return BankTransferData( + return TransferMoneyData( selectedTransaction.otherPartyName ?: "", selectedTransaction.otherPartyAccountId ?: "", selectedTransaction.otherPartyBankCode ?: "", diff --git a/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/views/ChipTanFlickerCodeView.kt b/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/views/ChipTanFlickerCodeView.kt index ca79fb81..17265df9 100644 --- a/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/views/ChipTanFlickerCodeView.kt +++ b/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/views/ChipTanFlickerCodeView.kt @@ -8,9 +8,9 @@ import android.widget.LinearLayout import kotlinx.android.synthetic.main.view_flicker_code.view.* import kotlinx.android.synthetic.main.view_tan_image_size_controls.view.* import net.dankito.banking.fints4java.android.R -import net.dankito.banking.fints4java.android.util.FlickercodeAnimator +import net.dankito.banking.fints4java.android.util.FlickerCodeAnimator +import net.dankito.banking.ui.model.tan.FlickerCode import net.dankito.fints.tan.Bit -import net.dankito.fints.tan.Flickercode import net.dankito.utils.android.extensions.asActivity @@ -40,7 +40,7 @@ open class ChipTanFlickerCodeView @JvmOverloads constructor( protected lateinit var allStripes: List - protected val animator = FlickercodeAnimator() + protected val animator = FlickerCodeAnimator() protected var stripesHeight = 360 @@ -160,12 +160,12 @@ open class ChipTanFlickerCodeView @JvmOverloads constructor( } - open fun setCode(flickercode: Flickercode) { + open fun setCode(flickerCode: FlickerCode) { animator.stop() setFrequency(currentFrequency) - animator.animateFlickercode(flickercode) { step -> + animator.animateFlickerCode(flickerCode) { step -> context.asActivity()?.runOnUiThread { showStepOnUiThread(step) } diff --git a/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/util/FlickercodeAnimator.kt b/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/util/FlickerCodeAnimator.kt similarity index 84% rename from fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/util/FlickercodeAnimator.kt rename to fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/util/FlickerCodeAnimator.kt index f0777303..03980dba 100644 --- a/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/util/FlickercodeAnimator.kt +++ b/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/util/FlickerCodeAnimator.kt @@ -1,20 +1,20 @@ package net.dankito.banking.fints4java.android.util +import net.dankito.banking.ui.model.tan.FlickerCode import net.dankito.fints.tan.Bit import net.dankito.fints.tan.FlickerCanvas -import net.dankito.fints.tan.Flickercode import org.slf4j.LoggerFactory import java.util.concurrent.TimeUnit -open class FlickercodeAnimator { // TODO: move to fints4javaLib +open class FlickerCodeAnimator { // TODO: move to fints4javaLib companion object { const val MinFrequency = 2 const val MaxFrequency = 40 const val DefaultFrequency = 20 - private val log = LoggerFactory.getLogger(FlickercodeAnimator::class.java) + private val log = LoggerFactory.getLogger(FlickerCodeAnimator::class.java) } @@ -27,14 +27,14 @@ open class FlickercodeAnimator { // TODO: move to fints4javaLib @JvmOverloads - open fun animateFlickercode(flickercode: Flickercode, frequency: Int = DefaultFrequency, showStep: (Array) -> Unit) { + open fun animateFlickerCode(flickerCode: FlickerCode, frequency: Int = DefaultFrequency, showStep: (Array) -> Unit) { currentFrequency = frequency currentStepIndex = 0 - val steps = FlickerCanvas(flickercode.parsedDataSet).steps + val steps = FlickerCanvas(flickerCode.parsedDataSet).steps stop() // stop may still running previous animation - calculateAnimationThread = Thread({ calculateAnimation(steps, showStep) }, "CalculateFlickercodeAnimation") + calculateAnimationThread = Thread({ calculateAnimation(steps, showStep) }, "CalculateFlickerCodeAnimation") calculateAnimationThread?.start() } diff --git a/fints4javaBankingClient/src/main/kotlin/net/dankito/banking/fints4javaBankingClient.kt b/fints4javaBankingClient/src/main/kotlin/net/dankito/banking/fints4javaBankingClient.kt index a775b450..74ab6961 100644 --- a/fints4javaBankingClient/src/main/kotlin/net/dankito/banking/fints4javaBankingClient.kt +++ b/fints4javaBankingClient/src/main/kotlin/net/dankito/banking/fints4javaBankingClient.kt @@ -1,6 +1,8 @@ package net.dankito.banking +import net.dankito.banking.ui.BankingClientCallback import net.dankito.banking.ui.IBankingClient +import net.dankito.banking.ui.model.Account import net.dankito.banking.ui.model.BankAccount import net.dankito.banking.ui.model.parameters.GetTransactionsParameter import net.dankito.banking.ui.model.parameters.TransferMoneyData @@ -9,9 +11,8 @@ 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.messages.datenelemente.implementierte.tan.TanGeneratorTanMedium +import net.dankito.fints.model.* import net.dankito.fints.model.mapper.BankDataMapper import net.dankito.fints.util.IBase64Service import net.dankito.utils.IThreadPool @@ -27,7 +28,7 @@ open class fints4javaBankingClient( webClient: IWebClient = OkHttpWebClient(), base64Service: IBase64Service, threadPool: IThreadPool = ThreadPool(), - callback: FinTsClientCallback + callback: BankingClientCallback ) : IBankingClient { @@ -39,12 +40,28 @@ open class fints4javaBankingClient( protected val customer = CustomerData(customerId, pin) - protected val client = FinTsClientForCustomer(bank, customer, webClient, base64Service, threadPool, callback) + protected lateinit var account: Account + + + protected val client = FinTsClientForCustomer(bank, customer, webClient, base64Service, threadPool, object : FinTsClientCallback { + override fun enterTan(customer: CustomerData, tanChallenge: TanChallenge): EnterTanResult { + val result = callback.enterTan(account, mapper.mapTanChallenge(tanChallenge)) + + return mapper.mapEnterTanResult(result, customer) + } + + override fun enterTanGeneratorAtc(customer: CustomerData, tanMedium: TanGeneratorTanMedium): EnterTanGeneratorAtcResult { + val result = callback.enterTanGeneratorAtc(mapper.mapTanMedium(tanMedium)) + + return mapper.mapEnterTanGeneratorAtcResult(result) + } + + }) override fun addAccountAsync(callback: (AddAccountResponse) -> Unit) { client.addAccountAsync { response -> - val account = mapper.mapAccount(customer, bank) + this.account = mapper.mapAccount(customer, bank) val mappedResponse = mapper.mapResponse(account, response) callback(mappedResponse) diff --git a/fints4javaBankingClient/src/main/kotlin/net/dankito/banking/mapper/fints4javaModelMapper.kt b/fints4javaBankingClient/src/main/kotlin/net/dankito/banking/mapper/fints4javaModelMapper.kt index 63d096a1..f26e1277 100644 --- a/fints4javaBankingClient/src/main/kotlin/net/dankito/banking/mapper/fints4javaModelMapper.kt +++ b/fints4javaBankingClient/src/main/kotlin/net/dankito/banking/mapper/fints4javaModelMapper.kt @@ -4,8 +4,8 @@ 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.banking.ui.model.tan.* import net.dankito.fints.messages.datenelemente.implementierte.signatur.Sicherheitsfunktion -import net.dankito.fints.messages.datenelemente.implementierte.tan.TanGeneratorTanMedium import net.dankito.fints.model.AccountData import net.dankito.fints.model.BankData import net.dankito.fints.model.CustomerData @@ -16,6 +16,40 @@ import java.math.BigDecimal open class fints4javaModelMapper { + + 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>() + var balances = mapOf() + + account.bankAccounts.firstOrNull()?.let { bankAccount -> // TODO: set bank account also on net.dankito.fints.response.client.GetTransactionsResponse + bookedTransactions = mapOf(bankAccount to mapTransactions(bankAccount, response.bookedTransactions)) + response.balance?.let { balances = mapOf(bankAccount to it) } + } + + return AddAccountResponse(response.isSuccessful, mapErrorToShowToUser(response), + account, response.supportsRetrievingTransactionsOfLast90DaysWithoutTan, + bookedTransactions, + mapOf(), // TODO: map unbooked transactions + balances) + } + + 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)), + mapOf(), // TODO: map unbooked transactions + response.balance?.let { mapOf(bankAccount to it) } ?: mapOf()) + } + + open fun mapErrorToShowToUser(response: FinTsClientResponse): String? { + return response.exception?.localizedMessage ?: response.errorsToShowToUser.joinToString("\n") + } + + open fun mapAccount(customer: CustomerData, bank: BankData): Account { val mappedBank = mapBank(bank) @@ -73,6 +107,7 @@ open class fints4javaModelMapper { ) } + open fun mapTanProcedures(tanProcedures: List): List { return tanProcedures.map { mapTanProcedure(it) } } @@ -107,13 +142,22 @@ open class fints4javaModelMapper { } open fun mapTanMedium(tanMedium: net.dankito.fints.messages.datenelemente.implementierte.tan.TanMedium): TanMedium { - val status = if (tanMedium.status.name.contains("Aktiv")) TanMediumStatus.Used else TanMediumStatus.Available + return TanMedium( + getDisplayNameForTanMedium(tanMedium), + mapTanMediumStatus(tanMedium) + ) + } - return TanMedium(getDisplayNameForTanMedium(tanMedium), status, tanMedium) + open fun mapTanMedium(tanMedium: net.dankito.fints.messages.datenelemente.implementierte.tan.TanGeneratorTanMedium): TanGeneratorTanMedium { + return TanGeneratorTanMedium( + getDisplayNameForTanMedium(tanMedium), + mapTanMediumStatus(tanMedium), + tanMedium.cardNumber + ) } protected open fun getDisplayNameForTanMedium(tanMedium: net.dankito.fints.messages.datenelemente.implementierte.tan.TanMedium): String { - if (tanMedium is TanGeneratorTanMedium) { + if (tanMedium is net.dankito.fints.messages.datenelemente.implementierte.tan.TanGeneratorTanMedium) { var cardNumber = tanMedium.cardNumber tanMedium.cardSequenceNumber?.let { cardNumber += " (Kartenfolgenummer $it)" // TODO: translate @@ -129,49 +173,37 @@ open class fints4javaModelMapper { return tanMedium.mediumClass.name } - - open fun mapResponse(response: FinTsClientResponse): BankingClientResponse { - return BankingClientResponse(response.isSuccessful, mapErrorToShowToUser(response)) + open fun mapTanMediumStatus(tanMedium: net.dankito.fints.messages.datenelemente.implementierte.tan.TanMedium): TanMediumStatus { + return if (tanMedium.status.name.contains("aktiv", true)) TanMediumStatus.Used else TanMediumStatus.Available } - open fun mapResponse(account: Account, response: net.dankito.fints.response.client.AddAccountResponse): AddAccountResponse { - var bookedTransactions = mapOf>() - var balances = mapOf() - - account.bankAccounts.firstOrNull()?.let { bankAccount -> // TODO: set bank account also on net.dankito.fints.response.client.GetTransactionsResponse - bookedTransactions = mapOf(bankAccount to mapTransactions(bankAccount, response.bookedTransactions)) - response.balance?.let { balances = mapOf(bankAccount to it) } + open fun mapTanMedium(tanMedium: TanMedium, customer: CustomerData): net.dankito.fints.messages.datenelemente.implementierte.tan.TanMedium { + if (tanMedium is TanGeneratorTanMedium) { + return mapTanMedium(tanMedium, customer) } - return AddAccountResponse(response.isSuccessful, mapErrorToShowToUser(response), - account, response.supportsRetrievingTransactionsOfLast90DaysWithoutTan, - bookedTransactions, - mapOf(), // TODO: map unbooked transactions - balances) + val statusToHave = if (tanMedium.status == TanMediumStatus.Used) listOf(net.dankito.fints.messages.datenelemente.implementierte.tan.TanMediumStatus.Aktiv, net.dankito.fints.messages.datenelemente.implementierte.tan.TanMediumStatus.AktivFolgekarte) + else listOf(net.dankito.fints.messages.datenelemente.implementierte.tan.TanMediumStatus.Verfuegbar, net.dankito.fints.messages.datenelemente.implementierte.tan.TanMediumStatus.VerfuegbarFolgekarte) + + return customer.tanMedia.first { tanMedium.displayName == it.mediumClass.name && statusToHave.contains(it.status) } } - 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)), - mapOf(), // TODO: map unbooked transactions - response.balance?.let { mapOf(bankAccount to it) } ?: mapOf()) - } - - open fun mapErrorToShowToUser(response: FinTsClientResponse): String? { - return response.exception?.localizedMessage ?: response.errorsToShowToUser.joinToString("\n") + open fun mapTanMedium(tanMedium: TanGeneratorTanMedium, customer: CustomerData): net.dankito.fints.messages.datenelemente.implementierte.tan.TanGeneratorTanMedium { + return customer.tanMedia.mapNotNull { it as? net.dankito.fints.messages.datenelemente.implementierte.tan.TanGeneratorTanMedium } + .first { it.cardNumber == tanMedium.cardNumber + && (it.cardSequenceNumber == null || tanMedium.displayName.contains(it.cardSequenceNumber!!)) } } - open fun mapTanProcedureBack(tanProcedure: TanProcedure): net.dankito.fints.model.TanProcedure { + open fun mapTanProcedure(tanProcedure: TanProcedure): net.dankito.fints.model.TanProcedure { return net.dankito.fints.model.TanProcedure( tanProcedure.displayName, Sicherheitsfunktion.values().first { it.code == tanProcedure.bankInternalProcedureCode }, - mapTanProcedureTypeBack(tanProcedure.type) + mapTanProcedureType(tanProcedure.type) ) } - open fun mapTanProcedureTypeBack(type: TanProcedureType): net.dankito.fints.model.TanProcedureType { + open fun mapTanProcedureType(type: TanProcedureType): net.dankito.fints.model.TanProcedureType { return when (type) { TanProcedureType.EnterTan -> net.dankito.fints.model.TanProcedureType.EnterTan TanProcedureType.ChipTanManuell -> net.dankito.fints.model.TanProcedureType.ChipTanManuell @@ -183,4 +215,64 @@ open class fints4javaModelMapper { } } + open fun mapEnterTanResult(result: EnterTanResult, customer: CustomerData): net.dankito.fints.model.EnterTanResult { + result.changeTanProcedureTo?.let { changeTanProcedureTo -> + return net.dankito.fints.model.EnterTanResult.userAsksToChangeTanProcedure(mapTanProcedure(changeTanProcedureTo)) + } + + result.changeTanMediumTo?.let { changeTanMediumTo -> + val callback: ((FinTsClientResponse) -> Unit)? = if (result.changeTanMediumResultCallback == null) null + else { response -> result.changeTanMediumResultCallback?.invoke(mapResponse(response)) } + return net.dankito.fints.model.EnterTanResult.userAsksToChangeTanMedium(mapTanMedium(changeTanMediumTo, customer), callback) + } + + result.enteredTan?.let { enteredTan -> + return net.dankito.fints.model.EnterTanResult.userEnteredTan(enteredTan) + } + + return net.dankito.fints.model.EnterTanResult.userDidNotEnterTan() + } + + open fun mapEnterTanGeneratorAtcResult(result: EnterTanGeneratorAtcResult): net.dankito.fints.model.EnterTanGeneratorAtcResult { + if (result.hasAtcBeenEntered) { + return net.dankito.fints.model.EnterTanGeneratorAtcResult.userEnteredAtc(result.tan!!, result.atc!!) + } + + return net.dankito.fints.model.EnterTanGeneratorAtcResult.userDidNotEnterTan() + } + + open fun mapTanChallenge(tanChallenge: net.dankito.fints.model.TanChallenge): TanChallenge { + if (tanChallenge is net.dankito.fints.model.FlickerCodeTanChallenge) { + return mapTanChallenge(tanChallenge) + } + + if (tanChallenge is net.dankito.fints.model.ImageTanChallenge) { + return mapTanChallenge(tanChallenge) + } + + return TanChallenge(tanChallenge.messageToShowToUser, + mapTanProcedure(tanChallenge.tanProcedure) + ) + } + + open fun mapTanChallenge(tanChallenge: net.dankito.fints.model.FlickerCodeTanChallenge): FlickerCodeTanChallenge { + return FlickerCodeTanChallenge(mapFlickerCode(tanChallenge.flickerCode), tanChallenge.messageToShowToUser, + mapTanProcedure(tanChallenge.tanProcedure) + ) + } + + open fun mapFlickerCode(flickerCode: net.dankito.fints.tan.FlickerCode): FlickerCode { + return FlickerCode(flickerCode.challengeHHD_UC, flickerCode.parsedDataSet, flickerCode.decodingError) + } + + open fun mapTanChallenge(tanChallenge: net.dankito.fints.model.ImageTanChallenge): ImageTanChallenge { + return ImageTanChallenge(mapTanImage(tanChallenge.image), tanChallenge.messageToShowToUser, + mapTanProcedure(tanChallenge.tanProcedure) + ) + } + + open fun mapTanImage(image: net.dankito.fints.tan.TanImage): TanImage { + return TanImage(image.mimeType, image.imageBytes, image.decodingError) + } + } \ No newline at end of file diff --git a/fints4javaLib/src/main/kotlin/net/dankito/fints/FinTsClient.kt b/fints4javaLib/src/main/kotlin/net/dankito/fints/FinTsClient.kt index 9fa33d27..8f979ff3 100644 --- a/fints4javaLib/src/main/kotlin/net/dankito/fints/FinTsClient.kt +++ b/fints4javaLib/src/main/kotlin/net/dankito/fints/FinTsClient.kt @@ -18,7 +18,7 @@ import net.dankito.fints.response.client.FinTsClientResponse import net.dankito.fints.response.client.GetTanMediaListResponse import net.dankito.fints.response.client.GetTransactionsResponse import net.dankito.fints.response.segments.* -import net.dankito.fints.tan.FlickercodeDecoder +import net.dankito.fints.tan.FlickerCodeDecoder import net.dankito.fints.tan.TanImageDecoder import net.dankito.fints.transactions.IAccountTransactionsParser import net.dankito.fints.transactions.Mt940AccountTransactionsParser @@ -648,7 +648,7 @@ open class FinTsClient @JvmOverloads constructor( return when (tanProcedure.type) { TanProcedureType.ChipTanOptisch, TanProcedureType.ChipTanManuell -> - FlickercodeTanChallenge(FlickercodeDecoder().decodeChallenge(challenge), messageToShowToUser, challenge, tanProcedure, tanResponse.tanMediaIdentifier) + FlickerCodeTanChallenge(FlickerCodeDecoder().decodeChallenge(challenge), messageToShowToUser, challenge, tanProcedure, tanResponse.tanMediaIdentifier) TanProcedureType.ChipTanQrCode, TanProcedureType.PhotoTan -> ImageTanChallenge(TanImageDecoder().decodeChallenge(challenge), messageToShowToUser, challenge, tanProcedure, tanResponse.tanMediaIdentifier) diff --git a/fints4javaLib/src/main/kotlin/net/dankito/fints/messages/datenelemente/implementierte/tan/TanGeneratorTanMedium.kt b/fints4javaLib/src/main/kotlin/net/dankito/fints/messages/datenelemente/implementierte/tan/TanGeneratorTanMedium.kt index bb5b9192..1f3391b1 100644 --- a/fints4javaLib/src/main/kotlin/net/dankito/fints/messages/datenelemente/implementierte/tan/TanGeneratorTanMedium.kt +++ b/fints4javaLib/src/main/kotlin/net/dankito/fints/messages/datenelemente/implementierte/tan/TanGeneratorTanMedium.kt @@ -3,7 +3,7 @@ package net.dankito.fints.messages.datenelemente.implementierte.tan import java.util.* -class TanGeneratorTanMedium( +open class TanGeneratorTanMedium( mediumClass: TanMediumKlasse, status: TanMediumStatus, val cardNumber: String, diff --git a/fints4javaLib/src/main/kotlin/net/dankito/fints/model/EnterTanResult.kt b/fints4javaLib/src/main/kotlin/net/dankito/fints/model/EnterTanResult.kt index eb6abcb3..686fcdc6 100644 --- a/fints4javaLib/src/main/kotlin/net/dankito/fints/model/EnterTanResult.kt +++ b/fints4javaLib/src/main/kotlin/net/dankito/fints/model/EnterTanResult.kt @@ -25,7 +25,7 @@ open class EnterTanResult protected constructor( return EnterTanResult(null, changeTanProcedureTo) } - fun userAsksToChangeTanMedium(changeTanMediumTo: TanMedium, changeTanMediumResultCallback: (FinTsClientResponse) -> Unit): EnterTanResult { + fun userAsksToChangeTanMedium(changeTanMediumTo: TanMedium, changeTanMediumResultCallback: ((FinTsClientResponse) -> Unit)?): EnterTanResult { return EnterTanResult(null, null, changeTanMediumTo, changeTanMediumResultCallback) } diff --git a/fints4javaLib/src/main/kotlin/net/dankito/fints/model/FlickercodeTanChallenge.kt b/fints4javaLib/src/main/kotlin/net/dankito/fints/model/FlickerCodeTanChallenge.kt similarity index 70% rename from fints4javaLib/src/main/kotlin/net/dankito/fints/model/FlickercodeTanChallenge.kt rename to fints4javaLib/src/main/kotlin/net/dankito/fints/model/FlickerCodeTanChallenge.kt index f4145631..c30434d1 100644 --- a/fints4javaLib/src/main/kotlin/net/dankito/fints/model/FlickercodeTanChallenge.kt +++ b/fints4javaLib/src/main/kotlin/net/dankito/fints/model/FlickerCodeTanChallenge.kt @@ -1,10 +1,10 @@ package net.dankito.fints.model -import net.dankito.fints.tan.Flickercode +import net.dankito.fints.tan.FlickerCode -open class FlickercodeTanChallenge( - val flickercode: Flickercode, +open class FlickerCodeTanChallenge( + val flickerCode: FlickerCode, messageToShowToUser: String, challenge: String, tanProcedure: TanProcedure, @@ -12,7 +12,7 @@ open class FlickercodeTanChallenge( ) : TanChallenge(messageToShowToUser, challenge, tanProcedure, tanMediaIdentifier) { override fun toString(): String { - return "$tanProcedure (medium: $tanMediaIdentifier) $flickercode: $messageToShowToUser" + return "$tanProcedure (medium: $tanMediaIdentifier) $flickerCode: $messageToShowToUser" } } \ No newline at end of file diff --git a/fints4javaLib/src/main/kotlin/net/dankito/fints/tan/FlickerCanvas.kt b/fints4javaLib/src/main/kotlin/net/dankito/fints/tan/FlickerCanvas.kt index a0e6e240..39e7cbc5 100644 --- a/fints4javaLib/src/main/kotlin/net/dankito/fints/tan/FlickerCanvas.kt +++ b/fints4javaLib/src/main/kotlin/net/dankito/fints/tan/FlickerCanvas.kt @@ -1,15 +1,8 @@ package net.dankito.fints.tan -import org.slf4j.LoggerFactory - open class FlickerCanvas(var code: String) { - companion object { - private val log = LoggerFactory.getLogger(FlickerCanvas::class.java) - } - - var halfbyteid = 0 var clock = Bit.High var bitarray = mutableListOf>() diff --git a/fints4javaLib/src/main/kotlin/net/dankito/fints/tan/Flickercode.kt b/fints4javaLib/src/main/kotlin/net/dankito/fints/tan/FlickerCode.kt similarity index 65% rename from fints4javaLib/src/main/kotlin/net/dankito/fints/tan/Flickercode.kt rename to fints4javaLib/src/main/kotlin/net/dankito/fints/tan/FlickerCode.kt index ac245a9e..c3c7b065 100644 --- a/fints4javaLib/src/main/kotlin/net/dankito/fints/tan/Flickercode.kt +++ b/fints4javaLib/src/main/kotlin/net/dankito/fints/tan/FlickerCode.kt @@ -1,19 +1,19 @@ package net.dankito.fints.tan -open class Flickercode( +open class FlickerCode( val challengeHHD_UC: String, val parsedDataSet: String, - val error: Exception? = null + val decodingError: Exception? = null ) { val decodingSuccessful: Boolean - get() = error == null + get() = decodingError == null override fun toString(): String { if (decodingSuccessful == false) { - return "Decoding error: $error" + return "Decoding error: $decodingError" } return "Parsed $challengeHHD_UC to $parsedDataSet" diff --git a/fints4javaLib/src/main/kotlin/net/dankito/fints/tan/FlickercodeDatenelement.kt b/fints4javaLib/src/main/kotlin/net/dankito/fints/tan/FlickerCodeDatenelement.kt similarity index 69% rename from fints4javaLib/src/main/kotlin/net/dankito/fints/tan/FlickercodeDatenelement.kt rename to fints4javaLib/src/main/kotlin/net/dankito/fints/tan/FlickerCodeDatenelement.kt index 85fabf4f..5a232638 100644 --- a/fints4javaLib/src/main/kotlin/net/dankito/fints/tan/FlickercodeDatenelement.kt +++ b/fints4javaLib/src/main/kotlin/net/dankito/fints/tan/FlickerCodeDatenelement.kt @@ -1,10 +1,10 @@ package net.dankito.fints.tan -open class FlickercodeDatenelement( +open class FlickerCodeDatenelement( val lengthInByte: String, val data: String, - val encoding: FlickercodeEncoding, + val encoding: FlickerCodeEncoding, val endIndex: Int ) { diff --git a/fints4javaLib/src/main/kotlin/net/dankito/fints/tan/FlickercodeDecoder.kt b/fints4javaLib/src/main/kotlin/net/dankito/fints/tan/FlickerCodeDecoder.kt similarity index 84% rename from fints4javaLib/src/main/kotlin/net/dankito/fints/tan/FlickercodeDecoder.kt rename to fints4javaLib/src/main/kotlin/net/dankito/fints/tan/FlickerCodeDecoder.kt index ff415d39..07c179b0 100644 --- a/fints4javaLib/src/main/kotlin/net/dankito/fints/tan/FlickercodeDecoder.kt +++ b/fints4javaLib/src/main/kotlin/net/dankito/fints/tan/FlickerCodeDecoder.kt @@ -4,16 +4,16 @@ import org.slf4j.LoggerFactory import java.util.regex.Pattern -open class FlickercodeDecoder { +open class FlickerCodeDecoder { companion object { val ContainsOtherSymbolsThanFiguresPattern: Pattern = Pattern.compile("\\D") - private val log = LoggerFactory.getLogger(FlickercodeDecoder::class.java) + private val log = LoggerFactory.getLogger(FlickerCodeDecoder::class.java) } - open fun decodeChallenge(challengeHHD_UC: String): Flickercode { + open fun decodeChallenge(challengeHHD_UC: String): FlickerCode { try { val challengeLength = parseIntToHex(challengeHHD_UC.substring(0, 2)) @@ -40,28 +40,28 @@ open class FlickercodeDecoder { val parsedDataSet = dataWithoutChecksum + luhnChecksum + xorChecksumString - return Flickercode(challengeHHD_UC, parsedDataSet) + return FlickerCode(challengeHHD_UC, parsedDataSet) } catch (e: Exception) { log.error("Could not decode challenge $challengeHHD_UC") - return Flickercode(challengeHHD_UC, "", e) + return FlickerCode(challengeHHD_UC, "", e) } } - protected fun parseStartCode(challengeHHD_UC: String, startIndex: Int): FlickercodeDatenelement { + protected open fun parseStartCode(challengeHHD_UC: String, startIndex: Int): FlickerCodeDatenelement { return parseDatenelement(challengeHHD_UC, startIndex) { lengthByteString -> parseIntToHex(lengthByteString) } } - protected open fun parseDatenelement(code: String, startIndex: Int): FlickercodeDatenelement { + protected open fun parseDatenelement(code: String, startIndex: Int): FlickerCodeDatenelement { return parseDatenelement(code, startIndex) { lengthByteString -> lengthByteString.toInt() } } - protected open fun parseDatenelement(code: String, startIndex: Int, lengthParser: (lengthByteString: String) -> Int): FlickercodeDatenelement { + protected open fun parseDatenelement(code: String, startIndex: Int, lengthParser: (lengthByteString: String) -> Int): FlickerCodeDatenelement { val lengthByteLength = 2 val dataElementAndRest = code.substring(startIndex) if (dataElementAndRest.isEmpty() || dataElementAndRest.length < lengthByteLength) { // data element not set - return FlickercodeDatenelement("", "", FlickercodeEncoding.BCD, startIndex) + return FlickerCodeDatenelement("", "", FlickerCodeEncoding.BCD, startIndex) } val lengthByteString = dataElementAndRest.substring(0, lengthByteLength) @@ -76,14 +76,14 @@ open class FlickercodeDecoder { // Sollte ein Datenelement eine Zahl mit Komma-Trennung oder Vorzeichen beinhalten (z. B. Betrag oder Anzahl), // so muss als Format ASCII gewählt werden, da ggf. auch ein Sonderzeichen mit übertragen werden muss. if (ContainsOtherSymbolsThanFiguresPattern.matcher(data).find()) { - encoding = FlickercodeEncoding.ASCII + encoding = FlickerCodeEncoding.ASCII } - if (encoding == FlickercodeEncoding.ASCII) { + if (encoding == FlickerCodeEncoding.ASCII) { data = data.map { toHex(it.toInt(), 2) }.joinToString("") } - if (encoding == FlickercodeEncoding.BCD && data.length % 2 != 0) { + if (encoding == FlickerCodeEncoding.BCD && data.length % 2 != 0) { data += "F" // Im Format BCD ggf. mit „F“ auf Bytegrenze ergänzt } @@ -91,7 +91,7 @@ open class FlickercodeDecoder { var lengthInByte = dataLength / 2 - if (encoding == FlickercodeEncoding.ASCII) { + if (encoding == FlickerCodeEncoding.ASCII) { if (lengthInByte < 16) { lengthInByte += 16 // set left half byte to '1' for ASCII } @@ -99,7 +99,7 @@ open class FlickercodeDecoder { val lengthInByteString = toHex(lengthInByte, 2) - return FlickercodeDatenelement( + return FlickerCodeDatenelement( lengthInByteString, data, encoding, @@ -107,8 +107,8 @@ open class FlickercodeDecoder { ) } - protected open fun getEncodingFromLengthByte(engthByte: Int): FlickercodeEncoding { - return if (isBitSet(engthByte, 6)) FlickercodeEncoding.ASCII else FlickercodeEncoding.BCD + protected open fun getEncodingFromLengthByte(engthByte: Int): FlickerCodeEncoding { + return if (isBitSet(engthByte, 6)) FlickerCodeEncoding.ASCII else FlickerCodeEncoding.BCD } protected open fun getLengthFromLengthByte(lengthByte: Int): Int { @@ -116,8 +116,8 @@ open class FlickercodeDecoder { } - protected open fun calculateLuhnChecksum(startCode: FlickercodeDatenelement, controlByte: String, - de1: FlickercodeDatenelement, de2: FlickercodeDatenelement, de3: FlickercodeDatenelement): Int { + protected open fun calculateLuhnChecksum(startCode: FlickerCodeDatenelement, controlByte: String, + de1: FlickerCodeDatenelement, de2: FlickerCodeDatenelement, de3: FlickerCodeDatenelement): Int { val luhnData = controlByte + startCode.data + de1.data + de2.data + de3.data diff --git a/fints4javaLib/src/main/kotlin/net/dankito/fints/tan/FlickercodeEncoding.kt b/fints4javaLib/src/main/kotlin/net/dankito/fints/tan/FlickerCodeEncoding.kt similarity index 61% rename from fints4javaLib/src/main/kotlin/net/dankito/fints/tan/FlickercodeEncoding.kt rename to fints4javaLib/src/main/kotlin/net/dankito/fints/tan/FlickerCodeEncoding.kt index 6ad84383..1f40aa60 100644 --- a/fints4javaLib/src/main/kotlin/net/dankito/fints/tan/FlickercodeEncoding.kt +++ b/fints4javaLib/src/main/kotlin/net/dankito/fints/tan/FlickerCodeEncoding.kt @@ -1,7 +1,7 @@ package net.dankito.fints.tan -enum class FlickercodeEncoding { +enum class FlickerCodeEncoding { BCD, diff --git a/fints4javaLib/src/main/kotlin/net/dankito/fints/tan/TanImage.kt b/fints4javaLib/src/main/kotlin/net/dankito/fints/tan/TanImage.kt index 14aeb818..ddc98e49 100644 --- a/fints4javaLib/src/main/kotlin/net/dankito/fints/tan/TanImage.kt +++ b/fints4javaLib/src/main/kotlin/net/dankito/fints/tan/TanImage.kt @@ -4,16 +4,16 @@ package net.dankito.fints.tan open class TanImage( val mimeType: String, val imageBytes: ByteArray, - val error: Exception? = null + val decodingError: Exception? = null ) { val decodingSuccessful: Boolean - get() = error == null + get() = decodingError == null override fun toString(): String { if (decodingSuccessful == false) { - return "Decoding error: $error" + return "Decoding error: $decodingError" } return "$mimeType ${imageBytes.size} bytes" diff --git a/fints4javaLib/src/test/kotlin/net/dankito/fints/tan/FlickercodeDecoderTest.kt b/fints4javaLib/src/test/kotlin/net/dankito/fints/tan/FlickerCodeDecoderTest.kt similarity index 94% rename from fints4javaLib/src/test/kotlin/net/dankito/fints/tan/FlickercodeDecoderTest.kt rename to fints4javaLib/src/test/kotlin/net/dankito/fints/tan/FlickerCodeDecoderTest.kt index c6010b9c..13f2d63f 100644 --- a/fints4javaLib/src/test/kotlin/net/dankito/fints/tan/FlickercodeDecoderTest.kt +++ b/fints4javaLib/src/test/kotlin/net/dankito/fints/tan/FlickerCodeDecoderTest.kt @@ -4,9 +4,9 @@ import org.assertj.core.api.Assertions.assertThat import org.junit.Test -class FlickercodeDecoderTest { +class FlickerCodeDecoderTest { - private val underTest = FlickercodeDecoder() + private val underTest = FlickerCodeDecoder() @Test diff --git a/settings.gradle b/settings.gradle index 99051208..7aacda42 100644 --- a/settings.gradle +++ b/settings.gradle @@ -6,4 +6,6 @@ include ':BankListCreator' include ':BankingUiCommon' +include ':fints4javaBankingClient' + include ':fints4javaAndroidApp' \ No newline at end of file