Compare commits

...

12 Commits

17 changed files with 75 additions and 57 deletions

View File

@ -8,6 +8,7 @@ import net.codinux.banking.client.model.response.GetAccountDataResponse
import net.codinux.banking.client.model.response.GetTransactionsResponse import net.codinux.banking.client.model.response.GetTransactionsResponse
import net.codinux.banking.client.model.response.Response import net.codinux.banking.client.model.response.Response
import net.codinux.banking.client.model.response.TransferMoneyResponse import net.codinux.banking.client.model.response.TransferMoneyResponse
import net.codinux.banking.client.model.tan.TanMethodType
interface BankingClient { interface BankingClient {
@ -41,7 +42,10 @@ interface BankingClient {
* *
* Optionally specify which [accounts] should be updated. If not specified all accounts will be updated. * Optionally specify which [accounts] should be updated. If not specified all accounts will be updated.
*/ */
suspend fun updateAccountTransactionsAsync(bank: BankAccess, accounts: List<BankAccount>? = null): Response<List<GetTransactionsResponse>> suspend fun updateAccountTransactionsAsync(
bank: BankAccess, accounts: List<BankAccount>? = null,
preferredTanMethodsIfSelectedTanMethodIsNotAvailable: List<TanMethodType>? = TanMethodType.TanMethodsPreferredByMostApplications
): Response<List<GetTransactionsResponse>>
suspend fun transferMoneyAsync(bankCode: String, loginName: String, password: String, recipientName: String, suspend fun transferMoneyAsync(bankCode: String, loginName: String, password: String, recipientName: String,

View File

@ -9,6 +9,7 @@ import net.codinux.banking.client.model.response.GetAccountDataResponse
import net.codinux.banking.client.model.response.GetTransactionsResponse import net.codinux.banking.client.model.response.GetTransactionsResponse
import net.codinux.banking.client.model.response.Response import net.codinux.banking.client.model.response.Response
import net.codinux.banking.client.model.response.TransferMoneyResponse import net.codinux.banking.client.model.response.TransferMoneyResponse
import net.codinux.banking.client.model.tan.TanMethodType
interface BankingClientForUser { interface BankingClientForUser {
@ -40,7 +41,10 @@ interface BankingClientForUser {
* Updates account's transactions beginning from [BankAccount.lastAccountUpdateTime]. * Updates account's transactions beginning from [BankAccount.lastAccountUpdateTime].
* This may requires TAN if [BankAccount.lastAccountUpdateTime] is older than 90 days. * This may requires TAN if [BankAccount.lastAccountUpdateTime] is older than 90 days.
*/ */
suspend fun updateAccountTransactionsAsync(accounts: List<BankAccount>? = null): Response<List<GetTransactionsResponse>> suspend fun updateAccountTransactionsAsync(
accounts: List<BankAccount>? = null,
preferredTanMethodsIfSelectedTanMethodIsNotAvailable: List<TanMethodType>? = TanMethodType.TanMethodsPreferredByMostApplications
): Response<List<GetTransactionsResponse>>
suspend fun transferMoneyAsync(recipientName: String, recipientAccountIdentifier: String, amount: Amount, paymentReference: String? = null): Response<TransferMoneyResponse> suspend fun transferMoneyAsync(recipientName: String, recipientAccountIdentifier: String, amount: Amount, paymentReference: String? = null): Response<TransferMoneyResponse>

View File

@ -10,6 +10,7 @@ import net.codinux.banking.client.model.request.TransferMoneyRequest
import net.codinux.banking.client.model.request.TransferMoneyRequestForUser import net.codinux.banking.client.model.request.TransferMoneyRequestForUser
import net.codinux.banking.client.model.response.GetTransactionsResponse import net.codinux.banking.client.model.response.GetTransactionsResponse
import net.codinux.banking.client.model.response.Response import net.codinux.banking.client.model.response.Response
import net.codinux.banking.client.model.tan.TanMethodType
abstract class BankingClientForUserBase( abstract class BankingClientForUserBase(
protected val credentials: AccountCredentials, protected val credentials: AccountCredentials,
@ -25,7 +26,7 @@ abstract class BankingClientForUserBase(
} }
} }
override suspend fun updateAccountTransactionsAsync(accounts: List<BankAccount>?): Response<List<GetTransactionsResponse>> = override suspend fun updateAccountTransactionsAsync(accounts: List<BankAccount>?, preferredTanMethodsIfSelectedTanMethodIsNotAvailable: List<TanMethodType>?): Response<List<GetTransactionsResponse>> =
client.updateAccountTransactionsAsync(bank, accounts) client.updateAccountTransactionsAsync(bank, accounts)

View File

@ -8,6 +8,7 @@ import net.codinux.banking.client.model.options.GetAccountDataOptions
import net.codinux.banking.client.model.request.GetAccountDataRequest import net.codinux.banking.client.model.request.GetAccountDataRequest
import net.codinux.banking.client.model.request.TransferMoneyRequest import net.codinux.banking.client.model.request.TransferMoneyRequest
import net.codinux.banking.client.model.request.TransferMoneyRequestForUser import net.codinux.banking.client.model.request.TransferMoneyRequestForUser
import net.codinux.banking.client.model.tan.TanMethodType
/* BankingClient */ /* BankingClient */
@ -19,8 +20,8 @@ fun BankingClient.getAccountData(request: GetAccountDataRequest) = runBlocking {
getAccountDataAsync(request) getAccountDataAsync(request)
} }
fun BankingClient.updateAccountTransactions(bank: BankAccess, accounts: List<BankAccount>? = null) = runBlocking { fun BankingClient.updateAccountTransactions(bank: BankAccess, accounts: List<BankAccount>? = null, preferredTanMethodsIfSelectedTanMethodIsNotAvailable: List<TanMethodType>? = TanMethodType.TanMethodsPreferredByMostApplications) = runBlocking {
updateAccountTransactionsAsync(bank, accounts) updateAccountTransactionsAsync(bank, accounts, preferredTanMethodsIfSelectedTanMethodIsNotAvailable)
} }
@ -44,8 +45,8 @@ fun BankingClientForUser.getAccountData(options: GetAccountDataOptions) = runBlo
getAccountDataAsync(options) getAccountDataAsync(options)
} }
fun BankingClientForUser.updateAccountTransactions() = runBlocking { fun BankingClientForUser.updateAccountTransactions(accounts: List<BankAccount>? = null, preferredTanMethodsIfSelectedTanMethodIsNotAvailable: List<TanMethodType>? = TanMethodType.TanMethodsPreferredByMostApplications) = runBlocking {
updateAccountTransactionsAsync() updateAccountTransactionsAsync(accounts, preferredTanMethodsIfSelectedTanMethodIsNotAvailable)
} }

View File

@ -27,14 +27,14 @@ open class GetAccountDataOptions(
* likes to use a different one, she can select another one in EnterTanDialog. * likes to use a different one, she can select another one in EnterTanDialog.
* *
* By default we prefer non visual TanMethods (like AppTan and SMS) over image based TanMethods (like QR-code and * By default we prefer non visual TanMethods (like AppTan and SMS) over image based TanMethods (like QR-code and
* photoTan) and exclude ChipTanUsb, which is not supported by application, and Flickercode, which is hard to * photoTan) and exclude ChipTanUsb, which is not supported by application, and FlickerCode, which is hard to
* implement and therefore most applications have not implemented. * implement and therefore most applications have not implemented.
* *
* Console apps can only handle non visual TanMethods. * Console apps can only handle non visual TanMethods.
* But also graphical applications prefer non visual TanMethods as then they only have to display a text field to input * But also graphical applications prefer non visual TanMethods as then they only have to display a text field to input
* TAN, and then image based TanMethods as then they additionally only have to display an image. * TAN, and then image based TanMethods as then they additionally only have to display an image.
*/ */
val preferredTanMethods: List<TanMethodType>? = TanMethodType.NonVisualOrImageBased, val preferredTanMethods: List<TanMethodType>? = TanMethodType.TanMethodsPreferredByMostApplications,
val tanMethodsNotSupportedByApplication: List<TanMethodType> = TanMethodType.TanMethodsNotSupportedByMostApplications, val tanMethodsNotSupportedByApplication: List<TanMethodType> = TanMethodType.TanMethodsNotSupportedByMostApplications,

View File

@ -64,14 +64,14 @@ open class TransferMoneyRequest(
* likes to use a different one, she can select another one in EnterTanDialog. * likes to use a different one, she can select another one in EnterTanDialog.
* *
* By default we prefer non visual TanMethods (like AppTan and SMS) over image based TanMethods (like QR-code and * By default we prefer non visual TanMethods (like AppTan and SMS) over image based TanMethods (like QR-code and
* photoTan) and exclude ChipTanUsb, which is not supported by application, and Flickercode, which is hard to * photoTan) and exclude ChipTanUsb, which is not supported by application, and FlickerCode, which is hard to
* implement and therefore most applications have not implemented. * implement and therefore most applications have not implemented.
* *
* Console apps can only handle non visual TanMethods. * Console apps can only handle non visual TanMethods.
* But also graphical applications prefer non visual TanMethods as then they only have to display a text field to input * But also graphical applications prefer non visual TanMethods as then they only have to display a text field to input
* TAN, and then image based TanMethods as then they additionally only have to display an image. * TAN, and then image based TanMethods as then they additionally only have to display an image.
*/ */
val preferredTanMethods: List<TanMethodType>? = TanMethodType.NonVisualOrImageBased, val preferredTanMethods: List<TanMethodType>? = TanMethodType.TanMethodsPreferredByMostApplications,
val tanMethodsNotSupportedByApplication: List<TanMethodType> = TanMethodType.TanMethodsNotSupportedByMostApplications, val tanMethodsNotSupportedByApplication: List<TanMethodType> = TanMethodType.TanMethodsNotSupportedByMostApplications,

View File

@ -35,7 +35,7 @@ open class TransferMoneyRequestForUser(
instantTransfer: Boolean = false, instantTransfer: Boolean = false,
preferredTanMethods: List<TanMethodType>? = TanMethodType.NonVisualOrImageBased, preferredTanMethods: List<TanMethodType>? = TanMethodType.TanMethodsPreferredByMostApplications,
tanMethodsNotSupportedByApplication: List<TanMethodType> = TanMethodType.TanMethodsNotSupportedByMostApplications, tanMethodsNotSupportedByApplication: List<TanMethodType> = TanMethodType.TanMethodsNotSupportedByMostApplications,
clientData: Any? = null, clientData: Any? = null,
@ -49,10 +49,13 @@ open class TransferMoneyRequestForUser(
constructor( constructor(
bank: BankAccess, account: BankAccount?, bank: BankAccess, account: BankAccount?,
recipientName: String, recipientAccountIdentifier: String, recipientBankIdentifier: String? = null, recipientName: String, recipientAccountIdentifier: String, recipientBankIdentifier: String? = null,
amount: Amount, currency: String = DefaultValues.DefaultCurrency, paymentReference: String? = null, instantTransfer: Boolean = false amount: Amount, currency: String = DefaultValues.DefaultCurrency, paymentReference: String? = null, instantTransfer: Boolean = false,
preferredTanMethods: List<TanMethodType>? = TanMethodType.TanMethodsPreferredByMostApplications
) : this(bank.domesticBankCode, bank.loginName, bank.password!!, account?.let { BankAccountIdentifier(it.identifier, it.subAccountNumber, it.iban) }, ) : this(bank.domesticBankCode, bank.loginName, bank.password!!, account?.let { BankAccountIdentifier(it.identifier, it.subAccountNumber, it.iban) },
recipientName, recipientAccountIdentifier, recipientBankIdentifier, amount, currency, paymentReference, instantTransfer, recipientName, recipientAccountIdentifier, recipientBankIdentifier, amount, currency, paymentReference, instantTransfer,
listOf(bank.selectedTanMethod.type) + TanMethodType.NonVisualOrImageBased, TanMethodType.TanMethodsNotSupportedByMostApplications, bank.clientData, bank.serializedClientData) { listOf(bank.selectedTanMethod.type) + (preferredTanMethods ?: emptyList()), TanMethodType.TanMethodsNotSupportedByMostApplications,
bank.clientData, bank.serializedClientData
) {
this.bank = bank this.bank = bank
this.account = account this.account = account
} }

View File

@ -88,7 +88,7 @@ open class TanChallenge(
return "$selectedTanMethod $forAction: $messageToShowToUser" + when (type) { return "$selectedTanMethod $forAction: $messageToShowToUser" + when (type) {
TanChallengeType.EnterTan -> "" TanChallengeType.EnterTan -> ""
TanChallengeType.Image -> ", Image: $tanImage" TanChallengeType.Image -> ", Image: $tanImage"
TanChallengeType.Flickercode -> ", FlickerCode: $flickerCode" TanChallengeType.FlickerCode -> ", FlickerCode: $flickerCode"
} }
} }

View File

@ -3,7 +3,7 @@ package net.codinux.banking.client.model.tan
enum class TanChallengeType { enum class TanChallengeType {
Image, Image,
Flickercode, FlickerCode,
EnterTan EnterTan
} }

View File

@ -3,9 +3,9 @@ package net.codinux.banking.client.model.tan
enum class TanMethodType { enum class TanMethodType {
EnterTan, EnterTan,
ChipTanManuell, ChipTanManual,
ChipTanFlickercode, ChipTanFlickerCode,
ChipTanUsb, ChipTanUsb,
@ -33,16 +33,34 @@ enum class TanMethodType {
companion object { companion object {
val NonVisual = listOf(TanMethodType.DecoupledTan, TanMethodType.DecoupledPushTan, TanMethodType.AppTan, TanMethodType.SmsTan, TanMethodType.ChipTanManuell, TanMethodType.EnterTan) val NonVisual = listOf(TanMethodType.DecoupledTan, TanMethodType.DecoupledPushTan, TanMethodType.AppTan, TanMethodType.SmsTan, TanMethodType.ChipTanManual, TanMethodType.EnterTan)
val ImageBased = listOf(TanMethodType.QrCode, TanMethodType.ChipTanQrCode, TanMethodType.photoTan, TanMethodType.ChipTanPhotoTanMatrixCode) val NonVisualWithoutChipTanManual = NonVisual.toMutableList().apply { remove(TanMethodType.ChipTanManual) }.toList()
val ImageBased = listOf(
TanMethodType.QrCode, TanMethodType.photoTan, // non ChipTan
TanMethodType.ChipTanQrCode, TanMethodType.ChipTanPhotoTanMatrixCode // ChipTan; QrCode (e.g. used by Sparkassen) is faster than MatrixCode (e.g. used by Volksbanken)
)
val NonVisualOrImageBased = buildList { val NonVisualOrImageBased = buildList {
addAll(listOf(TanMethodType.DecoupledTan, TanMethodType.DecoupledPushTan, TanMethodType.AppTan, TanMethodType.SmsTan, TanMethodType.EnterTan)) addAll(NonVisualWithoutChipTanManual)
addAll(ImageBased) addAll(ImageBased)
addAll(listOf(TanMethodType.ChipTanManuell)) // this is quite inconvenient for user, so i added it as last addAll(listOf(TanMethodType.ChipTanManual)) // this is quite inconvenient for user, so i added it as last
} }
/**
* The same as [NonVisualOrImageBased] but including [ChipTanFlickerCode] - for applications supporting it - as
* FlickerCode is still the most used ChipTan procedure.
*/
val NonVisualOrImageBasedOrFlickerCode = NonVisualOrImageBased.toMutableList().apply {
val index = this.indexOf(ChipTanQrCode)
this.add(index, ChipTanFlickerCode)
}.toList()
val TanMethodsPreferredByMostApplications = NonVisualOrImageBased
val TanMethodsNotSupportedByMostApplications = listOf(TanMethodType.ChipTanUsb) val TanMethodsNotSupportedByMostApplications = listOf(TanMethodType.ChipTanUsb)
} }

View File

@ -4,8 +4,6 @@ import org.jetbrains.kotlin.gradle.targets.js.dsl.ExperimentalWasmDsl
plugins { plugins {
kotlin("multiplatform") kotlin("multiplatform")
id("maven-publish")
} }
@ -34,7 +32,7 @@ kotlin {
browser { browser {
testTask { testTask {
useKarma { useKarma {
useChromeHeadless() // useChromeHeadless()
useFirefoxHeadless() useFirefoxHeadless()
} }
} }
@ -115,21 +113,6 @@ kotlin {
//ext["customArtifactId"] = "fints4k-banking-client" ext["customArtifactId"] = "fints4k-banking-client"
//
//apply(from = "../gradle/scripts/publish-codinux.gradle.kts")
apply(from = "../gradle/scripts/publish-codinux-repo.gradle.kts")
publishing {
repositories {
maven {
name = "codinux"
url = uri("https://maven.dankito.net/api/packages/codinux/maven")
credentials(PasswordCredentials::class.java) {
username = project.property("codinuxRegistryWriterUsername") as String
password = project.property("codinuxRegistryWriterPassword") as String
}
}
}
}

View File

@ -9,9 +9,9 @@ import net.codinux.banking.client.model.options.GetAccountDataOptions
import net.codinux.banking.client.model.request.GetAccountDataRequest import net.codinux.banking.client.model.request.GetAccountDataRequest
import net.codinux.banking.client.model.request.TransferMoneyRequestForUser import net.codinux.banking.client.model.request.TransferMoneyRequestForUser
import net.codinux.banking.client.model.response.* import net.codinux.banking.client.model.response.*
import net.codinux.banking.client.model.tan.TanMethodType
import net.codinux.banking.fints.FinTsClient import net.codinux.banking.fints.FinTsClient
import net.codinux.banking.fints.config.FinTsClientConfiguration import net.codinux.banking.fints.config.FinTsClientConfiguration
import net.codinux.banking.fints.model.BankData
open class FinTs4kBankingClient( open class FinTs4kBankingClient(
config: FinTsClientConfiguration = FinTsClientConfiguration(), config: FinTsClientConfiguration = FinTsClientConfiguration(),
@ -35,12 +35,14 @@ open class FinTs4kBankingClient(
return mapper.map(response, request.bankInfo) return mapper.map(response, request.bankInfo)
} }
override suspend fun updateAccountTransactionsAsync(bank: BankAccess, accounts: List<BankAccount>?): Response<List<GetTransactionsResponse>> { override suspend fun updateAccountTransactionsAsync(bank: BankAccess, accounts: List<BankAccount>?, preferredTanMethodsIfSelectedTanMethodIsNotAvailable: List<TanMethodType>?): Response<List<GetTransactionsResponse>> {
val accountsToRequest = (accounts ?: bank.accounts).filter { it.supportsAnyFeature(BankAccountFeatures.RetrieveBalance, BankAccountFeatures.RetrieveTransactions) } val accountsToRequest = (accounts ?: bank.accounts).filter { it.supportsAnyFeature(BankAccountFeatures.RetrieveBalance, BankAccountFeatures.RetrieveTransactions) }
if (accountsToRequest.isNotEmpty()) { if (accountsToRequest.isNotEmpty()) {
val responses = accountsToRequest.map { account -> val responses = accountsToRequest.map { account ->
val parameter = mapper.mapToUpdateAccountTransactionsParameter(bank, account) val preferredTanMethods = listOf(bank.selectedTanMethod.type) + (preferredTanMethodsIfSelectedTanMethodIsNotAvailable ?: emptyList())
val parameter = mapper.mapToUpdateAccountTransactionsParameter(bank, account, preferredTanMethods)
val response = client.getAccountDataAsync(parameter) val response = client.getAccountDataAsync(parameter)

View File

@ -62,18 +62,16 @@ open class FinTs4kMapper {
bank.serverAddress, bank.bic, bank.name bank.serverAddress, bank.bic, bank.name
) )
open fun mapToUpdateAccountTransactionsParameter(bank: BankAccess, account: BankAccount): GetAccountDataParameter { open fun mapToUpdateAccountTransactionsParameter(bank: BankAccess, account: BankAccount, preferredTanMethods: List<TanMethodType>? = null): GetAccountDataParameter {
val defaults = GetAccountDataOptions() val defaults = GetAccountDataOptions()
val accountIdentifier = BankAccountIdentifierImpl(account.identifier, account.subAccountNumber, account.iban) val accountIdentifier = BankAccountIdentifierImpl(account.identifier, account.subAccountNumber, account.iban)
val from = account.lastAccountUpdateTime?.toLocalDateTime(TimeZone.EuropeBerlin)?.date // TODO: in case lastTransactionsUpdateTime is not set, this would retrieve all transactions (and require a TAN im most cases) val from = account.lastAccountUpdateTime?.toLocalDateTime(TimeZone.EuropeBerlin)?.date // TODO: in case lastTransactionsUpdateTime is not set, this would retrieve all transactions (and require a TAN im most cases)
val retrieveTransactions = if (from != null) RetrieveTransactions.AccordingToRetrieveFromAndTo else RetrieveTransactions.valueOf(defaults.retrieveTransactions.name) val retrieveTransactions = if (from != null) RetrieveTransactions.AccordingToRetrieveFromAndTo else RetrieveTransactions.valueOf(defaults.retrieveTransactions.name)
// val preferredTanMethods = listOf(mapTanMethodType(bank.selectedTanMethod.type)) // TODO: currently we aren't saving TanMethods in database, re-enable as soon as TanMethods get saved
val preferredTanMethods = defaults.preferredTanMethods?.map { mapTanMethodType(it) }
return GetAccountDataParameter(bank.domesticBankCode, bank.loginName, bank.password!!, listOf(accountIdentifier), true, return GetAccountDataParameter(bank.domesticBankCode, bank.loginName, bank.password!!, listOf(accountIdentifier), true,
retrieveTransactions, from, retrieveTransactions, from,
preferredTanMethods = preferredTanMethods, preferredTanMethods = preferredTanMethods?.map { mapTanMethodType(it) },
preferredTanMedium = bank.selectedTanMediumIdentifier, preferredTanMedium = bank.selectedTanMediumIdentifier,
finTsModel = bank.clientData as? BankData, finTsModel = bank.clientData as? BankData,
serializedFinTsModel = bank.serializedClientData serializedFinTsModel = bank.serializedClientData
@ -329,7 +327,7 @@ open class FinTs4kMapper {
protected open fun mapTanChallengeType(challenge: net.codinux.banking.fints.model.TanChallenge): TanChallengeType = when { protected open fun mapTanChallengeType(challenge: net.codinux.banking.fints.model.TanChallenge): TanChallengeType = when {
challenge is ImageTanChallenge -> TanChallengeType.Image challenge is ImageTanChallenge -> TanChallengeType.Image
challenge is FlickerCodeTanChallenge -> TanChallengeType.Flickercode challenge is FlickerCodeTanChallenge -> TanChallengeType.FlickerCode
else -> TanChallengeType.EnterTan else -> TanChallengeType.EnterTan
} }
@ -414,7 +412,7 @@ open class FinTs4kMapper {
open fun mapToMoney(amount: Amount, currency: String): Money = Money(amount.toString(), currency) open fun mapToMoney(amount: Amount, currency: String): Money = Money(amount.toString(), currency)
open fun mapMessageLog(response: net.dankito.banking.client.model.response.FinTsClientResponse, bank: BankAccess? = null, account: BankAccount? = null) = open fun mapMessageLog(response: FinTsClientResponse, bank: BankAccess? = null, account: BankAccount? = null) =
mapMessageLog(response.messageLog, bank, account) mapMessageLog(response.messageLog, bank, account)
open fun mapMessageLog(messageLog: List<net.codinux.banking.fints.model.MessageLogEntry>, bank: BankAccess? = null, account: BankAccount? = null) = open fun mapMessageLog(messageLog: List<net.codinux.banking.fints.model.MessageLogEntry>, bank: BankAccess? = null, account: BankAccount? = null) =
@ -424,7 +422,7 @@ open class FinTs4kMapper {
// TODO: may map messageLogEntry.context.BankData to BankAccess // TODO: may map messageLogEntry.context.BankData to BankAccess
val context = messageLogEntry.context val context = messageLogEntry.context
val fintsAccount = context.account val fintsAccount = context.account
val effectiveAccount = account ?: bank?.accounts?.firstOrNull { it.identifier == fintsAccount?.accountIdentifier && it.subAccountNumber == fintsAccount?.subAccountAttribute } val effectiveAccount = account ?: bank?.accounts?.firstOrNull { it.identifier == fintsAccount?.accountIdentifier && it.subAccountNumber == fintsAccount.subAccountAttribute }
val messageNumberString = "${context.jobNumber.toString().padStart(2, '0')}_${context.dialogNumber.toString().padStart(2, '0')}_${context.messageNumber.toString().padStart(2, '0')}" val messageNumberString = "${context.jobNumber.toString().padStart(2, '0')}_${context.dialogNumber.toString().padStart(2, '0')}_${context.messageNumber.toString().padStart(2, '0')}"
@ -445,7 +443,7 @@ open class FinTs4kMapper {
} }
protected open fun <T> mapError(response: net.dankito.banking.client.model.response.FinTsClientResponse, messageLog: List<MessageLogEntry>): Response<T> = protected open fun <T> mapError(response: FinTsClientResponse, messageLog: List<MessageLogEntry>): Response<T> =
if (response.error != null) { if (response.error != null) {
Response.error(ErrorType.valueOf(response.error!!.name), if (response.error == ErrorCode.BankReturnedError) null else response.errorMessage, Response.error(ErrorType.valueOf(response.error!!.name), if (response.error == ErrorCode.BankReturnedError) null else response.errorMessage,
if (response.error == ErrorCode.BankReturnedError && response.errorMessage !== null) listOf(response.errorMessage!!) else emptyList(), messageLog) if (response.error == ErrorCode.BankReturnedError && response.errorMessage !== null) listOf(response.errorMessage!!) else emptyList(), messageLog)

View File

@ -3,6 +3,7 @@ package net.codinux.banking.client.fints4k
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import net.codinux.banking.client.SimpleBankingClientCallback import net.codinux.banking.client.SimpleBankingClientCallback
import net.codinux.banking.client.model.response.ResponseType import net.codinux.banking.client.model.response.ResponseType
import net.codinux.banking.client.model.tan.EnterTanResult
import kotlin.test.* import kotlin.test.*
@Ignore @Ignore
@ -18,7 +19,10 @@ class FinTs4kBankingClientTest {
private val underTest = FinTs4kBankingClientForUser(bankCode, loginName, password, SimpleBankingClientCallback { tanChallenge, callback -> private val underTest = FinTs4kBankingClientForUser(bankCode, loginName, password, SimpleBankingClientCallback { tanChallenge, callback ->
println("WARN: TAN is required to execute test: ${tanChallenge.messageToShowToUser}")
val enteredTan: String? = null
callback(EnterTanResult(enteredTan))
}) })

View File

@ -12,7 +12,7 @@ class FinTs4kMapperTest {
@Test @Test
fun getTotalBalance_TotalBalanceIsNull_CalculateByQuantityAndMarketValue() { fun getTotalBalance_TotalBalanceIsNull_CalculateByQuantityAndMarketValue() {
val holding = Holding("", null, null, null, 4, null, null, null, fints4kAmount("13.33")) val holding = Holding("", null, null, null, 4.0, null, null, null, fints4kAmount("13.33"))
val result = underTest.getTotalBalance(holding) val result = underTest.getTotalBalance(holding)
@ -21,7 +21,7 @@ class FinTs4kMapperTest {
@Test @Test
fun getTotalCostPrice_TotalCostPriceIsNull_CalculateByQuantityAndAverageCostPrice() { fun getTotalCostPrice_TotalCostPriceIsNull_CalculateByQuantityAndAverageCostPrice() {
val holding = Holding("", null, null, null, 47, fints4kAmount("16.828"), null) val holding = Holding("", null, null, null, 47.0, fints4kAmount("16.828"), null)
val result = underTest.getTotalCostPrice(holding) val result = underTest.getTotalCostPrice(holding)

View File

@ -23,7 +23,7 @@ allprojects {
} }
ext["sourceCodeRepositoryBaseUrl"] = "github.com/codinux/BankingClient" ext["sourceCodeRepositoryBaseUrl"] = "git.dankito.net/codinux/BankingClient"
ext["projectDescription"] = "Model and base definitions for Banking Client, a common abstraction for different implements of banking libraries" ext["projectDescription"] = "Model and base definitions for Banking Client, a common abstraction for different implements of banking libraries"
} }

@ -1 +1 @@
Subproject commit bdf8b14738c06016a48e1fc9781ad4d999e1219f Subproject commit 88f1b01167e6a34b5b91f8797845bca0b7e4d3ab