Implemented mapping and displaying if an account type is supported or not
This commit is contained in:
parent
a59b335316
commit
700e3e6da9
|
@ -9,7 +9,7 @@ However it's not a full implementation of FinTS standard but implements all comm
|
|||
## Features
|
||||
- Retrieving account information, balances and turnovers (Kontoumsätze und -saldo).
|
||||
- Transfer money and instant payments (SEPA Überweisungen und Echtzeitüberweisung).
|
||||
- Supports TAN procedures chipTAN manual, Flickercode, QrCode and Photo (Matrix code), pushTAN, smsTAN and appTAN.
|
||||
- Supports TAN methods chipTAN manual, Flickercode, QrCode and Photo (Matrix code), pushTAN, smsTAN and appTAN.
|
||||
|
||||
## Setup
|
||||
Not uploaded to Maven Central yet, will do this the next few days!
|
||||
|
|
|
@ -42,6 +42,8 @@ open class FinTsClient(
|
|||
) {
|
||||
|
||||
companion object {
|
||||
val SupportedAccountTypes = listOf(AccountType.Girokonto, AccountType.Festgeldkonto)
|
||||
|
||||
val FindAccountTransactionsStartRegex = Regex("^HIKAZ:\\d:\\d:\\d\\+@\\d+@", RegexOption.MULTILINE)
|
||||
val FindAccountTransactionsEndRegex = Regex("^-'", RegexOption.MULTILINE)
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package net.dankito.banking.fints.model
|
||||
|
||||
import net.dankito.banking.fints.FinTsClient
|
||||
import net.dankito.banking.fints.messages.datenelemente.abgeleiteteformate.Laenderkennzeichen
|
||||
import net.dankito.banking.fints.response.segments.AccountType
|
||||
import net.dankito.banking.fints.response.segments.JobParameters
|
||||
|
@ -27,6 +28,10 @@ open class AccountData(
|
|||
protected open val _supportedFeatures = mutableSetOf<AccountFeature>()
|
||||
|
||||
|
||||
open val isAccountTypeSupported: Boolean
|
||||
get() = FinTsClient.SupportedAccountTypes.contains(accountType)
|
||||
|
||||
|
||||
open fun supportsFeature(feature: AccountFeature): Boolean {
|
||||
return _supportedFeatures.contains(feature)
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ import net.dankito.banking.persistence.dao.*
|
|||
import net.dankito.banking.persistence.model.*
|
||||
|
||||
|
||||
@Database(entities = [ Bank::class, BankAccount::class, AccountTransaction::class, TanProcedure::class, TanMedium::class ],
|
||||
@Database(entities = [ Bank::class, BankAccount::class, AccountTransaction::class, TanMethod::class, TanMedium::class ],
|
||||
version = 1, exportSchema = false)
|
||||
@TypeConverters(net.dankito.banking.persistence.TypeConverters::class)
|
||||
abstract class BankingDatabase : RoomDatabase() {
|
||||
|
@ -18,7 +18,7 @@ abstract class BankingDatabase : RoomDatabase() {
|
|||
|
||||
abstract fun accountTransactionDao(): AccountTransactionDao
|
||||
|
||||
abstract fun tanProcedureDao(): TanProcedureDao
|
||||
abstract fun tanMethodDao(): TanMethodDao
|
||||
|
||||
abstract fun tanMediumDao(): TanMediumDao
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ open class RoomBankingPersistence(applicationContext: Context, password: String?
|
|||
|
||||
override fun saveOrUpdateAccount(customer: TypedCustomer, allCustomers: List<TypedCustomer>) {
|
||||
(customer as? Bank)?.let { bank ->
|
||||
bank.selectedTanProcedureId = bank.selectedTanProcedure?.technicalId
|
||||
bank.selectedTanMethodId = bank.selectedTanMethod?.technicalId
|
||||
|
||||
db.bankDao().saveOrUpdate(bank)
|
||||
|
||||
|
@ -43,19 +43,19 @@ open class RoomBankingPersistence(applicationContext: Context, password: String?
|
|||
accounts.forEach { it.bankId = bank.id }
|
||||
db.bankAccountDao().saveOrUpdate(accounts)
|
||||
|
||||
// TODO: in this way removed TAN procedures won't be deleted from DB and therefore still be visible to user
|
||||
val tanProcedures = bank.supportedTanProcedures.filterIsInstance<TanProcedure>()
|
||||
tanProcedures.forEach { tanProcedure ->
|
||||
if (tanProcedure.bankId == BaseDao.ObjectNotInsertedId) {
|
||||
tanProcedure.bankId = bank.id
|
||||
db.tanProcedureDao().insert(tanProcedure)
|
||||
// TODO: in this way removed TAN methods won't be deleted from DB and therefore still be visible to user
|
||||
val tanMethods = bank.supportedTanMethods.filterIsInstance<TanMethod>()
|
||||
tanMethods.forEach { tantanMethod ->
|
||||
if (tantanMethod.bankId == BaseDao.ObjectNotInsertedId) {
|
||||
tantanMethod.bankId = bank.id
|
||||
db.tanMethodDao().insert(tantanMethod)
|
||||
}
|
||||
else {
|
||||
db.tanProcedureDao().update(tanProcedure)
|
||||
db.tanMethodDao().update(tantanMethod)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: in this way removed TAN procedures won't be deleted from DB and therefore still be visible to user
|
||||
// TODO: in this way removed TAN media won't be deleted from DB and therefore still be visible to user
|
||||
val tanMedia = bank.tanMedia.map { tanMedium ->
|
||||
bank.tanMediumEntities.firstOrNull { it.id == tanMedium.technicalId } ?: map(bank, tanMedium)
|
||||
}
|
||||
|
@ -70,7 +70,7 @@ open class RoomBankingPersistence(applicationContext: Context, password: String?
|
|||
|
||||
db.bankAccountDao().delete(bank.accounts.filterIsInstance<BankAccount>())
|
||||
|
||||
db.tanProcedureDao().delete(bank.supportedTanProcedures.filterIsInstance<TanProcedure>())
|
||||
db.tanMethodDao().delete(bank.supportedTanMethods.filterIsInstance<TanMethod>())
|
||||
db.tanMediumDao().delete(bank.tanMedia.filterIsInstance<TanMedium>())
|
||||
|
||||
db.bankDao().delete(bank)
|
||||
|
@ -84,7 +84,7 @@ open class RoomBankingPersistence(applicationContext: Context, password: String?
|
|||
|
||||
val transactions = db.accountTransactionDao().getAll()
|
||||
|
||||
val tanProcedures = db.tanProcedureDao().getAll()
|
||||
val tanMethods = db.tanMethodDao().getAll()
|
||||
|
||||
val tanMedia = db.tanMediumDao().getAll()
|
||||
|
||||
|
@ -101,8 +101,8 @@ open class RoomBankingPersistence(applicationContext: Context, password: String?
|
|||
}
|
||||
}
|
||||
|
||||
bank.supportedTanProcedures = tanProcedures.filter { it.bankId == bank.id }
|
||||
bank.selectedTanProcedure = bank.supportedTanProcedures.firstOrNull { it.technicalId == bank.selectedTanProcedureId }
|
||||
bank.supportedTanMethods = tanMethods.filter { it.bankId == bank.id }
|
||||
bank.selectedTanMethod = bank.supportedTanMethods.firstOrNull { it.technicalId == bank.selectedTanMethodId }
|
||||
|
||||
bank.tanMediumEntities = tanMedia.filter { it.bankId == bank.id }
|
||||
bank.tanMedia = bank.tanMediumEntities.map { map(it) }
|
||||
|
|
|
@ -5,7 +5,7 @@ import net.dankito.banking.persistence.model.TanMediumType
|
|||
import net.dankito.banking.ui.model.BankAccountType
|
||||
import net.dankito.banking.ui.model.tan.AllowedTanFormat
|
||||
import net.dankito.banking.ui.model.tan.TanMediumStatus
|
||||
import net.dankito.banking.ui.model.tan.TanProcedureType
|
||||
import net.dankito.banking.ui.model.tan.TanMethodType
|
||||
import net.dankito.utils.multiplatform.BigDecimal
|
||||
import net.dankito.utils.multiplatform.Date
|
||||
|
||||
|
@ -46,13 +46,13 @@ open class TypeConverters {
|
|||
|
||||
|
||||
@TypeConverter
|
||||
fun fromTanProcedureType(value: TanProcedureType): Int {
|
||||
fun fromTanMethodType(value: TanMethodType): Int {
|
||||
return value.ordinal
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
fun toTanProcedureType(value: Int): TanProcedureType {
|
||||
return TanProcedureType.values().first { it.ordinal == value }
|
||||
fun toTanMethodType(value: Int): TanMethodType {
|
||||
return TanMethodType.values().first { it.ordinal == value }
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
package net.dankito.banking.persistence.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Query
|
||||
import net.dankito.banking.persistence.model.TanMethod
|
||||
|
||||
|
||||
@Dao
|
||||
interface TanMethodDao : BaseDao<TanMethod> {
|
||||
|
||||
@Query("SELECT * FROM TanMethod")
|
||||
fun getAll(): List<TanMethod>
|
||||
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
package net.dankito.banking.persistence.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Query
|
||||
import net.dankito.banking.persistence.model.TanProcedure
|
||||
|
||||
|
||||
@Dao
|
||||
interface TanProcedureDao : BaseDao<TanProcedure> {
|
||||
|
||||
@Query("SELECT * FROM TanProcedure")
|
||||
fun getAll(): List<TanProcedure>
|
||||
|
||||
}
|
|
@ -7,7 +7,7 @@ import net.dankito.banking.persistence.dao.BaseDao
|
|||
import net.dankito.banking.ui.model.TypedBankAccount
|
||||
import net.dankito.banking.ui.model.TypedCustomer
|
||||
import net.dankito.banking.ui.model.tan.TanMedium
|
||||
import net.dankito.banking.ui.model.tan.TanProcedure
|
||||
import net.dankito.banking.ui.model.tan.TanMethod
|
||||
|
||||
|
||||
@Entity
|
||||
|
@ -25,11 +25,11 @@ open class Bank(
|
|||
|
||||
@Ignore
|
||||
override var accounts: List<TypedBankAccount> = listOf(),
|
||||
|
||||
|
||||
@Ignore
|
||||
override var supportedTanProcedures: List<TanProcedure> = listOf(),
|
||||
override var supportedTanMethods: List<TanMethod> = listOf(),
|
||||
@Ignore
|
||||
override var selectedTanProcedure: TanProcedure? = null,
|
||||
override var selectedTanMethod: TanMethod? = null,
|
||||
@Ignore
|
||||
override var tanMedia: List<TanMedium> = listOf(),
|
||||
|
||||
|
@ -49,7 +49,7 @@ open class Bank(
|
|||
internal constructor() : this("", "", "", "", "", "", "") // for object deserializers
|
||||
|
||||
|
||||
open var selectedTanProcedureId: String? = null
|
||||
open var selectedTanMethodId: String? = null
|
||||
|
||||
@Ignore
|
||||
open var tanMediumEntities = listOf<net.dankito.banking.persistence.model.TanMedium>()
|
||||
|
|
|
@ -58,6 +58,8 @@ open class BankAccount(
|
|||
|
||||
override var haveAllTransactionsBeenFetched: Boolean = false
|
||||
|
||||
override var isAccountTypeSupported: Boolean = true
|
||||
|
||||
|
||||
override var userSetDisplayName: String? = null
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ import net.dankito.banking.ui.model.TypedBankAccount
|
|||
import net.dankito.banking.ui.model.TypedCustomer
|
||||
import net.dankito.banking.ui.model.mapper.IModelCreator
|
||||
import net.dankito.banking.ui.model.tan.AllowedTanFormat
|
||||
import net.dankito.banking.ui.model.tan.TanProcedureType
|
||||
import net.dankito.banking.ui.model.tan.TanMethodType
|
||||
import net.dankito.utils.multiplatform.BigDecimal
|
||||
import net.dankito.utils.multiplatform.Date
|
||||
|
||||
|
@ -66,8 +66,8 @@ open class RoomModelCreator : IModelCreator {
|
|||
}
|
||||
|
||||
|
||||
override fun createTanProcedure(displayName: String, type: TanProcedureType, bankInternalProcedureCode: String, maxTanInputLength: Int?, allowedTanFormat: AllowedTanFormat): net.dankito.banking.ui.model.tan.TanProcedure {
|
||||
return TanProcedure(displayName, type, bankInternalProcedureCode, maxTanInputLength, allowedTanFormat)
|
||||
override fun createTanMethod(displayName: String, type: TanMethodType, bankInternalMethodCode: String, maxTanInputLength: Int?, allowedTanFormat: AllowedTanFormat): net.dankito.banking.ui.model.tan.TanMethod {
|
||||
return TanMethod(displayName, type, bankInternalMethodCode, maxTanInputLength, allowedTanFormat)
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package net.dankito.banking.persistence.model
|
||||
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
import net.dankito.banking.persistence.dao.BaseDao
|
||||
import net.dankito.banking.ui.model.tan.AllowedTanFormat
|
||||
import net.dankito.banking.ui.model.tan.TanMethod
|
||||
import net.dankito.banking.ui.model.tan.TanMethodType
|
||||
|
||||
|
||||
@Entity
|
||||
open class TanMethod(
|
||||
override var displayName: String,
|
||||
override var type: TanMethodType,
|
||||
override var bankInternalMethodCode: String,
|
||||
override var maxTanInputLength: Int? = null,
|
||||
override var allowedTanFormat: AllowedTanFormat = AllowedTanFormat.Alphanumeric
|
||||
) : TanMethod(displayName, type, bankInternalMethodCode, maxTanInputLength, allowedTanFormat) {
|
||||
|
||||
internal constructor() : this("", TanMethodType.EnterTan, "") // for object deserializers
|
||||
|
||||
|
||||
@PrimaryKey
|
||||
open var id: String = technicalId
|
||||
|
||||
// Room doesn't allow me to add getters and setters -> have to map it manually
|
||||
open var bankId: Long = BaseDao.ObjectNotInsertedId
|
||||
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
package net.dankito.banking.persistence.model
|
||||
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
import net.dankito.banking.persistence.dao.BaseDao
|
||||
import net.dankito.banking.ui.model.tan.AllowedTanFormat
|
||||
import net.dankito.banking.ui.model.tan.TanProcedure
|
||||
import net.dankito.banking.ui.model.tan.TanProcedureType
|
||||
|
||||
|
||||
@Entity
|
||||
open class TanProcedure(
|
||||
displayName: String,
|
||||
type: TanProcedureType,
|
||||
bankInternalProcedureCode: String,
|
||||
maxTanInputLength: Int? = null,
|
||||
allowedTanFormat: AllowedTanFormat = AllowedTanFormat.Alphanumeric
|
||||
) : TanProcedure(displayName, type, bankInternalProcedureCode, maxTanInputLength, allowedTanFormat) {
|
||||
|
||||
internal constructor() : this("", TanProcedureType.EnterTan, "") // for object deserializers
|
||||
|
||||
|
||||
@PrimaryKey
|
||||
open var id: String = technicalId
|
||||
|
||||
// Room doesn't allow me to add getters and setters -> have to map it manually
|
||||
open var bankId: Long = BaseDao.ObjectNotInsertedId
|
||||
|
||||
}
|
|
@ -32,6 +32,7 @@ open class BankAccountEntity(
|
|||
override var technicalId: String = UUID.random(),
|
||||
override var userSetDisplayName: String? = null,
|
||||
override var haveAllTransactionsBeenFetched: Boolean = false,
|
||||
override var isAccountTypeSupported: Boolean = true,
|
||||
override var displayIndex: Int = 0
|
||||
|
||||
) : IBankAccount<AccountTransactionEntity> {
|
||||
|
|
|
@ -32,6 +32,13 @@ import javax.inject.Inject
|
|||
|
||||
class HomeFragment : Fragment() {
|
||||
|
||||
companion object {
|
||||
|
||||
val TransactionsCannotBeRetrievedStates = listOf(TransactionsRetrievalState.AccountTypeNotSupported, TransactionsRetrievalState.AccountDoesNotSupportFetchingTransactions)
|
||||
|
||||
}
|
||||
|
||||
|
||||
private lateinit var homeViewModel: HomeViewModel
|
||||
|
||||
private lateinit var mnitmBalance: MenuItem
|
||||
|
@ -262,10 +269,11 @@ class HomeFragment : Fragment() {
|
|||
|
||||
rcyvwAccountTransactions.visibility = if (haveTransactionsBeenRetrieved) View.VISIBLE else View.GONE
|
||||
lytNoTransactionsFetched.visibility = if (haveTransactionsBeenRetrieved || noAccountsAddedYet) View.GONE else View.VISIBLE
|
||||
btnRetrieveTransactions.visibility = if (transactionsRetrievalState == TransactionsRetrievalState.AccountDoesNotSupportFetchingTransactions) View.GONE else View.VISIBLE
|
||||
btnRetrieveTransactions.visibility = if (TransactionsCannotBeRetrievedStates.contains(transactionsRetrievalState)) View.GONE else View.VISIBLE
|
||||
btnAddAccount.visibility = if (noAccountsAddedYet) View.VISIBLE else View.GONE
|
||||
|
||||
val transactionsRetrievalStateMessageId = when (transactionsRetrievalState) {
|
||||
TransactionsRetrievalState.AccountTypeNotSupported -> R.string.fragment_home_transactions_retrieval_state_account_type_not_supported
|
||||
TransactionsRetrievalState.AccountDoesNotSupportFetchingTransactions -> R.string.fragment_home_transactions_retrieval_state_account_does_not_support_retrieving_transactions
|
||||
TransactionsRetrievalState.NoTransactionsInRetrievedPeriod -> R.string.fragment_home_transactions_retrieval_state_no_transactions_in_retrieved_period
|
||||
TransactionsRetrievalState.NeverRetrievedTransactions -> R.string.fragment_home_transactions_retrieval_state_never_retrieved_transactions
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
<string name="fragment_home_count_transactions">%d Umsätze</string>
|
||||
<string name="fragment_home_could_not_retrieve_account_transactions">Kontoumsätze für \'%1$s\' konnten nicht empfangen werden.\n\nFehlermeldung Ihrer Bank:\n\n%2$s</string>
|
||||
<string name="fragment_home_fetch_transactions">Umsätze abrufen</string>
|
||||
<string name="fragment_home_transactions_retrieval_state_account_type_not_supported">Kontotyp wird von App nicht unterstützt</string>
|
||||
<string name="fragment_home_transactions_retrieval_state_account_does_not_support_retrieving_transactions">Konto unterstützt Abrufen von Umsätzen nicht</string>
|
||||
<string name="fragment_home_transactions_retrieval_state_never_retrieved_transactions">Noch keine Umsätze abgerufen</string>
|
||||
<string name="fragment_home_transactions_retrieval_state_no_transactions_in_retrieved_period">Empfangener Zeitraum enthielt keine Umsätze</string>
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
<string name="fragment_home_count_transactions">%d transactions</string>
|
||||
<string name="fragment_home_could_not_retrieve_account_transactions">Could not retrieve account transactions for \'%1$s\'.\n\nError message from your bank:\n\n%2$s</string>
|
||||
<string name="fragment_home_fetch_transactions">Fetch transactions</string>
|
||||
<string name="fragment_home_transactions_retrieval_state_account_type_not_supported">Account type not supported by app</string>
|
||||
<string name="fragment_home_transactions_retrieval_state_account_does_not_support_retrieving_transactions">Account does not support retrieving transactions</string>
|
||||
<string name="fragment_home_transactions_retrieval_state_never_retrieved_transactions">No transactions fetched yet</string>
|
||||
<string name="fragment_home_transactions_retrieval_state_no_transactions_in_retrieved_period">There haven\'t been any transactions in retrieved period</string>
|
||||
|
|
|
@ -42,6 +42,8 @@ open class BankAccount @JvmOverloads constructor(
|
|||
|
||||
override var haveAllTransactionsBeenFetched: Boolean = false
|
||||
|
||||
override var isAccountTypeSupported: Boolean = true
|
||||
|
||||
|
||||
override var userSetDisplayName: String? = null
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ interface IBankAccount<TTransaction: IAccountTransaction> : OrderedDisplayable {
|
|||
var unbookedTransactions: List<Any>
|
||||
var technicalId: String
|
||||
var haveAllTransactionsBeenFetched: Boolean
|
||||
var isAccountTypeSupported: Boolean
|
||||
var userSetDisplayName: String?
|
||||
|
||||
|
||||
|
|
|
@ -3,6 +3,8 @@ package net.dankito.banking.ui.model
|
|||
|
||||
enum class TransactionsRetrievalState {
|
||||
|
||||
AccountTypeNotSupported,
|
||||
|
||||
AccountDoesNotSupportFetchingTransactions,
|
||||
|
||||
NeverRetrievedTransactions,
|
||||
|
|
|
@ -750,10 +750,18 @@ open class BankingPresenter(
|
|||
return TransactionsRetrievalState.NeverRetrievedTransactions
|
||||
}
|
||||
|
||||
return TransactionsRetrievalState.AccountDoesNotSupportFetchingTransactions
|
||||
if (states.contains(TransactionsRetrievalState.AccountDoesNotSupportFetchingTransactions)) {
|
||||
return TransactionsRetrievalState.AccountDoesNotSupportFetchingTransactions
|
||||
}
|
||||
|
||||
return TransactionsRetrievalState.AccountTypeNotSupported
|
||||
}
|
||||
|
||||
protected open fun getAccountTransactionRetrievalState(account: TypedBankAccount): TransactionsRetrievalState {
|
||||
if (account.isAccountTypeSupported == false) {
|
||||
return TransactionsRetrievalState.AccountTypeNotSupported
|
||||
}
|
||||
|
||||
if (account.supportsRetrievingAccountTransactions == false) {
|
||||
return TransactionsRetrievalState.AccountDoesNotSupportFetchingTransactions
|
||||
}
|
||||
|
|
|
@ -46,6 +46,7 @@
|
|||
<attribute name="haveAllTransactionsBeenFetched" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||
<attribute name="iban" optional="YES" attributeType="String"/>
|
||||
<attribute name="identifier" attributeType="String"/>
|
||||
<attribute name="isAccountTypeSupported" attributeType="Boolean" defaultValueString="YES" usesScalarValueType="YES"/>
|
||||
<attribute name="lastRetrievedTransactionsTimestamp" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
|
||||
<attribute name="productName" optional="YES" attributeType="String"/>
|
||||
<attribute name="subAccountNumber" optional="YES" attributeType="String"/>
|
||||
|
@ -89,7 +90,7 @@
|
|||
</entity>
|
||||
<elements>
|
||||
<element name="PersistedAccountTransaction" positionX="-36" positionY="45" width="128" height="553"/>
|
||||
<element name="PersistedBankAccount" positionX="-54" positionY="63" width="128" height="343"/>
|
||||
<element name="PersistedBankAccount" positionX="-54" positionY="63" width="128" height="358"/>
|
||||
<element name="PersistedCustomer" positionX="-63" positionY="-18" width="128" height="283"/>
|
||||
<element name="PersistedTanMedium" positionX="-45" positionY="144" width="128" height="28"/>
|
||||
<element name="PersistedTanMethod" positionX="-54" positionY="135" width="128" height="118"/>
|
||||
|
|
|
@ -76,6 +76,7 @@
|
|||
"Fetch all account transactions" = "Fetch earlier transactions (requires TAN)";
|
||||
|
||||
"Fetch transactions" = "Fetch transactions";
|
||||
"Account type not supported by app" = "Account type not supported by app";
|
||||
"Account does not support retrieving transactions" = "Account does not support retrieving transactions";
|
||||
"No transactions fetched yet" = "No transactions fetched yet";
|
||||
"There haven't been any transactions in retrieved period" = "There haven't been any transactions in retrieved period";
|
||||
|
|
|
@ -76,6 +76,7 @@
|
|||
"Fetch all account transactions" = "Ältere Umsätze laden (erfordert TAN)";
|
||||
|
||||
"Fetch transactions" = "Umsätze abrufen";
|
||||
"Account type not supported by app" = "Kontotyp wird von App nicht unterstützt";
|
||||
"Account does not support retrieving transactions" = "Konto unterstützt Abrufen von Umsätzen nicht";
|
||||
"No transactions fetched yet" = "Noch keine Umsätze abgerufen";
|
||||
"There haven't been any transactions in retrieved period" = "Empfangener Zeitraum enthielt keine Umsätze";
|
||||
|
|
|
@ -61,6 +61,7 @@ class Mapper {
|
|||
let mapped = BankAccount(customer: customer, identifier: map(account.identifier), accountHolderName: map(account.accountHolderName), iban: account.iban, subAccountNumber: account.subAccountNumber, customerId: map(account.customerId), balance: map(account.balance), currency: map(account.currency), type: map(account.type), productName: account.productName, accountLimit: account.accountLimit, lastRetrievedTransactionsTimestamp: map(account.lastRetrievedTransactionsTimestamp), supportsRetrievingAccountTransactions: account.supportsRetrievingAccountTransactions, supportsRetrievingBalance: account.supportsRetrievingBalance, supportsTransferringMoney: account.supportsTransferringMoney, supportsInstantPaymentMoneyTransfer: account.supportsInstantPaymentMoneyTransfer, bookedTransactions: [], unbookedTransactions: [])
|
||||
|
||||
mapped.haveAllTransactionsBeenFetched = account.haveAllTransactionsBeenFetched
|
||||
mapped.isAccountTypeSupported = account.isAccountTypeSupported
|
||||
|
||||
mapped.userSetDisplayName = account.userSetDisplayName
|
||||
mapped.displayIndex = account.displayIndex
|
||||
|
@ -88,6 +89,7 @@ class Mapper {
|
|||
mapped.balance = account.balance.decimal
|
||||
mapped.currency = account.currency
|
||||
mapped.type = map(account.type)
|
||||
mapped.isAccountTypeSupported = account.isAccountTypeSupported
|
||||
mapped.productName = account.productName
|
||||
mapped.accountLimit = account.accountLimit
|
||||
mapped.lastRetrievedTransactionsTimestamp = account.lastRetrievedTransactionsTimestamp?.date
|
||||
|
|
|
@ -183,7 +183,7 @@ struct AccountTransactionsDialog: View {
|
|||
self.showTransactionsList = haveTransactionsBeenRetrievedForSelectedAccounts
|
||||
|
||||
self.noTransactionsFetchedMessage = getNoTransactionsFetchedMessage(transactionsRetrievalState)
|
||||
self.showFetchTransactionsButton = transactionsRetrievalState != .accountdoesnotsupportfetchingtransactions
|
||||
self.showFetchTransactionsButton = transactionsRetrievalState != .accountdoesnotsupportfetchingtransactions && transactionsRetrievalState != .accounttypenotsupported
|
||||
}
|
||||
|
||||
|
||||
|
@ -248,9 +248,12 @@ struct AccountTransactionsDialog: View {
|
|||
else if state == .notransactionsinretrievedperiod {
|
||||
return "There haven't been any transactions in retrieved period"
|
||||
}
|
||||
else {
|
||||
else if state == .accountdoesnotsupportfetchingtransactions {
|
||||
return "Account does not support retrieving transactions"
|
||||
}
|
||||
else {
|
||||
return "Account type not supported by app"
|
||||
}
|
||||
}
|
||||
|
||||
private func filterTransactions(_ query: String) {
|
||||
|
|
|
@ -19,6 +19,7 @@ struct BankAccountListItem : View {
|
|||
AmountLabel(amount: account.balance)
|
||||
}.frame(height: 35)
|
||||
}
|
||||
.disabled( !account.isAccountTypeSupported)
|
||||
.contextMenu {
|
||||
Button(action: { self.navigateToBankAccountSettingsDialog() }) {
|
||||
HStack {
|
||||
|
|
|
@ -119,6 +119,7 @@ open class fints4kModelMapper(protected val modelCreator: IModelCreator) {
|
|||
|
||||
account.currency = accountData.currency ?: "EUR"
|
||||
account.type = mapBankAccountType(accountData.accountType)
|
||||
account.isAccountTypeSupported = accountData.isAccountTypeSupported
|
||||
account.productName = accountData.productName
|
||||
account.accountLimit = accountData.accountLimit
|
||||
|
||||
|
|
|
@ -83,9 +83,9 @@ open class HbciCallback(
|
|||
/* TAN */
|
||||
|
||||
// ADDED: Auswaehlen welches PinTan Verfahren verwendet werden soll
|
||||
HBCICallback.NEED_PT_SECMECH -> selectTanProcedure(retData.toString())?.let { selectedTanProcedure ->
|
||||
customer.selectedTanProcedure = selectedTanProcedure
|
||||
retData.replace(0, retData.length, selectedTanProcedure.bankInternalProcedureCode)
|
||||
HBCICallback.NEED_PT_SECMECH -> selectTanMethod(retData.toString())?.let { selectedTanMethod ->
|
||||
customer.selectedTanMethod = selectedTanMethod
|
||||
retData.replace(0, retData.length, selectedTanMethod.bankInternalMethodCode)
|
||||
}
|
||||
|
||||
// chipTan or simple TAN request (iTAN, smsTAN, ...)
|
||||
|
@ -99,7 +99,7 @@ open class HbciCallback(
|
|||
HBCICallback.NEED_PT_QRTAN -> { // use class QRCode to display QR code
|
||||
val qrData = retData.toString()
|
||||
val qrCode = QRCode(qrData, msg)
|
||||
val enterTanResult = callback.enterTan(customer, ImageTanChallenge(TanImage(qrCode.mimetype, qrCode.image), msg, customer.selectedTanProcedure!!))
|
||||
val enterTanResult = callback.enterTan(customer, ImageTanChallenge(TanImage(qrCode.mimetype, qrCode.image), msg, customer.selectedTanMethod!!))
|
||||
enterTanResult.enteredTan?.let { enteredTan ->
|
||||
retData.replace(0, retData.length, enteredTan)
|
||||
}
|
||||
|
@ -108,7 +108,7 @@ open class HbciCallback(
|
|||
// photoTan
|
||||
HBCICallback.NEED_PT_PHOTOTAN -> { // use class MatrixCode to display photo
|
||||
val matrixCode = MatrixCode(retData.toString())
|
||||
val enterTanResult = callback.enterTan(customer, ImageTanChallenge(TanImage(matrixCode.mimetype, matrixCode.image), msg, customer.selectedTanProcedure!!))
|
||||
val enterTanResult = callback.enterTan(customer, ImageTanChallenge(TanImage(matrixCode.mimetype, matrixCode.image), msg, customer.selectedTanMethod!!))
|
||||
enterTanResult.enteredTan?.let { enteredTan ->
|
||||
retData.replace(0, retData.length, enteredTan)
|
||||
}
|
||||
|
@ -183,14 +183,14 @@ open class HbciCallback(
|
|||
// werden.
|
||||
|
||||
val enterTanResult = if (challengeHHD_UC.isNullOrEmpty()) {
|
||||
callback.enterTan(customer, TanChallenge(messageToShowToUser, customer.selectedTanProcedure!!))
|
||||
callback.enterTan(customer, TanChallenge(messageToShowToUser, customer.selectedTanMethod!!))
|
||||
}
|
||||
else {
|
||||
// for Sparkasse messageToShowToUser started with "chipTAN optisch\nTAN-Nummer\n\n"
|
||||
val usefulMessage = messageToShowToUser.split("\n").last().trim()
|
||||
|
||||
// val parsedDataSet = FlickerCode(challengeHHD_UC).render()
|
||||
callback.enterTan(customer, FlickerCodeTanChallenge(net.dankito.banking.ui.model.tan.FlickerCode("", challengeHHD_UC), usefulMessage, customer.selectedTanProcedure!!))
|
||||
callback.enterTan(customer, FlickerCodeTanChallenge(net.dankito.banking.ui.model.tan.FlickerCode("", challengeHHD_UC), usefulMessage, customer.selectedTanMethod!!))
|
||||
}
|
||||
|
||||
return enterTanResult.enteredTan
|
||||
|
@ -198,15 +198,15 @@ open class HbciCallback(
|
|||
|
||||
|
||||
|
||||
open fun selectTanProcedure(supportedTanProceduresString: String): net.dankito.banking.ui.model.tan.TanProcedure? {
|
||||
val supportedTanProcedures = mapper.mapTanProcedures(supportedTanProceduresString)
|
||||
open fun selectTanMethod(supportedTanMethodsString: String): net.dankito.banking.ui.model.tan.TanMethod? {
|
||||
val supportedTanMethods = mapper.mapTanMethods(supportedTanMethodsString)
|
||||
|
||||
customer.supportedTanProcedures = supportedTanProcedures
|
||||
customer.supportedTanMethods = supportedTanMethods
|
||||
|
||||
if (supportedTanProcedures.isNotEmpty()) {
|
||||
// select any procedure, user then can select her preferred one in EnterTanDialog; try not to select 'chipTAN manuell'
|
||||
return supportedTanProcedures.firstOrNull { it.displayName.contains("manuell", true) == false }
|
||||
?: supportedTanProcedures.firstOrNull()
|
||||
if (supportedTanMethods.isNotEmpty()) {
|
||||
// select any method, user then can select her preferred one in EnterTanDialog; try not to select 'chipTAN manuell'
|
||||
return supportedTanMethods.firstOrNull { it.displayName.contains("manuell", true) == false }
|
||||
?: supportedTanMethods.firstOrNull()
|
||||
}
|
||||
|
||||
return null
|
||||
|
|
|
@ -5,7 +5,7 @@ import net.dankito.banking.ui.model.mapper.IModelCreator
|
|||
import net.dankito.utils.multiplatform.BigDecimal
|
||||
import net.dankito.utils.multiplatform.toBigDecimal
|
||||
import net.dankito.banking.ui.model.parameters.TransferMoneyData
|
||||
import net.dankito.banking.ui.model.tan.TanProcedureType
|
||||
import net.dankito.banking.ui.model.tan.TanMethodType
|
||||
import org.kapott.hbci.passport.HBCIPassport
|
||||
import org.kapott.hbci.structures.Konto
|
||||
import org.kapott.hbci.structures.Value
|
||||
|
@ -55,6 +55,7 @@ open class hbci4jModelMapper(
|
|||
|
||||
result.currency = bankAccount.curr
|
||||
result.type = mapBankAccountType(bankAccount)
|
||||
result.isAccountTypeSupported = result.type == BankAccountType.Girokonto || result.type == BankAccountType.Festgeldkonto
|
||||
result.accountLimit = bankAccount.limit?.value?.let { mapValue(it).toString() }
|
||||
|
||||
result.supportsRetrievingBalance = bankAccount.allowedGVs.contains("HKSAL")
|
||||
|
@ -88,14 +89,14 @@ open class hbci4jModelMapper(
|
|||
}
|
||||
|
||||
|
||||
open fun mapTanProcedures(tanProceduresString: String): List<net.dankito.banking.ui.model.tan.TanProcedure> {
|
||||
return tanProceduresString.split('|')
|
||||
.map { mapTanProcedure(it) }
|
||||
open fun mapTanMethods(tanMethodsString: String): List<net.dankito.banking.ui.model.tan.TanMethod> {
|
||||
return tanMethodsString.split('|')
|
||||
.map { mapTanMethod(it) }
|
||||
.filterNotNull()
|
||||
}
|
||||
|
||||
open fun mapTanProcedure(tanProcedureString: String): net.dankito.banking.ui.model.tan.TanProcedure? {
|
||||
val parts = tanProcedureString.split(':')
|
||||
open fun mapTanMethod(tanMethodString: String): net.dankito.banking.ui.model.tan.TanMethod? {
|
||||
val parts = tanMethodString.split(':')
|
||||
|
||||
if (parts.size > 1) {
|
||||
val code = parts[0]
|
||||
|
@ -103,18 +104,18 @@ open class hbci4jModelMapper(
|
|||
val displayNameLowerCase = displayName.toLowerCase()
|
||||
|
||||
return when {
|
||||
// TODO: implement all TAN procedures
|
||||
// TODO: implement all TAN methods
|
||||
displayNameLowerCase.contains("chiptan") -> {
|
||||
if (displayNameLowerCase.contains("qr")) {
|
||||
modelCreator.createTanProcedure(displayName, TanProcedureType.ChipTanQrCode, code)
|
||||
modelCreator.createTanMethod(displayName, TanMethodType.ChipTanQrCode, code)
|
||||
}
|
||||
else {
|
||||
modelCreator.createTanProcedure(displayName, TanProcedureType.ChipTanFlickercode, code)
|
||||
modelCreator.createTanMethod(displayName, TanMethodType.ChipTanFlickercode, code)
|
||||
}
|
||||
}
|
||||
|
||||
displayNameLowerCase.contains("sms") -> modelCreator.createTanProcedure(displayName, TanProcedureType.SmsTan, code)
|
||||
displayNameLowerCase.contains("push") -> modelCreator.createTanProcedure(displayName, TanProcedureType.AppTan, code)
|
||||
displayNameLowerCase.contains("sms") -> modelCreator.createTanMethod(displayName, TanMethodType.SmsTan, code)
|
||||
displayNameLowerCase.contains("push") -> modelCreator.createTanMethod(displayName, TanMethodType.AppTan, code)
|
||||
|
||||
// we filter out iTAN and Einschritt-Verfahren as they are not permitted anymore according to PSD2
|
||||
else -> null
|
||||
|
|
Loading…
Reference in New Issue