Converted fints4k to a Kotlin multi platform project
This commit is contained in:
parent
d1bb7d81c3
commit
e44a68addc
33
build.gradle
33
build.gradle
|
@ -4,9 +4,24 @@ ext {
|
|||
|
||||
appVersionCode = 3
|
||||
|
||||
|
||||
/* MPP / basic dependencies */
|
||||
|
||||
kotlinVersion = '1.3.72'
|
||||
kotlinCoroutinesVersion = "1.3.5"
|
||||
|
||||
serializationVersion = "0.20.0"
|
||||
|
||||
|
||||
ktorVersion = "1.3.1"
|
||||
|
||||
klockVersion = "1.8.4"
|
||||
|
||||
bigNumVersion = "0.1.5"
|
||||
|
||||
uuidVersion = "0.1.0"
|
||||
|
||||
|
||||
javaUtilsVersion = '1.0.16'
|
||||
|
||||
luceneUtilsVersion = "0.5.1-SNAPSHOT"
|
||||
|
@ -17,6 +32,15 @@ ext {
|
|||
|
||||
/* Android */
|
||||
|
||||
androidCompileSdkVersion = 28
|
||||
|
||||
androidBuildToolsVersion = "29.0.3"
|
||||
|
||||
androidMinSdkVersion = 16
|
||||
|
||||
androidTargetSdkVersion = 28
|
||||
|
||||
|
||||
androidUtilsVersion = '1.1.1-SNAPSHOT'
|
||||
|
||||
materialDrawerVersion = "8.0.1"
|
||||
|
@ -44,6 +68,10 @@ ext {
|
|||
/* Test */
|
||||
|
||||
junitVersion = '4.12'
|
||||
junit5Version = '5.5.2'
|
||||
|
||||
atriumVersion = "0.12.0"
|
||||
|
||||
assertJVersion = '3.12.2'
|
||||
|
||||
mockitoVersion = '2.22.0'
|
||||
|
@ -54,15 +82,16 @@ ext {
|
|||
}
|
||||
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.3.61'
|
||||
ext.kotlin_version = '1.3.72'
|
||||
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.5.1'
|
||||
classpath 'com.android.tools.build:gradle:4.0.0'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
|
||||
|
||||
// Nexus staging plugin has to be downgraded to 0.10.0 to be applicable to sub projects, see https://github.com/UweTrottmann/SeriesGuide/commit/ca33e8ad2fa6cc5c426450c8aef3417ba073ca7f
|
||||
classpath "io.codearte.gradle.nexus:gradle-nexus-staging-plugin:0.10.0"
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
apply plugin: 'java-library'
|
||||
apply plugin: 'kotlin'
|
||||
|
||||
sourceCompatibility = "8"
|
||||
targetCompatibility = "8"
|
||||
|
||||
|
||||
dependencies {
|
||||
api project(":fints4k")
|
||||
}
|
|
@ -1,36 +1,144 @@
|
|||
apply plugin: 'java-library'
|
||||
apply plugin: 'kotlin'
|
||||
|
||||
buildscript {
|
||||
repositories {
|
||||
jcenter()
|
||||
}
|
||||
}
|
||||
|
||||
sourceCompatibility = "1.7"
|
||||
targetCompatibility = "1.7"
|
||||
|
||||
compileKotlin.kotlinOptions.jvmTarget = "1.6"
|
||||
|
||||
compileTestKotlin.kotlinOptions.jvmTarget = "1.8"
|
||||
plugins {
|
||||
id "org.jetbrains.kotlin.multiplatform"
|
||||
id "org.jetbrains.kotlin.plugin.serialization"
|
||||
id "com.android.library"
|
||||
}
|
||||
|
||||
|
||||
|
||||
dependencies {
|
||||
api "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion"
|
||||
|
||||
api "net.dankito.utils:java-utils:$javaUtilsVersion"
|
||||
|
||||
implementation "net.dankito.search:lucene-4-utils:$luceneUtilsVersion"
|
||||
|
||||
|
||||
testImplementation "junit:junit:$junitVersion"
|
||||
testImplementation "org.assertj:assertj-core:$assertJVersion"
|
||||
|
||||
testImplementation "org.mockito:mockito-core:$mockitoVersion"
|
||||
testImplementation "com.nhaarman:mockito-kotlin:$mockitoKotlinVersion" // so that Mockito.any() doesn't return null which null-safe Kotlin parameter don't like
|
||||
// for how to enable mocking final class (which is standard in Kotlin) with Mockito see https://github.com/mockito/mockito/wiki/What's-new-in-Mockito-2#mock-the-unmockable-opt-in-mocking-of-final-classesmethods
|
||||
|
||||
testImplementation "ch.qos.logback:logback-classic:$logbackVersion"
|
||||
|
||||
testImplementation("net.dankito.utils:java-fx-utils:$javaFxUtilsVersion") {
|
||||
exclude group: "org.controlsfx"
|
||||
kotlin {
|
||||
jvm("jvm6") {
|
||||
compilations.main.kotlinOptions {
|
||||
jvmTarget = "1.6"
|
||||
}
|
||||
}
|
||||
|
||||
android()
|
||||
|
||||
|
||||
sourceSets {
|
||||
commonMain {
|
||||
dependencies {
|
||||
implementation kotlin("stdlib-common")
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core-common:$kotlinCoroutinesVersion"
|
||||
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime-common:$serializationVersion"
|
||||
|
||||
implementation "io.ktor:ktor-client-core:$ktorVersion"
|
||||
//
|
||||
// implementation("io.ktor:ktor-client-serialization:$ktor_version")
|
||||
|
||||
api "com.soywiz.korlibs.klock:klock:$klockVersion"
|
||||
|
||||
api("com.ionspin.kotlin:bignum:$bigNumVersion")
|
||||
|
||||
implementation "com.benasher44:uuid:$uuidVersion"
|
||||
}
|
||||
}
|
||||
|
||||
commonTest {
|
||||
dependencies {
|
||||
implementation kotlin("test-common")
|
||||
implementation kotlin("test-annotations-common")
|
||||
|
||||
|
||||
implementation project(":BankingUiCommon")
|
||||
implementation project(":BankFinder")
|
||||
implementation project(":fints4kBankingClient")
|
||||
|
||||
implementation "ch.tutteli.atrium:atrium-fluent-en_GB:$atriumVersion"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
jvm6Main {
|
||||
dependencies {
|
||||
// implementation "io.ktor:ktor-client-cio:$ktorVersion"
|
||||
implementation "io.ktor:ktor-client-okhttp:$ktorVersion"
|
||||
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime:$serializationVersion"
|
||||
|
||||
api "com.soywiz.korlibs.klock:klock-jvm:$klockVersion"
|
||||
|
||||
implementation "org.slf4j:slf4j-api:$slf4jVersion"
|
||||
}
|
||||
}
|
||||
|
||||
jvm6Test {
|
||||
dependencies {
|
||||
implementation kotlin("test-junit")
|
||||
|
||||
implementation "org.junit.jupiter:junit-jupiter:$junit5Version"
|
||||
runtimeOnly "org.junit.jupiter:junit-jupiter-engine:$junit5Version"
|
||||
|
||||
implementation "org.assertj:assertj-core:$assertJVersion"
|
||||
implementation "org.mockito:mockito-core:$mockitoVersion"
|
||||
|
||||
|
||||
implementation "org.apache.commons:commons-csv:1.8"
|
||||
|
||||
implementation "org.slf4j:slf4j-simple:$slf4jVersion"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
androidMain {
|
||||
dependsOn jvm6Main
|
||||
|
||||
dependencies {
|
||||
implementation "io.ktor:ktor-client-android:$ktorVersion"
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
testImplementation "org.apache.commons:commons-csv:1.8"
|
||||
}
|
|
@ -1,5 +1,8 @@
|
|||
package net.dankito.banking.fints
|
||||
|
||||
import com.soywiz.klock.DateTime
|
||||
import com.soywiz.klock.DateTimeSpan
|
||||
import com.soywiz.klock.DateTimeTz
|
||||
import net.dankito.banking.fints.callback.FinTsClientCallback
|
||||
import net.dankito.banking.fints.messages.MessageBuilder
|
||||
import net.dankito.banking.fints.messages.MessageBuilderResult
|
||||
|
@ -25,43 +28,37 @@ import net.dankito.banking.fints.tan.TanImageDecoder
|
|||
import net.dankito.banking.fints.transactions.IAccountTransactionsParser
|
||||
import net.dankito.banking.fints.transactions.Mt940AccountTransactionsParser
|
||||
import net.dankito.banking.fints.util.IBase64Service
|
||||
import net.dankito.utils.IThreadPool
|
||||
import net.dankito.utils.ThreadPool
|
||||
import net.dankito.utils.web.client.IWebClient
|
||||
import net.dankito.utils.web.client.OkHttpWebClient
|
||||
import net.dankito.utils.web.client.RequestParameters
|
||||
import net.dankito.utils.web.client.WebClientResponse
|
||||
import org.slf4j.LoggerFactory
|
||||
import java.math.BigDecimal
|
||||
import java.util.*
|
||||
import java.util.concurrent.CopyOnWriteArrayList
|
||||
import net.dankito.banking.fints.util.IThreadPool
|
||||
import net.dankito.banking.fints.util.PureKotlinBase64Service
|
||||
import net.dankito.banking.fints.util.log.LoggerFactory
|
||||
import net.dankito.banking.fints.webclient.IWebClient
|
||||
import net.dankito.banking.fints.webclient.KtorWebClient
|
||||
import net.dankito.banking.fints.webclient.WebClientResponse
|
||||
|
||||
|
||||
open class FinTsClient @JvmOverloads constructor(
|
||||
open class FinTsClient(
|
||||
protected val callback: FinTsClientCallback,
|
||||
protected val base64Service: IBase64Service,
|
||||
protected val webClient: IWebClient = OkHttpWebClient(),
|
||||
protected val webClient: IWebClient = KtorWebClient(),
|
||||
protected val base64Service: IBase64Service = PureKotlinBase64Service(),
|
||||
protected val threadPool: IThreadPool,
|
||||
protected val messageBuilder: MessageBuilder = MessageBuilder(),
|
||||
protected val responseParser: ResponseParser = ResponseParser(),
|
||||
protected val mt940Parser: IAccountTransactionsParser = Mt940AccountTransactionsParser(),
|
||||
protected val threadPool: IThreadPool = ThreadPool(),
|
||||
protected val product: ProductData = ProductData("15E53C26816138699C7B6A3E8", "1.0.0") // TODO: get version dynamically
|
||||
) {
|
||||
|
||||
companion object {
|
||||
const val NinetyDaysAgoMilliseconds = 90 * 24 * 60 * 60 * 1000L
|
||||
|
||||
val FindAccountTransactionsStartRegex = Regex("^HIKAZ:\\d:\\d:\\d\\+@\\d+@", RegexOption.MULTILINE)
|
||||
val FindAccountTransactionsEndRegex = Regex("^-'", RegexOption.MULTILINE)
|
||||
|
||||
|
||||
private val log = LoggerFactory.getLogger(FinTsClient::class.java)
|
||||
private val log = LoggerFactory.getLogger(FinTsClient::class)
|
||||
}
|
||||
|
||||
|
||||
open var areWeThatGentleToCloseDialogs: Boolean = true
|
||||
|
||||
protected val messageLogField = CopyOnWriteArrayList<MessageLogEntry>()
|
||||
protected val messageLogField = ArrayList<MessageLogEntry>() // TODO: make thread safe like with CopyOnWriteArrayList
|
||||
|
||||
// in either case remove sensitive data after response is parsed as otherwise some information like account holder name and accounts may is not set yet on CustomerData
|
||||
open val messageLogWithoutSensitiveData: List<MessageLogEntry>
|
||||
|
@ -215,7 +212,7 @@ open class FinTsClient @JvmOverloads constructor(
|
|||
|
||||
// also check if retrieving account transactions of last 90 days without tan is supported (and thereby may retrieve first account transactions)
|
||||
val transactionsOfLast90DaysResponses = mutableListOf<GetTransactionsResponse>()
|
||||
val balances = mutableMapOf<AccountData, BigDecimal>()
|
||||
val balances = mutableMapOf<AccountData, Money>()
|
||||
customer.accounts.forEach { account ->
|
||||
if (account.supportsFeature(AccountFeature.RetrieveAccountTransactions)) {
|
||||
val response = tryGetTransactionsOfLast90DaysWithoutTan(bank, customer, account, false)
|
||||
|
@ -252,10 +249,10 @@ open class FinTsClient @JvmOverloads constructor(
|
|||
protected open fun tryGetTransactionsOfLast90DaysWithoutTan(bank: BankData, customer: CustomerData, account: AccountData,
|
||||
hasRetrievedTransactionsWithTanJustBefore: Boolean): GetTransactionsResponse {
|
||||
|
||||
val now = Date()
|
||||
val ninetyDaysAgo = Date(now.time - NinetyDaysAgoMilliseconds - now.timezoneOffset * 60 * 1000) // map to UTC
|
||||
val now = DateTimeTz.nowLocal()
|
||||
val ninetyDaysAgo = now.minus(DateTimeSpan(days = 90))
|
||||
|
||||
val response = getTransactions(GetTransactionsParameter(account.supportsFeature(AccountFeature.RetrieveBalance), ninetyDaysAgo, abortIfTanIsRequired = true), bank, customer, account)
|
||||
val response = getTransactions(GetTransactionsParameter(account.supportsFeature(AccountFeature.RetrieveBalance), ninetyDaysAgo.local.date, abortIfTanIsRequired = true), bank, customer, account)
|
||||
|
||||
|
||||
account.triedToRetrieveTransactionsOfLast90DaysWithoutTan = true
|
||||
|
@ -290,7 +287,7 @@ open class FinTsClient @JvmOverloads constructor(
|
|||
}
|
||||
|
||||
|
||||
var balance: BigDecimal? = null
|
||||
var balance: Money? = null
|
||||
|
||||
if (parameter.alsoRetrieveBalance && account.supportsFeature(AccountFeature.RetrieveBalance)) {
|
||||
val balanceResponse = getBalanceAfterDialogInit(account, dialogContext)
|
||||
|
@ -301,7 +298,7 @@ open class FinTsClient @JvmOverloads constructor(
|
|||
}
|
||||
|
||||
balanceResponse.getFirstSegmentById<BalanceSegment>(InstituteSegmentId.Balance)?.let {
|
||||
balance = it.balance
|
||||
balance = Money(it.balance, it.currency)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -576,9 +573,7 @@ open class FinTsClient @JvmOverloads constructor(
|
|||
protected open fun getResponseForMessage(requestBody: String, finTs3ServerAddress: String): WebClientResponse {
|
||||
val encodedRequestBody = base64Service.encode(requestBody)
|
||||
|
||||
return webClient.post(
|
||||
RequestParameters(finTs3ServerAddress, encodedRequestBody, "application/octet-stream")
|
||||
)
|
||||
return webClient.post(finTs3ServerAddress, encodedRequestBody, "application/octet-stream")
|
||||
}
|
||||
|
||||
protected open fun fireAndForgetMessage(message: MessageBuilderResult, dialogContext: DialogContext) {
|
||||
|
@ -594,7 +589,7 @@ open class FinTsClient @JvmOverloads constructor(
|
|||
protected open fun handleResponse(webResponse: WebClientResponse, dialogContext: DialogContext): Response {
|
||||
val responseBody = webResponse.body
|
||||
|
||||
if (webResponse.isSuccessful && responseBody != null) {
|
||||
if (webResponse.successful && responseBody != null) {
|
||||
|
||||
try {
|
||||
val decodedResponse = decodeBase64Response(responseBody)
|
||||
|
@ -603,14 +598,14 @@ open class FinTsClient @JvmOverloads constructor(
|
|||
|
||||
return responseParser.parse(decodedResponse)
|
||||
} catch (e: Exception) {
|
||||
log.error("Could not decode responseBody:\r\n'$responseBody'", e)
|
||||
log.error(e) { "Could not decode responseBody:\r\n'$responseBody'" }
|
||||
|
||||
return Response(false, exception = e)
|
||||
}
|
||||
}
|
||||
else {
|
||||
val bank = dialogContext.bank
|
||||
log.error("Request to $bank (${bank.finTs3ServerAddress}) failed", webResponse.error)
|
||||
log.error { "Request to $bank (${bank.finTs3ServerAddress}) failed" } // TODO: add webResponse.error
|
||||
}
|
||||
|
||||
return Response(false, exception = webResponse.error)
|
||||
|
@ -633,14 +628,12 @@ open class FinTsClient @JvmOverloads constructor(
|
|||
|
||||
|
||||
protected open fun addMessageLog(message: String, type: MessageLogEntryType, dialogContext: DialogContext) {
|
||||
val timeStamp = Date()
|
||||
val timeStamp = DateTime.now()
|
||||
val messagePrefix = "${if (type == MessageLogEntryType.Sent) "Sending" else "Received"} message:\r\n" // currently no need to translate
|
||||
val prettyPrintMessage = prettyPrintHbciMessage(message)
|
||||
val prettyPrintMessageWithPrefix = "$messagePrefix$prettyPrintMessage"
|
||||
|
||||
if (log.isDebugEnabled) {
|
||||
log.debug(prettyPrintMessageWithPrefix)
|
||||
}
|
||||
log.debug { prettyPrintMessageWithPrefix }
|
||||
|
||||
messageLogField.add(MessageLogEntry(prettyPrintMessageWithPrefix, timeStamp, dialogContext.customer))
|
||||
}
|
|
@ -10,26 +10,26 @@ import net.dankito.banking.fints.response.client.GetTransactionsResponse
|
|||
import net.dankito.banking.fints.transactions.IAccountTransactionsParser
|
||||
import net.dankito.banking.fints.transactions.Mt940AccountTransactionsParser
|
||||
import net.dankito.banking.fints.util.IBase64Service
|
||||
import net.dankito.utils.IThreadPool
|
||||
import net.dankito.utils.ThreadPool
|
||||
import net.dankito.utils.web.client.IWebClient
|
||||
import net.dankito.utils.web.client.OkHttpWebClient
|
||||
import net.dankito.banking.fints.util.IThreadPool
|
||||
import net.dankito.banking.fints.util.PureKotlinBase64Service
|
||||
import net.dankito.banking.fints.webclient.IWebClient
|
||||
import net.dankito.banking.fints.webclient.KtorWebClient
|
||||
|
||||
|
||||
open class FinTsClientForCustomer @JvmOverloads constructor(
|
||||
open class FinTsClientForCustomer(
|
||||
val bank: BankData,
|
||||
val customer: CustomerData,
|
||||
webClient: IWebClient = OkHttpWebClient(),
|
||||
base64Service: IBase64Service,
|
||||
threadPool: IThreadPool = ThreadPool(),
|
||||
callback: FinTsClientCallback,
|
||||
webClient: IWebClient = KtorWebClient(),
|
||||
base64Service: IBase64Service = PureKotlinBase64Service(),
|
||||
threadPool: IThreadPool,
|
||||
messageBuilder: MessageBuilder = MessageBuilder(),
|
||||
responseParser: ResponseParser = ResponseParser(),
|
||||
mt940Parser: IAccountTransactionsParser = Mt940AccountTransactionsParser(),
|
||||
product: ProductData = ProductData("15E53C26816138699C7B6A3E8", "1.0.0") // TODO: get version dynamically
|
||||
) {
|
||||
|
||||
protected val client = FinTsClient(callback, base64Service, webClient, messageBuilder, responseParser, mt940Parser, threadPool, product)
|
||||
protected val client = FinTsClient(callback, webClient, base64Service, threadPool, messageBuilder, responseParser, mt940Parser, product)
|
||||
|
||||
|
||||
open val messageLogWithoutSensitiveData: List<MessageLogEntry>
|
|
@ -1,5 +1,7 @@
|
|||
package net.dankito.banking.fints.messages
|
||||
|
||||
import io.ktor.utils.io.charsets.Charsets
|
||||
|
||||
|
||||
/**
|
||||
* Der HBCI-Basiszeichensatz baut auf dem international normierten Zeichensatz ISO 8859 auf.
|
|
@ -1,5 +1,6 @@
|
|||
package net.dankito.banking.fints.messages
|
||||
|
||||
import com.soywiz.klock.DateTime
|
||||
import net.dankito.banking.fints.messages.datenelemente.implementierte.Aufsetzpunkt
|
||||
import net.dankito.banking.fints.messages.datenelemente.implementierte.KundensystemID
|
||||
import net.dankito.banking.fints.messages.datenelemente.implementierte.Synchronisierungsmodus
|
||||
|
@ -22,7 +23,7 @@ import net.dankito.banking.fints.response.segments.JobParameters
|
|||
import net.dankito.banking.fints.response.segments.SepaAccountInfoParameters
|
||||
import net.dankito.banking.fints.response.segments.TanResponse
|
||||
import net.dankito.banking.fints.util.FinTsUtils
|
||||
import net.dankito.utils.extensions.containsAny
|
||||
import kotlin.math.absoluteValue
|
||||
import kotlin.random.Random
|
||||
|
||||
|
||||
|
@ -356,7 +357,7 @@ open class MessageBuilder(protected val generator: ISegmentNumberGenerator = Seg
|
|||
}
|
||||
|
||||
protected open fun createControlReference(): String {
|
||||
return Math.abs(Random(System.nanoTime()).nextInt()).toString()
|
||||
return Random(DateTime.nowUnixLong()).nextInt().absoluteValue.toString()
|
||||
}
|
||||
|
||||
|
||||
|
@ -442,4 +443,16 @@ open class MessageBuilder(protected val generator: ISegmentNumberGenerator = Seg
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
// TODO: move to a library
|
||||
fun <T> Collection<T>.containsAny(otherCollection: Collection<T>): Boolean {
|
||||
for (otherItem in otherCollection) {
|
||||
if (this.contains(otherItem)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
}
|
|
@ -1,9 +1,10 @@
|
|||
package net.dankito.banking.fints.messages.datenelemente.abgeleiteteformate
|
||||
|
||||
import com.soywiz.klock.Date
|
||||
import com.soywiz.klock.DateFormat
|
||||
import com.soywiz.klock.parse
|
||||
import net.dankito.banking.fints.messages.Existenzstatus
|
||||
import net.dankito.banking.fints.messages.datenelemente.basisformate.NumerischesDatenelement
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
|
||||
/**
|
||||
|
@ -16,11 +17,20 @@ open class Datum(date: Int?, existenzstatus: Existenzstatus) : NumerischesDatene
|
|||
companion object {
|
||||
const val HbciDateFormatString = "yyyyMMdd"
|
||||
|
||||
val HbciDateFormat = SimpleDateFormat(HbciDateFormatString)
|
||||
val HbciDateFormat = DateFormat(HbciDateFormatString)
|
||||
|
||||
|
||||
fun format(date: Date): String {
|
||||
return HbciDateFormat.format(date.dateTimeDayStart.localUnadjusted) // TODO: is this correct?
|
||||
}
|
||||
|
||||
fun parse(dateString: String): Date {
|
||||
return HbciDateFormat.parse(dateString).utc.date // TODO: really use UTC?
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
constructor(date: Date?, existenzstatus: Existenzstatus)
|
||||
: this(date?.let { HbciDateFormat.format(it).toInt() }, existenzstatus)
|
||||
: this(date?.let { format(it).toInt() }, existenzstatus)
|
||||
|
||||
}
|
|
@ -1,9 +1,8 @@
|
|||
package net.dankito.banking.fints.messages.datenelemente.abgeleiteteformate
|
||||
|
||||
import com.soywiz.klock.*
|
||||
import net.dankito.banking.fints.messages.Existenzstatus
|
||||
import net.dankito.banking.fints.messages.datenelemente.basisformate.ZiffernDatenelement
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
|
||||
/**
|
||||
|
@ -17,11 +16,20 @@ open class Uhrzeit(time: Int?, existenzstatus: Existenzstatus) : ZiffernDatenele
|
|||
companion object {
|
||||
const val HbciTimeFormatString = "HHmmss"
|
||||
|
||||
val HbciTimeFormat = SimpleDateFormat(HbciTimeFormatString)
|
||||
val HbciTimeFormat = DateFormat(HbciTimeFormatString)
|
||||
|
||||
|
||||
fun format(time: Time): String {
|
||||
return HbciTimeFormat.format(DateTimeTz.Companion.fromUnixLocal(time.encoded.milliseconds)) // TODO: is this correct?
|
||||
}
|
||||
|
||||
fun parse(dateString: String): Time {
|
||||
return HbciTimeFormat.parse(dateString).utc.time // TODO: is this correct?
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
constructor(time: Date?, existenzstatus: Existenzstatus)
|
||||
: this(time?.let { HbciTimeFormat.format(it).toInt() }, existenzstatus)
|
||||
constructor(time: Time?, existenzstatus: Existenzstatus)
|
||||
: this(time?.let { format(time).toInt() }, existenzstatus)
|
||||
|
||||
}
|
|
@ -1,5 +1,7 @@
|
|||
package net.dankito.banking.fints.messages.datenelemente.basisformate
|
||||
|
||||
import io.ktor.utils.io.charsets.encode
|
||||
import io.ktor.utils.io.charsets.name
|
||||
import net.dankito.banking.fints.messages.Existenzstatus
|
||||
import net.dankito.banking.fints.messages.HbciCharset
|
||||
import net.dankito.banking.fints.messages.Separators
|
||||
|
@ -35,8 +37,10 @@ abstract class TextDatenelement(var value: String?, existenzstatus: Existenzstat
|
|||
checkIfMandatoryValueIsSet()
|
||||
|
||||
try {
|
||||
if (HbciCharset.DefaultCharset.newEncoder().canEncode(value) == false) {
|
||||
throwInvalidCharacterException()
|
||||
value?.let { // at this time value is != null otherwise checkIfMandatoryValueIsSet() would fail
|
||||
if (HbciCharset.DefaultCharset.newEncoder().encode(it).canRead() == false) {
|
||||
throwInvalidCharacterException()
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
throwInvalidCharacterException()
|
||||
|
@ -46,14 +50,14 @@ abstract class TextDatenelement(var value: String?, existenzstatus: Existenzstat
|
|||
|
||||
protected open fun checkIfMandatoryValueIsSet() {
|
||||
if (existenzstatus == Existenzstatus.Mandatory && value == null) {
|
||||
throwValidationException("Wert ist auf dem Pflichtfeld ${javaClass.simpleName} not set")
|
||||
throwValidationException("Wert ist auf dem Pflichtfeld ${this::class.simpleName} not set")
|
||||
}
|
||||
}
|
||||
|
||||
protected open fun throwInvalidCharacterException() {
|
||||
throwValidationException(
|
||||
"Wert '$value' enthält Zeichen die gemäß des Zeichensatzes " +
|
||||
"${HbciCharset.DefaultCharset.displayName()} nicht erlaubt sind."
|
||||
"${HbciCharset.DefaultCharset.name} nicht erlaubt sind."
|
||||
)
|
||||
}
|
||||
|
|
@ -3,14 +3,15 @@ package net.dankito.banking.fints.messages.datenelemente.implementierte.sepa
|
|||
import net.dankito.banking.fints.messages.Existenzstatus
|
||||
import net.dankito.banking.fints.messages.datenelemente.basisformate.BinaerDatenelement
|
||||
import net.dankito.banking.fints.messages.segmente.implementierte.sepa.ISepaMessageCreator
|
||||
import net.dankito.banking.fints.messages.segmente.implementierte.sepa.PaymentInformationMessages
|
||||
|
||||
|
||||
open class SepaMessage(
|
||||
filename: String,
|
||||
messageTemplate: PaymentInformationMessages,
|
||||
replacementStrings: Map<String, String>,
|
||||
messageCreator: ISepaMessageCreator
|
||||
)
|
||||
: BinaerDatenelement(messageCreator.createXmlFile(filename, replacementStrings), Existenzstatus.Mandatory) {
|
||||
: BinaerDatenelement(messageCreator.createXmlFile(messageTemplate, replacementStrings), Existenzstatus.Mandatory) {
|
||||
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue