Added FinTs4kBankingClient
This commit is contained in:
parent
c581a9ebb1
commit
3e4dfee615
|
@ -0,0 +1,125 @@
|
|||
@file:OptIn(ExperimentalWasmDsl::class)
|
||||
|
||||
import org.jetbrains.kotlin.gradle.targets.js.dsl.ExperimentalWasmDsl
|
||||
|
||||
plugins {
|
||||
kotlin("multiplatform")
|
||||
}
|
||||
|
||||
|
||||
repositories {
|
||||
mavenLocal()
|
||||
// TODO: remove again as soon as kmp-web-client is released
|
||||
maven {
|
||||
setUrl("https://oss.sonatype.org/content/repositories/snapshots/")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
kotlin {
|
||||
jvmToolchain(8)
|
||||
|
||||
jvm {
|
||||
withJava()
|
||||
|
||||
testRuns["test"].executionTask.configure {
|
||||
useJUnitPlatform()
|
||||
|
||||
testLogging {
|
||||
showExceptions = true
|
||||
showStandardStreams = true
|
||||
events("passed", "skipped", "failed")
|
||||
// exceptionFormat = org.gradle.api.tasks.testing.logging.TestExceptionFormat.FULL
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// js {
|
||||
// moduleName = "fints4k-banking-client"
|
||||
// binaries.executable()
|
||||
//
|
||||
// browser {
|
||||
// testTask {
|
||||
// useKarma {
|
||||
// useChromeHeadless()
|
||||
// useFirefoxHeadless()
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// nodejs {
|
||||
// testTask {
|
||||
// useMocha {
|
||||
// timeout = "20s" // Mocha times out after 2 s, which is too short for bufferExceeded() test
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// wasmJs()
|
||||
//
|
||||
//
|
||||
// linuxX64()
|
||||
// mingwX64()
|
||||
//
|
||||
// iosArm64()
|
||||
// iosSimulatorArm64()
|
||||
// macosX64()
|
||||
// macosArm64()
|
||||
// watchosArm64()
|
||||
// watchosSimulatorArm64()
|
||||
// tvosArm64()
|
||||
// tvosSimulatorArm64()
|
||||
|
||||
applyDefaultHierarchyTemplate()
|
||||
|
||||
|
||||
|
||||
val coroutinesVersion: String by project
|
||||
|
||||
sourceSets {
|
||||
commonMain {
|
||||
dependencies {
|
||||
api(project(":BankingClient"))
|
||||
|
||||
api("net.codinux.banking:fints4k:1.0.0-Alpha-10")
|
||||
|
||||
// implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion")
|
||||
}
|
||||
}
|
||||
commonTest {
|
||||
dependencies {
|
||||
implementation(kotlin("test"))
|
||||
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutinesVersion")
|
||||
}
|
||||
}
|
||||
|
||||
jvmMain {
|
||||
dependencies {
|
||||
// implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:$coroutinesVersion")
|
||||
}
|
||||
}
|
||||
jvmTest {
|
||||
dependencies {
|
||||
implementation(kotlin("test"))
|
||||
}
|
||||
}
|
||||
|
||||
// jsMain {
|
||||
// dependencies {
|
||||
//// implementation(npm("@js-joda/timezone", "2.3.0"))
|
||||
// }
|
||||
// }
|
||||
// jsTest { }
|
||||
//
|
||||
// nativeMain { }
|
||||
// nativeTest { }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
ext["customArtifactId"] = "fints4k-banking-client"
|
||||
|
||||
apply(from = "../gradle/scripts/publish-codinux.gradle.kts")
|
|
@ -0,0 +1,26 @@
|
|||
package net.codinux.banking.client.fints4k
|
||||
|
||||
import net.codinux.banking.client.BankingClient
|
||||
import net.codinux.banking.client.model.AccountCredentials
|
||||
import net.codinux.banking.client.model.options.GetAccountDataOptions
|
||||
import net.codinux.banking.client.model.response.GetAccountDataResponse
|
||||
import net.codinux.banking.client.model.response.Response
|
||||
import net.dankito.banking.fints.FinTsClient
|
||||
import net.dankito.banking.fints.callback.SimpleFinTsClientCallback
|
||||
|
||||
class FinTs4kBankingClient : BankingClient {
|
||||
|
||||
private val mapper = FinTs4kMapper()
|
||||
|
||||
private val client = FinTsClient(SimpleFinTsClientCallback { tanChallenge ->
|
||||
// callback.enterTan()
|
||||
})
|
||||
|
||||
|
||||
override suspend fun getAccountDataAsync(credentials: AccountCredentials, options: GetAccountDataOptions): Response<GetAccountDataResponse> {
|
||||
val response = client.getAccountDataAsync(mapper.mapToGetAccountDataParameter(credentials, options))
|
||||
|
||||
return mapper.map(response)
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package net.codinux.banking.client.fints4k
|
||||
|
||||
import net.codinux.banking.client.BankingClientForCustomerBase
|
||||
import net.codinux.banking.client.model.AccountCredentials
|
||||
|
||||
class FinTs4kBankingClientForCustomer(credentials: AccountCredentials)
|
||||
: BankingClientForCustomerBase(credentials, FinTs4kBankingClient()) {
|
||||
|
||||
constructor(bankCode: String, loginName: String, password: String)
|
||||
: this(AccountCredentials(bankCode, loginName, password))
|
||||
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
package net.codinux.banking.client.fints4k
|
||||
|
||||
import net.codinux.banking.client.model.*
|
||||
import net.codinux.banking.client.model.options.GetAccountDataOptions
|
||||
import net.codinux.banking.client.model.response.*
|
||||
import net.dankito.banking.client.model.parameter.GetAccountDataParameter
|
||||
import net.dankito.banking.client.model.parameter.RetrieveTransactions
|
||||
import net.dankito.banking.client.model.response.ErrorCode
|
||||
import net.dankito.banking.fints.model.Money
|
||||
|
||||
class FinTs4kMapper {
|
||||
|
||||
fun mapToGetAccountDataParameter(credentials: AccountCredentials, options: GetAccountDataOptions) = GetAccountDataParameter(
|
||||
credentials.bankCode, credentials.loginName, credentials.password,
|
||||
null,
|
||||
options.retrieveBalance,
|
||||
RetrieveTransactions.valueOf(options.retrieveTransactions.name), options.retrieveTransactionsFrom, options.retrieveTransactionsTo,
|
||||
abortIfTanIsRequired = options.abortIfTanIsRequired
|
||||
)
|
||||
|
||||
|
||||
fun map(response: net.dankito.banking.client.model.response.GetAccountDataResponse): Response<GetAccountDataResponse> {
|
||||
return if (response.successful && response.customerAccount != null) {
|
||||
Response(ResponseType.Success, mapCustomer(response.customerAccount!!))
|
||||
} else {
|
||||
mapError(response)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun mapCustomer(customer: net.dankito.banking.client.model.CustomerAccount): GetAccountDataResponse {
|
||||
val mapped = CustomerAccount(
|
||||
customer.bankCode, customer.loginName, customer.password,
|
||||
customer.bankName, customer.bic, customer.customerName, customer.userId,
|
||||
customer.accounts.map { mapAccount(it) }
|
||||
)
|
||||
|
||||
return GetAccountDataResponse(mapped)
|
||||
}
|
||||
|
||||
|
||||
private fun mapAccount(account: net.dankito.banking.client.model.BankAccount): BankAccount = BankAccount(
|
||||
account.identifier, account.accountHolderName, mapAccountType(account.type), account.iban, account.subAccountNumber,
|
||||
account.productName, account.currency, account.accountLimit, isAccountTypeSupported(account),
|
||||
mapFeatures(account),
|
||||
mapAmount(account.balance), account.retrievedTransactionsFrom, account.retrievedTransactionsTo,
|
||||
// TODO: map haveAllTransactionsBeenRetrieved and countDaysForWhichTransactionsAreKept
|
||||
bookedTransactions = account.bookedTransactions.map { mapTransaction(it) }.toMutableList()
|
||||
)
|
||||
|
||||
private fun mapAccountType(type: net.dankito.banking.client.model.BankAccountType): BankAccountType =
|
||||
BankAccountType.valueOf(type.name)
|
||||
|
||||
private fun mapFeatures(account: net.dankito.banking.client.model.BankAccount): Set<BankAccountFeatures> = buildSet {
|
||||
if (account.supportsRetrievingBalance) {
|
||||
add(BankAccountFeatures.RetrieveBalance)
|
||||
}
|
||||
if (account.supportsRetrievingTransactions) {
|
||||
add(BankAccountFeatures.RetrieveTransactions)
|
||||
}
|
||||
if (account.supportsTransferringMoney) {
|
||||
add(BankAccountFeatures.TransferMoney)
|
||||
}
|
||||
if (account.supportsInstantPayment) {
|
||||
add(BankAccountFeatures.InstantPayment)
|
||||
}
|
||||
}
|
||||
|
||||
private fun isAccountTypeSupported(account: net.dankito.banking.client.model.BankAccount): Boolean {
|
||||
// TODO:
|
||||
// open val isAccountTypeSupportedByApplication: Boolean
|
||||
// get() = FinTsClient.SupportedAccountTypes.contains(accountType)
|
||||
// || allowedJobNames.contains(CustomerSegmentId.Balance.id)
|
||||
// || allowedJobNames.contains(CustomerSegmentId.AccountTransactionsMt940.id)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
private fun mapTransaction(transaction: net.dankito.banking.client.model.AccountTransaction): AccountTransaction = AccountTransaction(
|
||||
mapAmount(transaction.amount), transaction.amount.currency.code, transaction.unparsedReference,
|
||||
transaction.bookingDate, transaction.valueDate,
|
||||
transaction.otherPartyName, transaction.otherPartyBankCode, transaction.otherPartyAccountId,
|
||||
transaction.bookingText, null,
|
||||
transaction.statementNumber, transaction.sequenceNumber,
|
||||
mapNullableAmount(transaction.openingBalance), mapNullableAmount(transaction.closingBalance),
|
||||
// TODO: map other properties
|
||||
)
|
||||
|
||||
private fun mapNullableAmount(amount: Money?) = amount?.let { mapAmount(it) }
|
||||
|
||||
private fun mapAmount(amount: Money) = Amount.fromString(amount.amount.string.replace(',', '.'))
|
||||
|
||||
|
||||
private fun <T> mapError(response: net.dankito.banking.client.model.response.GetAccountDataResponse): Response<T> {
|
||||
val error = if (response.error != null) {
|
||||
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())
|
||||
} else {
|
||||
Error(ErrorType.UnknownError, response.errorMessage)
|
||||
}
|
||||
|
||||
return Response(ResponseType.Error, null, error)
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package net.codinux.banking.client.fints4k
|
||||
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import net.codinux.banking.client.model.response.ResponseType
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertNotNull
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class FinTs4kBankingClientTest {
|
||||
|
||||
companion object {
|
||||
|
||||
// set your credentials here:
|
||||
private const val bankCode = ""
|
||||
private const val loginName = ""
|
||||
private const val password = ""
|
||||
}
|
||||
|
||||
|
||||
private val underTest = FinTs4kBankingClientForCustomer(bankCode, loginName, password)
|
||||
|
||||
|
||||
@Test
|
||||
fun getAccountDataAsync() = runTest {
|
||||
val result = underTest.getAccountDataAsync()
|
||||
|
||||
assertEquals(ResponseType.Success, result.type)
|
||||
assertNotNull(result.data)
|
||||
assertTrue(result.data!!.bookedTransactions.isNotEmpty())
|
||||
}
|
||||
|
||||
}
|
|
@ -28,13 +28,17 @@ allprojects {
|
|||
tasks.register("publishAllToMavenLocal") {
|
||||
dependsOn(
|
||||
":BankingClientModel:publishToMavenLocal",
|
||||
":BankingClient:publishToMavenLocal"
|
||||
":BankingClient:publishToMavenLocal",
|
||||
|
||||
":FinTs4jBankingClient:publishToMavenLocal"
|
||||
)
|
||||
}
|
||||
|
||||
tasks.register("publishAll") {
|
||||
dependsOn(
|
||||
":BankingClientModel:publish",
|
||||
":BankingClient:publish"
|
||||
":BankingClient:publish",
|
||||
|
||||
":FinTs4jBankingClient:publish"
|
||||
)
|
||||
}
|
|
@ -26,3 +26,5 @@ rootProject.name = "BankingClientProject"
|
|||
|
||||
include("BankingClientModel")
|
||||
include("BankingClient")
|
||||
|
||||
include("FinTs4jBankingClient")
|
||||
|
|
Loading…
Reference in New Issue