Implemented mapping and displaying if an account type is supported or not

This commit is contained in:
dankito 2020-09-22 01:59:00 +02:00
parent a59b335316
commit 700e3e6da9
30 changed files with 145 additions and 101 deletions

View File

@ -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!

View File

@ -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)

View File

@ -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)
}

View File

@ -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

View File

@ -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) }

View File

@ -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 }
}

View File

@ -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>
}

View File

@ -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>
}

View File

@ -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>()

View File

@ -58,6 +58,8 @@ open class BankAccount(
override var haveAllTransactionsBeenFetched: Boolean = false
override var isAccountTypeSupported: Boolean = true
override var userSetDisplayName: String? = null

View File

@ -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)
}
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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> {

View File

@ -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

View File

@ -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>

View File

@ -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>

View File

@ -42,6 +42,8 @@ open class BankAccount @JvmOverloads constructor(
override var haveAllTransactionsBeenFetched: Boolean = false
override var isAccountTypeSupported: Boolean = true
override var userSetDisplayName: String? = null

View File

@ -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?

View File

@ -3,6 +3,8 @@ package net.dankito.banking.ui.model
enum class TransactionsRetrievalState {
AccountTypeNotSupported,
AccountDoesNotSupportFetchingTransactions,
NeverRetrievedTransactions,

View File

@ -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
}

View File

@ -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"/>

View File

@ -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";

View File

@ -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";

View File

@ -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

View File

@ -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) {

View File

@ -19,6 +19,7 @@ struct BankAccountListItem : View {
AmountLabel(amount: account.balance)
}.frame(height: 35)
}
.disabled( !account.isAccountTypeSupported)
.contextMenu {
Button(action: { self.navigateToBankAccountSettingsDialog() }) {
HStack {

View File

@ -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

View File

@ -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

View File

@ -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