Implemented selected TAN procedure after successfully adding an account

This commit is contained in:
dankl 2019-10-31 00:52:49 +01:00 committed by dankito
parent ce3a7c564d
commit 8892368782
7 changed files with 166 additions and 28 deletions

View File

@ -11,6 +11,7 @@ import net.dankito.fints.response.client.FinTsClientResponse
import net.dankito.fints.response.client.GetTransactionsResponse import net.dankito.fints.response.client.GetTransactionsResponse
import net.dankito.utils.IThreadPool import net.dankito.utils.IThreadPool
import net.dankito.utils.ThreadPool import net.dankito.utils.ThreadPool
import java.math.BigDecimal
import java.util.* import java.util.*
import kotlin.collections.ArrayList import kotlin.collections.ArrayList
@ -28,9 +29,11 @@ open class MainWindowPresenter(callback: FinTsClientCallback) {
protected val accounts = mutableMapOf<CustomerData, BankData>() protected val accounts = mutableMapOf<CustomerData, BankData>()
protected val bookedTransactions = mutableSetOf<AccountTransaction>() // TODO: map by account protected val bookedTransactions = mutableMapOf<CustomerData, MutableSet<AccountTransaction>>()
protected val unbookedTransactions = mutableSetOf<Any>() protected val unbookedTransactions = mutableMapOf<CustomerData, MutableSet<Any>>()
protected val balances = mutableMapOf<CustomerData, BigDecimal>()
protected val accountAddedListeners = mutableListOf<(BankData, CustomerData) -> Unit>() protected val accountAddedListeners = mutableListOf<(BankData, CustomerData) -> Unit>()
@ -45,9 +48,11 @@ open class MainWindowPresenter(callback: FinTsClientCallback) {
if (response.isSuccessful) { if (response.isSuccessful) {
accounts.put(customer, bank) accounts.put(customer, bank)
// TODO: show booked transactions of last 90 days in HomeFragment if available
callAccountAddedListeners(bank, customer) callAccountAddedListeners(bank, customer)
if (response.supportsRetrievingTransactionsOfLast90DaysWithoutTan) {
retrievedAccountTransactions(customer, response)
}
} }
callback(response) callback(response)
@ -65,21 +70,43 @@ open class MainWindowPresenter(callback: FinTsClientCallback) {
callback: (GetTransactionsResponse) -> Unit) { callback: (GetTransactionsResponse) -> Unit) {
finTsClient.getTransactionsAsync(GetTransactionsParameter(true, fromDate), bank, customer) { response -> finTsClient.getTransactionsAsync(GetTransactionsParameter(true, fromDate), bank, customer) { response ->
if (response.isSuccessful) { retrievedAccountTransactions(customer, response)
bookedTransactions.addAll(response.bookedTransactions) // TODO: does currently not work, overwrite equals()
unbookedTransactions.addAll(response.unbookedTransactions)
}
callback(response) // TODO: does not return all booked transactions, only the newly retrieved ones! callback(response) // TODO: does not return all booked transactions, only the newly retrieved ones!
} }
} }
open fun updateAccountsTransactionsAsync(callback: (GetTransactionsResponse) -> Unit) { open fun updateAccountsTransactionsAsync(callback: (GetTransactionsResponse) -> Unit) {
val today = Date() // TODO: still don't know where this bug is coming from that bank returns a transaction dated at end of year accounts.forEach { entry ->
val lastRetrievedTransactionDate = bookedTransactions.firstOrNull { it.bookingDate <= today }?.bookingDate // TODO: make multi-account ready; currently if don't differentiate booked transactions by accounts val customer = entry.key
val fromDate = lastRetrievedTransactionDate?.let { Date(it.time - 24 * 60 * 60 * 1000) } // on day before last received transaction 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 = bookedTransactions[customer]?.firstOrNull { it.bookingDate <= today }?.bookingDate
val fromDate = lastRetrievedTransactionDate?.let { Date(it.time - 24 * 60 * 60 * 1000) } // on day before last received transaction
accounts.forEach { entry -> getAccountTransactionsAsync(entry.value, entry.key, fromDate, callback) } // TODO: this is not a good solution for multiple accounts getAccountTransactionsAsync(entry.value, customer, fromDate, callback)
}
}
protected open fun retrievedAccountTransactions(customer: CustomerData, response: GetTransactionsResponse) {
if (response.isSuccessful) {
if (bookedTransactions.containsKey(customer) == false) {
bookedTransactions.put(customer, response.bookedTransactions.toMutableSet())
}
else {
bookedTransactions[customer]?.addAll(response.bookedTransactions) // TODO: does currently not work, overwrite equals()
}
if (unbookedTransactions.containsKey(customer) == false) {
unbookedTransactions.put(customer, response.unbookedTransactions.toMutableSet())
}
else {
unbookedTransactions[customer]?.addAll(response.unbookedTransactions)
}
response.balance?.let {
balances[customer] = it
}
}
} }
@ -105,10 +132,10 @@ open class MainWindowPresenter(callback: FinTsClientCallback) {
val queryLowercase = query.trim().toLowerCase() val queryLowercase = query.trim().toLowerCase()
if (queryLowercase.isEmpty()) { if (queryLowercase.isEmpty()) {
return bookedTransactions.toList() return bookedTransactions.values.flatten().toList()
} }
return bookedTransactions.filter { return bookedTransactions.values.flatten().filter {
it.otherPartyName?.toLowerCase()?.contains(queryLowercase) == true it.otherPartyName?.toLowerCase()?.contains(queryLowercase) == true
|| it.usage.toLowerCase().contains(queryLowercase) || it.usage.toLowerCase().contains(queryLowercase)
|| it.bookingText?.toLowerCase()?.contains(queryLowercase) == true || it.bookingText?.toLowerCase()?.contains(queryLowercase) == true

View File

@ -0,0 +1,25 @@
package net.dankito.banking.fints4java.android.ui.adapter
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import net.dankito.banking.fints4java.android.R
import net.dankito.fints.model.TanProcedure
import net.dankito.utils.android.extensions.asActivity
import net.dankito.utils.android.ui.adapter.ListAdapter
open class TanProceduresAdapter : ListAdapter<TanProcedure>() {
override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View? {
val procedure = getItem(position)
val view = convertView ?: parent?.context?.asActivity()?.layoutInflater?.inflate(
R.layout.list_item_tan_procedure, parent, false)
view?.findViewById<TextView>(R.id.txtTanProcedureDisplayName)?.text = procedure.displayName
return view
}
}

View File

@ -1,5 +1,6 @@
package net.dankito.banking.fints4java.android.ui.dialogs package net.dankito.banking.fints4java.android.ui.dialogs
import android.content.Context
import android.content.DialogInterface import android.content.DialogInterface
import android.os.Bundle import android.os.Bundle
import android.support.v4.app.DialogFragment import android.support.v4.app.DialogFragment
@ -10,11 +11,15 @@ import android.text.TextWatcher
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.AdapterView
import android.widget.Spinner
import android.widget.TextView
import kotlinx.android.synthetic.main.dialog_add_account.* import kotlinx.android.synthetic.main.dialog_add_account.*
import kotlinx.android.synthetic.main.dialog_add_account.view.* import kotlinx.android.synthetic.main.dialog_add_account.view.*
import net.dankito.banking.fints4java.android.R import net.dankito.banking.fints4java.android.R
import net.dankito.banking.fints4java.android.ui.MainWindowPresenter import net.dankito.banking.fints4java.android.ui.MainWindowPresenter
import net.dankito.banking.fints4java.android.ui.adapter.BankListAdapter import net.dankito.banking.fints4java.android.ui.adapter.BankListAdapter
import net.dankito.banking.fints4java.android.ui.adapter.TanProceduresAdapter
import net.dankito.fints.model.BankInfo import net.dankito.fints.model.BankInfo
import net.dankito.fints.response.client.AddAccountResponse import net.dankito.fints.response.client.AddAccountResponse
import net.dankito.utils.android.extensions.asActivity import net.dankito.utils.android.extensions.asActivity
@ -91,16 +96,7 @@ open class AddAccountDialog : DialogFragment() {
if (response.isSuccessful) { if (response.isSuccessful) {
this.dismiss() this.dismiss()
val messageId = if (response.supportsRetrievingTransactionsOfLast90DaysWithoutTan) showMessageForSuccessfullyAddedAccount(context, response)
R.string.dialog_add_account_message_successfully_added_account_support_retrieving_transactions_of_last_90_days_without_tan
else R.string.dialog_add_account_message_successfully_added_account
AlertDialog.Builder(context)
.setMessage(messageId)
.setPositiveButton(R.string.yes) { dialog, _ -> retrieveAccountTransactionsAndDismiss(response, dialog) }
.setNeutralButton(R.string.later) { dialog, _ -> dialog.dismiss() }
.setNegativeButton(R.string.do_not_ask_anymore) { dialog, _ -> setDoNotAskAnymoreAndDismiss(dialog) }
.show()
} }
else { else {
AlertDialog.Builder(context) AlertDialog.Builder(context)
@ -111,6 +107,47 @@ open class AddAccountDialog : DialogFragment() {
} }
} }
protected open fun showMessageForSuccessfullyAddedAccount(context: Context, response: AddAccountResponse) {
val view = createSuccessfullyAddedAccountView(context, response)
AlertDialog.Builder(context)
.setView(view)
.setPositiveButton(R.string.yes) { dialog, _ -> retrieveAccountTransactionsAndDismiss(response, dialog) }
.setNeutralButton(R.string.later) { dialog, _ -> dialog.dismiss() }
.setNegativeButton(R.string.do_not_ask_anymore) { dialog, _ -> setDoNotAskAnymoreAndDismiss(dialog) }
.show()
}
protected open fun createSuccessfullyAddedAccountView(context: Context, response: AddAccountResponse): View? {
val messageId = if (response.supportsRetrievingTransactionsOfLast90DaysWithoutTan)
R.string.dialog_add_account_message_successfully_added_account_support_retrieving_transactions_of_last_90_days_without_tan
else R.string.dialog_add_account_message_successfully_added_account
val view = context.asActivity()?.layoutInflater?.inflate(R.layout.view_successfully_added_account, null)
val adapter = TanProceduresAdapter()
adapter.setItems(response.customer.supportedTanProcedures)
view?.findViewById<TextView>(R.id.txtSuccessfullyAddedAccountMessage)?.setText(messageId)
view?.findViewById<Spinner>(R.id.spnTanProcedures)?.let { spinner ->
spinner.adapter = adapter
spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onNothingSelected(parent: AdapterView<*>?) {}
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
response.customer.selectedTanProcedure = adapter.getItem(position)
}
}
spinner.setSelection(adapter.getItems().indexOfFirst { it.displayName.contains("manuell", true) == false })
}
return view
}
protected open fun retrieveAccountTransactionsAndDismiss(response: AddAccountResponse, messageDialog: DialogInterface) { protected open fun retrieveAccountTransactionsAndDismiss(response: AddAccountResponse, messageDialog: DialogInterface) {
presenter.getAccountTransactionsAsync(response.bank, response.customer) { } // TODO: show error message if not successful. Here or in HomeFragment presenter.getAccountTransactionsAsync(response.bank, response.customer) { } // TODO: show error message if not successful. Here or in HomeFragment

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/txtTanProcedureDisplayName"
style="@style/TextAppearance.AppCompat.Medium"
android:singleLine="true"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:ellipsize="marquee"
/>

View File

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="@dimen/view_successfully_added_account_padding"
>
<TextView
android:id="@+id/txtSuccessfullyAddedAccountMessage"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/view_successfully_added_account_message_margin_bottom"
style="@style/TextAppearance.AppCompat.Medium"
/>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="@dimen/view_successfully_added_account_tan_procedures_height"
android:gravity="center_vertical"
>
<Spinner
android:id="@+id/spnTanProcedures"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center_vertical"
/>
</LinearLayout>
</LinearLayout>

View File

@ -29,6 +29,10 @@
<dimen name="list_item_bank_info_bank_code_and_address_height">30dp</dimen> <dimen name="list_item_bank_info_bank_code_and_address_height">30dp</dimen>
<dimen name="list_item_bank_info_bank_code_width">80dp</dimen> <dimen name="list_item_bank_info_bank_code_width">80dp</dimen>
<dimen name="view_successfully_added_account_padding">12dp</dimen>
<dimen name="view_successfully_added_account_message_margin_bottom">12dp</dimen>
<dimen name="view_successfully_added_account_tan_procedures_height">40dp</dimen>
<dimen name="dialog_bank_transfer_padding">4dp</dimen> <dimen name="dialog_bank_transfer_padding">4dp</dimen>
<dimen name="dialog_bank_transfer_input_fields_height">40dp</dimen> <dimen name="dialog_bank_transfer_input_fields_height">40dp</dimen>
<dimen name="dialog_bank_transfer_autocomplete_fields_height">50dp</dimen> <dimen name="dialog_bank_transfer_autocomplete_fields_height">50dp</dimen>

View File

@ -12,8 +12,8 @@ open class AddAccountResponse(
val bank: BankData, val bank: BankData,
val customer: CustomerData, val customer: CustomerData,
val supportsRetrievingTransactionsOfLast90DaysWithoutTan: Boolean = false, val supportsRetrievingTransactionsOfLast90DaysWithoutTan: Boolean = false,
val bookedTransactionsOfLast90Days: List<AccountTransaction> = listOf(), bookedTransactionsOfLast90Days: List<AccountTransaction> = listOf(),
val unbookedTransactionsOfLast90Days: List<Any> = listOf(), unbookedTransactionsOfLast90Days: List<Any> = listOf(),
val balance: BigDecimal? = null balance: BigDecimal? = null
) )
: FinTsClientResponse(response) : GetTransactionsResponse(response, bookedTransactionsOfLast90Days, unbookedTransactionsOfLast90Days, balance)