From 700e3e6da9fd0882a8f21ff99b762a1641139273 Mon Sep 17 00:00:00 2001 From: dankito Date: Tue, 22 Sep 2020 01:59:00 +0200 Subject: [PATCH] Implemented mapping and displaying if an account type is supported or not --- README.md | 2 +- .../net/dankito/banking/fints/FinTsClient.kt | 2 ++ .../banking/fints/model/AccountData.kt | 5 ++++ .../banking/persistence/BankingDatabase.kt | 4 +-- .../persistence/RoomBankingPersistence.kt | 26 ++++++++--------- .../banking/persistence/TypeConverters.kt | 8 ++--- .../banking/persistence/dao/TanMethodDao.kt | 14 +++++++++ .../persistence/dao/TanProcedureDao.kt | 14 --------- .../dankito/banking/persistence/model/Bank.kt | 10 +++---- .../banking/persistence/model/BankAccount.kt | 2 ++ .../persistence/model/RoomModelCreator.kt | 6 ++-- .../banking/persistence/model/TanMethod.kt | 29 +++++++++++++++++++ .../banking/persistence/model/TanProcedure.kt | 29 ------------------- .../persistence/model/BankAccountEntity.kt | 1 + .../banking/ui/android/home/HomeFragment.kt | 10 ++++++- .../src/main/res/values-de/strings.xml | 1 + .../src/main/res/values/strings.xml | 1 + .../dankito/banking/ui/model/BankAccount.kt | 2 ++ .../dankito/banking/ui/model/IBankAccount.kt | 1 + .../ui/model/TransactionsRetrievalState.kt | 2 ++ .../banking/ui/presenter/BankingPresenter.kt | 10 ++++++- .../BankingiOSApp.xcdatamodel/contents | 3 +- .../Base.lproj/Localizable.strings | 1 + .../de.lproj/Localizable.strings | 1 + .../BankingiOSApp/persistence/Mapper.swift | 2 ++ .../dialogs/AccountTransactionsDialog.swift | 7 +++-- .../views/listitems/BankAccountListItem.swift | 1 + .../banking/mapper/fints4kModelMapper.kt | 1 + .../net/dankito/banking/HbciCallback.kt | 28 +++++++++--------- .../dankito/banking/util/hbci4jModelMapper.kt | 23 ++++++++------- 30 files changed, 145 insertions(+), 101 deletions(-) create mode 100644 persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/dao/TanMethodDao.kt delete mode 100644 persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/dao/TanProcedureDao.kt create mode 100644 persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/model/TanMethod.kt delete mode 100644 persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/model/TanProcedure.kt diff --git a/README.md b/README.md index 4e2cac40..39044ded 100644 --- a/README.md +++ b/README.md @@ -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! diff --git a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/FinTsClient.kt b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/FinTsClient.kt index ea879071..51a3b222 100644 --- a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/FinTsClient.kt +++ b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/FinTsClient.kt @@ -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) diff --git a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/model/AccountData.kt b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/model/AccountData.kt index aa06aba2..c0d24dd4 100644 --- a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/model/AccountData.kt +++ b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/model/AccountData.kt @@ -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() + open val isAccountTypeSupported: Boolean + get() = FinTsClient.SupportedAccountTypes.contains(accountType) + + open fun supportsFeature(feature: AccountFeature): Boolean { return _supportedFeatures.contains(feature) } diff --git a/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/BankingDatabase.kt b/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/BankingDatabase.kt index 0ce032c6..c6b29932 100644 --- a/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/BankingDatabase.kt +++ b/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/BankingDatabase.kt @@ -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 diff --git a/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/RoomBankingPersistence.kt b/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/RoomBankingPersistence.kt index 2a24eb48..8de340ee 100644 --- a/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/RoomBankingPersistence.kt +++ b/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/RoomBankingPersistence.kt @@ -34,7 +34,7 @@ open class RoomBankingPersistence(applicationContext: Context, password: String? override fun saveOrUpdateAccount(customer: TypedCustomer, allCustomers: List) { (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() - 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() + 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()) - db.tanProcedureDao().delete(bank.supportedTanProcedures.filterIsInstance()) + db.tanMethodDao().delete(bank.supportedTanMethods.filterIsInstance()) db.tanMediumDao().delete(bank.tanMedia.filterIsInstance()) 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) } diff --git a/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/TypeConverters.kt b/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/TypeConverters.kt index 8536262c..b067a05c 100644 --- a/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/TypeConverters.kt +++ b/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/TypeConverters.kt @@ -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 } } diff --git a/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/dao/TanMethodDao.kt b/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/dao/TanMethodDao.kt new file mode 100644 index 00000000..cae83b1a --- /dev/null +++ b/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/dao/TanMethodDao.kt @@ -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 { + + @Query("SELECT * FROM TanMethod") + fun getAll(): List + +} \ No newline at end of file diff --git a/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/dao/TanProcedureDao.kt b/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/dao/TanProcedureDao.kt deleted file mode 100644 index 9152264e..00000000 --- a/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/dao/TanProcedureDao.kt +++ /dev/null @@ -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 { - - @Query("SELECT * FROM TanProcedure") - fun getAll(): List - -} \ No newline at end of file diff --git a/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/model/Bank.kt b/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/model/Bank.kt index 6bce7740..0fba0c23 100644 --- a/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/model/Bank.kt +++ b/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/model/Bank.kt @@ -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 = listOf(), - + @Ignore - override var supportedTanProcedures: List = listOf(), + override var supportedTanMethods: List = listOf(), @Ignore - override var selectedTanProcedure: TanProcedure? = null, + override var selectedTanMethod: TanMethod? = null, @Ignore override var tanMedia: List = 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() diff --git a/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/model/BankAccount.kt b/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/model/BankAccount.kt index 41cf56a6..a68e478b 100644 --- a/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/model/BankAccount.kt +++ b/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/model/BankAccount.kt @@ -58,6 +58,8 @@ open class BankAccount( override var haveAllTransactionsBeenFetched: Boolean = false + override var isAccountTypeSupported: Boolean = true + override var userSetDisplayName: String? = null diff --git a/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/model/RoomModelCreator.kt b/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/model/RoomModelCreator.kt index db8579dc..32fb394b 100644 --- a/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/model/RoomModelCreator.kt +++ b/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/model/RoomModelCreator.kt @@ -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) } } \ No newline at end of file diff --git a/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/model/TanMethod.kt b/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/model/TanMethod.kt new file mode 100644 index 00000000..a8edd57f --- /dev/null +++ b/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/model/TanMethod.kt @@ -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 + +} \ No newline at end of file diff --git a/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/model/TanProcedure.kt b/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/model/TanProcedure.kt deleted file mode 100644 index 7a6a0424..00000000 --- a/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/model/TanProcedure.kt +++ /dev/null @@ -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 - -} \ No newline at end of file diff --git a/persistence/json/BankingPersistenceJson/src/main/kotlin/net/dankito/banking/persistence/model/BankAccountEntity.kt b/persistence/json/BankingPersistenceJson/src/main/kotlin/net/dankito/banking/persistence/model/BankAccountEntity.kt index 6ad2e3bd..f69e9a2f 100644 --- a/persistence/json/BankingPersistenceJson/src/main/kotlin/net/dankito/banking/persistence/model/BankAccountEntity.kt +++ b/persistence/json/BankingPersistenceJson/src/main/kotlin/net/dankito/banking/persistence/model/BankAccountEntity.kt @@ -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 { diff --git a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/home/HomeFragment.kt b/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/home/HomeFragment.kt index f8ee61dc..19b0f0ea 100644 --- a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/home/HomeFragment.kt +++ b/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/home/HomeFragment.kt @@ -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 diff --git a/ui/BankingAndroidApp/src/main/res/values-de/strings.xml b/ui/BankingAndroidApp/src/main/res/values-de/strings.xml index ece5c98d..3f583f4b 100644 --- a/ui/BankingAndroidApp/src/main/res/values-de/strings.xml +++ b/ui/BankingAndroidApp/src/main/res/values-de/strings.xml @@ -39,6 +39,7 @@ %d Umsätze Kontoumsätze für \'%1$s\' konnten nicht empfangen werden.\n\nFehlermeldung Ihrer Bank:\n\n%2$s Umsätze abrufen + Kontotyp wird von App nicht unterstützt Konto unterstützt Abrufen von Umsätzen nicht Noch keine Umsätze abgerufen Empfangener Zeitraum enthielt keine Umsätze diff --git a/ui/BankingAndroidApp/src/main/res/values/strings.xml b/ui/BankingAndroidApp/src/main/res/values/strings.xml index 45d7ae83..8776d1b0 100644 --- a/ui/BankingAndroidApp/src/main/res/values/strings.xml +++ b/ui/BankingAndroidApp/src/main/res/values/strings.xml @@ -39,6 +39,7 @@ %d transactions Could not retrieve account transactions for \'%1$s\'.\n\nError message from your bank:\n\n%2$s Fetch transactions + Account type not supported by app Account does not support retrieving transactions No transactions fetched yet There haven\'t been any transactions in retrieved period diff --git a/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/model/BankAccount.kt b/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/model/BankAccount.kt index 27db5f39..6a676e6a 100644 --- a/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/model/BankAccount.kt +++ b/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/model/BankAccount.kt @@ -42,6 +42,8 @@ open class BankAccount @JvmOverloads constructor( override var haveAllTransactionsBeenFetched: Boolean = false + override var isAccountTypeSupported: Boolean = true + override var userSetDisplayName: String? = null diff --git a/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/model/IBankAccount.kt b/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/model/IBankAccount.kt index 63ab391b..16dbdb3d 100644 --- a/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/model/IBankAccount.kt +++ b/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/model/IBankAccount.kt @@ -28,6 +28,7 @@ interface IBankAccount : OrderedDisplayable { var unbookedTransactions: List var technicalId: String var haveAllTransactionsBeenFetched: Boolean + var isAccountTypeSupported: Boolean var userSetDisplayName: String? diff --git a/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/model/TransactionsRetrievalState.kt b/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/model/TransactionsRetrievalState.kt index e8d2a745..016fc352 100644 --- a/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/model/TransactionsRetrievalState.kt +++ b/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/model/TransactionsRetrievalState.kt @@ -3,6 +3,8 @@ package net.dankito.banking.ui.model enum class TransactionsRetrievalState { + AccountTypeNotSupported, + AccountDoesNotSupportFetchingTransactions, NeverRetrievedTransactions, diff --git a/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/presenter/BankingPresenter.kt b/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/presenter/BankingPresenter.kt index 4b615ed8..0aa9f4d8 100644 --- a/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/presenter/BankingPresenter.kt +++ b/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/presenter/BankingPresenter.kt @@ -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 } diff --git a/ui/BankingiOSApp/BankingiOSApp/BankingiOSApp.xcdatamodeld/BankingiOSApp.xcdatamodel/contents b/ui/BankingiOSApp/BankingiOSApp/BankingiOSApp.xcdatamodeld/BankingiOSApp.xcdatamodel/contents index 9083c987..ec59f0e1 100644 --- a/ui/BankingiOSApp/BankingiOSApp/BankingiOSApp.xcdatamodeld/BankingiOSApp.xcdatamodel/contents +++ b/ui/BankingiOSApp/BankingiOSApp/BankingiOSApp.xcdatamodeld/BankingiOSApp.xcdatamodel/contents @@ -46,6 +46,7 @@ + @@ -89,7 +90,7 @@ - + diff --git a/ui/BankingiOSApp/BankingiOSApp/Base.lproj/Localizable.strings b/ui/BankingiOSApp/BankingiOSApp/Base.lproj/Localizable.strings index 58095e2a..dd9936a0 100644 --- a/ui/BankingiOSApp/BankingiOSApp/Base.lproj/Localizable.strings +++ b/ui/BankingiOSApp/BankingiOSApp/Base.lproj/Localizable.strings @@ -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"; diff --git a/ui/BankingiOSApp/BankingiOSApp/de.lproj/Localizable.strings b/ui/BankingiOSApp/BankingiOSApp/de.lproj/Localizable.strings index 29ed0403..a6ffad84 100644 --- a/ui/BankingiOSApp/BankingiOSApp/de.lproj/Localizable.strings +++ b/ui/BankingiOSApp/BankingiOSApp/de.lproj/Localizable.strings @@ -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"; diff --git a/ui/BankingiOSApp/BankingiOSApp/persistence/Mapper.swift b/ui/BankingiOSApp/BankingiOSApp/persistence/Mapper.swift index e61334a6..b082a74a 100644 --- a/ui/BankingiOSApp/BankingiOSApp/persistence/Mapper.swift +++ b/ui/BankingiOSApp/BankingiOSApp/persistence/Mapper.swift @@ -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 diff --git a/ui/BankingiOSApp/BankingiOSApp/ui/dialogs/AccountTransactionsDialog.swift b/ui/BankingiOSApp/BankingiOSApp/ui/dialogs/AccountTransactionsDialog.swift index a45840b3..4df4eb22 100644 --- a/ui/BankingiOSApp/BankingiOSApp/ui/dialogs/AccountTransactionsDialog.swift +++ b/ui/BankingiOSApp/BankingiOSApp/ui/dialogs/AccountTransactionsDialog.swift @@ -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) { diff --git a/ui/BankingiOSApp/BankingiOSApp/ui/views/listitems/BankAccountListItem.swift b/ui/BankingiOSApp/BankingiOSApp/ui/views/listitems/BankAccountListItem.swift index 38db6028..6eec4756 100644 --- a/ui/BankingiOSApp/BankingiOSApp/ui/views/listitems/BankAccountListItem.swift +++ b/ui/BankingiOSApp/BankingiOSApp/ui/views/listitems/BankAccountListItem.swift @@ -19,6 +19,7 @@ struct BankAccountListItem : View { AmountLabel(amount: account.balance) }.frame(height: 35) } + .disabled( !account.isAccountTypeSupported) .contextMenu { Button(action: { self.navigateToBankAccountSettingsDialog() }) { HStack { diff --git a/ui/fints4kBankingClient/src/commonMain/kotlin/net/dankito/banking/mapper/fints4kModelMapper.kt b/ui/fints4kBankingClient/src/commonMain/kotlin/net/dankito/banking/mapper/fints4kModelMapper.kt index 94c1f097..da893c23 100644 --- a/ui/fints4kBankingClient/src/commonMain/kotlin/net/dankito/banking/mapper/fints4kModelMapper.kt +++ b/ui/fints4kBankingClient/src/commonMain/kotlin/net/dankito/banking/mapper/fints4kModelMapper.kt @@ -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 diff --git a/ui/hbci4jBankingClient/src/main/kotlin/net/dankito/banking/HbciCallback.kt b/ui/hbci4jBankingClient/src/main/kotlin/net/dankito/banking/HbciCallback.kt index 3260b618..74b1e9fe 100644 --- a/ui/hbci4jBankingClient/src/main/kotlin/net/dankito/banking/HbciCallback.kt +++ b/ui/hbci4jBankingClient/src/main/kotlin/net/dankito/banking/HbciCallback.kt @@ -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 diff --git a/ui/hbci4jBankingClient/src/main/kotlin/net/dankito/banking/util/hbci4jModelMapper.kt b/ui/hbci4jBankingClient/src/main/kotlin/net/dankito/banking/util/hbci4jModelMapper.kt index 65548fa8..d4725115 100644 --- a/ui/hbci4jBankingClient/src/main/kotlin/net/dankito/banking/util/hbci4jModelMapper.kt +++ b/ui/hbci4jBankingClient/src/main/kotlin/net/dankito/banking/util/hbci4jModelMapper.kt @@ -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 { - return tanProceduresString.split('|') - .map { mapTanProcedure(it) } + open fun mapTanMethods(tanMethodsString: String): List { + 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