Implemented serializing transactions to JSON
This commit is contained in:
parent
85d6b079d6
commit
ed66168c0b
|
@ -1,11 +1,13 @@
|
|||
package net.dankito.banking.client.model
|
||||
|
||||
import kotlinx.datetime.LocalDate
|
||||
import kotlinx.serialization.Serializable
|
||||
import net.dankito.banking.fints.model.Amount
|
||||
import net.dankito.banking.fints.model.Money
|
||||
import net.dankito.utils.multiplatform.extensions.atUnixEpochStart
|
||||
|
||||
|
||||
@Serializable
|
||||
open class AccountTransaction(
|
||||
val amount: Money, // TODO: if we decide to stick with Money, create own type, don't use that one from fints.model (or move over from)
|
||||
val unparsedReference: String,
|
||||
|
|
|
@ -1,25 +1,27 @@
|
|||
package net.dankito.banking.client.model
|
||||
|
||||
import kotlinx.datetime.LocalDate
|
||||
import kotlinx.serialization.Serializable
|
||||
import net.dankito.banking.fints.model.Currency
|
||||
import net.dankito.banking.fints.model.Money
|
||||
|
||||
|
||||
@Serializable
|
||||
open class BankAccount(
|
||||
identifier: String,
|
||||
subAccountNumber: String?,
|
||||
iban: String?,
|
||||
val accountHolderName: String,
|
||||
val type: BankAccountType = BankAccountType.CheckingAccount,
|
||||
val productName: String? = null,
|
||||
val currency: String = Currency.DefaultCurrencyCode, // TODO: may parse to a value object
|
||||
val accountLimit: String? = null,
|
||||
override val identifier: String,
|
||||
override val subAccountNumber: String?,
|
||||
override val iban: String?,
|
||||
open val accountHolderName: String,
|
||||
open val type: BankAccountType = BankAccountType.CheckingAccount,
|
||||
open val productName: String? = null,
|
||||
open val currency: String = Currency.DefaultCurrencyCode, // TODO: may parse to a value object
|
||||
open val accountLimit: String? = null,
|
||||
// TODO: create an enum AccountCapabilities [ RetrieveBalance, RetrieveTransactions, TransferMoney / MoneyTransfer(?), InstantPayment ]
|
||||
val supportsRetrievingTransactions: Boolean = false,
|
||||
val supportsRetrievingBalance: Boolean = false,
|
||||
val supportsTransferringMoney: Boolean = false,
|
||||
val supportsInstantPayment: Boolean = false
|
||||
) : BankAccountIdentifier(identifier, subAccountNumber, iban) {
|
||||
open val supportsRetrievingTransactions: Boolean = false,
|
||||
open val supportsRetrievingBalance: Boolean = false,
|
||||
open val supportsTransferringMoney: Boolean = false,
|
||||
open val supportsInstantPayment: Boolean = false
|
||||
) : BankAccountIdentifier {
|
||||
|
||||
internal constructor() : this("", null, null, "") // for object deserializers
|
||||
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
package net.dankito.banking.client.model
|
||||
|
||||
interface BankAccountIdentifier {
|
||||
|
||||
open class BankAccountIdentifier(
|
||||
open val identifier: String,
|
||||
open val subAccountNumber: String?,
|
||||
open val iban: String?,
|
||||
)
|
||||
val identifier: String
|
||||
|
||||
val subAccountNumber: String?
|
||||
|
||||
val iban: String?
|
||||
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package net.dankito.banking.client.model
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
|
||||
@Serializable
|
||||
open class BankAccountIdentifierImpl(
|
||||
override val identifier: String,
|
||||
override val subAccountNumber: String?,
|
||||
override val iban: String?,
|
||||
) : BankAccountIdentifier
|
|
@ -1,5 +1,6 @@
|
|||
package net.dankito.banking.client.model
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
import net.dankito.banking.fints.messages.datenelemente.implementierte.tan.TanMedium
|
||||
import net.dankito.banking.fints.model.TanMethod
|
||||
|
||||
|
@ -7,6 +8,7 @@ import net.dankito.banking.fints.model.TanMethod
|
|||
//import net.dankito.banking.client.model.tan.TanMethod
|
||||
|
||||
|
||||
@Serializable
|
||||
open class CustomerAccount(
|
||||
override var bankCode: String,
|
||||
override var loginName: String,
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
package net.dankito.banking.client.model.serializer
|
||||
|
||||
import kotlinx.serialization.KSerializer
|
||||
import kotlinx.serialization.descriptors.PrimitiveKind
|
||||
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
|
||||
import kotlinx.serialization.descriptors.SerialDescriptor
|
||||
import kotlinx.serialization.encoding.Decoder
|
||||
import kotlinx.serialization.encoding.Encoder
|
||||
import net.dankito.banking.fints.model.Amount
|
||||
|
||||
|
||||
class AmountSerializer : KSerializer<Amount> {
|
||||
|
||||
override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("Amount", PrimitiveKind.STRING)
|
||||
|
||||
override fun serialize(encoder: Encoder, value: Amount) {
|
||||
encoder.encodeString(value.string)
|
||||
}
|
||||
|
||||
override fun deserialize(decoder: Decoder): Amount {
|
||||
return Amount(decoder.decodeString())
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package net.dankito.banking.client.model.serializer
|
||||
|
||||
import kotlinx.serialization.KSerializer
|
||||
import kotlinx.serialization.descriptors.PrimitiveKind
|
||||
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
|
||||
import kotlinx.serialization.descriptors.SerialDescriptor
|
||||
import kotlinx.serialization.encoding.Decoder
|
||||
import kotlinx.serialization.encoding.Encoder
|
||||
import net.dankito.banking.fints.model.Currency
|
||||
|
||||
|
||||
class CurrencySerializer : KSerializer<Currency> {
|
||||
|
||||
override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("Currency", PrimitiveKind.STRING)
|
||||
|
||||
override fun serialize(encoder: Encoder, value: Currency) {
|
||||
encoder.encodeString(value.code)
|
||||
}
|
||||
|
||||
override fun deserialize(decoder: Decoder): Currency {
|
||||
return Currency(decoder.decodeString())
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package net.dankito.banking.client.model.serializer
|
||||
|
||||
import kotlinx.serialization.KSerializer
|
||||
import kotlinx.serialization.descriptors.PrimitiveKind
|
||||
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
|
||||
import kotlinx.serialization.descriptors.SerialDescriptor
|
||||
import kotlinx.serialization.encoding.Decoder
|
||||
import kotlinx.serialization.encoding.Encoder
|
||||
import net.dankito.banking.fints.model.Amount
|
||||
import net.dankito.banking.fints.model.Currency
|
||||
import net.dankito.banking.fints.model.Money
|
||||
|
||||
|
||||
class MoneySerializer : KSerializer<Money> {
|
||||
|
||||
override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("Money", PrimitiveKind.STRING)
|
||||
|
||||
override fun serialize(encoder: Encoder, value: Money) {
|
||||
encoder.encodeString(value.amount.string + " " + value.currency.code)
|
||||
}
|
||||
|
||||
override fun deserialize(decoder: Decoder): Money {
|
||||
val value = decoder.decodeString()
|
||||
val parts = value.split(" ")
|
||||
|
||||
if (parts.size > 1) {
|
||||
return Money(Amount(parts[0]), parts[1])
|
||||
}
|
||||
|
||||
return Money(Amount(value), Currency.DefaultCurrencyCode)
|
||||
}
|
||||
|
||||
}
|
|
@ -3,7 +3,6 @@ package net.dankito.banking.fints.mapper
|
|||
import net.dankito.banking.client.model.*
|
||||
import net.dankito.banking.client.model.AccountTransaction
|
||||
import net.dankito.banking.client.model.parameter.FinTsClientParameter
|
||||
import net.dankito.banking.client.model.parameter.GetAccountDataParameter
|
||||
import net.dankito.banking.client.model.response.ErrorCode
|
||||
import net.dankito.banking.fints.messages.datenelemente.abgeleiteteformate.Laenderkennzeichen
|
||||
import net.dankito.banking.fints.model.*
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package net.dankito.banking.fints.messages.datenelemente.implementierte.tan
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
|
||||
/**
|
||||
* Informationen zu Art und Parametrisierung von TAN-Medien. Als TAN-Medien werden sowohl
|
||||
|
@ -8,6 +10,7 @@ package net.dankito.banking.fints.messages.datenelemente.implementierte.tan
|
|||
*
|
||||
* Wird das Datenelement „TAN-Medium-Klasse“ mit „B“ (bilateral vereinbart) belegt, so muss im Element „Sicherheitsfunktion, kodiert“ die entsprechende Sicherheitsfunktion in der DEG „Verfahrensparameter Zwei-Schritt-Verfahren“ referenziert werden.
|
||||
*/
|
||||
@Serializable
|
||||
open class TanMedium(
|
||||
open val mediumClass: TanMediumKlasse,
|
||||
open val status: TanMediumStatus,
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
package net.dankito.banking.fints.model
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
import net.dankito.banking.client.model.serializer.AmountSerializer
|
||||
|
||||
|
||||
@Serializable(with = AmountSerializer::class)
|
||||
open class Amount(
|
||||
val string: String
|
||||
) {
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
package net.dankito.banking.fints.model
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
import net.dankito.banking.client.model.serializer.CurrencySerializer
|
||||
|
||||
|
||||
@Serializable(with = CurrencySerializer::class)
|
||||
open class Currency(
|
||||
val code: String
|
||||
) {
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
package net.dankito.banking.fints.model
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
|
||||
@Serializable
|
||||
open class DecoupledTanMethodParameters(
|
||||
open val manualConfirmationAllowed: Boolean,
|
||||
open val periodicStateRequestsAllowed: Boolean,
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
package net.dankito.banking.fints.model
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
import net.dankito.banking.client.model.serializer.MoneySerializer
|
||||
|
||||
|
||||
@Serializable(with = MoneySerializer::class)
|
||||
open class Money(
|
||||
val amount: Amount,
|
||||
val currency: Currency
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
package net.dankito.banking.fints.model
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
import net.dankito.banking.fints.messages.datenelemente.implementierte.signatur.Sicherheitsfunktion
|
||||
import net.dankito.banking.fints.messages.datenelemente.implementierte.tan.AllowedTanFormat
|
||||
|
||||
|
||||
@Serializable
|
||||
open class TanMethod(
|
||||
open val displayName: String,
|
||||
open val securityFunction: Sicherheitsfunktion,
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
import com.soywiz.korio.file.std.localCurrentDirVfs
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.datetime.LocalDate
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
import net.dankito.banking.client.model.AccountTransaction
|
||||
import net.dankito.banking.client.model.CustomerAccount
|
||||
import net.dankito.banking.client.model.parameter.GetAccountDataParameter
|
||||
|
@ -20,7 +24,7 @@ class NativeApp {
|
|||
getAccountData(GetAccountDataParameter(bankCode, loginName, password))
|
||||
}
|
||||
|
||||
fun getAccountData(param: GetAccountDataParameter) {
|
||||
fun getAccountData(param: GetAccountDataParameter, outputFilePath: String? = null) {
|
||||
val response = client.getAccountData(param)
|
||||
|
||||
if (response.error != null) {
|
||||
|
@ -28,9 +32,13 @@ class NativeApp {
|
|||
}
|
||||
|
||||
response.customerAccount?.let { account ->
|
||||
println("Retrieved response from ${account.bankName} for ${account.customerName}")
|
||||
if (outputFilePath != null) {
|
||||
writeResponseToFile(outputFilePath, account)
|
||||
} else {
|
||||
println("Retrieved response from ${account.bankName} for ${account.customerName}")
|
||||
|
||||
displayRetrievedAccountData(account)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -100,4 +108,18 @@ class NativeApp {
|
|||
return date.dayOfMonth.toStringWithTwoDigits() + "." + date.monthNumber.toStringWithTwoDigits() + "." + date.year
|
||||
}
|
||||
|
||||
|
||||
private fun writeResponseToFile(outputFilePath: String, customer: CustomerAccount) {
|
||||
try {
|
||||
val outputFile = localCurrentDirVfs.get(outputFilePath)
|
||||
println("Writing file to ${outputFile.absolutePath}")
|
||||
|
||||
val json = Json.encodeToString(customer)
|
||||
|
||||
runBlocking { outputFile.writeString(json) }
|
||||
} catch (e: Exception) {
|
||||
println("Could not write file to $outputFilePath: $e")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -38,6 +38,8 @@ class fints4kCommandLineInterface : CliktCommand(name = "fints", printHelpOnEmpt
|
|||
val retrieveTransactionsForLastNDays by option("-l", "--last-n-days", help = "Retrieve transactions for last n days. If set 'retrieveTransactions' gets set to '${RetrieveTransactions.AccordingToRetrieveFromAndTo}' and 'retrieveTransactionsFrom' will be ignored.").int()
|
||||
|
||||
|
||||
val outputFile by option("-o", help = "Write retrieved account transactions to file instead of stdout. Supported formats: JSON")
|
||||
|
||||
val preferredTanMethods by option("-m", "--tan-method", help = "Your preferred TAN methods to use if action affords a TAN. Can be repeated like '-m AppTan -m SmsTan'").enum<TanMethodType>().multiple()
|
||||
|
||||
val abortIfRequiresTan by option("-a", "--abort-if-requires-tan", help = "If actions should be aborted if it affords a TAN. Defaults to false").flag(default = false)
|
||||
|
@ -71,7 +73,7 @@ class fints4kCommandLineInterface : CliktCommand(name = "fints", printHelpOnEmpt
|
|||
|
||||
|
||||
app.getAccountData(GetAccountDataParameter(bankCode, loginName, password, null, retrieveBalance, effectiveRetrieveTransactions,
|
||||
retrieveTransactionsFromDate, retrieveTransactionsToDate, preferredTanMethods, abortIfTanIsRequired = abortIfRequiresTan))
|
||||
retrieveTransactionsFromDate, retrieveTransactionsToDate, preferredTanMethods, abortIfTanIsRequired = abortIfRequiresTan), outputFile)
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue