Converted fints4kBankingClient to a multi platform project

This commit is contained in:
dankito 2020-07-12 12:26:16 +02:00
parent 42f9e5f018
commit 82628d8a6b
5 changed files with 147 additions and 51 deletions

View File

@ -1,22 +1,127 @@
apply plugin: 'java-library' plugins {
apply plugin: 'kotlin' id "org.jetbrains.kotlin.multiplatform"
id "com.android.library"
id "maven-publish"
}
ext.artifactName = "fints4k-banking-client" ext.artifactName = "fints4k-banking-client"
sourceCompatibility = "1.7" kotlin {
targetCompatibility = "1.7" jvm {
compilations.main.kotlinOptions {
jvmTarget = "1.6"
}
}
compileKotlin { targets {
kotlinOptions.jvmTarget = "1.6" // Select iOS target for real device or emulator.
} final def iOSIsRealDevice = System.getenv('SDK_NAME')?.startsWith("iphoneos")
compileTestKotlin { final def iOSTarget = iOSIsRealDevice ? presets.iosArm64 : presets.iosX64
kotlinOptions.jvmTarget = "1.6"
// iOS target.
fromPreset(iOSTarget, 'ios') {
binaries {
framework {
baseName = "fints4kBankingClient"
}
}
}
}
sourceSets {
commonMain {
dependencies {
implementation kotlin("stdlib-common")
implementation project(":BankingUiCommon")
implementation project(":fints4k")
}
}
jvmMain {
dependencies {
api kotlin("stdlib-jdk7")
}
}
iosMain {
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-common:$kotlinVersion"
}
}
}
} }
dependencies { // Task to generate iOS framework for xcode projects.
api project(':BankingUiCommon') task packForXCode(type: Sync) {
api project(':fints4k')
final File frameworkDir = new File(buildDir, "xcode-frameworks")
final String mode = project.findProperty("XCODE_CONFIGURATION")?.toUpperCase() ?: 'DEBUG'
final def framework = kotlin.targets.ios.binaries.getFramework("", mode)
inputs.property "mode", mode
dependsOn framework.linkTask
from { framework.outputFile.parentFile }
into frameworkDir
doLast {
new File(frameworkDir, 'gradlew').with {
text = "#!/bin/bash\nexport 'JAVA_HOME=${System.getProperty("java.home")}'\ncd '${rootProject.rootDir}'\n./gradlew \$@\n"
setExecutable(true)
}
}
}
// Run packForXCode when building.
tasks.build.dependsOn packForXCode
android {
compileSdkVersion androidCompileSdkVersion
defaultConfig {
minSdkVersion androidMinSdkVersion
targetSdkVersion androidTargetSdkVersion
versionName version
versionCode appVersionCode
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
packagingOptions {
pickFirst 'META-INF/ktor-http.kotlin_module'
pickFirst 'META-INF/kotlinx-io.kotlin_module'
pickFirst 'META-INF/atomicfu.kotlin_module'
pickFirst 'META-INF/ktor-utils.kotlin_module'
pickFirst 'META-INF/kotlinx-coroutines-io.kotlin_module'
pickFirst 'META-INF/ktor-client-core.kotlin_module'
pickFirst 'META-INF/DEPENDENCIES'
pickFirst 'META-INF/NOTICE'
pickFirst 'META-INF/LICENSE'
pickFirst 'META-INF/LICENSE.txt'
pickFirst 'META-INF/NOTICE.txt'
}
lintOptions {
abortOnError false
}
} }

View File

@ -1,7 +1,5 @@
package net.dankito.banking package net.dankito.banking
import com.soywiz.klock.jvm.toDate
import net.dankito.banking.extensions.toKlockDate
import net.dankito.banking.ui.BankingClientCallback import net.dankito.banking.ui.BankingClientCallback
import net.dankito.banking.ui.IBankingClient import net.dankito.banking.ui.IBankingClient
import net.dankito.banking.ui.model.Customer import net.dankito.banking.ui.model.Customer
@ -19,17 +17,14 @@ import net.dankito.banking.fints.model.*
import net.dankito.banking.mapper.BankDataMapper import net.dankito.banking.mapper.BankDataMapper
import net.dankito.banking.fints.util.IBase64Service import net.dankito.banking.fints.util.IBase64Service
import net.dankito.banking.fints.util.PureKotlinBase64Service import net.dankito.banking.fints.util.PureKotlinBase64Service
import net.dankito.utils.serialization.JacksonJsonSerializer
import net.dankito.banking.fints.webclient.IWebClient import net.dankito.banking.fints.webclient.IWebClient
import net.dankito.banking.fints.webclient.KtorWebClient import net.dankito.banking.fints.webclient.KtorWebClient
import net.dankito.banking.bankfinder.BankInfo import net.dankito.banking.bankfinder.BankInfo
import net.dankito.banking.extensions.toAmount
import net.dankito.banking.extensions.toMoney import net.dankito.banking.extensions.toMoney
import net.dankito.utils.multiplatform.log.Slf4jLoggerFactory import net.dankito.banking.util.ISerializer
import net.dankito.utils.multiplatform.toDate import net.dankito.utils.multiplatform.Date
import org.slf4j.LoggerFactory import net.dankito.utils.multiplatform.File
import java.io.File import net.dankito.utils.multiplatform.log.LoggerFactory
import java.math.BigDecimal
open class fints4kBankingClient( open class fints4kBankingClient(
@ -37,6 +32,7 @@ open class fints4kBankingClient(
customerId: String, customerId: String,
pin: String, pin: String,
protected val dataFolder: File, protected val dataFolder: File,
protected val serializer: ISerializer,
webClient: IWebClient = KtorWebClient(), webClient: IWebClient = KtorWebClient(),
base64Service: IBase64Service = PureKotlinBase64Service(), base64Service: IBase64Service = PureKotlinBase64Service(),
callback: BankingClientCallback callback: BankingClientCallback
@ -46,12 +42,7 @@ open class fints4kBankingClient(
companion object { companion object {
val fints4kClientDataFilename = "fints4kClientData.json" val fints4kClientDataFilename = "fints4kClientData.json"
private val log = LoggerFactory.getLogger(fints4kBankingClient::class.java) private val log = LoggerFactory.getLogger(fints4kBankingClient::class)
init {
net.dankito.banking.fints.util.log.LoggerFactory.loggerFactory = net.dankito.banking.fints.util.log.Slf4jLoggerFactory()
}
} }
@ -59,8 +50,6 @@ open class fints4kBankingClient(
protected val bankDataMapper = BankDataMapper() protected val bankDataMapper = BankDataMapper()
protected val serializer = JacksonJsonSerializer()
protected val bank = bankDataMapper.mapFromBankInfo(bankInfo) protected val bank = bankDataMapper.mapFromBankInfo(bankInfo)
@ -96,7 +85,7 @@ open class fints4kBankingClient(
override val messageLogWithoutSensitiveData: List<MessageLogEntry> override val messageLogWithoutSensitiveData: List<MessageLogEntry>
get() = client.messageLogWithoutSensitiveData.map { MessageLogEntry(it.message, it.time.toDate(), customer) } get() = client.messageLogWithoutSensitiveData.map { MessageLogEntry(it.message, it.time, customer) }
override fun addAccountAsync(callback: (AddAccountResponse) -> Unit) { override fun addAccountAsync(callback: (AddAccountResponse) -> Unit) {
@ -117,7 +106,8 @@ open class fints4kBankingClient(
callback(GetTransactionsResponse(bankAccount, false, "Cannot find account for ${bankAccount.identifier}")) // TODO: translate callback(GetTransactionsResponse(bankAccount, false, "Cannot find account for ${bankAccount.identifier}")) // TODO: translate
} }
else { else {
client.getTransactionsAsync(GetTransactionsParameter(parameter.alsoRetrieveBalance, parameter.fromDate?.toKlockDate(), parameter.toDate?.toKlockDate(), null, parameter.abortIfTanIsRequired, client.getTransactionsAsync(GetTransactionsParameter(parameter.alsoRetrieveBalance, parameter.fromDate,
parameter.toDate, null, parameter.abortIfTanIsRequired,
{ parameter.retrievedChunkListener?.invoke(mapper.mapTransactions(bankAccount, it)) } ), account) { response -> { parameter.retrievedChunkListener?.invoke(mapper.mapTransactions(bankAccount, it)) } ), account) { response ->
val mappedResponse = mapper.mapResponse(bankAccount, response) val mappedResponse = mapper.mapResponse(bankAccount, response)
@ -148,7 +138,7 @@ open class fints4kBankingClient(
override fun restoreData() { override fun restoreData() {
val deserializedCustomer = serializer.deserializeObject(getFints4kClientDataFile(), CustomerData::class.java) val deserializedCustomer = serializer.deserializeObject(getFints4kClientDataFile(), CustomerData::class)
deserializedCustomer?.let { deserializedCustomer?.let {
mapper.updateCustomer(fints4kCustomer, deserializedCustomer) mapper.updateCustomer(fints4kCustomer, deserializedCustomer)
@ -161,7 +151,7 @@ open class fints4kBankingClient(
try { try {
val clientDataFile = getFints4kClientDataFile() val clientDataFile = getFints4kClientDataFile()
clientDataFile.parentFile.mkdirs() clientDataFile.parent?.mkdirs()
serializer.serializeObject(fints4kCustomer, clientDataFile) serializer.serializeObject(fints4kCustomer, clientDataFile)
} catch (e: Exception) { } catch (e: Exception) {

View File

@ -5,10 +5,11 @@ import net.dankito.banking.ui.IBankingClient
import net.dankito.banking.ui.IBankingClientCreator import net.dankito.banking.ui.IBankingClientCreator
import net.dankito.banking.bankfinder.BankInfo import net.dankito.banking.bankfinder.BankInfo
import net.dankito.banking.util.IAsyncRunner import net.dankito.banking.util.IAsyncRunner
import java.io.File import net.dankito.banking.util.ISerializer
import net.dankito.utils.multiplatform.File
open class fints4kBankingClientCreator : IBankingClientCreator { open class fints4kBankingClientCreator(protected val serializer: ISerializer) : IBankingClientCreator {
override fun createClient( override fun createClient(
bankInfo: BankInfo, bankInfo: BankInfo,
@ -19,7 +20,7 @@ open class fints4kBankingClientCreator : IBankingClientCreator {
callback: BankingClientCallback callback: BankingClientCallback
): IBankingClient { ): IBankingClient {
return fints4kBankingClient(bankInfo, customerId, pin, dataFolder, callback = callback) return fints4kBankingClient(bankInfo, customerId, pin, dataFolder, serializer, callback = callback)
} }
} }

View File

@ -1,7 +1,7 @@
package net.dankito.banking.mapper package net.dankito.banking.mapper
import net.dankito.banking.extensions.toJavaBigDecimal import net.dankito.utils.multiplatform.BigDecimal
import net.dankito.banking.extensions.toJavaUtilDate import net.dankito.banking.extensions.toBigDecimal
import net.dankito.banking.ui.model.* import net.dankito.banking.ui.model.*
import net.dankito.banking.ui.model.responses.AddAccountResponse import net.dankito.banking.ui.model.responses.AddAccountResponse
import net.dankito.banking.ui.model.responses.BankingClientResponse import net.dankito.banking.ui.model.responses.BankingClientResponse
@ -15,14 +15,13 @@ import net.dankito.banking.fints.model.CustomerData
import net.dankito.banking.fints.model.Money import net.dankito.banking.fints.model.Money
import net.dankito.banking.fints.response.client.FinTsClientResponse import net.dankito.banking.fints.response.client.FinTsClientResponse
import net.dankito.banking.fints.response.segments.AccountType import net.dankito.banking.fints.response.segments.AccountType
import net.dankito.utils.exception.ExceptionHelper //import net.dankito.utils.exception.ExceptionHelper
import java.math.BigDecimal
open class fints4kModelMapper { open class fints4kModelMapper {
private val exceptionHelper = ExceptionHelper() // private val exceptionHelper = ExceptionHelper()
open fun mapResponse(response: FinTsClientResponse): BankingClientResponse { open fun mapResponse(response: FinTsClientResponse): BankingClientResponse {
@ -31,7 +30,7 @@ open class fints4kModelMapper {
open fun mapResponse(customer: Customer, response: net.dankito.banking.fints.response.client.AddAccountResponse): AddAccountResponse { open fun mapResponse(customer: Customer, response: net.dankito.banking.fints.response.client.AddAccountResponse): AddAccountResponse {
val balances = response.balances.mapKeys { findMatchingBankAccount(customer, it.key) }.filter { it.key != null } val balances = response.balances.mapKeys { findMatchingBankAccount(customer, it.key) }.filter { it.key != null }
.mapValues { (it.value as Money).toJavaBigDecimal() } as Map<BankAccount, BigDecimal> .mapValues { (it.value as Money).toBigDecimal() } as Map<BankAccount, BigDecimal>
val bookedTransactions = response.bookedTransactions.associateBy { it.account } val bookedTransactions = response.bookedTransactions.associateBy { it.account }
val mappedBookedTransactions = mutableMapOf<BankAccount, List<AccountTransaction>>() val mappedBookedTransactions = mutableMapOf<BankAccount, List<AccountTransaction>>()
@ -56,14 +55,15 @@ open class fints4kModelMapper {
return GetTransactionsResponse(bankAccount, response.isSuccessful, mapErrorToShowToUser(response), return GetTransactionsResponse(bankAccount, response.isSuccessful, mapErrorToShowToUser(response),
mapTransactions(bankAccount, response.bookedTransactions), mapTransactions(bankAccount, response.bookedTransactions),
listOf(), // TODO: map unbooked transactions listOf(), // TODO: map unbooked transactions
response.balance?.toJavaBigDecimal(), response.balance?.toBigDecimal(),
response.exception, response.userCancelledAction, response.tanRequiredButWeWereToldToAbortIfSo) response.exception, response.userCancelledAction, response.tanRequiredButWeWereToldToAbortIfSo)
} }
open fun mapErrorToShowToUser(response: FinTsClientResponse): String? { open fun mapErrorToShowToUser(response: FinTsClientResponse): String? {
val innerException = response.exception?.let { exception -> exceptionHelper.getInnerException(exception) } // val innerException = response.exception?.let { exception -> exceptionHelper.getInnerException(exception) }
val innerException = response.exception // TODO
return innerException?.localizedMessage ?: response.errorsToShowToUser.joinToString("\n") return innerException?.message ?: response.errorsToShowToUser.joinToString("\n")
} }
@ -102,7 +102,7 @@ open class fints4kModelMapper {
open fun mapBankAccount(customer: Customer, accountData: AccountData): BankAccount { open fun mapBankAccount(customer: Customer, accountData: AccountData): BankAccount {
return BankAccount(customer, accountData.accountIdentifier, accountData.accountHolderName, accountData.iban, return BankAccount(customer, accountData.accountIdentifier, accountData.accountHolderName, accountData.iban,
accountData.subAccountAttribute, accountData.customerId, BigDecimal.ZERO, accountData.currency ?: "EUR", accountData.subAccountAttribute, accountData.customerId, BigDecimal.Zero, accountData.currency ?: "EUR",
mapBankAccountType(accountData.accountType), accountData.productName, accountData.accountLimit, mapBankAccountType(accountData.accountType), accountData.productName, accountData.accountLimit,
null, accountData.supportsFeature(AccountFeature.RetrieveAccountTransactions), null, accountData.supportsFeature(AccountFeature.RetrieveAccountTransactions),
accountData.supportsFeature(AccountFeature.RetrieveBalance), accountData.supportsFeature(AccountFeature.TransferMoney), accountData.supportsFeature(AccountFeature.RetrieveBalance), accountData.supportsFeature(AccountFeature.TransferMoney),
@ -176,19 +176,19 @@ open class fints4kModelMapper {
open fun mapTransaction(bankAccount: BankAccount, transaction: net.dankito.banking.fints.model.AccountTransaction): AccountTransaction { open fun mapTransaction(bankAccount: BankAccount, transaction: net.dankito.banking.fints.model.AccountTransaction): AccountTransaction {
return AccountTransaction( return AccountTransaction(
bankAccount, bankAccount,
transaction.amount.toJavaBigDecimal(), transaction.amount.toBigDecimal(),
transaction.amount.currency.code, transaction.amount.currency.code,
transaction.unparsedUsage, transaction.unparsedUsage,
transaction.bookingDate.toJavaUtilDate(), transaction.bookingDate,
transaction.otherPartyName, transaction.otherPartyName,
transaction.otherPartyBankCode, transaction.otherPartyBankCode,
transaction.otherPartyAccountId, transaction.otherPartyAccountId,
transaction.bookingText, transaction.bookingText,
transaction.valueDate.toJavaUtilDate(), transaction.valueDate,
transaction.statementNumber, transaction.statementNumber,
transaction.sequenceNumber, transaction.sequenceNumber,
transaction.openingBalance?.toJavaBigDecimal(), transaction.openingBalance?.toBigDecimal(),
transaction.closingBalance?.toJavaBigDecimal(), transaction.closingBalance?.toBigDecimal(),
transaction.endToEndReference, transaction.endToEndReference,
transaction.customerReference, transaction.customerReference,