Compare commits
126 commits
v1.0.0-Alp
...
main
Author | SHA1 | Date | |
---|---|---|---|
bf17bde9f5 | |||
9f3e4eff4d | |||
f89de94aa7 | |||
684b3fb40e | |||
df692ea222 | |||
636963b3d4 | |||
4802493886 | |||
ecf930fcad | |||
ce3b1d32d7 | |||
c39789dfde | |||
ab0b676216 | |||
20fe60d9f6 | |||
529caeaa87 | |||
3d6c68e743 | |||
7cdb7247c8 | |||
d7d2702869 | |||
67b58117e1 | |||
66801a1c7a | |||
2410504ede | |||
2a3b962af5 | |||
8346fb5077 | |||
8dc2174081 | |||
05322aface | |||
dcbbe043f0 | |||
65d983a5e7 | |||
9aad2a5101 | |||
be3a2df6d9 | |||
dea8be3bfa | |||
cba2f25335 | |||
825217ef88 | |||
b3cb76e77d | |||
b0c2f38bd6 | |||
fca1542b5c | |||
07672d1189 | |||
62aa04a667 | |||
3aa0edfb34 | |||
e4d605531e | |||
a42de32260 | |||
95e60b2706 | |||
fd9eadf45e | |||
7ddeb88475 | |||
90a7543641 | |||
d1de7f5eb0 | |||
ef8045fa96 | |||
2031cb9e9f | |||
e260eaa535 | |||
891641fc6f | |||
c158097d3a | |||
6908f52e48 | |||
61d8f2c342 | |||
6bf7fdcb44 | |||
fbafbb62e3 | |||
9372d17313 | |||
9b1a5fa929 | |||
42bf002626 | |||
20f06387c5 | |||
75320da2be | |||
be2908517f | |||
c4f504dd0a | |||
0848586894 | |||
83c2882567 | |||
f069f9155c | |||
bf5ee4890e | |||
ed4214fd49 | |||
b8fe9e78e1 | |||
da2bf8d469 | |||
113b817627 | |||
bd18644c0d | |||
b32cf94e25 | |||
8cc2f3bdcd | |||
59b8213163 | |||
cb34c86665 | |||
70c1082531 | |||
30e9a57b96 | |||
bf76de4f23 | |||
47e2b851b9 | |||
f90e280b74 | |||
9600e2f11b | |||
b2fb04372f | |||
3b05a8b9c8 | |||
d689c7663f | |||
6238b5abb2 | |||
1f8c1d303e | |||
09c2080481 | |||
e36c27c0e0 | |||
6865f64880 | |||
3f9921a62e | |||
504fbaf13b | |||
fb70bcd443 | |||
952fa9c13a | |||
b47fcabc1c | |||
878d32ea16 | |||
5f7b07a601 | |||
7e8d005fcb | |||
21215300b3 | |||
b826ee3c8f | |||
32defa20f7 | |||
c5432883ef | |||
dae6084ebb | |||
c564750832 | |||
d16289d824 | |||
a2ac04f424 | |||
8247584a61 | |||
34e40aeee1 | |||
5d7ea48a46 | |||
d055b61ed9 | |||
87c59e63ee | |||
40b916a49f | |||
eabe2c4930 | |||
0f151a8f4f | |||
33a86607df | |||
f154e60e1e | |||
7e5a455c24 | |||
d8b0c89be7 | |||
3d385b5bdf | |||
4f3924f2cd | |||
c0796cfc38 | |||
9857a0565d | |||
a3dbe8f142 | |||
88f6d53ccb | |||
850beb8421 | |||
da50b72898 | |||
237802b18d | |||
88c64f1ff1 | |||
5e7d880499 | |||
199506547b |
419 changed files with 6410 additions and 2998 deletions
24
README.md
24
README.md
|
@ -4,35 +4,49 @@ fints4k is an implementation of the FinTS 3.0 online banking protocol used by mo
|
|||
|
||||
It's fast, easy extendable and running on multiple platforms: JVM, Android, (iOS, JavaScript, Windows, MacOS, Linux).
|
||||
|
||||
However it's not a full implementation of FinTS standard but implements all common use cases:
|
||||
|
||||
## Features
|
||||
- Retrieving account information, balances and turnovers (Kontoumsätze und -saldo).
|
||||
- Transfer money and real-time transfers (SEPA Überweisungen und Echtzeitüberweisung).
|
||||
- Supports TAN methods chipTAN manual, Flickercode, QrCode and Photo (Matrix code), pushTAN, smsTAN and appTAN.
|
||||
|
||||
However, this is quite a low level implementation and in most cases not what you want to use.
|
||||
In most cases you want to use a higher level abstraction like [FinTs4kBankingClient](https://git.dankito.net/codinux/BankingClient).
|
||||
|
||||
## Setup
|
||||
Not uploaded to Maven Central yet, will do this the next few days!
|
||||
|
||||
Gradle:
|
||||
```
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven {
|
||||
setUrl("https://maven.dankito.net/api/packages/codinux/maven")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
dependencies {
|
||||
compile 'net.dankito.banking:fints4k:0.1.0'
|
||||
implementation("net.codinux.banking:fints4k:1.0.0-Alpha-13")
|
||||
}
|
||||
```
|
||||
|
||||
Maven:
|
||||
```
|
||||
|
||||
// add Repository https://maven.dankito.net/api/packages/codinux/maven
|
||||
|
||||
<dependency>
|
||||
<groupId>net.dankito.banking</groupId>
|
||||
<artifactId>fints4k</artifactId>
|
||||
<version>0.1.0</version>
|
||||
<artifactId>fints4k-jvm</artifactId>
|
||||
<version>1.0.0-Alpha-11</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
Quite outdated, have to update it. In most cases use [FinTs4kBankingClient](https://git.dankito.net/codinux/BankingClient).
|
||||
|
||||
See e.g. [JavaShowcase](fints4k/src/test/java/net/dankito/banking/fints/JavaShowcase.java) or [FinTsClientTest](fints4k/src/test/kotlin/net/dankito/banking/fints/FinTsClientTest.kt).
|
||||
|
||||
```java
|
||||
|
|
|
@ -7,9 +7,9 @@ import kotlinx.coroutines.withContext
|
|||
import kotlinx.datetime.LocalDate
|
||||
import net.dankito.banking.client.model.parameter.GetAccountDataParameter
|
||||
import net.dankito.banking.client.model.response.GetAccountDataResponse
|
||||
import net.dankito.banking.fints.FinTsClient
|
||||
import net.dankito.banking.fints.callback.SimpleFinTsClientCallback
|
||||
import net.dankito.banking.fints.model.TanChallenge
|
||||
import net.codinux.banking.fints.FinTsClient
|
||||
import net.codinux.banking.fints.callback.SimpleFinTsClientCallback
|
||||
import net.codinux.banking.fints.model.TanChallenge
|
||||
import net.dankito.utils.multiplatform.extensions.millisSinceEpochAtSystemDefaultTimeZone
|
||||
import org.slf4j.LoggerFactory
|
||||
import java.math.BigDecimal
|
||||
|
|
|
@ -5,7 +5,7 @@ import net.codinux.banking.fints4k.android.Presenter
|
|||
import net.codinux.banking.fints4k.android.R
|
||||
import net.codinux.banking.fints4k.android.adapter.viewholder.AccountTransactionsViewHolder
|
||||
import net.dankito.banking.client.model.AccountTransaction
|
||||
import net.dankito.banking.fints.util.toBigDecimal
|
||||
import net.codinux.banking.fints.util.toBigDecimal
|
||||
import net.dankito.utils.android.extensions.setTextColorToColorResource
|
||||
import net.dankito.utils.android.ui.adapter.ListRecyclerAdapter
|
||||
import org.slf4j.LoggerFactory
|
||||
|
|
|
@ -15,9 +15,9 @@ import androidx.fragment.app.DialogFragment
|
|||
import androidx.fragment.app.FragmentActivity
|
||||
import net.codinux.banking.fints4k.android.Presenter
|
||||
import net.codinux.banking.fints4k.android.R
|
||||
import net.dankito.banking.fints.model.FlickerCodeTanChallenge
|
||||
import net.dankito.banking.fints.model.ImageTanChallenge
|
||||
import net.dankito.banking.fints.model.TanChallenge
|
||||
import net.codinux.banking.fints.model.FlickerCodeTanChallenge
|
||||
import net.codinux.banking.fints.model.ImageTanChallenge
|
||||
import net.codinux.banking.fints.model.TanChallenge
|
||||
import net.dankito.utils.android.extensions.getSpannedFromHtml
|
||||
import net.dankito.utils.android.extensions.show
|
||||
|
||||
|
|
|
@ -13,12 +13,12 @@ import net.dankito.banking.client.model.CustomerAccount
|
|||
import net.dankito.banking.client.model.parameter.GetAccountDataParameter
|
||||
import net.dankito.banking.client.model.parameter.RetrieveTransactions
|
||||
import net.dankito.banking.client.model.parameter.TransferMoneyParameter
|
||||
import net.dankito.banking.fints.FinTsClient
|
||||
import net.dankito.banking.fints.callback.SimpleFinTsClientCallback
|
||||
import net.dankito.banking.fints.extensions.toStringWithMinDigits
|
||||
import net.dankito.banking.fints.getAccountData
|
||||
import net.dankito.banking.fints.model.TanChallenge
|
||||
import net.dankito.banking.fints.transferMoney
|
||||
import net.codinux.banking.fints.FinTsClient
|
||||
import net.codinux.banking.fints.callback.SimpleFinTsClientCallback
|
||||
import net.codinux.banking.fints.extensions.toStringWithMinDigits
|
||||
import net.codinux.banking.fints.getAccountData
|
||||
import net.codinux.banking.fints.model.TanChallenge
|
||||
import net.codinux.banking.fints.transferMoney
|
||||
import util.CsvWriter
|
||||
import util.OutputFormat
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package commands
|
||||
|
||||
import NativeApp
|
||||
import net.dankito.banking.fints.model.TanMethodType
|
||||
import net.codinux.banking.fints.model.TanMethodType
|
||||
|
||||
|
||||
data class CommonConfig(
|
||||
|
|
|
@ -5,10 +5,10 @@ import com.github.ajalt.clikt.core.requireObject
|
|||
import com.github.ajalt.clikt.parameters.arguments.argument
|
||||
import com.github.ajalt.clikt.parameters.options.option
|
||||
import net.dankito.banking.client.model.parameter.TransferMoneyParameter
|
||||
import net.dankito.banking.fints.model.AccountData
|
||||
import net.dankito.banking.fints.model.Amount
|
||||
import net.dankito.banking.fints.model.Currency
|
||||
import net.dankito.banking.fints.model.Money
|
||||
import net.codinux.banking.fints.model.AccountData
|
||||
import net.codinux.banking.fints.model.Amount
|
||||
import net.codinux.banking.fints.model.Currency
|
||||
import net.codinux.banking.fints.model.Money
|
||||
|
||||
|
||||
class TransferMoneyCommand : CliktCommand("Transfers money from your account to a recipient", name = "transfer", printHelpOnEmptyArgs = true) {
|
||||
|
|
|
@ -12,8 +12,8 @@ import kotlinx.datetime.LocalDate
|
|||
import kotlinx.datetime.minus
|
||||
import net.dankito.banking.client.model.parameter.GetAccountDataParameter
|
||||
import net.dankito.banking.client.model.parameter.RetrieveTransactions
|
||||
import net.dankito.banking.fints.model.TanMethodType
|
||||
import net.dankito.banking.fints.extensions.todayAtEuropeBerlin
|
||||
import net.codinux.banking.fints.model.TanMethodType
|
||||
import net.codinux.banking.fints.extensions.todayAtEuropeBerlin
|
||||
import util.OutputFormat
|
||||
|
||||
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
package net.dankito.banking.fints
|
||||
package net.codinux.banking.fints
|
||||
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import net.dankito.banking.client.model.parameter.GetAccountDataParameter
|
||||
import net.dankito.banking.client.model.parameter.TransferMoneyParameter
|
||||
import net.dankito.banking.client.model.response.GetAccountDataResponse
|
||||
import net.dankito.banking.client.model.response.TransferMoneyResponse
|
||||
import net.dankito.banking.fints.model.Money
|
||||
import net.codinux.banking.fints.model.Money
|
||||
|
||||
|
||||
fun FinTsClient.getAccountData(bankCode: String, loginName: String, password: String): GetAccountDataResponse {
|
|
@ -41,8 +41,8 @@ open class CsvWriter {
|
|||
protected open suspend fun writeToFile(stream: AsyncStream, valueSeparator: String, customer: CustomerAccount, account: BankAccount, transaction: AccountTransaction) {
|
||||
val amount = if (valueSeparator == ";") transaction.amount.amount.string.replace('.', ',') else transaction.amount.amount.string.replace(',', '.')
|
||||
|
||||
stream.writeString(listOf(customer.bankName, account.identifier, transaction.valueDate, amount, transaction.amount.currency, ensureNotNull(transaction.bookingText), wrap(transaction.reference),
|
||||
ensureNotNull(transaction.otherPartyName), ensureNotNull(transaction.otherPartyBankCode), ensureNotNull(transaction.otherPartyAccountId)).joinToString(valueSeparator))
|
||||
stream.writeString(listOf(customer.bankName, account.identifier, transaction.valueDate, amount, transaction.amount.currency, ensureNotNull(transaction.postingText), wrap(transaction.reference ?: ""),
|
||||
ensureNotNull(transaction.otherPartyName), ensureNotNull(transaction.otherPartyBankId), ensureNotNull(transaction.otherPartyAccountId)).joinToString(valueSeparator))
|
||||
|
||||
stream.writeString(NewLine)
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import net.dankito.banking.client.model.AccountTransaction
|
||||
import net.dankito.banking.fints.model.TanChallenge
|
||||
import net.codinux.banking.fints.model.TanChallenge
|
||||
import react.*
|
||||
import react.dom.*
|
||||
import styled.styledDiv
|
||||
|
|
|
@ -2,8 +2,8 @@ import io.ktor.util.encodeBase64
|
|||
import kotlinx.html.InputType
|
||||
import kotlinx.html.js.onChangeFunction
|
||||
import kotlinx.html.style
|
||||
import net.dankito.banking.fints.model.ImageTanChallenge
|
||||
import net.dankito.banking.fints.model.TanChallenge
|
||||
import net.codinux.banking.fints.model.ImageTanChallenge
|
||||
import net.codinux.banking.fints.model.TanChallenge
|
||||
import org.w3c.dom.HTMLInputElement
|
||||
import react.Props
|
||||
import react.RBuilder
|
||||
|
|
|
@ -6,11 +6,11 @@ import net.dankito.banking.client.model.parameter.GetAccountDataParameter
|
|||
import net.dankito.banking.client.model.parameter.TransferMoneyParameter
|
||||
import net.dankito.banking.client.model.response.GetAccountDataResponse
|
||||
import net.dankito.banking.client.model.response.TransferMoneyResponse
|
||||
import net.dankito.banking.fints.FinTsClient
|
||||
import net.dankito.banking.fints.callback.SimpleFinTsClientCallback
|
||||
import net.dankito.banking.fints.model.*
|
||||
import net.dankito.banking.fints.webclient.KtorWebClient
|
||||
import net.dankito.banking.fints.webclient.ProxyingWebClient
|
||||
import net.codinux.banking.fints.FinTsClient
|
||||
import net.codinux.banking.fints.callback.SimpleFinTsClientCallback
|
||||
import net.codinux.banking.fints.model.*
|
||||
import net.codinux.banking.fints.webclient.KtorWebClient
|
||||
import net.codinux.banking.fints.webclient.ProxyingWebClient
|
||||
import net.dankito.utils.multiplatform.log.LoggerFactory
|
||||
|
||||
open class Presenter {
|
||||
|
|
16
build.gradle
16
build.gradle
|
@ -1,16 +1,16 @@
|
|||
// TODO: move to versions.gradle
|
||||
ext {
|
||||
appVersionName = '1.0.0-Alpha-11'
|
||||
appVersionName = "1.0.0-Alpha-16-SNAPSHOT"
|
||||
|
||||
|
||||
/* Test */
|
||||
|
||||
assertJVersion = '3.12.2'
|
||||
assertJVersion = "3.12.2"
|
||||
|
||||
mockitoVersion = '2.22.0'
|
||||
mockitoKotlinVersion = '1.6.0'
|
||||
mockitoVersion = "2.22.0"
|
||||
mockitoKotlinVersion = "1.6.0"
|
||||
|
||||
logbackVersion = '1.2.3'
|
||||
logbackVersion = "1.2.3"
|
||||
}
|
||||
|
||||
buildscript {
|
||||
|
@ -48,4 +48,10 @@ task publishAllToMavenLocal {
|
|||
dependsOn = [
|
||||
"fints4k:publishToMavenLocal",
|
||||
]
|
||||
}
|
||||
|
||||
task publishAll {
|
||||
dependsOn = [
|
||||
"fints4k:publish",
|
||||
]
|
||||
}
|
26
docs/Vokabular.md
Normal file
26
docs/Vokabular.md
Normal file
|
@ -0,0 +1,26 @@
|
|||
| | |
|
||||
|--------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------|
|
||||
| Geschäftsvorfall | Business Transaction / Job |
|
||||
| Verwendungszweck | Remittance information, reference, (payment) purpose |
|
||||
| Überweisung | Remittance (techn.), money transfer, bank transfer, wire transfer (Amerik.), credit transfer |
|
||||
| Buchungsschlüssel | posting key |
|
||||
| Buchungstext | posting text |
|
||||
| | |
|
||||
| Ende-zu-Ende Referenz | End to End Reference |
|
||||
| Kundenreferenz | Reference of the submitting customer |
|
||||
| Mandatsreferenz | mandate reference |
|
||||
| Creditor Identifier | Creditor Identifier |
|
||||
| Originators Identification Code | Originators Identification Code |
|
||||
| Compensation Amount | Compensation Amount |
|
||||
| Original Amount | Original Amount |
|
||||
| Abweichender Überweisender (CT-AT08) / Abweichender Zahlungsempfänger (DD-AT38) | payer’s/debtor’s reference party (for credit transfer / payee’s / creditor’s reference party (for a direct debit) |
|
||||
| Abweichender Zahlungsempfänger (CT-AT28) / Abweichender Zahlungspflichtiger (DDAT15) | payee’s/creditor’s reference party / payer’s/debtor’s reference party |
|
||||
| | |
|
||||
| Überweisender | Payer, debtor |
|
||||
| Zahlungsempfänger | Payee, creditor |
|
||||
| Zahlungseingang | Payment receipt |
|
||||
| Lastschrift | direct debit |
|
||||
| | |
|
||||
| | |
|
||||
| Primanoten-Nr. | Journal no. |
|
||||
| | |
|
|
@ -8,11 +8,15 @@ plugins {
|
|||
|
||||
|
||||
kotlin {
|
||||
jvmToolchain(8)
|
||||
jvmToolchain(11)
|
||||
|
||||
compilerOptions {
|
||||
// suppresses compiler warning: [EXPECT_ACTUAL_CLASSIFIERS_ARE_IN_BETA_WARNING] 'expect'/'actual' classes (including interfaces, objects, annotations, enums, and 'actual' typealiases) are in Beta.
|
||||
freeCompilerArgs.add("-Xexpect-actual-classes")
|
||||
|
||||
if (System.getProperty("idea.debugger.dispatch.addr") != null) {
|
||||
freeCompilerArgs.add("-Xdebug")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -34,7 +38,7 @@ kotlin {
|
|||
browser {
|
||||
testTask {
|
||||
useKarma {
|
||||
// useChromeHeadless()
|
||||
useChromeHeadless()
|
||||
useFirefoxHeadless()
|
||||
}
|
||||
}
|
||||
|
@ -43,10 +47,13 @@ kotlin {
|
|||
nodejs()
|
||||
}
|
||||
|
||||
// wasmJs() // ktor is not available for wasmJs yet
|
||||
|
||||
|
||||
linuxX64()
|
||||
mingwX64()
|
||||
|
||||
iosX64()
|
||||
iosArm64()
|
||||
iosSimulatorArm64()
|
||||
macosX64()
|
||||
|
@ -69,8 +76,9 @@ kotlin {
|
|||
implementation("io.ktor:ktor-client-core:$ktorVersion")
|
||||
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-serialization-core:$kotlinxSerializationVersion")
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:$kotlinxSerializationVersion")
|
||||
|
||||
implementation("net.codinux.log:kmp-log:$klfVersion")
|
||||
implementation("net.codinux.log:klf:$klfVersion")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package net.dankito.banking.fints
|
||||
package net.codinux.banking.fints
|
||||
|
||||
import net.dankito.banking.client.model.parameter.FinTsClientParameter
|
||||
import net.dankito.banking.client.model.parameter.GetAccountDataParameter
|
||||
|
@ -6,15 +6,21 @@ import net.dankito.banking.client.model.parameter.TransferMoneyParameter
|
|||
import net.dankito.banking.client.model.response.ErrorCode
|
||||
import net.dankito.banking.client.model.response.GetAccountDataResponse
|
||||
import net.dankito.banking.client.model.response.TransferMoneyResponse
|
||||
import net.dankito.banking.fints.callback.FinTsClientCallback
|
||||
import net.dankito.banking.fints.config.FinTsClientConfiguration
|
||||
import net.dankito.banking.fints.mapper.FinTsModelMapper
|
||||
import net.dankito.banking.fints.model.*
|
||||
import net.dankito.banking.fints.response.client.FinTsClientResponse
|
||||
import net.dankito.banking.fints.response.client.GetAccountInfoResponse
|
||||
import net.dankito.banking.fints.response.client.GetAccountTransactionsResponse
|
||||
import net.dankito.banking.fints.response.segments.AccountType
|
||||
import net.dankito.banking.fints.util.BicFinder
|
||||
import net.codinux.banking.fints.callback.FinTsClientCallback
|
||||
import net.codinux.banking.fints.config.FinTsClientConfiguration
|
||||
import net.codinux.banking.fints.mapper.FinTsModelMapper
|
||||
import net.codinux.banking.fints.messages.datenelemente.implementierte.KundensystemID
|
||||
import net.codinux.banking.fints.model.*
|
||||
import net.codinux.banking.fints.response.client.FinTsClientResponse
|
||||
import net.codinux.banking.fints.response.client.GetAccountInfoResponse
|
||||
import net.codinux.banking.fints.response.client.GetAccountTransactionsResponse
|
||||
import net.codinux.banking.fints.response.segments.AccountType
|
||||
import net.codinux.banking.fints.response.segments.BankParameters
|
||||
import net.codinux.banking.fints.util.BicFinder
|
||||
import net.codinux.log.LogLevel
|
||||
import net.codinux.log.LoggerFactory
|
||||
import kotlin.js.JsName
|
||||
import kotlin.jvm.JvmName
|
||||
|
||||
|
||||
open class FinTsClient(
|
||||
|
@ -35,56 +41,59 @@ open class FinTsClient(
|
|||
protected open val bicFinder = BicFinder()
|
||||
|
||||
|
||||
init {
|
||||
LoggerFactory.getLogger("net.codinux.banking.fints.log.MessageLogCollector").level = if (config.options.appendFinTsMessagesToLog) {
|
||||
LogLevel.Debug
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
open suspend fun getAccountDataAsync(bankCode: String, loginName: String, password: String): GetAccountDataResponse {
|
||||
return getAccountDataAsync(GetAccountDataParameter(bankCode, loginName, password))
|
||||
}
|
||||
|
||||
open suspend fun getAccountDataAsync(param: GetAccountDataParameter): GetAccountDataResponse {
|
||||
val finTsServerAddress = config.finTsServerAddressFinder.findFinTsServerAddress(param.bankCode)
|
||||
if (finTsServerAddress.isNullOrBlank()) {
|
||||
return GetAccountDataResponse(ErrorCode.BankDoesNotSupportFinTs3, "Either bank does not support FinTS 3.0 or we don't know its FinTS server address", null, listOf())
|
||||
}
|
||||
val basicAccountDataResponse = getRequiredDataToSendUserJobs(param)
|
||||
val bank = basicAccountDataResponse.finTsModel
|
||||
|
||||
val bank = mapper.mapToBankData(param, finTsServerAddress)
|
||||
val accounts = param.accounts
|
||||
|
||||
if (accounts.isNullOrEmpty() || param.retrieveOnlyAccountInfo) { // then first retrieve customer's bank accounts
|
||||
val getAccountInfoResponse = getAccountInfo(param, bank)
|
||||
|
||||
if (getAccountInfoResponse.successful == false || param.retrieveOnlyAccountInfo) {
|
||||
return GetAccountDataResponse(mapper.mapErrorCode(getAccountInfoResponse), mapper.mapErrorMessages(getAccountInfoResponse), null,
|
||||
getAccountInfoResponse.messageLog, bank)
|
||||
} else {
|
||||
return getAccountData(param, getAccountInfoResponse.bank, getAccountInfoResponse.bank.accounts, getAccountInfoResponse)
|
||||
}
|
||||
if (basicAccountDataResponse.successful == false || param.retrieveOnlyAccountInfo || bank == null) {
|
||||
return GetAccountDataResponse(basicAccountDataResponse.error, basicAccountDataResponse.errorMessage, null,
|
||||
basicAccountDataResponse.messageLog, bank)
|
||||
} else {
|
||||
return getAccountData(param, bank, accounts.map { mapper.mapToAccountData(it, param) }, null)
|
||||
return getAccountData(param, bank, bank.accounts, basicAccountDataResponse.messageLog)
|
||||
}
|
||||
}
|
||||
|
||||
protected open suspend fun getAccountData(param: GetAccountDataParameter, bank: BankData, accounts: List<AccountData>, previousJobResponse: FinTsClientResponse?): GetAccountDataResponse {
|
||||
protected open suspend fun getAccountData(param: GetAccountDataParameter, bank: BankData, accounts: List<AccountData>, previousJobMessageLog: List<MessageLogEntry>?): GetAccountDataResponse {
|
||||
val retrievedTransactionsResponses = mutableListOf<GetAccountTransactionsResponse>()
|
||||
|
||||
val accountsSupportingRetrievingTransactions = accounts.filter { it.supportsRetrievingBalance || it.supportsRetrievingAccountTransactions }
|
||||
|
||||
if (accountsSupportingRetrievingTransactions.isEmpty()) {
|
||||
val errorMessage = "None of the accounts ${accounts.map { it.productName }} supports retrieving balance or transactions" // TODO: translate
|
||||
return GetAccountDataResponse(ErrorCode.NoneOfTheAccountsSupportsRetrievingData, errorMessage, mapper.map(bank), previousJobResponse?.messageLog ?: listOf(), bank)
|
||||
return GetAccountDataResponse(ErrorCode.NoneOfTheAccountsSupportsRetrievingData, errorMessage, mapper.map(bank), previousJobMessageLog ?: listOf(), bank)
|
||||
}
|
||||
|
||||
accountsSupportingRetrievingTransactions.forEach { account ->
|
||||
retrievedTransactionsResponses.add(getAccountData(param, bank, account))
|
||||
for (account in accountsSupportingRetrievingTransactions) {
|
||||
val response = getAccountTransactions(param, bank, account)
|
||||
retrievedTransactionsResponses.add(response)
|
||||
|
||||
if (response.tanRequiredButWeWereToldToAbortIfSo || response.userCancelledAction) { // if user cancelled action or TAN is required but we were told to abort then, then don't continue with next account
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
val unsuccessfulJob = retrievedTransactionsResponses.firstOrNull { it.successful == false }
|
||||
val errorCode = unsuccessfulJob?.let { mapper.mapErrorCode(it) }
|
||||
?: if (retrievedTransactionsResponses.size < accountsSupportingRetrievingTransactions.size) ErrorCode.DidNotRetrieveAllAccountData else null
|
||||
return GetAccountDataResponse(errorCode, mapper.mapErrorMessages(unsuccessfulJob), mapper.map(bank, retrievedTransactionsResponses),
|
||||
mapper.mergeMessageLog(previousJobResponse, *retrievedTransactionsResponses.toTypedArray()), bank)
|
||||
return GetAccountDataResponse(errorCode, mapper.mapErrorMessages(unsuccessfulJob), mapper.map(bank, retrievedTransactionsResponses, param.retrieveTransactionsTo),
|
||||
mapper.mergeMessageLog(previousJobMessageLog, *retrievedTransactionsResponses.map { it.messageLog }.toTypedArray()), bank)
|
||||
}
|
||||
|
||||
protected open suspend fun getAccountData(param: GetAccountDataParameter, bank: BankData, account: AccountData): GetAccountTransactionsResponse {
|
||||
val context = JobContext(JobContextType.GetTransactions, this.callback, config, bank, account)
|
||||
protected open suspend fun getAccountTransactions(param: GetAccountDataParameter, bank: BankData, account: AccountData): GetAccountTransactionsResponse {
|
||||
val context = JobContext(JobContextType.GetTransactions, this.callback, config, bank, account, param.preferredTanMethods, param.tanMethodsNotSupportedByApplication, param.preferredTanMedium)
|
||||
|
||||
return config.jobExecutor.getTransactionsAsync(context, mapper.toGetAccountTransactionsParameter(param, bank, account))
|
||||
}
|
||||
|
@ -142,7 +151,7 @@ open class FinTsClient(
|
|||
accountToUse = selectedAccount
|
||||
}
|
||||
|
||||
val context = JobContext(JobContextType.TransferMoney, this.callback, config, bank, accountToUse)
|
||||
val context = JobContext(JobContextType.TransferMoney, this.callback, config, bank, accountToUse, param.preferredTanMethods, param.tanMethodsNotSupportedByApplication, param.preferredTanMedium)
|
||||
|
||||
val response = config.jobExecutor.transferMoneyAsync(context, BankTransferData(param.recipientName, param.recipientAccountIdentifier, recipientBankIdentifier,
|
||||
param.amount, param.reference, param.instantPayment))
|
||||
|
@ -163,25 +172,65 @@ open class FinTsClient(
|
|||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures all basic data to initialize a dialog with strong customer authorization is retrieved so you can send your
|
||||
* actual jobs (Geschäftsvorfälle) to your bank's FinTS server.
|
||||
*
|
||||
* These data include:
|
||||
* - Bank communication data like FinTS server address, BIC, bank name, bank code used for FinTS.
|
||||
* - BPD (BankParameterDaten): bank name, BPD version, supported languages, supported HBCI versions, supported TAN methods,
|
||||
* max count jobs per message (Anzahl Geschäftsvorfallsarten) (see [BankParameters] [BankParameters](src/commonMain/kotlin/net/codinux/banking/fints/response/segmentsBankParameters) ).
|
||||
* - Min and max online banking password length, min TAN length, hint for login name (for all: if available)
|
||||
* - UPD (UserParameterDaten): username, UPD version.
|
||||
* - Customer system ID (Kundensystem-ID, see [KundensystemID]), TAN methods available for user and may user's TAN media.
|
||||
* - Which jobs the bank supports and which jobs need strong customer authorization (= require HKTAN segment).
|
||||
* - Which jobs the user is allowed to use.
|
||||
* - Which jobs can be called for a specific bank account.
|
||||
*
|
||||
* When implementing your own jobs, call this method first, then send an init dialog message and in next message your actual jobs.
|
||||
*
|
||||
* More or less implements everything of 02 FinTS_3.0_Formals.pdf so that you can start directly with the jobs from
|
||||
* 04 FinTS_3.0_Messages_Geschaeftsvorfaelle.pdf
|
||||
*/
|
||||
open suspend fun getRequiredDataToSendUserJobs(param: FinTsClientParameter): net.dankito.banking.client.model.response.FinTsClientResponse {
|
||||
param.finTsModelOrDeserialized?.let { finTsModel ->
|
||||
return net.dankito.banking.client.model.response.FinTsClientResponse(null, null, emptyList(), finTsModel)
|
||||
}
|
||||
|
||||
val defaultValues = (param as? GetAccountDataParameter)?.defaultBankValues
|
||||
|
||||
val finTsServerAddress = defaultValues?.finTs3ServerAddress ?: config.finTsServerAddressFinder.findFinTsServerAddress(param.bankCode)
|
||||
if (finTsServerAddress.isNullOrBlank()) {
|
||||
return net.dankito.banking.client.model.response.FinTsClientResponse(ErrorCode.BankDoesNotSupportFinTs3, "Either bank does not support FinTS 3.0 or we don't know its FinTS server address", emptyList(), null)
|
||||
}
|
||||
|
||||
val bank = mapper.mapToBankData(param, finTsServerAddress, defaultValues)
|
||||
|
||||
val getAccountInfoResponse = getAccountInfo(param, bank)
|
||||
|
||||
return net.dankito.banking.client.model.response.FinTsClientResponse(mapper.mapErrorCode(getAccountInfoResponse), mapper.mapErrorMessages(getAccountInfoResponse),
|
||||
getAccountInfoResponse.messageLog, bank)
|
||||
}
|
||||
|
||||
protected open suspend fun getAccountInfo(param: FinTsClientParameter, bank: BankData): GetAccountInfoResponse {
|
||||
param.finTsModel?.let {
|
||||
param.finTsModelOrDeserialized?.let {
|
||||
// TODO: implement
|
||||
// return GetAccountInfoResponse(it)
|
||||
}
|
||||
|
||||
val context = JobContext(JobContextType.GetAccountInfo, this.callback, config, bank)
|
||||
val context = JobContext(JobContextType.GetAccountInfo, this.callback, config, bank, null, param.preferredTanMethods, param.tanMethodsNotSupportedByApplication, param.preferredTanMedium)
|
||||
|
||||
/* First dialog: Get user's basic data like BPD, customer system ID and her TAN methods */
|
||||
|
||||
val newUserInfoResponse = config.jobExecutor.retrieveBasicDataLikeUsersTanMethods(context, param.preferredTanMethods, param.preferredTanMedium)
|
||||
val newUserInfoResponse = config.jobExecutor.retrieveBasicDataLikeUsersTanMethods(context)
|
||||
|
||||
/* Second dialog, executed in retrieveBasicDataLikeUsersTanMethods() if required: some banks require that in order to initialize a dialog with
|
||||
strong customer authorization TAN media is required */
|
||||
|
||||
if (newUserInfoResponse.successful == false) { // bank parameter (FinTS server address, ...) already seem to be wrong
|
||||
return GetAccountInfoResponse(context, newUserInfoResponse)
|
||||
}
|
||||
|
||||
/* Second dialog, executed in retrieveBasicDataLikeUsersTanMethods() if required: some banks require that in order to initialize a dialog with
|
||||
strong customer authorization TAN media is required */
|
||||
|
||||
val getAccountsResponse = config.jobExecutor.getAccounts(context)
|
||||
|
||||
return GetAccountInfoResponse(context, getAccountsResponse)
|
|
@ -1,17 +1,14 @@
|
|||
package net.dankito.banking.fints
|
||||
package net.codinux.banking.fints
|
||||
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.datetime.*
|
||||
import net.dankito.banking.fints.callback.FinTsClientCallback
|
||||
import net.dankito.banking.fints.config.FinTsClientConfiguration
|
||||
import net.dankito.banking.fints.extensions.minusDays
|
||||
import net.dankito.banking.fints.extensions.todayAtEuropeBerlin
|
||||
import net.dankito.banking.fints.messages.datenelemente.implementierte.tan.*
|
||||
import net.dankito.banking.fints.model.*
|
||||
import net.dankito.banking.fints.response.BankResponse
|
||||
import net.dankito.banking.fints.response.client.*
|
||||
import net.dankito.banking.fints.webclient.IWebClient
|
||||
import net.codinux.banking.fints.callback.FinTsClientCallback
|
||||
import net.codinux.banking.fints.config.FinTsClientConfiguration
|
||||
import net.codinux.banking.fints.extensions.minusDays
|
||||
import net.codinux.banking.fints.extensions.todayAtEuropeBerlin
|
||||
import net.codinux.banking.fints.messages.datenelemente.implementierte.tan.*
|
||||
import net.codinux.banking.fints.model.*
|
||||
import net.codinux.banking.fints.response.BankResponse
|
||||
import net.codinux.banking.fints.response.client.*
|
||||
|
||||
|
||||
/**
|
||||
|
@ -26,19 +23,6 @@ open class FinTsClientDeprecated(
|
|||
constructor(callback: FinTsClientCallback) : this(FinTsClientConfiguration(), callback)
|
||||
|
||||
|
||||
/**
|
||||
* Retrieves information about bank (e.g. supported HBCI versions, FinTS server address,
|
||||
* supported jobs, ...).
|
||||
*
|
||||
* On success [bank] parameter is updated afterwards.
|
||||
*/
|
||||
open fun getAnonymousBankInfoAsync(bank: BankData, callback: (FinTsClientResponse) -> Unit) {
|
||||
|
||||
GlobalScope.launch {
|
||||
callback(getAnonymousBankInfo(bank))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves information about bank (e.g. supported HBCI versions, FinTS server address,
|
||||
* supported jobs, ...).
|
||||
|
@ -53,13 +37,13 @@ open class FinTsClientDeprecated(
|
|||
}
|
||||
|
||||
|
||||
open suspend fun addAccountAsync(parameter: AddAccountParameter): AddAccountResponse {
|
||||
val bank = parameter.bank
|
||||
val context = JobContext(JobContextType.AddAccount, this.callback, config, bank)
|
||||
open suspend fun addAccountAsync(param: AddAccountParameter): AddAccountResponse {
|
||||
val bank = param.bank
|
||||
val context = JobContext(JobContextType.AddAccount, this.callback, config, bank, null, param.preferredTanMethods, param.tanMethodsNotSupportedByApplication, param.preferredTanMedium)
|
||||
|
||||
/* First dialog: Get user's basic data like BPD, customer system ID and her TAN methods */
|
||||
|
||||
val newUserInfoResponse = config.jobExecutor.retrieveBasicDataLikeUsersTanMethods(context, parameter.preferredTanMethods, parameter.preferredTanMedium)
|
||||
val newUserInfoResponse = config.jobExecutor.retrieveBasicDataLikeUsersTanMethods(context)
|
||||
|
||||
if (newUserInfoResponse.successful == false) { // bank parameter (FinTS server address, ...) already seem to be wrong
|
||||
return AddAccountResponse(context, newUserInfoResponse)
|
||||
|
@ -68,7 +52,7 @@ open class FinTsClientDeprecated(
|
|||
/* Second dialog, executed in retrieveBasicDataLikeUsersTanMethods() if required: some banks require that in order to initialize a dialog with
|
||||
strong customer authorization TAN media is required */
|
||||
|
||||
return addAccountGetAccountsAndTransactions(context, parameter)
|
||||
return addAccountGetAccountsAndTransactions(context, param)
|
||||
}
|
||||
|
||||
protected open suspend fun addAccountGetAccountsAndTransactions(context: JobContext, parameter: AddAccountParameter): AddAccountResponse {
|
||||
|
@ -134,11 +118,11 @@ open class FinTsClientDeprecated(
|
|||
return GetAccountTransactionsParameter(bank, account, account.supportsRetrievingBalance, ninetyDaysAgo, abortIfTanIsRequired = true)
|
||||
}
|
||||
|
||||
open suspend fun getAccountTransactionsAsync(parameter: GetAccountTransactionsParameter): GetAccountTransactionsResponse {
|
||||
open suspend fun getAccountTransactionsAsync(param: GetAccountTransactionsParameter): GetAccountTransactionsResponse {
|
||||
|
||||
val context = JobContext(JobContextType.GetTransactions, this.callback, config, parameter.bank, parameter.account)
|
||||
val context = JobContext(JobContextType.GetTransactions, this.callback, config, param.bank, param.account)
|
||||
|
||||
return config.jobExecutor.getTransactionsAsync(context, parameter)
|
||||
return config.jobExecutor.getTransactionsAsync(context, param)
|
||||
}
|
||||
|
||||
|
||||
|
@ -151,7 +135,7 @@ open class FinTsClientDeprecated(
|
|||
}
|
||||
|
||||
|
||||
open suspend fun changeTanMedium(newActiveTanMedium: TanGeneratorTanMedium, bank: BankData): FinTsClientResponse {
|
||||
open suspend fun changeTanMedium(newActiveTanMedium: TanMedium, bank: BankData): FinTsClientResponse {
|
||||
val context = JobContext(JobContextType.ChangeTanMedium, this.callback, config, bank)
|
||||
|
||||
val response = config.jobExecutor.changeTanMedium(context, newActiveTanMedium)
|
|
@ -1,11 +1,11 @@
|
|||
package net.dankito.banking.fints
|
||||
package net.codinux.banking.fints
|
||||
|
||||
import net.dankito.banking.fints.callback.FinTsClientCallback
|
||||
import net.dankito.banking.fints.config.FinTsClientConfiguration
|
||||
import net.dankito.banking.fints.model.*
|
||||
import net.dankito.banking.fints.response.client.AddAccountResponse
|
||||
import net.dankito.banking.fints.response.client.FinTsClientResponse
|
||||
import net.dankito.banking.fints.response.client.GetAccountTransactionsResponse
|
||||
import net.codinux.banking.fints.callback.FinTsClientCallback
|
||||
import net.codinux.banking.fints.config.FinTsClientConfiguration
|
||||
import net.codinux.banking.fints.model.*
|
||||
import net.codinux.banking.fints.response.client.AddAccountResponse
|
||||
import net.codinux.banking.fints.response.client.FinTsClientResponse
|
||||
import net.codinux.banking.fints.response.client.GetAccountTransactionsResponse
|
||||
|
||||
|
||||
open class FinTsClientForCustomer(
|
|
@ -1,26 +1,28 @@
|
|||
package net.dankito.banking.fints
|
||||
package net.codinux.banking.fints
|
||||
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.datetime.Instant
|
||||
import kotlinx.datetime.LocalDate
|
||||
import net.codinux.banking.fints.extensions.*
|
||||
import net.codinux.log.logger
|
||||
import net.dankito.banking.fints.messages.MessageBuilder
|
||||
import net.dankito.banking.fints.messages.MessageBuilderResult
|
||||
import net.dankito.banking.fints.messages.datenelemente.implementierte.signatur.VersionDesSicherheitsverfahrens
|
||||
import net.dankito.banking.fints.messages.datenelemente.implementierte.tan.*
|
||||
import net.dankito.banking.fints.messages.segmente.id.CustomerSegmentId
|
||||
import net.dankito.banking.fints.messages.segmente.id.ISegmentId
|
||||
import net.dankito.banking.fints.model.*
|
||||
import net.dankito.banking.fints.model.mapper.ModelMapper
|
||||
import net.dankito.banking.fints.response.BankResponse
|
||||
import net.dankito.banking.fints.response.InstituteSegmentId
|
||||
import net.dankito.banking.fints.response.client.*
|
||||
import net.dankito.banking.fints.response.segments.*
|
||||
import net.dankito.banking.fints.tan.FlickerCodeDecoder
|
||||
import net.dankito.banking.fints.tan.TanImageDecoder
|
||||
import net.dankito.banking.fints.util.TanMethodSelector
|
||||
import net.dankito.banking.fints.extensions.minusDays
|
||||
import net.dankito.banking.fints.extensions.todayAtEuropeBerlin
|
||||
import net.dankito.banking.fints.extensions.todayAtSystemDefaultTimeZone
|
||||
import net.codinux.banking.fints.messages.MessageBuilder
|
||||
import net.codinux.banking.fints.messages.MessageBuilderResult
|
||||
import net.codinux.banking.fints.messages.datenelemente.implementierte.signatur.VersionDesSicherheitsverfahrens
|
||||
import net.codinux.banking.fints.messages.datenelemente.implementierte.tan.*
|
||||
import net.codinux.banking.fints.messages.segmente.id.CustomerSegmentId
|
||||
import net.codinux.banking.fints.messages.segmente.id.ISegmentId
|
||||
import net.codinux.banking.fints.model.*
|
||||
import net.codinux.banking.fints.model.mapper.ModelMapper
|
||||
import net.codinux.banking.fints.response.BankResponse
|
||||
import net.codinux.banking.fints.response.InstituteSegmentId
|
||||
import net.codinux.banking.fints.response.client.*
|
||||
import net.codinux.banking.fints.response.segments.*
|
||||
import net.codinux.banking.fints.tan.FlickerCodeDecoder
|
||||
import net.codinux.banking.fints.tan.TanImageDecoder
|
||||
import net.codinux.banking.fints.util.TanMethodSelector
|
||||
import net.codinux.log.Log
|
||||
import kotlin.math.max
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
|
||||
|
||||
/**
|
||||
|
@ -72,8 +74,7 @@ open class FinTsJobExecutor(
|
|||
*
|
||||
* Be aware this method resets BPD, UPD and selected TAN method!
|
||||
*/
|
||||
open suspend fun retrieveBasicDataLikeUsersTanMethods(context: JobContext, preferredTanMethods: List<TanMethodType>? = null, preferredTanMedium: String? = null,
|
||||
closeDialog: Boolean = false): BankResponse {
|
||||
open suspend fun retrieveBasicDataLikeUsersTanMethods(context: JobContext): BankResponse {
|
||||
val bank = context.bank
|
||||
|
||||
// just to ensure settings are in its initial state and that bank sends us bank parameter (BPD),
|
||||
|
@ -89,7 +90,7 @@ open class FinTsJobExecutor(
|
|||
bank.resetSelectedTanMethod()
|
||||
|
||||
// this is the only case where Einschritt-TAN-Verfahren is accepted: to get user's TAN methods
|
||||
context.startNewDialog(closeDialog, versionOfSecurityProcedure = VersionDesSicherheitsverfahrens.Version_1)
|
||||
context.startNewDialog(versionOfSecurityProcedure = VersionDesSicherheitsverfahrens.Version_1)
|
||||
|
||||
val message = messageBuilder.createInitDialogMessage(context)
|
||||
|
||||
|
@ -102,12 +103,10 @@ open class FinTsJobExecutor(
|
|||
if (bank.tanMethodsAvailableForUser.isEmpty()) { // could not retrieve supported tan methods for user
|
||||
return getTanMethodsResponse
|
||||
} else {
|
||||
getUsersTanMethod(context, preferredTanMethods)
|
||||
getUsersTanMethod(context)
|
||||
|
||||
if (bank.isTanMethodSelected == false) {
|
||||
return getTanMethodsResponse
|
||||
} else if (bank.tanMedia.isEmpty() && isJobSupported(bank, CustomerSegmentId.TanMediaList)) { // tan media not retrieved yet
|
||||
getTanMediaList(context, TanMedienArtVersion.Alle, TanMediumKlasse.AlleMedien, preferredTanMedium)
|
||||
if (bank.isTanMethodSelected && bank.tanMedia.isEmpty() && bank.tanMethodsAvailableForUser.any { it.nameOfTanMediumRequired } && isJobSupported(bank, CustomerSegmentId.TanMediaList)) { // tan media not retrieved yet
|
||||
getTanMediaList(context, TanMedienArtVersion.Alle, TanMediumKlasse.AlleMedien, context.preferredTanMedium)
|
||||
|
||||
return getTanMethodsResponse // TODO: judge if bank requires selecting TAN media and if though evaluate getTanMediaListResponse
|
||||
} else {
|
||||
|
@ -146,6 +145,7 @@ open class FinTsJobExecutor(
|
|||
return BankResponse(true, internalError = "Die TAN Verfahren der Bank konnten nicht ermittelt werden") // TODO: translate
|
||||
} else {
|
||||
bank.tanMethodsAvailableForUser = bank.tanMethodsSupportedByBank
|
||||
.filterNot { context.tanMethodsNotSupportedByApplication.contains(it.type) }
|
||||
|
||||
val didSelectTanMethod = getUsersTanMethod(context)
|
||||
|
||||
|
@ -202,6 +202,29 @@ open class FinTsJobExecutor(
|
|||
var balance: Money? = balanceResponse?.getFirstSegmentById<BalanceSegment>(InstituteSegmentId.Balance)?.let {
|
||||
Money(it.balance, it.currency)
|
||||
}
|
||||
|
||||
// TODO: for larger portfolios there can be a Aufsetzpunkt, but for balances we currently do not support sending multiple messages
|
||||
val statementOfHoldings = balanceResponse?.getFirstSegmentById<SecuritiesAccountBalanceSegment>(InstituteSegmentId.SecuritiesAccountBalance)?.let {
|
||||
val statementOfHoldings = it.statementOfHoldings
|
||||
val statementOfHolding = statementOfHoldings.firstOrNull { it.totalBalance != null }
|
||||
if (statementOfHolding != null) {
|
||||
balance = Money(statementOfHolding.totalBalance!!, statementOfHolding.currency ?: Currency.DefaultCurrencyCode)
|
||||
}
|
||||
statementOfHoldings
|
||||
} ?: emptyList()
|
||||
|
||||
if (parameter.account.supportsRetrievingAccountTransactions == false) {
|
||||
if (balanceResponse == null) {
|
||||
return GetAccountTransactionsResponse(context, BankResponse(false, "Balance could not be retrieved"), RetrievedAccountData.unsuccessful(parameter.account))
|
||||
} else {
|
||||
val successful = balance != null || balanceResponse.tanRequiredButWeWereToldToAbortIfSo
|
||||
val retrievedData = RetrievedAccountData(parameter.account, successful, balance, emptyList(), emptyList(), statementOfHoldings, Instant.nowExt(), null, null, balanceResponse?.internalError)
|
||||
|
||||
return GetAccountTransactionsResponse(context, balanceResponse, retrievedData)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
val bookedTransactions = mutableSetOf<AccountTransaction>()
|
||||
val unbookedTransactions = mutableSetOf<Any>()
|
||||
|
||||
|
@ -217,27 +240,30 @@ open class FinTsJobExecutor(
|
|||
context.bank, parameter.account)
|
||||
|
||||
bookedTransactions.addAll(chunkTransaction)
|
||||
remainingMt940String = remainder
|
||||
remainingMt940String = remainder ?: ""
|
||||
|
||||
parameter.retrievedChunkListener?.invoke(bookedTransactions)
|
||||
}
|
||||
|
||||
response.getFirstSegmentById<ReceivedCreditCardTransactionsAndBalance>(InstituteSegmentId.CreditCardTransactions)?.let { creditCardTransactionsSegment ->
|
||||
balance = Money(creditCardTransactionsSegment.balance.amount, creditCardTransactionsSegment.balance.currency ?: "EUR")
|
||||
bookedTransactions.addAll(creditCardTransactionsSegment.transactions.map { AccountTransaction(parameter.account, it.amount, it.description, it.bookingDate, it.transactionDescriptionBase ?: "", null, null, "", it.valueDate) })
|
||||
bookedTransactions.addAll(creditCardTransactionsSegment.transactions.map { AccountTransaction(parameter.account, it.amount, it.description, it.bookingDate, it.valueDate, it.transactionDescriptionBase ?: "", null, null) })
|
||||
}
|
||||
}
|
||||
|
||||
val startTime = Instant.nowExt()
|
||||
|
||||
val response = getAndHandleResponseForMessage(context, message)
|
||||
|
||||
closeDialog(context)
|
||||
|
||||
val successful = response.tanRequiredButWeWereToldToAbortIfSo
|
||||
|| (response.successful && (parameter.alsoRetrieveBalance == false || balance != null))
|
||||
|| (response.successful && (parameter.alsoRetrieveBalance == false || balance != null))
|
||||
|| (parameter.account.supportsRetrievingAccountTransactions == false && balance != null)
|
||||
val fromDate = parameter.fromDate
|
||||
?: parameter.account.countDaysForWhichTransactionsAreKept?.let { LocalDate.todayAtSystemDefaultTimeZone().minusDays(it) }
|
||||
?: parameter.account.serverTransactionsRetentionDays?.let { LocalDate.todayAtSystemDefaultTimeZone().minusDays(it) }
|
||||
?: bookedTransactions.minByOrNull { it.valueDate }?.valueDate
|
||||
val retrievedData = RetrievedAccountData(parameter.account, successful, balance, bookedTransactions, unbookedTransactions, fromDate, parameter.toDate ?: LocalDate.todayAtEuropeBerlin(), response.internalError)
|
||||
val retrievedData = RetrievedAccountData(parameter.account, successful, balance, bookedTransactions, unbookedTransactions, statementOfHoldings, startTime, fromDate, parameter.toDate ?: LocalDate.todayAtEuropeBerlin(), response.internalError)
|
||||
|
||||
return GetAccountTransactionsResponse(context, response, retrievedData,
|
||||
if (parameter.maxCountEntries != null) parameter.isSettingMaxCountEntriesAllowedByBank else null)
|
||||
|
@ -307,6 +333,7 @@ open class FinTsJobExecutor(
|
|||
|
||||
bank.selectedTanMedium = preferredTanMedium?.let { bank.tanMedia.firstOrNull { it.mediumName == preferredTanMedium } }
|
||||
?: bank.selectedTanMedium?.let { selected -> bank.tanMedia.firstOrNull { it.mediumName == selected.mediumName } } // try to find selectedTanMedium in new TanMedia instances
|
||||
?: bank.tanMedia.firstOrNull { it.status == TanMediumStatus.Aktiv && it.mediumName != null }
|
||||
?: bank.tanMedia.firstOrNull { it.mediumName != null }
|
||||
}
|
||||
|
||||
|
@ -314,7 +341,7 @@ open class FinTsJobExecutor(
|
|||
}
|
||||
|
||||
|
||||
open suspend fun changeTanMedium(context: JobContext, newActiveTanMedium: TanGeneratorTanMedium): BankResponse {
|
||||
open suspend fun changeTanMedium(context: JobContext, newActiveTanMedium: TanMedium): BankResponse {
|
||||
val bank = context.bank
|
||||
|
||||
if (bank.changeTanMediumParameters?.enteringAtcAndTanRequired == true) {
|
||||
|
@ -331,7 +358,7 @@ open class FinTsJobExecutor(
|
|||
}
|
||||
}
|
||||
|
||||
protected open suspend fun sendChangeTanMediumMessage(context: JobContext, newActiveTanMedium: TanGeneratorTanMedium, enteredAtc: EnterTanGeneratorAtcResult?): BankResponse {
|
||||
protected open suspend fun sendChangeTanMediumMessage(context: JobContext, newActiveTanMedium: TanMedium, enteredAtc: EnterTanGeneratorAtcResult?): BankResponse {
|
||||
|
||||
return sendMessageInNewDialogAndHandleResponse(context, null, true) {
|
||||
messageBuilder.createChangeTanMediumMessage(context, newActiveTanMedium, enteredAtc?.tan, enteredAtc?.atc)
|
||||
|
@ -374,20 +401,36 @@ open class FinTsJobExecutor(
|
|||
protected open suspend fun handleEnteringTanRequired(context: JobContext, tanResponse: TanResponse, response: BankResponse): BankResponse {
|
||||
// on all platforms run on Dispatchers.Main, but on iOS skip this (or wrap in withContext(Dispatchers.IO) )
|
||||
// val enteredTanResult = GlobalScope.async {
|
||||
val tanChallenge = createTanChallenge(tanResponse, modelMapper.mapToActionRequiringTan(context.type), context.bank, context.account)
|
||||
val tanChallenge = createTanChallenge(tanResponse, modelMapper.mapToActionRequiringTan(context.type), context.bank, context.account)
|
||||
|
||||
context.callback.enterTan(tanChallenge)
|
||||
context.callback.enterTan(tanChallenge)
|
||||
|
||||
while (tanChallenge.enterTanResult == null) {
|
||||
delay(250)
|
||||
mayRetrieveAutomaticallyIfUserEnteredDecoupledTan(context, tanChallenge, tanResponse)
|
||||
|
||||
mayRetrieveAutomaticallyIfUserEnteredDecoupledTan(context, tanChallenge, tanResponse)
|
||||
var invocationCount = 0 // TODO: remove again
|
||||
|
||||
// TODO: add a timeout of e.g. 30 min
|
||||
while (tanChallenge.isEnteringTanDone == false) {
|
||||
delay(500)
|
||||
|
||||
if (++invocationCount % 10 == 0) {
|
||||
Log.info { "Waiting for TAN input invocation count: $invocationCount" }
|
||||
}
|
||||
|
||||
val now = Instant.nowExt()
|
||||
if ((tanChallenge.tanExpirationTime != null && now > tanChallenge.tanExpirationTime) ||
|
||||
// most TANs a valid 5 - 15 minutes. So terminate wait process after that time
|
||||
(tanChallenge.tanExpirationTime == null && now > tanChallenge.challengeCreationTimestamp.plusMinutes(15))) {
|
||||
if (tanChallenge.isEnteringTanDone == false) {
|
||||
Log.info { "Terminating waiting for TAN input" } // TODO: remove again
|
||||
|
||||
tanChallenge.tanExpired()
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
val enteredTanResult = tanChallenge.enterTanResult!!
|
||||
// }
|
||||
|
||||
return handleEnterTanResult(context, enteredTanResult, tanResponse, response)
|
||||
}
|
||||
|
@ -401,27 +444,82 @@ open class FinTsJobExecutor(
|
|||
return when (tanMethod.type) {
|
||||
TanMethodType.ChipTanFlickercode ->
|
||||
FlickerCodeTanChallenge(
|
||||
FlickerCodeDecoder().decodeChallenge(challenge, tanMethod.hhdVersion ?: HHDVersion.HHD_1_4), // HHD 1.4 is currently the most used version
|
||||
forAction, messageToShowToUser, challenge, tanMethod, tanResponse.tanMediaIdentifier, bank, account)
|
||||
FlickerCodeDecoder().decodeChallenge(challenge, tanMethod.hhdVersion ?: getFallbackHhdVersion(challenge)),
|
||||
forAction, messageToShowToUser, challenge, tanMethod, tanResponse.tanMediaIdentifier, bank, account, tanResponse.tanExpirationTime)
|
||||
|
||||
TanMethodType.ChipTanQrCode, TanMethodType.ChipTanPhotoTanMatrixCode,
|
||||
TanMethodType.QrCode, TanMethodType.photoTan ->
|
||||
ImageTanChallenge(TanImageDecoder().decodeChallenge(challenge), forAction, messageToShowToUser, challenge, tanMethod, tanResponse.tanMediaIdentifier, bank, account)
|
||||
ImageTanChallenge(TanImageDecoder().decodeChallenge(challenge), forAction, messageToShowToUser, challenge, tanMethod, tanResponse.tanMediaIdentifier, bank, account, tanResponse.tanExpirationTime)
|
||||
|
||||
else -> TanChallenge(forAction, messageToShowToUser, challenge, tanMethod, tanResponse.tanMediaIdentifier, bank, account)
|
||||
else -> TanChallenge(forAction, messageToShowToUser, challenge, tanMethod, tanResponse.tanMediaIdentifier, bank, account, tanResponse.tanExpirationTime)
|
||||
}
|
||||
}
|
||||
|
||||
protected open fun mayRetrieveAutomaticallyIfUserEnteredDecoupledTan(context: JobContext, tanChallenge: TanChallenge, tanResponse: TanResponse) {
|
||||
protected open fun getFallbackHhdVersion(challenge: String): HHDVersion {
|
||||
if (challenge.length <= 35) { // is this true in all circumstances?
|
||||
return HHDVersion.HHD_1_3
|
||||
}
|
||||
|
||||
return HHDVersion.HHD_1_4 // HHD 1.4 is currently the most used version
|
||||
}
|
||||
|
||||
protected open suspend fun mayRetrieveAutomaticallyIfUserEnteredDecoupledTan(context: JobContext, tanChallenge: TanChallenge, tanResponse: TanResponse) {
|
||||
context.bank.selectedTanMethod.decoupledParameters?.let { decoupledTanMethodParameters ->
|
||||
if (tanResponse.tanProcess == TanProcess.AppTan && decoupledTanMethodParameters.periodicStateRequestsAllowed) {
|
||||
automaticallyRetrieveIfUserEnteredDecoupledTan(context, tanChallenge)
|
||||
if (decoupledTanMethodParameters.periodicStateRequestsAllowed) {
|
||||
val responseAfterApprovingDecoupledTan =
|
||||
automaticallyRetrieveIfUserEnteredDecoupledTan(context, tanChallenge, tanResponse, decoupledTanMethodParameters)
|
||||
|
||||
if (responseAfterApprovingDecoupledTan != null) {
|
||||
tanChallenge.userApprovedDecoupledTan(responseAfterApprovingDecoupledTan)
|
||||
} else {
|
||||
tanChallenge.userDidNotEnterTan()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected open fun automaticallyRetrieveIfUserEnteredDecoupledTan(context: JobContext, tanChallenge: TanChallenge) {
|
||||
protected open suspend fun automaticallyRetrieveIfUserEnteredDecoupledTan(context: JobContext, tanChallenge: TanChallenge, tanResponse: TanResponse, parameters: DecoupledTanMethodParameters): BankResponse? {
|
||||
log.info { "automaticallyRetrieveIfUserEnteredDecoupledTan() called for $tanChallenge" }
|
||||
|
||||
delay(max(5, parameters.initialDelayInSecondsForStateRequest).seconds)
|
||||
|
||||
var iteration = 0
|
||||
val minWaitTime = when {
|
||||
parameters.maxNumberOfStateRequests <= 10 -> 30
|
||||
parameters.maxNumberOfStateRequests <= 24 -> 10
|
||||
else -> 3
|
||||
}
|
||||
val delayForNextStateRequest = max(minWaitTime, parameters.delayInSecondsForNextStateRequest).seconds
|
||||
|
||||
while (iteration < parameters.maxNumberOfStateRequests) {
|
||||
try {
|
||||
val message = messageBuilder.createDecoupledTanStatusMessage(context, tanResponse)
|
||||
|
||||
val response = getAndHandleResponseForMessage(context, message)
|
||||
|
||||
val tanFeedbacks = response.segmentFeedbacks.filter { it.referenceSegmentNumber == MessageBuilder.SignedMessagePayloadFirstSegmentNumber }
|
||||
if (tanFeedbacks.isNotEmpty()) {
|
||||
// new feedback code for Decoupled TAN: 0900 Sicherheitsfreigabe gültig
|
||||
// Sparkasse responds for pushTan with: HIRMS:4:2:3+0020::Der Auftrag wurde ausgeführt.+0020::Die gebuchten Umsätze wurden übermittelt.'
|
||||
val isTanApproved = tanFeedbacks.any { it.feedbacks.any { it.responseCode == 900 || it.responseCode == 20 } }
|
||||
if (isTanApproved) {
|
||||
return response
|
||||
}
|
||||
}
|
||||
|
||||
iteration++
|
||||
// sometimes delayInSecondsForNextStateRequests is only 1 or 2 seconds, that's too fast i think
|
||||
delay(delayForNextStateRequest)
|
||||
} catch (e: Throwable) {
|
||||
log.error(e) { "Could not check status of Decoupled TAN" }
|
||||
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
tanChallenge.tanExpired()
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
protected open suspend fun handleEnterTanResult(context: JobContext, enteredTanResult: EnterTanResult, tanResponse: TanResponse,
|
||||
|
@ -429,19 +527,18 @@ open class FinTsJobExecutor(
|
|||
|
||||
if (enteredTanResult.changeTanMethodTo != null) {
|
||||
return handleUserAsksToChangeTanMethodAndResendLastMessage(context, enteredTanResult.changeTanMethodTo)
|
||||
}
|
||||
else if (enteredTanResult.changeTanMediumTo is TanGeneratorTanMedium) {
|
||||
} else if (enteredTanResult.changeTanMediumTo != null) {
|
||||
return handleUserAsksToChangeTanMediumAndResendLastMessage(context, enteredTanResult.changeTanMediumTo,
|
||||
enteredTanResult.changeTanMediumResultCallback)
|
||||
}
|
||||
else if (enteredTanResult.enteredTan == null) {
|
||||
} else if (enteredTanResult.userApprovedDecoupledTan == true && enteredTanResult.responseAfterApprovingDecoupledTan != null) {
|
||||
return enteredTanResult.responseAfterApprovingDecoupledTan
|
||||
} else if (enteredTanResult.enteredTan == null) {
|
||||
// i tried to send a HKTAN with cancelJob = true but then i saw there are no tan methods that support cancellation (at least not at my bank)
|
||||
// but it's not required anyway, tan times out after some time. Simply don't respond anything and close dialog
|
||||
response.tanRequiredButUserDidNotEnterOne = true
|
||||
|
||||
return response
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return sendTanToBank(context, enteredTanResult.enteredTan, tanResponse)
|
||||
}
|
||||
}
|
||||
|
@ -465,7 +562,7 @@ open class FinTsJobExecutor(
|
|||
return resendMessageInNewDialog(context, lastCreatedMessage)
|
||||
}
|
||||
|
||||
protected open suspend fun handleUserAsksToChangeTanMediumAndResendLastMessage(context: JobContext, changeTanMediumTo: TanGeneratorTanMedium,
|
||||
protected open suspend fun handleUserAsksToChangeTanMediumAndResendLastMessage(context: JobContext, changeTanMediumTo: TanMedium,
|
||||
changeTanMediumResultCallback: ((FinTsClientResponse) -> Unit)?): BankResponse {
|
||||
|
||||
val lastCreatedMessage = context.dialog.currentMessage
|
||||
|
@ -493,7 +590,8 @@ open class FinTsJobExecutor(
|
|||
|
||||
val initDialogResponse = initDialogWithStrongCustomerAuthentication(context)
|
||||
|
||||
if (initDialogResponse.successful == false) {
|
||||
// if lastCreatedMessage was a dialog init message, there's no need to send this message again, we just initialized a new dialog in initDialogWithStrongCustomerAuthentication()
|
||||
if (initDialogResponse.successful == false || lastCreatedMessage.isDialogInitMessage()) {
|
||||
return initDialogResponse
|
||||
} else {
|
||||
val newMessage = messageBuilder.rebuildMessage(context, lastCreatedMessage)
|
||||
|
@ -566,7 +664,7 @@ open class FinTsJobExecutor(
|
|||
|
||||
protected open suspend fun initDialogWithStrongCustomerAuthenticationAfterSuccessfulPreconditionChecks(context: JobContext): BankResponse {
|
||||
|
||||
context.startNewDialog(false) // don't know if it's ok for all invocations of this method to set closeDialog to false (was actually only set in getAccounts())
|
||||
context.startNewDialog() // don't know if it's ok for all invocations of this method to set closeDialog to false (was actually only set in getAccounts())
|
||||
|
||||
val message = messageBuilder.createInitDialogMessage(context)
|
||||
|
||||
|
@ -642,7 +740,7 @@ open class FinTsJobExecutor(
|
|||
return BankResponse(true, noTanMethodSelected = noTanMethodSelected, internalError = errorMessage)
|
||||
}
|
||||
|
||||
open suspend fun getUsersTanMethod(context: JobContext, preferredTanMethods: List<TanMethodType>? = null): Boolean {
|
||||
open suspend fun getUsersTanMethod(context: JobContext): Boolean {
|
||||
val bank = context.bank
|
||||
|
||||
if (bank.tanMethodsAvailableForUser.size == 1) { // user has only one TAN method -> set it and we're done
|
||||
|
@ -650,13 +748,13 @@ open class FinTsJobExecutor(
|
|||
return true
|
||||
}
|
||||
else {
|
||||
tanMethodSelector.findPreferredTanMethod(bank.tanMethodsAvailableForUser, preferredTanMethods)?.let {
|
||||
tanMethodSelector.findPreferredTanMethod(bank.tanMethodsAvailableForUser, context.preferredTanMethods, context.tanMethodsNotSupportedByApplication)?.let {
|
||||
bank.selectedTanMethod = it
|
||||
return true
|
||||
}
|
||||
|
||||
// we know user's supported tan methods, now ask user which one to select
|
||||
val suggestedTanMethod = tanMethodSelector.getSuggestedTanMethod(bank.tanMethodsAvailableForUser)
|
||||
val suggestedTanMethod = tanMethodSelector.getSuggestedTanMethod(bank.tanMethodsAvailableForUser, context.tanMethodsNotSupportedByApplication)
|
||||
|
||||
val selectedTanMethod = context.callback.askUserForTanMethod(bank.tanMethodsAvailableForUser, suggestedTanMethod)
|
||||
|
||||
|
@ -677,14 +775,14 @@ open class FinTsJobExecutor(
|
|||
|
||||
protected open fun updateBankAndCustomerDataIfResponseSuccessful(context: JobContext, response: BankResponse) {
|
||||
if (response.successful) {
|
||||
updateBankAndCustomerData(context.bank, response)
|
||||
updateBankAndCustomerData(context.bank, response, context)
|
||||
}
|
||||
}
|
||||
|
||||
protected open fun updateBankAndCustomerData(bank: BankData, response: BankResponse) {
|
||||
protected open fun updateBankAndCustomerData(bank: BankData, response: BankResponse, context: JobContext) {
|
||||
updateBankData(bank, response)
|
||||
|
||||
modelMapper.updateCustomerData(bank, response)
|
||||
modelMapper.updateCustomerData(bank, response, context)
|
||||
}
|
||||
|
||||
|
|
@ -1,17 +1,18 @@
|
|||
package net.dankito.banking.fints
|
||||
package net.codinux.banking.fints
|
||||
|
||||
import net.codinux.log.logger
|
||||
import net.dankito.banking.fints.messages.MessageBuilder
|
||||
import net.dankito.banking.fints.messages.MessageBuilderResult
|
||||
import net.dankito.banking.fints.model.*
|
||||
import net.dankito.banking.fints.response.BankResponse
|
||||
import net.dankito.banking.fints.response.segments.TanResponse
|
||||
import net.dankito.banking.fints.util.IBase64Service
|
||||
import net.dankito.banking.fints.util.PureKotlinBase64Service
|
||||
import net.dankito.banking.fints.webclient.IWebClient
|
||||
import net.dankito.banking.fints.webclient.KtorWebClient
|
||||
import net.dankito.banking.fints.webclient.WebClientResponse
|
||||
import net.dankito.banking.fints.extensions.getAllExceptionMessagesJoined
|
||||
import net.codinux.banking.fints.messages.MessageBuilder
|
||||
import net.codinux.banking.fints.messages.MessageBuilderResult
|
||||
import net.codinux.banking.fints.model.*
|
||||
import net.codinux.banking.fints.response.BankResponse
|
||||
import net.codinux.banking.fints.response.segments.TanResponse
|
||||
import net.codinux.banking.fints.util.IBase64Service
|
||||
import net.codinux.banking.fints.util.PureKotlinBase64Service
|
||||
import net.codinux.banking.fints.webclient.IWebClient
|
||||
import net.codinux.banking.fints.webclient.KtorWebClient
|
||||
import net.codinux.banking.fints.webclient.WebClientResponse
|
||||
import net.codinux.banking.fints.extensions.getAllExceptionMessagesJoined
|
||||
import net.codinux.banking.fints.response.segments.ReceivedSegment
|
||||
|
||||
|
||||
open class RequestExecutor(
|
||||
|
@ -104,9 +105,11 @@ open class RequestExecutor(
|
|||
try {
|
||||
val decodedResponse = decodeBase64Response(responseBody)
|
||||
|
||||
addMessageLog(context, MessageLogEntryType.Received, decodedResponse)
|
||||
val parsedResponse = context.responseParser.parse(decodedResponse)
|
||||
|
||||
return context.responseParser.parse(decodedResponse)
|
||||
addMessageLog(context, MessageLogEntryType.Received, decodedResponse, parsedResponse.receivedSegments)
|
||||
|
||||
return parsedResponse
|
||||
} catch (e: Exception) {
|
||||
logError(context, "Could not decode responseBody:\r\n'$responseBody'", e)
|
||||
|
||||
|
@ -164,8 +167,8 @@ open class RequestExecutor(
|
|||
}
|
||||
|
||||
|
||||
protected open fun addMessageLog(context: JobContext, type: MessageLogEntryType, message: String) {
|
||||
context.addMessageLog(type, message)
|
||||
protected open fun addMessageLog(context: JobContext, type: MessageLogEntryType, message: String, parsedSegments: List<ReceivedSegment> = emptyList()) {
|
||||
context.addMessageLog(type, message, parsedSegments)
|
||||
}
|
||||
|
||||
protected open fun logError(context: JobContext, message: String, e: Exception?) {
|
|
@ -1,7 +1,7 @@
|
|||
package net.dankito.banking.fints.callback
|
||||
package net.codinux.banking.fints.callback
|
||||
|
||||
import net.dankito.banking.fints.messages.datenelemente.implementierte.tan.TanGeneratorTanMedium
|
||||
import net.dankito.banking.fints.model.*
|
||||
import net.codinux.banking.fints.messages.datenelemente.implementierte.tan.TanMedium
|
||||
import net.codinux.banking.fints.model.*
|
||||
|
||||
|
||||
interface FinTsClientCallback {
|
||||
|
@ -25,6 +25,13 @@ interface FinTsClientCallback {
|
|||
*
|
||||
* If you do not support entering TAN generator ATC, return [EnterTanGeneratorAtcResult.userDidNotEnterAtc]
|
||||
*/
|
||||
suspend fun enterTanGeneratorAtc(bank: BankData, tanMedium: TanGeneratorTanMedium): EnterTanGeneratorAtcResult
|
||||
suspend fun enterTanGeneratorAtc(bank: BankData, tanMedium: TanMedium): EnterTanGeneratorAtcResult
|
||||
|
||||
/**
|
||||
* Gets fired when a FinTS message get sent to bank server, a FinTS message is received from bank server or an error occurred.
|
||||
*
|
||||
* Be aware, in order that this message gets fired [net.codinux.banking.fints.config.FinTsClientOptions.fireCallbackOnMessageLogs] has to be set to true.
|
||||
*/
|
||||
fun messageLogAdded(messageLogEntry: MessageLogEntry)
|
||||
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
package net.dankito.banking.fints.callback
|
||||
package net.codinux.banking.fints.callback
|
||||
|
||||
import net.dankito.banking.fints.messages.datenelemente.implementierte.tan.TanGeneratorTanMedium
|
||||
import net.dankito.banking.fints.model.*
|
||||
import net.codinux.banking.fints.messages.datenelemente.implementierte.tan.TanMedium
|
||||
import net.codinux.banking.fints.model.*
|
||||
|
||||
|
||||
open class NoOpFinTsClientCallback : FinTsClientCallback {
|
||||
|
@ -14,8 +14,12 @@ open class NoOpFinTsClientCallback : FinTsClientCallback {
|
|||
return tanChallenge.userDidNotEnterTan()
|
||||
}
|
||||
|
||||
override suspend fun enterTanGeneratorAtc(bank: BankData, tanMedium: TanGeneratorTanMedium): EnterTanGeneratorAtcResult {
|
||||
override suspend fun enterTanGeneratorAtc(bank: BankData, tanMedium: TanMedium): EnterTanGeneratorAtcResult {
|
||||
return EnterTanGeneratorAtcResult.userDidNotEnterAtc()
|
||||
}
|
||||
|
||||
override fun messageLogAdded(messageLogEntry: MessageLogEntry) {
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,18 +1,19 @@
|
|||
package net.dankito.banking.fints.callback
|
||||
package net.codinux.banking.fints.callback
|
||||
|
||||
import net.dankito.banking.fints.messages.datenelemente.implementierte.tan.TanGeneratorTanMedium
|
||||
import net.dankito.banking.fints.model.*
|
||||
import net.codinux.banking.fints.messages.datenelemente.implementierte.tan.TanMedium
|
||||
import net.codinux.banking.fints.model.*
|
||||
|
||||
|
||||
open class SimpleFinTsClientCallback(
|
||||
protected open val enterTan: ((tanChallenge: TanChallenge) -> Unit)? = null,
|
||||
protected open val enterTanGeneratorAtc: ((bank: BankData, tanMedium: TanGeneratorTanMedium) -> EnterTanGeneratorAtcResult)? = null,
|
||||
protected open val askUserForTanMethod: ((supportedTanMethods: List<TanMethod>, suggestedTanMethod: TanMethod?) -> TanMethod?)? = null
|
||||
protected open val askUserForTanMethod: ((supportedTanMethods: List<TanMethod>, suggestedTanMethod: TanMethod?) -> TanMethod?)? = null,
|
||||
protected open val messageLogAdded: ((MessageLogEntry) -> Unit)? = null,
|
||||
protected open val enterTanGeneratorAtc: ((bank: BankData, tanMedium: TanMedium) -> EnterTanGeneratorAtcResult)? = null,
|
||||
protected open val enterTan: ((tanChallenge: TanChallenge) -> Unit)? = null
|
||||
) : FinTsClientCallback {
|
||||
|
||||
constructor() : this(null) // Swift does not support default parameter values -> create constructor overloads
|
||||
constructor() : this(null as ((tanChallenge: TanChallenge) -> Unit)?) // Swift does not support default parameter values -> create constructor overloads
|
||||
|
||||
constructor(enterTan: ((tanChallenge: TanChallenge) -> Unit)?) : this(enterTan, null)
|
||||
constructor(enterTan: ((tanChallenge: TanChallenge) -> Unit)?) : this(null, null, null, enterTan)
|
||||
|
||||
|
||||
override suspend fun askUserForTanMethod(supportedTanMethods: List<TanMethod>, suggestedTanMethod: TanMethod?): TanMethod? {
|
||||
|
@ -24,8 +25,12 @@ open class SimpleFinTsClientCallback(
|
|||
enterTan?.invoke(tanChallenge) ?: run { tanChallenge.userDidNotEnterTan() }
|
||||
}
|
||||
|
||||
override suspend fun enterTanGeneratorAtc(bank: BankData, tanMedium: TanGeneratorTanMedium): EnterTanGeneratorAtcResult {
|
||||
override suspend fun enterTanGeneratorAtc(bank: BankData, tanMedium: TanMedium): EnterTanGeneratorAtcResult {
|
||||
return enterTanGeneratorAtc?.invoke(bank, tanMedium) ?: EnterTanGeneratorAtcResult.userDidNotEnterAtc()
|
||||
}
|
||||
|
||||
override fun messageLogAdded(messageLogEntry: MessageLogEntry) {
|
||||
messageLogAdded?.invoke(messageLogEntry)
|
||||
}
|
||||
|
||||
}
|
|
@ -1,15 +1,15 @@
|
|||
package net.dankito.banking.fints.config
|
||||
package net.codinux.banking.fints.config
|
||||
|
||||
import net.dankito.banking.fints.FinTsJobExecutor
|
||||
import net.dankito.banking.fints.RequestExecutor
|
||||
import net.dankito.banking.fints.messages.MessageBuilder
|
||||
import net.dankito.banking.fints.model.mapper.ModelMapper
|
||||
import net.dankito.banking.fints.util.FinTsServerAddressFinder
|
||||
import net.dankito.banking.fints.util.IBase64Service
|
||||
import net.dankito.banking.fints.util.PureKotlinBase64Service
|
||||
import net.dankito.banking.fints.util.TanMethodSelector
|
||||
import net.dankito.banking.fints.webclient.IWebClient
|
||||
import net.dankito.banking.fints.webclient.KtorWebClient
|
||||
import net.codinux.banking.fints.FinTsJobExecutor
|
||||
import net.codinux.banking.fints.RequestExecutor
|
||||
import net.codinux.banking.fints.messages.MessageBuilder
|
||||
import net.codinux.banking.fints.model.mapper.ModelMapper
|
||||
import net.codinux.banking.fints.util.FinTsServerAddressFinder
|
||||
import net.codinux.banking.fints.util.IBase64Service
|
||||
import net.codinux.banking.fints.util.PureKotlinBase64Service
|
||||
import net.codinux.banking.fints.util.TanMethodSelector
|
||||
import net.codinux.banking.fints.webclient.IWebClient
|
||||
import net.codinux.banking.fints.webclient.KtorWebClient
|
||||
|
||||
class FinTsClientConfiguration(
|
||||
var options: FinTsClientOptions = FinTsClientOptions(),
|
|
@ -0,0 +1,40 @@
|
|||
package net.codinux.banking.fints.config
|
||||
|
||||
import net.codinux.banking.fints.model.ProductData
|
||||
|
||||
data class FinTsClientOptions(
|
||||
|
||||
/**
|
||||
* If FinTS messages sent to and received from bank servers and errors should be collected. They are then accessible
|
||||
* via [net.codinux.banking.fints.response.client.FinTsClientResponse.messageLog].
|
||||
*
|
||||
* Set to false by default.
|
||||
*/
|
||||
val collectMessageLog: Boolean = false,
|
||||
|
||||
/**
|
||||
* If set to true then [net.codinux.banking.fints.callback.FinTsClientCallback.messageLogAdded] get fired when a
|
||||
* FinTS message get sent to bank server, a FinTS message is received from bank server or an error occurred.
|
||||
*
|
||||
* Defaults to false.
|
||||
*/
|
||||
val fireCallbackOnMessageLogs: Boolean = false,
|
||||
|
||||
/**
|
||||
* If sensitive data like user name, password, login name should be removed from FinTS messages before being logged.
|
||||
*
|
||||
* Defaults to true.
|
||||
*/
|
||||
val removeSensitiveDataFromMessageLog: Boolean = true,
|
||||
|
||||
val appendFinTsMessagesToLog: Boolean = false,
|
||||
|
||||
val closeDialogs: Boolean = true,
|
||||
|
||||
val version: String = "1.0.0", // TODO: get version dynamically
|
||||
val productName: String = "15E53C26816138699C7B6A3E8" // TODO: extract constant // TODO: get product number for fints4k and Bankmeister (if we stick with that name)
|
||||
) {
|
||||
|
||||
val product: ProductData by lazy { ProductData(productName, version) }
|
||||
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package net.codinux.banking.fints.extensions
|
||||
|
||||
import kotlinx.datetime.Clock
|
||||
import kotlinx.datetime.DateTimeUnit
|
||||
import kotlinx.datetime.Instant
|
||||
import kotlinx.datetime.plus
|
||||
|
||||
|
||||
// should actually be named `now()`, but that name is already shadowed by deprecated Instant.Companion.now() method
|
||||
fun Instant.Companion.nowExt(): Instant = Clock.System.now()
|
||||
|
||||
fun Instant.plusMinutes(minutes: Int) = this.plus(minutes, DateTimeUnit.MINUTE)
|
|
@ -1,4 +1,4 @@
|
|||
package net.dankito.banking.fints.extensions
|
||||
package net.codinux.banking.fints.extensions
|
||||
|
||||
import kotlinx.datetime.*
|
||||
import kotlin.js.JsName
|
||||
|
@ -12,7 +12,7 @@ fun LocalDate.Companion.todayAtSystemDefaultTimeZone(): LocalDate {
|
|||
}
|
||||
|
||||
fun LocalDate.Companion.todayAtEuropeBerlin(): LocalDate {
|
||||
return nowAt(TimeZone.europeBerlin)
|
||||
return nowAt(TimeZone.EuropeBerlin)
|
||||
}
|
||||
|
||||
@JsName("nowAtForDate")
|
|
@ -1,4 +1,4 @@
|
|||
package net.dankito.banking.fints.extensions
|
||||
package net.codinux.banking.fints.extensions
|
||||
|
||||
import kotlinx.datetime.*
|
||||
|
||||
|
@ -9,9 +9,9 @@ fun LocalDateTime.Companion.nowAtUtc(): LocalDateTime {
|
|||
}
|
||||
|
||||
fun LocalDateTime.Companion.nowAtEuropeBerlin(): LocalDateTime {
|
||||
return nowAt(TimeZone.europeBerlin)
|
||||
return nowAt(TimeZone.EuropeBerlin)
|
||||
}
|
||||
|
||||
fun LocalDateTime.Companion.nowAt(timeZone: TimeZone): LocalDateTime {
|
||||
return Clock.System.now().toLocalDateTime(timeZone)
|
||||
return Instant.nowExt().toLocalDateTime(timeZone)
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package net.dankito.banking.fints.extensions
|
||||
package net.codinux.banking.fints.extensions
|
||||
|
||||
|
||||
fun Int.toStringWithMinDigits(minimumCountDigits: Int, fillerString: Char = '0'): String {
|
|
@ -0,0 +1,11 @@
|
|||
package net.codinux.banking.fints.extensions
|
||||
|
||||
import kotlinx.datetime.Instant
|
||||
import kotlin.random.Random
|
||||
|
||||
|
||||
fun randomWithSeed(): Random = Random(randomSeed())
|
||||
|
||||
fun randomSeed(): Long {
|
||||
return Instant.nowExt().nanosecondsOfSecond.toLong() + Instant.nowExt().toEpochMilliseconds()
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package net.dankito.banking.fints.extensions
|
||||
package net.codinux.banking.fints.extensions
|
||||
|
||||
|
||||
/**
|
|
@ -1,4 +1,4 @@
|
|||
package net.dankito.banking.fints.extensions
|
||||
package net.codinux.banking.fints.extensions
|
||||
|
||||
|
||||
fun Throwable.getAllExceptionMessagesJoined(maxDepth: Int = 5): String {
|
|
@ -0,0 +1,7 @@
|
|||
package net.codinux.banking.fints.extensions
|
||||
|
||||
import kotlinx.datetime.TimeZone
|
||||
|
||||
|
||||
val TimeZone.Companion.EuropeBerlin: TimeZone
|
||||
get() = TimeZone.of("Europe/Berlin")
|
|
@ -0,0 +1,10 @@
|
|||
package net.codinux.banking.fints.log
|
||||
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
|
||||
interface IMessageLogAppender {
|
||||
|
||||
fun logError(loggingClass: KClass<*>, message: String, e: Throwable? = null)
|
||||
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
package net.codinux.banking.fints.log
|
||||
|
||||
import net.codinux.banking.fints.model.AccountData
|
||||
import net.codinux.banking.fints.model.BankData
|
||||
import net.codinux.banking.fints.model.MessageType
|
||||
import net.codinux.banking.fints.model.JobContextType
|
||||
|
||||
|
||||
class MessageContext(
|
||||
val jobType: JobContextType,
|
||||
val messageType: MessageType,
|
||||
val jobNumber: Int,
|
||||
val dialogNumber: Int,
|
||||
val messageNumber: Int,
|
||||
val bank: BankData,
|
||||
val account: AccountData?
|
||||
) {
|
||||
override fun toString() = "${jobNumber}_${dialogNumber}_$messageNumber ${bank.bankCode} $jobType $messageType"
|
||||
}
|
|
@ -1,19 +1,22 @@
|
|||
package net.dankito.banking.fints.log
|
||||
package net.codinux.banking.fints.log
|
||||
|
||||
import net.codinux.log.LoggerFactory
|
||||
import net.codinux.log.logger
|
||||
import net.dankito.banking.fints.config.FinTsClientOptions
|
||||
import net.dankito.banking.fints.model.BankData
|
||||
import net.dankito.banking.fints.model.MessageLogEntry
|
||||
import net.dankito.banking.fints.model.MessageLogEntryType
|
||||
import net.dankito.banking.fints.extensions.getInnerException
|
||||
import net.dankito.banking.fints.extensions.nthIndexOf
|
||||
import net.dankito.banking.fints.extensions.toStringWithMinDigits
|
||||
import net.dankito.banking.fints.util.FinTsUtils
|
||||
import net.codinux.banking.fints.callback.FinTsClientCallback
|
||||
import net.codinux.banking.fints.config.FinTsClientOptions
|
||||
import net.codinux.banking.fints.model.BankData
|
||||
import net.codinux.banking.fints.model.MessageLogEntry
|
||||
import net.codinux.banking.fints.model.MessageLogEntryType
|
||||
import net.codinux.banking.fints.extensions.getInnerException
|
||||
import net.codinux.banking.fints.extensions.nthIndexOf
|
||||
import net.codinux.banking.fints.extensions.toStringWithMinDigits
|
||||
import net.codinux.banking.fints.response.segments.ReceivedSegment
|
||||
import net.codinux.banking.fints.util.FinTsUtils
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
|
||||
open class MessageLogCollector(
|
||||
private val callback: FinTsClientCallback,
|
||||
private val options: FinTsClientOptions = FinTsClientOptions(),
|
||||
private val finTsUtils: FinTsUtils = FinTsUtils()
|
||||
) {
|
||||
|
@ -34,43 +37,57 @@ open class MessageLogCollector(
|
|||
|
||||
// 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 BankData
|
||||
open val messageLog: List<MessageLogEntry>
|
||||
// safe CPU cycles by only formatting and removing sensitive data if messageLog is really requested
|
||||
get() = _messageLog.map { MessageLogEntry(it.type, it.context, it.messageTrace, createMessageForLog(it), it.error, it.time) }
|
||||
// safe CPU cycles by only removing sensitive data if messageLog is really requested
|
||||
get() = _messageLog.map {
|
||||
val message = createMessageForLog(it)
|
||||
val messageWithoutSensitiveData = if (options.removeSensitiveDataFromMessageLog) {
|
||||
safelyRemoveSensitiveDataFromMessage(message, it.context.bank)
|
||||
} else {
|
||||
message
|
||||
}
|
||||
|
||||
private fun createMessageForLog(logEntry: MessageLogEntry): String {
|
||||
val message = if (logEntry.type == MessageLogEntryType.Error) {
|
||||
logEntry.messageTrace + logEntry.message + (if (logEntry.error != null) NewLine + getStackTrace(logEntry.error!!) else "")
|
||||
} else {
|
||||
logEntry.messageTrace + "\n" + prettyPrintFinTsMessage(logEntry.message)
|
||||
MessageLogEntry(it.type, it.context, it.messageTrace, message, messageWithoutSensitiveData, it.error, it.parsedSegments, it.time)
|
||||
}
|
||||
|
||||
return if (options.removeSensitiveDataFromMessageLog) {
|
||||
safelyRemoveSensitiveDataFromMessage(message, logEntry.context.bank)
|
||||
private fun createMessageForLog(logEntry: MessageLogEntry): String =
|
||||
if (logEntry.type == MessageLogEntryType.Error) {
|
||||
logEntry.message + (if (logEntry.error != null) NewLine + getStackTrace(logEntry.error!!) else "")
|
||||
} else {
|
||||
message
|
||||
logEntry.message
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
open fun addMessageLog(type: MessageLogEntryType, message: String, context: MessageContext) {
|
||||
open fun addMessageLog(type: MessageLogEntryType, message: String, context: MessageContext, parsedSegments: List<ReceivedSegment> = emptyList()) {
|
||||
val messageTrace = createMessageTraceString(type, context)
|
||||
val prettyPrintMessage = prettyPrintMessageIfRequired(message)
|
||||
|
||||
addMessageLogEntry(type, context, messageTrace, message)
|
||||
log.debug { "$messageTrace\n$prettyPrintMessage" }
|
||||
|
||||
log.debug { "$messageTrace\n${prettyPrintFinTsMessage(message)}" }
|
||||
addMessageLogEntry(type, context, messageTrace, prettyPrintMessage, null, parsedSegments)
|
||||
}
|
||||
|
||||
open fun logError(loggingClass: KClass<*>, message: String, context: MessageContext, e: Exception? = null) {
|
||||
open fun logError(loggingClass: KClass<*>, message: String, context: MessageContext, e: Throwable? = null) {
|
||||
val type = MessageLogEntryType.Error
|
||||
val messageTrace = createMessageTraceString(type, context)
|
||||
val prettyPrintMessage = prettyPrintFinTsMessage(message) // error messages almost always get logged / displayed -> pretty print
|
||||
|
||||
LoggerFactory.getLogger(loggingClass).error(e) { messageTrace + messageTrace }
|
||||
LoggerFactory.getLogger(loggingClass).error(e) { "$messageTrace\n$prettyPrintMessage" }
|
||||
|
||||
addMessageLogEntry(type, context, messageTrace, message, e)
|
||||
addMessageLogEntry(type, context, messageTrace, prettyPrintMessage, e)
|
||||
}
|
||||
|
||||
protected open fun addMessageLogEntry(type: MessageLogEntryType, context: MessageContext, messageTrace: String, message: String, error: Throwable? = null) {
|
||||
_messageLog.add(MessageLogEntry(type, context, messageTrace, message, error))
|
||||
protected open fun addMessageLogEntry(type: MessageLogEntryType, context: MessageContext, messageTrace: String, message: String, error: Throwable? = null, parsedSegments: List<ReceivedSegment> = emptyList()) {
|
||||
if (options.collectMessageLog || options.fireCallbackOnMessageLogs) {
|
||||
val newEntry = MessageLogEntry(type, context, messageTrace, message, null, error, parsedSegments)
|
||||
|
||||
if (options.collectMessageLog) {
|
||||
_messageLog.add(newEntry)
|
||||
}
|
||||
|
||||
if (options.fireCallbackOnMessageLogs) {
|
||||
callback.messageLogAdded(newEntry)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -78,7 +95,7 @@ open class MessageLogCollector(
|
|||
return "${twoDigits(context.jobNumber)}_${twoDigits(context.dialogNumber)}_${twoDigits(context.messageNumber)}_" +
|
||||
"${context.bank.bankCode}_${context.bank.customerId}" +
|
||||
"${ context.account?.let { "_${it.accountIdentifier}" } ?: "" }_" +
|
||||
"${context.jobType.name}_${context.dialogType.name} " +
|
||||
"${context.jobType.name}_${context.messageType.name} " +
|
||||
"${getMessageTypeString(type)}:"
|
||||
}
|
||||
|
||||
|
@ -88,12 +105,19 @@ open class MessageLogCollector(
|
|||
|
||||
protected open fun getMessageTypeString(type: MessageLogEntryType): String {
|
||||
return when (type) {
|
||||
MessageLogEntryType.Sent -> "Sending message"
|
||||
MessageLogEntryType.Received -> "Received message"
|
||||
MessageLogEntryType.Error -> "Error"
|
||||
MessageLogEntryType.Sent -> "01 Sending message"
|
||||
MessageLogEntryType.Received -> "02 Received message"
|
||||
MessageLogEntryType.Error -> "03 Error"
|
||||
}
|
||||
}
|
||||
|
||||
protected open fun prettyPrintMessageIfRequired(message: String): String =
|
||||
if (options.collectMessageLog || options.fireCallbackOnMessageLogs || log.isDebugEnabled) { // only use CPU cycles if message will ever be used / displayed
|
||||
prettyPrintFinTsMessage(message)
|
||||
} else {
|
||||
message
|
||||
}
|
||||
|
||||
protected open fun prettyPrintFinTsMessage(message: String): String =
|
||||
finTsUtils.prettyPrintFinTsMessage(message)
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package net.dankito.banking.fints.mapper
|
||||
package net.codinux.banking.fints.mapper
|
||||
|
||||
import kotlinx.datetime.LocalDate
|
||||
import net.dankito.banking.client.model.*
|
||||
|
@ -7,14 +7,14 @@ import net.dankito.banking.client.model.parameter.FinTsClientParameter
|
|||
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.messages.datenelemente.abgeleiteteformate.Laenderkennzeichen
|
||||
import net.dankito.banking.fints.model.*
|
||||
import net.dankito.banking.fints.response.client.FinTsClientResponse
|
||||
import net.dankito.banking.fints.response.client.GetAccountTransactionsResponse
|
||||
import net.dankito.banking.fints.response.segments.AccountType
|
||||
import net.dankito.banking.fints.util.BicFinder
|
||||
import net.dankito.banking.fints.extensions.minusDays
|
||||
import net.dankito.banking.fints.extensions.todayAtEuropeBerlin
|
||||
import net.codinux.banking.fints.messages.datenelemente.abgeleiteteformate.Laenderkennzeichen
|
||||
import net.codinux.banking.fints.model.*
|
||||
import net.codinux.banking.fints.response.client.FinTsClientResponse
|
||||
import net.codinux.banking.fints.response.client.GetAccountTransactionsResponse
|
||||
import net.codinux.banking.fints.response.segments.AccountType
|
||||
import net.codinux.banking.fints.util.BicFinder
|
||||
import net.codinux.banking.fints.extensions.minusDays
|
||||
import net.codinux.banking.fints.extensions.todayAtEuropeBerlin
|
||||
|
||||
|
||||
open class FinTsModelMapper {
|
||||
|
@ -22,8 +22,11 @@ open class FinTsModelMapper {
|
|||
protected open val bicFinder = BicFinder()
|
||||
|
||||
|
||||
open fun mapToBankData(param: FinTsClientParameter, finTsServerAddress: String): BankData {
|
||||
return BankData(param.bankCode, param.loginName, param.password, finTsServerAddress, bicFinder.findBic(param.bankCode) ?: "")
|
||||
open fun mapToBankData(param: FinTsClientParameter, finTsServerAddress: String, defaultValues: BankData? = null): BankData {
|
||||
return BankData(
|
||||
param.bankCode, param.loginName, param.password, finTsServerAddress,
|
||||
defaultValues?.bic ?: bicFinder.findBic(param.bankCode) ?: "", defaultValues?.bankName ?: ""
|
||||
)
|
||||
}
|
||||
|
||||
open fun mapToAccountData(credentials: BankAccountIdentifier, param: FinTsClientParameter): AccountData {
|
||||
|
@ -51,7 +54,7 @@ open class FinTsModelMapper {
|
|||
|
||||
open fun map(account: AccountData): BankAccount {
|
||||
return BankAccount(account.accountIdentifier, account.subAccountAttribute, account.iban, account.accountHolderName, map(account.accountType), account.productName,
|
||||
account.currency ?: Currency.DefaultCurrencyCode, account.accountLimit, account.countDaysForWhichTransactionsAreKept, account.isAccountTypeSupportedByApplication,
|
||||
account.currency ?: Currency.DefaultCurrencyCode, account.accountLimit, account.serverTransactionsRetentionDays, account.isAccountTypeSupportedByApplication,
|
||||
account.supportsRetrievingAccountTransactions, account.supportsRetrievingBalance, account.supportsTransferringMoney, account.supportsRealTimeTransfer)
|
||||
}
|
||||
|
||||
|
@ -70,16 +73,34 @@ open class FinTsModelMapper {
|
|||
}
|
||||
}
|
||||
|
||||
open fun map(bank: BankData, retrievedTransactionsResponses: List<GetAccountTransactionsResponse>): CustomerAccount {
|
||||
open fun map(bank: BankData, retrievedTransactionsResponses: List<GetAccountTransactionsResponse>, retrieveTransactionsTo: LocalDate? = null): CustomerAccount {
|
||||
val customerAccount = map(bank)
|
||||
val retrievedData = retrievedTransactionsResponses.mapNotNull { it.retrievedData }
|
||||
|
||||
customerAccount.accounts.forEach { bankAccount ->
|
||||
retrievedData.firstOrNull { it.account.accountIdentifier == bankAccount.identifier }?.let { accountTransactionsResponse ->
|
||||
bankAccount.balance = accountTransactionsResponse.balance ?: Money.Zero
|
||||
bankAccount.retrievedTransactionsFrom = accountTransactionsResponse.retrievedTransactionsFrom
|
||||
bankAccount.retrievedTransactionsTo = accountTransactionsResponse.retrievedTransactionsTo
|
||||
bankAccount.bookedTransactions = map(accountTransactionsResponse)
|
||||
accountTransactionsResponse.balance?.let { balance ->
|
||||
bankAccount.balance = balance
|
||||
}
|
||||
|
||||
if (accountTransactionsResponse.retrievedTransactionsFrom != null && (bankAccount.retrievedTransactionsFrom == null ||
|
||||
accountTransactionsResponse.retrievedTransactionsFrom!! < bankAccount.retrievedTransactionsFrom!!)) {
|
||||
bankAccount.retrievedTransactionsFrom = accountTransactionsResponse.retrievedTransactionsFrom
|
||||
}
|
||||
|
||||
val retrievalTime = accountTransactionsResponse.retrievalTime
|
||||
if (retrieveTransactionsTo == null && (bankAccount.lastAccountUpdateTime == null || bankAccount.lastAccountUpdateTime!! <= retrievalTime || // if retrieveTransactionsTo is set, then we don't retrieve all current transactions -> don't set lastAccountUpdateTime
|
||||
(bankAccount.supportsRetrievingTransactions == false && accountTransactionsResponse.statementOfHoldings.isNotEmpty()))) { // TODO: really check for supportsRetrievingTransactions == false if statementOfHoldings are set? Are there really accounts that support HKWPD and HKKAZ?
|
||||
bankAccount.lastAccountUpdateTime = retrievalTime
|
||||
}
|
||||
|
||||
if (accountTransactionsResponse.bookedTransactions.isNotEmpty()) {
|
||||
bankAccount.bookedTransactions = bankAccount.bookedTransactions.toMutableList().apply {
|
||||
addAll(map(accountTransactionsResponse))
|
||||
}
|
||||
}
|
||||
|
||||
bankAccount.statementOfHoldings = accountTransactionsResponse.statementOfHoldings
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -90,15 +111,29 @@ open class FinTsModelMapper {
|
|||
return data.bookedTransactions.map { map(it) }
|
||||
}
|
||||
|
||||
open fun map(transaction: net.dankito.banking.fints.model.AccountTransaction): AccountTransaction {
|
||||
return AccountTransaction(transaction.amount, transaction.unparsedReference, transaction.bookingDate,
|
||||
transaction.otherPartyName, transaction.otherPartyBankCode, transaction.otherPartyAccountId, transaction.bookingText, transaction.valueDate,
|
||||
transaction.statementNumber, transaction.sequenceNumber, transaction.openingBalance, transaction.closingBalance,
|
||||
transaction.endToEndReference, transaction.customerReference, transaction.mandateReference, transaction.creditorIdentifier, transaction.originatorsIdentificationCode,
|
||||
transaction.compensationAmount, transaction.originalAmount, transaction.sepaReference, transaction.deviantOriginator, transaction.deviantRecipient,
|
||||
transaction.referenceWithNoSpecialType, transaction.primaNotaNumber, transaction.textKeySupplement,
|
||||
transaction.currencyType, transaction.bookingKey, transaction.referenceForTheAccountOwner, transaction.referenceOfTheAccountServicingInstitution, transaction.supplementaryDetails,
|
||||
transaction.transactionReferenceNumber, transaction.relatedReferenceNumber)
|
||||
open fun map(transaction: net.codinux.banking.fints.model.AccountTransaction): AccountTransaction {
|
||||
return AccountTransaction(
|
||||
transaction.amount, transaction.reference,
|
||||
transaction.bookingDate, transaction.valueDate,
|
||||
transaction.otherPartyName, transaction.otherPartyBankId, transaction.otherPartyAccountId,
|
||||
|
||||
transaction.postingText,
|
||||
|
||||
transaction.openingBalance, transaction.closingBalance,
|
||||
|
||||
transaction.statementNumber, transaction.sheetNumber,
|
||||
|
||||
transaction.customerReference, transaction.bankReference, transaction.furtherInformation,
|
||||
|
||||
transaction.endToEndReference, transaction.mandateReference, transaction.creditorIdentifier, transaction.originatorsIdentificationCode,
|
||||
transaction.compensationAmount, transaction.originalAmount, transaction.deviantOriginator, transaction.deviantRecipient,
|
||||
transaction.referenceWithNoSpecialType,
|
||||
|
||||
transaction.journalNumber, transaction.textKeyAddition,
|
||||
transaction.orderReferenceNumber, transaction.referenceNumber,
|
||||
|
||||
transaction.isReversal
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
|
@ -157,6 +192,10 @@ open class FinTsModelMapper {
|
|||
else errorMessages.joinToString("\r\n")
|
||||
}
|
||||
|
||||
open fun mergeMessageLog(vararg messageLogs: List<MessageLogEntry>?): List<MessageLogEntry> {
|
||||
return messageLogs.filterNotNull().flatten()
|
||||
}
|
||||
|
||||
open fun mergeMessageLog(vararg responses: FinTsClientResponse?): List<MessageLogEntry> {
|
||||
return responses.filterNotNull().flatMap { it.messageLog }
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package net.dankito.banking.fints.messages
|
||||
package net.codinux.banking.fints.messages
|
||||
|
||||
|
||||
enum class Existenzstatus {
|
|
@ -1,4 +1,4 @@
|
|||
package net.dankito.banking.fints.messages
|
||||
package net.codinux.banking.fints.messages
|
||||
|
||||
import io.ktor.utils.io.charsets.Charsets
|
||||
|
|
@ -1,26 +1,24 @@
|
|||
package net.dankito.banking.fints.messages
|
||||
package net.codinux.banking.fints.messages
|
||||
|
||||
import net.dankito.banking.fints.extensions.randomWithSeed
|
||||
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
|
||||
import net.dankito.banking.fints.messages.datenelemente.implementierte.tan.TanGeneratorTanMedium
|
||||
import net.dankito.banking.fints.messages.datenelemente.implementierte.tan.TanMedienArtVersion
|
||||
import net.dankito.banking.fints.messages.datenelemente.implementierte.tan.TanMediumKlasse
|
||||
import net.dankito.banking.fints.messages.datenelemente.implementierte.tan.TanProcess
|
||||
import net.dankito.banking.fints.messages.segmente.Segment
|
||||
import net.dankito.banking.fints.messages.segmente.Synchronisierung
|
||||
import net.dankito.banking.fints.messages.segmente.id.CustomerSegmentId
|
||||
import net.dankito.banking.fints.messages.segmente.id.ISegmentId
|
||||
import net.dankito.banking.fints.messages.segmente.implementierte.*
|
||||
import net.dankito.banking.fints.messages.segmente.implementierte.sepa.SepaBankTransferBase
|
||||
import net.dankito.banking.fints.messages.segmente.implementierte.tan.TanGeneratorListeAnzeigen
|
||||
import net.dankito.banking.fints.messages.segmente.implementierte.tan.TanGeneratorTanMediumAnOderUmmelden
|
||||
import net.dankito.banking.fints.messages.segmente.implementierte.umsaetze.*
|
||||
import net.dankito.banking.fints.model.*
|
||||
import net.dankito.banking.fints.response.InstituteSegmentId
|
||||
import net.dankito.banking.fints.response.segments.*
|
||||
import net.dankito.banking.fints.util.FinTsUtils
|
||||
import net.codinux.banking.fints.extensions.randomWithSeed
|
||||
import net.codinux.banking.fints.messages.datenelemente.implementierte.Aufsetzpunkt
|
||||
import net.codinux.banking.fints.messages.datenelemente.implementierte.KundensystemID
|
||||
import net.codinux.banking.fints.messages.datenelemente.implementierte.Synchronisierungsmodus
|
||||
import net.codinux.banking.fints.messages.datenelemente.implementierte.tan.*
|
||||
import net.codinux.banking.fints.messages.segmente.Segment
|
||||
import net.codinux.banking.fints.messages.segmente.Synchronisierung
|
||||
import net.codinux.banking.fints.messages.segmente.id.CustomerSegmentId
|
||||
import net.codinux.banking.fints.messages.segmente.id.ISegmentId
|
||||
import net.codinux.banking.fints.messages.segmente.implementierte.*
|
||||
import net.codinux.banking.fints.messages.segmente.implementierte.depot.Depotaufstellung
|
||||
import net.codinux.banking.fints.messages.segmente.implementierte.sepa.SepaBankTransferBase
|
||||
import net.codinux.banking.fints.messages.segmente.implementierte.tan.TanGeneratorListeAnzeigen
|
||||
import net.codinux.banking.fints.messages.segmente.implementierte.tan.TanGeneratorTanMediumAnOderUmmelden
|
||||
import net.codinux.banking.fints.messages.segmente.implementierte.umsaetze.*
|
||||
import net.codinux.banking.fints.model.*
|
||||
import net.codinux.banking.fints.response.InstituteSegmentId
|
||||
import net.codinux.banking.fints.response.segments.*
|
||||
import net.codinux.banking.fints.util.FinTsUtils
|
||||
import kotlin.math.absoluteValue
|
||||
|
||||
|
||||
|
@ -41,7 +39,7 @@ open class MessageBuilder(protected val utils: FinTsUtils = FinTsUtils()) {
|
|||
|
||||
private const val SignatureHeaderSegmentNumber = MessageHeaderSegmentNumber + 1
|
||||
|
||||
private const val SignedMessagePayloadFirstSegmentNumber = SignatureHeaderSegmentNumber + 1
|
||||
const val SignedMessagePayloadFirstSegmentNumber = SignatureHeaderSegmentNumber + 1
|
||||
}
|
||||
|
||||
|
||||
|
@ -133,7 +131,7 @@ open class MessageBuilder(protected val utils: FinTsUtils = FinTsUtils()) {
|
|||
}
|
||||
|
||||
if (context.bank.customerSystemId == KundensystemID.Anonymous) {
|
||||
segments.add(Synchronisierung(segments.size + 3, Synchronisierungsmodus.NeueKundensystemIdZurueckmelden))
|
||||
segments.add(Synchronisierung(SignedMessagePayloadFirstSegmentNumber + segments.size, Synchronisierungsmodus.NeueKundensystemIdZurueckmelden))
|
||||
}
|
||||
|
||||
return createSignedMessageBuilderResult(context, MessageType.DialogInit, segments)
|
||||
|
@ -242,17 +240,38 @@ open class MessageBuilder(protected val utils: FinTsUtils = FinTsUtils()) {
|
|||
return createSignedMessageBuilderResult(context, MessageType.GetBalance, segments)
|
||||
}
|
||||
|
||||
val securitiesAccountResult = supportsGetSecuritiesAccountBalance(account)
|
||||
|
||||
if (securitiesAccountResult.isJobVersionSupported) {
|
||||
return createGetSecuritiesAccountBalanceMessage(context, result, account)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
protected open fun createGetSecuritiesAccountBalanceMessage(context: JobContext, result: MessageBuilderResult,
|
||||
account: AccountData): MessageBuilderResult {
|
||||
|
||||
val segments = mutableListOf<Segment>(Depotaufstellung(SignedMessagePayloadFirstSegmentNumber, account))
|
||||
|
||||
addTanSegmentIfRequired(context, CustomerSegmentId.SecuritiesAccountBalance, segments, SignedMessagePayloadFirstSegmentNumber + 1)
|
||||
|
||||
return createSignedMessageBuilderResult(context, MessageType.GetSecuritiesAccountBalance, segments)
|
||||
}
|
||||
|
||||
open fun supportsGetBalance(account: AccountData): Boolean {
|
||||
return supportsGetBalanceMessage(account).isJobVersionSupported
|
||||
|| supportsGetSecuritiesAccountBalance(account).isJobVersionSupported
|
||||
}
|
||||
|
||||
protected open fun supportsGetBalanceMessage(account: AccountData): MessageBuilderResult {
|
||||
return getSupportedVersionsOfJobForAccount(CustomerSegmentId.Balance, account, listOf(5, 6, 7, 8))
|
||||
}
|
||||
|
||||
protected open fun supportsGetSecuritiesAccountBalance(account: AccountData): MessageBuilderResult {
|
||||
return getSupportedVersionsOfJobForAccount(CustomerSegmentId.SecuritiesAccountBalance, account, listOf(6))
|
||||
}
|
||||
|
||||
|
||||
open fun createGetTanMediaListMessage(context: JobContext,
|
||||
tanMediaKind: TanMedienArtVersion = TanMedienArtVersion.Alle,
|
||||
|
@ -272,7 +291,7 @@ open class MessageBuilder(protected val utils: FinTsUtils = FinTsUtils()) {
|
|||
}
|
||||
|
||||
// TODO: no HKTAN needed?
|
||||
open fun createChangeTanMediumMessage(context: JobContext, newActiveTanMedium: TanGeneratorTanMedium,
|
||||
open fun createChangeTanMediumMessage(context: JobContext, newActiveTanMedium: TanMedium,
|
||||
tan: String? = null, atc: Int? = null): MessageBuilderResult {
|
||||
|
||||
val result = getSupportedVersionsOfJobForBank(CustomerSegmentId.ChangeTanMedium, context.bank, listOf(1, 2, 3))
|
||||
|
@ -295,12 +314,22 @@ open class MessageBuilder(protected val utils: FinTsUtils = FinTsUtils()) {
|
|||
|
||||
val segments = listOf(
|
||||
ZweiSchrittTanEinreichung(SignedMessagePayloadFirstSegmentNumber, tanProcess, null,
|
||||
tanResponse.jobHashValue, tanResponse.jobReference, false, null, tanResponse.tanMediaIdentifier)
|
||||
tanResponse.jobHashValue, tanResponse.jobReference, false, null, tanResponse.tanMediaIdentifier, tanResponse.segmentVersion)
|
||||
)
|
||||
|
||||
return createSignedMessageBuilderResult(context, MessageType.Tan, createSignedMessage(context, enteredTan, segments), segments)
|
||||
}
|
||||
|
||||
open fun createDecoupledTanStatusMessage(context: JobContext, tanResponse: TanResponse): MessageBuilderResult {
|
||||
|
||||
val segments = listOf(
|
||||
ZweiSchrittTanEinreichung(SignedMessagePayloadFirstSegmentNumber, TanProcess.AppTan,
|
||||
jobReference = tanResponse.jobReference, furtherTanFollows = false, segmentVersion = 7, tanMediaIdentifier = tanResponse.tanMediaIdentifier)
|
||||
)
|
||||
|
||||
return createSignedMessageBuilderResult(context, MessageType.CheckDecoupledTanStatus, createSignedMessage(context, null, segments), segments)
|
||||
}
|
||||
|
||||
|
||||
open fun createBankTransferMessage(context: JobContext, data: BankTransferData, account: AccountData): MessageBuilderResult {
|
||||
|
||||
|
@ -394,7 +423,7 @@ open class MessageBuilder(protected val utils: FinTsUtils = FinTsUtils()) {
|
|||
return createSignedMessage(context, null, payloadSegments)
|
||||
}
|
||||
|
||||
open fun createSignedMessage(context: JobContext, tan: String? = null, payloadSegments: List<Segment>): String {
|
||||
protected open fun createSignedMessage(context: JobContext, tan: String? = null, payloadSegments: List<Segment>): String {
|
||||
|
||||
val date = utils.formatDateTodayAsInt()
|
||||
val time = utils.formatTimeNowAsInt()
|
||||
|
@ -406,7 +435,7 @@ open class MessageBuilder(protected val utils: FinTsUtils = FinTsUtils()) {
|
|||
return createMessage(context, encryptedPayload, payloadSegments.size)
|
||||
}
|
||||
|
||||
open fun createMessage(context: JobContext, payloadSegments: List<Segment>, countWrappedSegments: Int = 0): String {
|
||||
protected open fun createMessage(context: JobContext, payloadSegments: List<Segment>, countWrappedSegments: Int = 0): String {
|
||||
|
||||
val dialog = context.dialog
|
||||
dialog.increaseMessageNumber()
|
||||
|
@ -521,8 +550,10 @@ open class MessageBuilder(protected val utils: FinTsUtils = FinTsUtils()) {
|
|||
}
|
||||
|
||||
protected open fun createTwoStepTanSegment(context: JobContext, segmentId: CustomerSegmentId, segmentNumber: Int): ZweiSchrittTanEinreichung {
|
||||
val bank = context.bank
|
||||
|
||||
return ZweiSchrittTanEinreichung(segmentNumber, TanProcess.TanProcess4, segmentId,
|
||||
tanMediaIdentifier = getTanMediaIdentifierIfRequired(context))
|
||||
tanMediaIdentifier = getTanMediaIdentifierIfRequired(context), segmentVersion = bank.selectedTanMethod.hktanVersion)
|
||||
}
|
||||
|
||||
protected open fun getTanMediaIdentifierIfRequired(context: JobContext): String? {
|
||||
|
@ -536,8 +567,7 @@ open class MessageBuilder(protected val utils: FinTsUtils = FinTsUtils()) {
|
|||
}
|
||||
|
||||
protected open fun isTanRequiredForJob(context: JobContext, segmentId: CustomerSegmentId): Boolean {
|
||||
return context.bank.pinInfo?.jobTanConfiguration?.first { it.segmentId == segmentId.id }?.tanRequired
|
||||
?: false // TODO: actually in this case it's not allowed to execute job via PIN/TAN at all
|
||||
return context.bank.doesJobRequireTan(segmentId)
|
||||
}
|
||||
|
||||
protected open fun getSepaUrnFor(segmentId: CustomerSegmentId, bank: BankData, sepaDataFormat: String): String? {
|
|
@ -1,7 +1,9 @@
|
|||
package net.dankito.banking.fints.messages
|
||||
package net.codinux.banking.fints.messages
|
||||
|
||||
import net.dankito.banking.fints.messages.segmente.Segment
|
||||
import net.dankito.banking.fints.messages.segmente.implementierte.ZweiSchrittTanEinreichung
|
||||
import net.codinux.banking.fints.messages.datenelementgruppen.implementierte.Segmentkopf
|
||||
import net.codinux.banking.fints.messages.segmente.Segment
|
||||
import net.codinux.banking.fints.messages.segmente.implementierte.Verarbeitungsvorbereitung
|
||||
import net.codinux.banking.fints.messages.segmente.implementierte.ZweiSchrittTanEinreichung
|
||||
|
||||
|
||||
open class MessageBuilderResult(
|
||||
|
@ -32,4 +34,10 @@ open class MessageBuilderResult(
|
|||
&& messageBodySegments.first() is ZweiSchrittTanEinreichung
|
||||
}
|
||||
|
||||
open fun isDialogInitMessage(): Boolean =
|
||||
messageBodySegments.any { it is Verarbeitungsvorbereitung }
|
||||
|
||||
|
||||
override fun toString() = "${messageBodySegments.joinToString { (it.dataElementsAndGroups.firstOrNull() as? Segmentkopf)?.let { "${it.identifier}:${it.segmentVersion}" } ?: "<No Segment header>" } }}"
|
||||
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
package net.dankito.banking.fints.messages
|
||||
package net.codinux.banking.fints.messages
|
||||
|
||||
import net.dankito.banking.fints.util.MessageUtils
|
||||
import net.codinux.banking.fints.util.MessageUtils
|
||||
|
||||
|
||||
abstract class Nachrichtenteil(protected val messageUtils: MessageUtils = MessageUtils()) {
|
|
@ -1,4 +1,4 @@
|
|||
package net.dankito.banking.fints.messages
|
||||
package net.codinux.banking.fints.messages
|
||||
|
||||
|
||||
class Separators {
|
|
@ -1,6 +1,6 @@
|
|||
package net.dankito.banking.fints.messages.datenelemente
|
||||
package net.codinux.banking.fints.messages.datenelemente
|
||||
|
||||
import net.dankito.banking.fints.messages.Existenzstatus
|
||||
import net.codinux.banking.fints.messages.Existenzstatus
|
||||
|
||||
|
||||
abstract class Datenelement(existenzstatus: Existenzstatus): DatenelementBase(existenzstatus) {
|
|
@ -0,0 +1,7 @@
|
|||
package net.codinux.banking.fints.messages.datenelemente
|
||||
|
||||
import net.codinux.banking.fints.messages.Existenzstatus
|
||||
import net.codinux.banking.fints.messages.Nachrichtenteil
|
||||
|
||||
|
||||
abstract class DatenelementBase(val existenzstatus: Existenzstatus) : Nachrichtenteil()
|
|
@ -1,8 +1,8 @@
|
|||
package net.dankito.banking.fints.messages.datenelemente.abgeleiteteformate
|
||||
package net.codinux.banking.fints.messages.datenelemente.abgeleiteteformate
|
||||
|
||||
import net.dankito.banking.fints.messages.Existenzstatus
|
||||
import net.dankito.banking.fints.messages.datenelemente.basisformate.AlphanumerischesDatenelement
|
||||
import net.dankito.banking.fints.messages.datenelemente.implementierte.ICodeEnum
|
||||
import net.codinux.banking.fints.messages.Existenzstatus
|
||||
import net.codinux.banking.fints.messages.datenelemente.basisformate.AlphanumerischesDatenelement
|
||||
import net.codinux.banking.fints.messages.datenelemente.implementierte.ICodeEnum
|
||||
|
||||
|
||||
/**
|
|
@ -1,10 +1,10 @@
|
|||
package net.dankito.banking.fints.messages.datenelemente.abgeleiteteformate
|
||||
package net.codinux.banking.fints.messages.datenelemente.abgeleiteteformate
|
||||
|
||||
import kotlinx.datetime.LocalDate
|
||||
import net.codinux.log.logger
|
||||
import net.dankito.banking.fints.extensions.toStringWithMinDigits
|
||||
import net.dankito.banking.fints.messages.Existenzstatus
|
||||
import net.dankito.banking.fints.messages.datenelemente.basisformate.NumerischesDatenelement
|
||||
import net.codinux.banking.fints.extensions.toStringWithMinDigits
|
||||
import net.codinux.banking.fints.messages.Existenzstatus
|
||||
import net.codinux.banking.fints.messages.datenelemente.basisformate.NumerischesDatenelement
|
||||
|
||||
|
||||
/**
|
|
@ -1,7 +1,7 @@
|
|||
package net.dankito.banking.fints.messages.datenelemente.abgeleiteteformate
|
||||
package net.codinux.banking.fints.messages.datenelemente.abgeleiteteformate
|
||||
|
||||
import net.dankito.banking.fints.messages.Existenzstatus
|
||||
import net.dankito.banking.fints.messages.datenelemente.basisformate.AlphanumerischesDatenelement
|
||||
import net.codinux.banking.fints.messages.Existenzstatus
|
||||
import net.codinux.banking.fints.messages.datenelemente.basisformate.AlphanumerischesDatenelement
|
||||
|
||||
|
||||
/**
|
|
@ -1,7 +1,7 @@
|
|||
package net.dankito.banking.fints.messages.datenelemente.abgeleiteteformate
|
||||
package net.codinux.banking.fints.messages.datenelemente.abgeleiteteformate
|
||||
|
||||
import net.dankito.banking.fints.messages.Existenzstatus
|
||||
import net.dankito.banking.fints.messages.datenelemente.basisformate.AlphanumerischesDatenelement
|
||||
import net.codinux.banking.fints.messages.Existenzstatus
|
||||
import net.codinux.banking.fints.messages.datenelemente.basisformate.AlphanumerischesDatenelement
|
||||
|
||||
|
||||
/**
|
|
@ -1,7 +1,7 @@
|
|||
package net.dankito.banking.fints.messages.datenelemente.abgeleiteteformate
|
||||
package net.codinux.banking.fints.messages.datenelemente.abgeleiteteformate
|
||||
|
||||
import net.dankito.banking.fints.messages.Existenzstatus
|
||||
import net.dankito.banking.fints.messages.datenelemente.basisformate.ZiffernDatenelement
|
||||
import net.codinux.banking.fints.messages.Existenzstatus
|
||||
import net.codinux.banking.fints.messages.datenelemente.basisformate.ZiffernDatenelement
|
||||
|
||||
|
||||
/**
|
|
@ -1,10 +1,10 @@
|
|||
package net.dankito.banking.fints.messages.datenelemente.abgeleiteteformate
|
||||
package net.codinux.banking.fints.messages.datenelemente.abgeleiteteformate
|
||||
|
||||
import kotlinx.datetime.LocalTime
|
||||
import net.codinux.log.logger
|
||||
import net.dankito.banking.fints.extensions.toStringWithMinDigits
|
||||
import net.dankito.banking.fints.messages.Existenzstatus
|
||||
import net.dankito.banking.fints.messages.datenelemente.basisformate.ZiffernDatenelement
|
||||
import net.codinux.banking.fints.extensions.toStringWithMinDigits
|
||||
import net.codinux.banking.fints.messages.Existenzstatus
|
||||
import net.codinux.banking.fints.messages.datenelemente.basisformate.ZiffernDatenelement
|
||||
|
||||
|
||||
/**
|
|
@ -1,6 +1,6 @@
|
|||
package net.dankito.banking.fints.messages.datenelemente.basisformate
|
||||
package net.codinux.banking.fints.messages.datenelemente.basisformate
|
||||
|
||||
import net.dankito.banking.fints.messages.Existenzstatus
|
||||
import net.codinux.banking.fints.messages.Existenzstatus
|
||||
|
||||
|
||||
/**
|
|
@ -1,6 +1,6 @@
|
|||
package net.dankito.banking.fints.messages.datenelemente.basisformate
|
||||
package net.codinux.banking.fints.messages.datenelemente.basisformate
|
||||
|
||||
import net.dankito.banking.fints.messages.Existenzstatus
|
||||
import net.codinux.banking.fints.messages.Existenzstatus
|
||||
|
||||
|
||||
/**
|
|
@ -1,6 +1,6 @@
|
|||
package net.dankito.banking.fints.messages.datenelemente.basisformate
|
||||
package net.codinux.banking.fints.messages.datenelemente.basisformate
|
||||
|
||||
import net.dankito.banking.fints.messages.Existenzstatus
|
||||
import net.codinux.banking.fints.messages.Existenzstatus
|
||||
|
||||
|
||||
/**
|
|
@ -1,11 +1,11 @@
|
|||
package net.dankito.banking.fints.messages.datenelemente.basisformate
|
||||
package net.codinux.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
|
||||
import net.dankito.banking.fints.messages.datenelemente.Datenelement
|
||||
import net.codinux.banking.fints.messages.Existenzstatus
|
||||
import net.codinux.banking.fints.messages.HbciCharset
|
||||
import net.codinux.banking.fints.messages.Separators
|
||||
import net.codinux.banking.fints.messages.datenelemente.Datenelement
|
||||
|
||||
|
||||
/**
|
|
@ -1,6 +1,6 @@
|
|||
package net.dankito.banking.fints.messages.datenelemente.basisformate
|
||||
package net.codinux.banking.fints.messages.datenelemente.basisformate
|
||||
|
||||
import net.dankito.banking.fints.messages.Existenzstatus
|
||||
import net.codinux.banking.fints.messages.Existenzstatus
|
||||
|
||||
|
||||
/**
|
|
@ -1,7 +1,7 @@
|
|||
package net.dankito.banking.fints.messages.datenelemente.implementierte
|
||||
package net.codinux.banking.fints.messages.datenelemente.implementierte
|
||||
|
||||
import net.dankito.banking.fints.messages.Existenzstatus
|
||||
import net.dankito.banking.fints.messages.datenelemente.basisformate.AlphanumerischesDatenelement
|
||||
import net.codinux.banking.fints.messages.Existenzstatus
|
||||
import net.codinux.banking.fints.messages.datenelemente.basisformate.AlphanumerischesDatenelement
|
||||
|
||||
|
||||
/**
|
|
@ -1,7 +1,7 @@
|
|||
package net.dankito.banking.fints.messages.datenelemente.implementierte
|
||||
package net.codinux.banking.fints.messages.datenelemente.implementierte
|
||||
|
||||
import net.dankito.banking.fints.messages.Existenzstatus
|
||||
import net.dankito.banking.fints.messages.datenelemente.basisformate.NumerischesDatenelement
|
||||
import net.codinux.banking.fints.messages.Existenzstatus
|
||||
import net.codinux.banking.fints.messages.datenelemente.basisformate.NumerischesDatenelement
|
||||
|
||||
|
||||
/**
|
|
@ -1,7 +1,7 @@
|
|||
package net.dankito.banking.fints.messages.datenelemente.implementierte
|
||||
package net.codinux.banking.fints.messages.datenelemente.implementierte
|
||||
|
||||
import net.dankito.banking.fints.messages.Existenzstatus
|
||||
import net.dankito.banking.fints.messages.datenelemente.abgeleiteteformate.Identifikation
|
||||
import net.codinux.banking.fints.messages.Existenzstatus
|
||||
import net.codinux.banking.fints.messages.datenelemente.abgeleiteteformate.Identifikation
|
||||
|
||||
|
||||
/**
|
|
@ -1,7 +1,7 @@
|
|||
package net.dankito.banking.fints.messages.datenelemente.implementierte
|
||||
package net.codinux.banking.fints.messages.datenelemente.implementierte
|
||||
|
||||
import net.dankito.banking.fints.messages.Existenzstatus
|
||||
import net.dankito.banking.fints.messages.datenelemente.basisformate.NumerischesDatenelement
|
||||
import net.codinux.banking.fints.messages.Existenzstatus
|
||||
import net.codinux.banking.fints.messages.datenelemente.basisformate.NumerischesDatenelement
|
||||
|
||||
|
||||
/**
|
|
@ -1,6 +1,6 @@
|
|||
package net.dankito.banking.fints.messages.datenelemente.implementierte
|
||||
package net.codinux.banking.fints.messages.datenelemente.implementierte
|
||||
|
||||
import net.dankito.banking.fints.messages.Existenzstatus
|
||||
import net.codinux.banking.fints.messages.Existenzstatus
|
||||
|
||||
|
||||
open class BezugssegmentInKreditinstitutsnachricht(segmentNumber: Int) : Bezugssegment(segmentNumber, Existenzstatus.Optional)
|
|
@ -1,6 +1,6 @@
|
|||
package net.dankito.banking.fints.messages.datenelemente.implementierte
|
||||
package net.codinux.banking.fints.messages.datenelemente.implementierte
|
||||
|
||||
import net.dankito.banking.fints.messages.Existenzstatus
|
||||
import net.codinux.banking.fints.messages.Existenzstatus
|
||||
|
||||
|
||||
open class BezugssegmentInKundennachricht(segmentNumber: Int) : Bezugssegment(segmentNumber, Existenzstatus.NotAllowed)
|
|
@ -1,7 +1,7 @@
|
|||
package net.dankito.banking.fints.messages.datenelemente.implementierte
|
||||
package net.codinux.banking.fints.messages.datenelemente.implementierte
|
||||
|
||||
import net.dankito.banking.fints.messages.Existenzstatus
|
||||
import net.dankito.banking.fints.messages.datenelemente.abgeleiteteformate.Identifikation
|
||||
import net.codinux.banking.fints.messages.Existenzstatus
|
||||
import net.codinux.banking.fints.messages.datenelemente.abgeleiteteformate.Identifikation
|
||||
|
||||
|
||||
/**
|
|
@ -0,0 +1,21 @@
|
|||
package net.codinux.banking.fints.messages.datenelemente.implementierte
|
||||
|
||||
|
||||
enum class Dialogsprache(override val code: String) : ICodeEnum {
|
||||
|
||||
/**
|
||||
* Der Kunde darf lediglich ein Sprachkennzeichen einstellen, das im Rahmen
|
||||
* der BPD vom Kreditinstitut an das Kundensystem übermittelt wurde.
|
||||
* Wenn noch keine BPD vorliegen, sollte das Kundenprodukt mit Hilfe eines
|
||||
* anonymen Dialogs die aktuelle BPD des Instituts ermitteln und die Standardsprache des Instituts einstellen, die in den Bankparameterdaten mitgeteilt
|
||||
* wird. Falls die BPD nicht abgerufen werden kann, ist der Wert „0“ einzustellen. Das Kreditinstitut antwortet in diesem Fall in seiner Standardsprache.
|
||||
*/
|
||||
Default("0"),
|
||||
|
||||
German("1"),
|
||||
|
||||
English("2"),
|
||||
|
||||
French("3")
|
||||
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
package net.dankito.banking.fints.messages.datenelemente.implementierte
|
||||
package net.codinux.banking.fints.messages.datenelemente.implementierte
|
||||
|
||||
import net.dankito.banking.fints.messages.Existenzstatus
|
||||
import net.dankito.banking.fints.messages.datenelemente.abgeleiteteformate.Code
|
||||
import net.codinux.banking.fints.messages.Existenzstatus
|
||||
import net.codinux.banking.fints.messages.datenelemente.abgeleiteteformate.Code
|
||||
|
||||
|
||||
/**
|
|
@ -1,7 +1,7 @@
|
|||
package net.dankito.banking.fints.messages.datenelemente.implementierte
|
||||
package net.codinux.banking.fints.messages.datenelemente.implementierte
|
||||
|
||||
import net.dankito.banking.fints.messages.Existenzstatus
|
||||
import net.dankito.banking.fints.messages.datenelemente.basisformate.TextDatenelement
|
||||
import net.codinux.banking.fints.messages.Existenzstatus
|
||||
import net.codinux.banking.fints.messages.datenelemente.basisformate.TextDatenelement
|
||||
|
||||
|
||||
/**
|
|
@ -1,4 +1,4 @@
|
|||
package net.dankito.banking.fints.messages.datenelemente.implementierte
|
||||
package net.codinux.banking.fints.messages.datenelemente.implementierte
|
||||
|
||||
|
||||
enum class HbciVersion(val versionNumber: Int, override val code: String) : ICodeEnum {
|
|
@ -1,7 +1,7 @@
|
|||
package net.dankito.banking.fints.messages.datenelemente.implementierte
|
||||
package net.codinux.banking.fints.messages.datenelemente.implementierte
|
||||
|
||||
import net.dankito.banking.fints.messages.Existenzstatus
|
||||
import net.dankito.banking.fints.messages.datenelemente.basisformate.NumerischesDatenelement
|
||||
import net.codinux.banking.fints.messages.Existenzstatus
|
||||
import net.codinux.banking.fints.messages.datenelemente.basisformate.NumerischesDatenelement
|
||||
|
||||
|
||||
/**
|
|
@ -1,4 +1,4 @@
|
|||
package net.dankito.banking.fints.messages.datenelemente.implementierte
|
||||
package net.codinux.banking.fints.messages.datenelemente.implementierte
|
||||
|
||||
|
||||
inline fun <reified T : Enum<T>> allCodes(): List<String> {
|
|
@ -1,7 +1,7 @@
|
|||
package net.dankito.banking.fints.messages.datenelemente.implementierte
|
||||
package net.codinux.banking.fints.messages.datenelemente.implementierte
|
||||
|
||||
import net.dankito.banking.fints.messages.Existenzstatus
|
||||
import net.dankito.banking.fints.messages.datenelemente.basisformate.AlphanumerischesDatenelement
|
||||
import net.codinux.banking.fints.messages.Existenzstatus
|
||||
import net.codinux.banking.fints.messages.datenelemente.basisformate.AlphanumerischesDatenelement
|
||||
|
||||
|
||||
/**
|
|
@ -1,7 +1,7 @@
|
|||
package net.dankito.banking.fints.messages.datenelemente.implementierte
|
||||
package net.codinux.banking.fints.messages.datenelemente.implementierte
|
||||
|
||||
import net.dankito.banking.fints.messages.Existenzstatus
|
||||
import net.dankito.banking.fints.messages.datenelemente.abgeleiteteformate.Identifikation
|
||||
import net.codinux.banking.fints.messages.Existenzstatus
|
||||
import net.codinux.banking.fints.messages.datenelemente.abgeleiteteformate.Identifikation
|
||||
|
||||
|
||||
/**
|
|
@ -1,7 +1,7 @@
|
|||
package net.dankito.banking.fints.messages.datenelemente.implementierte
|
||||
package net.codinux.banking.fints.messages.datenelemente.implementierte
|
||||
|
||||
import net.dankito.banking.fints.messages.Existenzstatus
|
||||
import net.dankito.banking.fints.messages.datenelemente.abgeleiteteformate.Identifikation
|
||||
import net.codinux.banking.fints.messages.Existenzstatus
|
||||
import net.codinux.banking.fints.messages.datenelemente.abgeleiteteformate.Identifikation
|
||||
|
||||
|
||||
/**
|
|
@ -1,7 +1,7 @@
|
|||
package net.dankito.banking.fints.messages.datenelemente.implementierte
|
||||
package net.codinux.banking.fints.messages.datenelemente.implementierte
|
||||
|
||||
import net.dankito.banking.fints.messages.Existenzstatus
|
||||
import net.dankito.banking.fints.messages.datenelemente.abgeleiteteformate.Code
|
||||
import net.codinux.banking.fints.messages.Existenzstatus
|
||||
import net.codinux.banking.fints.messages.datenelemente.abgeleiteteformate.Code
|
||||
|
||||
|
||||
/**
|
|
@ -0,0 +1,21 @@
|
|||
package net.codinux.banking.fints.messages.datenelemente.implementierte
|
||||
|
||||
/**
|
||||
* Information darüber, ob die Kundensystem-ID erforderlich ist.
|
||||
*/
|
||||
enum class KundensystemStatusWerte(override val code: String) : ICodeEnum {
|
||||
|
||||
/**
|
||||
* Kundensystem-ID wird nicht benötigt (HBCI DDV-Verfahren und
|
||||
* chipkartenbasierte Verfahren ab Sicherheitsprofil-Version 3)
|
||||
* und PinTan bis über HKSYN eine Kundensystem-ID vom Bankserver abgerufen wurde.
|
||||
*/
|
||||
NichtBenoetigt("0"),
|
||||
|
||||
/**
|
||||
* Kundensystem-ID wird benötigt (sonstige HBCI RAH- /
|
||||
* RDH- und PIN/TAN-Verfahren)
|
||||
*/
|
||||
Benoetigt("1")
|
||||
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
package net.dankito.banking.fints.messages.datenelemente.implementierte
|
||||
package net.codinux.banking.fints.messages.datenelemente.implementierte
|
||||
|
||||
import net.dankito.banking.fints.messages.Existenzstatus
|
||||
import net.dankito.banking.fints.messages.datenelemente.basisformate.ZiffernDatenelement
|
||||
import net.codinux.banking.fints.messages.Existenzstatus
|
||||
import net.codinux.banking.fints.messages.datenelemente.basisformate.ZiffernDatenelement
|
||||
|
||||
|
||||
/**
|
|
@ -1,7 +1,7 @@
|
|||
package net.dankito.banking.fints.messages.datenelemente.implementierte
|
||||
package net.codinux.banking.fints.messages.datenelemente.implementierte
|
||||
|
||||
import net.dankito.banking.fints.messages.Existenzstatus
|
||||
import net.dankito.banking.fints.messages.datenelemente.basisformate.NumerischesDatenelement
|
||||
import net.codinux.banking.fints.messages.Existenzstatus
|
||||
import net.codinux.banking.fints.messages.datenelemente.basisformate.NumerischesDatenelement
|
||||
|
||||
|
||||
/**
|
|
@ -0,0 +1,7 @@
|
|||
package net.codinux.banking.fints.messages.datenelemente.implementierte
|
||||
|
||||
import net.codinux.banking.fints.messages.Existenzstatus
|
||||
import net.codinux.banking.fints.messages.datenelemente.basisformate.TextDatenelement
|
||||
|
||||
|
||||
open class NotAllowedDatenelement : TextDatenelement("", Existenzstatus.NotAllowed)
|
|
@ -1,7 +1,7 @@
|
|||
package net.dankito.banking.fints.messages.datenelemente.implementierte
|
||||
package net.codinux.banking.fints.messages.datenelemente.implementierte
|
||||
|
||||
import net.dankito.banking.fints.messages.Existenzstatus
|
||||
import net.dankito.banking.fints.messages.datenelemente.basisformate.AlphanumerischesDatenelement
|
||||
import net.codinux.banking.fints.messages.Existenzstatus
|
||||
import net.codinux.banking.fints.messages.datenelemente.basisformate.AlphanumerischesDatenelement
|
||||
|
||||
|
||||
/**
|
|
@ -1,7 +1,7 @@
|
|||
package net.dankito.banking.fints.messages.datenelemente.implementierte
|
||||
package net.codinux.banking.fints.messages.datenelemente.implementierte
|
||||
|
||||
import net.dankito.banking.fints.messages.Existenzstatus
|
||||
import net.dankito.banking.fints.messages.datenelemente.basisformate.AlphanumerischesDatenelement
|
||||
import net.codinux.banking.fints.messages.Existenzstatus
|
||||
import net.codinux.banking.fints.messages.datenelemente.basisformate.AlphanumerischesDatenelement
|
||||
|
||||
|
||||
/**
|
|
@ -1,7 +1,7 @@
|
|||
package net.dankito.banking.fints.messages.datenelemente.implementierte
|
||||
package net.codinux.banking.fints.messages.datenelemente.implementierte
|
||||
|
||||
import net.dankito.banking.fints.messages.Existenzstatus
|
||||
import net.dankito.banking.fints.messages.datenelemente.basisformate.AlphanumerischesDatenelement
|
||||
import net.codinux.banking.fints.messages.Existenzstatus
|
||||
import net.codinux.banking.fints.messages.datenelemente.basisformate.AlphanumerischesDatenelement
|
||||
|
||||
|
||||
/**
|
|
@ -1,7 +1,7 @@
|
|||
package net.dankito.banking.fints.messages.datenelemente.implementierte
|
||||
package net.codinux.banking.fints.messages.datenelemente.implementierte
|
||||
|
||||
import net.dankito.banking.fints.messages.Existenzstatus
|
||||
import net.dankito.banking.fints.messages.datenelemente.basisformate.NumerischesDatenelement
|
||||
import net.codinux.banking.fints.messages.Existenzstatus
|
||||
import net.codinux.banking.fints.messages.datenelemente.basisformate.NumerischesDatenelement
|
||||
|
||||
|
||||
/**
|
|
@ -1,7 +1,7 @@
|
|||
package net.dankito.banking.fints.messages.datenelemente.implementierte
|
||||
package net.codinux.banking.fints.messages.datenelemente.implementierte
|
||||
|
||||
import net.dankito.banking.fints.messages.Existenzstatus
|
||||
import net.dankito.banking.fints.messages.datenelemente.basisformate.NumerischesDatenelement
|
||||
import net.codinux.banking.fints.messages.Existenzstatus
|
||||
import net.codinux.banking.fints.messages.datenelemente.basisformate.NumerischesDatenelement
|
||||
|
||||
|
||||
/**
|
|
@ -1,4 +1,4 @@
|
|||
package net.dankito.banking.fints.messages.datenelemente.implementierte
|
||||
package net.codinux.banking.fints.messages.datenelemente.implementierte
|
||||
|
||||
|
||||
enum class Synchronisierungsmodus(override val code: String) : ICodeEnum {
|
|
@ -1,7 +1,7 @@
|
|||
package net.dankito.banking.fints.messages.datenelemente.implementierte
|
||||
package net.codinux.banking.fints.messages.datenelemente.implementierte
|
||||
|
||||
import net.dankito.banking.fints.messages.Existenzstatus
|
||||
import net.dankito.banking.fints.messages.datenelemente.abgeleiteteformate.Code
|
||||
import net.codinux.banking.fints.messages.Existenzstatus
|
||||
import net.codinux.banking.fints.messages.datenelemente.abgeleiteteformate.Code
|
||||
|
||||
|
||||
/**
|
|
@ -1,7 +1,7 @@
|
|||
package net.dankito.banking.fints.messages.datenelemente.implementierte
|
||||
package net.codinux.banking.fints.messages.datenelemente.implementierte
|
||||
|
||||
import net.dankito.banking.fints.messages.Existenzstatus
|
||||
import net.dankito.banking.fints.messages.datenelemente.basisformate.NumerischesDatenelement
|
||||
import net.codinux.banking.fints.messages.Existenzstatus
|
||||
import net.codinux.banking.fints.messages.datenelemente.basisformate.NumerischesDatenelement
|
||||
|
||||
|
||||
/**
|
|
@ -1,7 +1,7 @@
|
|||
package net.dankito.banking.fints.messages.datenelemente.implementierte.account
|
||||
package net.codinux.banking.fints.messages.datenelemente.implementierte.account
|
||||
|
||||
import net.dankito.banking.fints.messages.Existenzstatus
|
||||
import net.dankito.banking.fints.messages.datenelemente.abgeleiteteformate.JaNein
|
||||
import net.codinux.banking.fints.messages.Existenzstatus
|
||||
import net.codinux.banking.fints.messages.datenelemente.abgeleiteteformate.JaNein
|
||||
|
||||
|
||||
/**
|
|
@ -0,0 +1,7 @@
|
|||
package net.codinux.banking.fints.messages.datenelemente.implementierte.account
|
||||
|
||||
import net.codinux.banking.fints.messages.Existenzstatus
|
||||
import net.codinux.banking.fints.messages.datenelemente.basisformate.AlphanumerischesDatenelement
|
||||
|
||||
|
||||
open class BIC(bic: String, existenzstatus: Existenzstatus) : AlphanumerischesDatenelement(bic, existenzstatus, 11)
|
|
@ -0,0 +1,7 @@
|
|||
package net.codinux.banking.fints.messages.datenelemente.implementierte.account
|
||||
|
||||
import net.codinux.banking.fints.messages.Existenzstatus
|
||||
import net.codinux.banking.fints.messages.datenelemente.basisformate.AlphanumerischesDatenelement
|
||||
|
||||
|
||||
open class IBAN(iban: String, existenzstatus: Existenzstatus) : AlphanumerischesDatenelement(iban, existenzstatus, 34)
|
|
@ -1,7 +1,7 @@
|
|||
package net.dankito.banking.fints.messages.datenelemente.implementierte.account
|
||||
package net.codinux.banking.fints.messages.datenelemente.implementierte.account
|
||||
|
||||
import net.dankito.banking.fints.messages.Existenzstatus
|
||||
import net.dankito.banking.fints.messages.datenelemente.abgeleiteteformate.Identifikation
|
||||
import net.codinux.banking.fints.messages.Existenzstatus
|
||||
import net.codinux.banking.fints.messages.datenelemente.abgeleiteteformate.Identifikation
|
||||
|
||||
|
||||
/**
|
|
@ -1,8 +1,8 @@
|
|||
package net.dankito.banking.fints.messages.datenelemente.implementierte.account
|
||||
package net.codinux.banking.fints.messages.datenelemente.implementierte.account
|
||||
|
||||
import net.dankito.banking.fints.messages.Existenzstatus
|
||||
import net.dankito.banking.fints.messages.datenelemente.basisformate.NumerischesDatenelement
|
||||
import net.dankito.banking.fints.model.GetAccountTransactionsParameter
|
||||
import net.codinux.banking.fints.messages.Existenzstatus
|
||||
import net.codinux.banking.fints.messages.datenelemente.basisformate.NumerischesDatenelement
|
||||
import net.codinux.banking.fints.model.GetAccountTransactionsParameter
|
||||
|
||||
|
||||
/**
|
|
@ -1,7 +1,7 @@
|
|||
package net.dankito.banking.fints.messages.datenelemente.implementierte.account
|
||||
package net.codinux.banking.fints.messages.datenelemente.implementierte.account
|
||||
|
||||
import net.dankito.banking.fints.messages.Existenzstatus
|
||||
import net.dankito.banking.fints.messages.datenelemente.abgeleiteteformate.Identifikation
|
||||
import net.codinux.banking.fints.messages.Existenzstatus
|
||||
import net.codinux.banking.fints.messages.datenelemente.abgeleiteteformate.Identifikation
|
||||
|
||||
|
||||
/**
|
|
@ -1,6 +1,6 @@
|
|||
package net.dankito.banking.fints.messages.datenelemente.implementierte.encryption
|
||||
package net.codinux.banking.fints.messages.datenelemente.implementierte.encryption
|
||||
|
||||
import net.dankito.banking.fints.messages.datenelemente.implementierte.ICodeEnum
|
||||
import net.codinux.banking.fints.messages.datenelemente.implementierte.ICodeEnum
|
||||
|
||||
|
||||
enum class BezeichnerFuerAlgorithmusparameterIV(override val code: String) : ICodeEnum {
|
|
@ -1,8 +1,8 @@
|
|||
package net.dankito.banking.fints.messages.datenelemente.implementierte.encryption
|
||||
package net.codinux.banking.fints.messages.datenelemente.implementierte.encryption
|
||||
|
||||
import net.dankito.banking.fints.messages.Existenzstatus
|
||||
import net.dankito.banking.fints.messages.datenelemente.abgeleiteteformate.Code
|
||||
import net.dankito.banking.fints.messages.datenelemente.implementierte.allCodes
|
||||
import net.codinux.banking.fints.messages.Existenzstatus
|
||||
import net.codinux.banking.fints.messages.datenelemente.abgeleiteteformate.Code
|
||||
import net.codinux.banking.fints.messages.datenelemente.implementierte.allCodes
|
||||
|
||||
|
||||
/**
|
|
@ -1,6 +1,6 @@
|
|||
package net.dankito.banking.fints.messages.datenelemente.implementierte.encryption
|
||||
package net.codinux.banking.fints.messages.datenelemente.implementierte.encryption
|
||||
|
||||
import net.dankito.banking.fints.messages.datenelemente.implementierte.ICodeEnum
|
||||
import net.codinux.banking.fints.messages.datenelemente.implementierte.ICodeEnum
|
||||
|
||||
|
||||
enum class BezeichnerFuerAlgorithmusparameterSchluessel(override val code: String) : ICodeEnum {
|
|
@ -1,8 +1,8 @@
|
|||
package net.dankito.banking.fints.messages.datenelemente.implementierte.encryption
|
||||
package net.codinux.banking.fints.messages.datenelemente.implementierte.encryption
|
||||
|
||||
import net.dankito.banking.fints.messages.Existenzstatus
|
||||
import net.dankito.banking.fints.messages.datenelemente.abgeleiteteformate.Code
|
||||
import net.dankito.banking.fints.messages.datenelemente.implementierte.allCodes
|
||||
import net.codinux.banking.fints.messages.Existenzstatus
|
||||
import net.codinux.banking.fints.messages.datenelemente.abgeleiteteformate.Code
|
||||
import net.codinux.banking.fints.messages.datenelemente.implementierte.allCodes
|
||||
|
||||
|
||||
/**
|
|
@ -1,6 +1,6 @@
|
|||
package net.dankito.banking.fints.messages.datenelemente.implementierte.encryption
|
||||
package net.codinux.banking.fints.messages.datenelemente.implementierte.encryption
|
||||
|
||||
import net.dankito.banking.fints.messages.datenelemente.implementierte.ICodeEnum
|
||||
import net.codinux.banking.fints.messages.datenelemente.implementierte.ICodeEnum
|
||||
|
||||
|
||||
enum class Komprimierungsfunktion(val abbreviation: String, override val code: String) : ICodeEnum {
|
|
@ -1,8 +1,8 @@
|
|||
package net.dankito.banking.fints.messages.datenelemente.implementierte.encryption
|
||||
package net.codinux.banking.fints.messages.datenelemente.implementierte.encryption
|
||||
|
||||
import net.dankito.banking.fints.messages.Existenzstatus
|
||||
import net.dankito.banking.fints.messages.datenelemente.abgeleiteteformate.Code
|
||||
import net.dankito.banking.fints.messages.datenelemente.implementierte.allCodes
|
||||
import net.codinux.banking.fints.messages.Existenzstatus
|
||||
import net.codinux.banking.fints.messages.datenelemente.abgeleiteteformate.Code
|
||||
import net.codinux.banking.fints.messages.datenelemente.implementierte.allCodes
|
||||
|
||||
|
||||
/**
|
|
@ -1,7 +1,7 @@
|
|||
package net.dankito.banking.fints.messages.datenelemente.implementierte.encryption
|
||||
package net.codinux.banking.fints.messages.datenelemente.implementierte.encryption
|
||||
|
||||
import net.dankito.banking.fints.messages.Existenzstatus
|
||||
import net.dankito.banking.fints.messages.datenelemente.basisformate.BinaerDatenelement
|
||||
import net.codinux.banking.fints.messages.Existenzstatus
|
||||
import net.codinux.banking.fints.messages.datenelemente.basisformate.BinaerDatenelement
|
||||
|
||||
|
||||
/**
|
|
@ -1,6 +1,6 @@
|
|||
package net.dankito.banking.fints.messages.datenelemente.implementierte.encryption
|
||||
package net.codinux.banking.fints.messages.datenelemente.implementierte.encryption
|
||||
|
||||
import net.dankito.banking.fints.messages.datenelemente.implementierte.ICodeEnum
|
||||
import net.codinux.banking.fints.messages.datenelemente.implementierte.ICodeEnum
|
||||
|
||||
|
||||
enum class Verschluesselungsalgorithmus(override val code: String) : ICodeEnum {
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue