Implemented continueing at Aufsetzpunkt
This commit is contained in:
parent
14bc302c6d
commit
ee3cd937df
|
@ -6,8 +6,11 @@ ext {
|
||||||
kotlinVersion = '1.3.41'
|
kotlinVersion = '1.3.41'
|
||||||
|
|
||||||
javaUtilsVersion = '1.0.8'
|
javaUtilsVersion = '1.0.8'
|
||||||
|
|
||||||
androidUtilsVersion = '1.1.0'
|
androidUtilsVersion = '1.1.0'
|
||||||
|
|
||||||
|
javaFxUtilsVersion = '1.0.3'
|
||||||
|
|
||||||
junitVersion = '4.12'
|
junitVersion = '4.12'
|
||||||
assertJVersion = '3.12.2'
|
assertJVersion = '3.12.2'
|
||||||
|
|
||||||
|
|
|
@ -31,4 +31,6 @@ dependencies {
|
||||||
|
|
||||||
testCompile "ch.qos.logback:logback-core:$logbackVersion"
|
testCompile "ch.qos.logback:logback-core:$logbackVersion"
|
||||||
testCompile "ch.qos.logback:logback-classic:$logbackVersion"
|
testCompile "ch.qos.logback:logback-classic:$logbackVersion"
|
||||||
|
|
||||||
|
testCompile "net.dankito.utils:java-fx-utils:$javaFxUtilsVersion"
|
||||||
}
|
}
|
|
@ -255,15 +255,36 @@ open class FinTsClient @JvmOverloads constructor(
|
||||||
tryGetTransactionsOfLast90DaysWithoutTan(bank, customer)
|
tryGetTransactionsOfLast90DaysWithoutTan(bank, customer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val bookedAndUnbookedTransactions = getTransactionsFromResponse(response, transactions)
|
||||||
|
|
||||||
return GetTransactionsResponse(response,
|
return GetTransactionsResponse(response,
|
||||||
transactions.bookedTransactions.sortedByDescending { it.bookingDate },
|
bookedAndUnbookedTransactions.first.sortedByDescending { it.bookingDate },
|
||||||
transactions.unbookedTransactions,
|
bookedAndUnbookedTransactions.second,
|
||||||
balance)
|
balance)
|
||||||
}
|
}
|
||||||
|
|
||||||
return GetTransactionsResponse(response)
|
return GetTransactionsResponse(response)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected open fun getTransactionsFromResponse(response: Response, transactions: ReceivedAccountTransactions): Pair<List<AccountTransaction>, List<Any>> {
|
||||||
|
val bookedTransactions = mutableListOf<AccountTransaction>()
|
||||||
|
val unbookedTransactions = mutableListOf<Any>()
|
||||||
|
|
||||||
|
bookedTransactions.addAll(transactions.bookedTransactions)
|
||||||
|
unbookedTransactions.addAll(transactions.unbookedTransactions)
|
||||||
|
|
||||||
|
response.followUpResponse?.let { followUpResponse ->
|
||||||
|
followUpResponse.getFirstSegmentById<ReceivedAccountTransactions>(InstituteSegmentId.AccountTransactionsMt940)?.let { followUpTransactions ->
|
||||||
|
val followUpBookedAndUnbookedTransactions = getTransactionsFromResponse(followUpResponse, followUpTransactions)
|
||||||
|
|
||||||
|
bookedTransactions.addAll(followUpBookedAndUnbookedTransactions.first)
|
||||||
|
unbookedTransactions.addAll(followUpBookedAndUnbookedTransactions.second)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Pair(bookedTransactions, unbookedTransactions)
|
||||||
|
}
|
||||||
|
|
||||||
protected open fun getBalanceAfterDialogInit(bank: BankData, customer: CustomerData,
|
protected open fun getBalanceAfterDialogInit(bank: BankData, customer: CustomerData,
|
||||||
dialogData: DialogData): Response {
|
dialogData: DialogData): Response {
|
||||||
|
|
||||||
|
@ -433,6 +454,32 @@ open class FinTsClient @JvmOverloads constructor(
|
||||||
customer: CustomerData, dialogData: DialogData): Response {
|
customer: CustomerData, dialogData: DialogData): Response {
|
||||||
val response = getAndHandleResponseForMessage(message, bank)
|
val response = getAndHandleResponseForMessage(message, bank)
|
||||||
|
|
||||||
|
val handledResponse = handleMayRequiredTan(response, bank, customer, dialogData)
|
||||||
|
|
||||||
|
// if there's a Aufsetzpunkt (continuationId) set, then response is not complete yet, there's more information to fetch by sending this Aufsetzpunkt
|
||||||
|
handledResponse.aufsetzpunkt?.let { continuationId ->
|
||||||
|
handledResponse.followUpResponse = getFollowUpMessageForContinuationId(handledResponse, continuationId, message, bank, customer, dialogData)
|
||||||
|
|
||||||
|
handledResponse.hasFollowUpMessageButCouldNotReceiveIt = handledResponse.followUpResponse == null
|
||||||
|
}
|
||||||
|
|
||||||
|
return handledResponse
|
||||||
|
}
|
||||||
|
|
||||||
|
protected open fun getFollowUpMessageForContinuationId(response: Response, continuationId: String, message: MessageBuilderResult,
|
||||||
|
bank: BankData, customer: CustomerData, dialogData: DialogData): Response? {
|
||||||
|
|
||||||
|
messageBuilder.rebuildMessageWithContinuationId(message, continuationId, bank, customer, dialogData)?.let { followUpMessage ->
|
||||||
|
return getAndHandleResponseForMessageThatMayRequiresTan(followUpMessage, bank, customer, dialogData)
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
protected open fun getAndHandleResponseForMessageThatMayRequiresTan(message: String, bank: BankData,
|
||||||
|
customer: CustomerData, dialogData: DialogData): Response {
|
||||||
|
val response = getAndHandleResponseForMessage(message, bank)
|
||||||
|
|
||||||
return handleMayRequiredTan(response, bank, customer, dialogData)
|
return handleMayRequiredTan(response, bank, customer, dialogData)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package net.dankito.fints.messages
|
package net.dankito.fints.messages
|
||||||
|
|
||||||
import net.dankito.fints.extensions.containsAny
|
import net.dankito.fints.extensions.containsAny
|
||||||
|
import net.dankito.fints.messages.datenelemente.implementierte.Aufsetzpunkt
|
||||||
import net.dankito.fints.messages.datenelemente.implementierte.Synchronisierungsmodus
|
import net.dankito.fints.messages.datenelemente.implementierte.Synchronisierungsmodus
|
||||||
import net.dankito.fints.messages.datenelemente.implementierte.tan.TanProcess
|
import net.dankito.fints.messages.datenelemente.implementierte.tan.TanProcess
|
||||||
import net.dankito.fints.messages.segmente.ISegmentNumberGenerator
|
import net.dankito.fints.messages.segmente.ISegmentNumberGenerator
|
||||||
|
@ -107,11 +108,12 @@ open class MessageBuilder(protected val generator: ISegmentNumberGenerator = Seg
|
||||||
else if (result.isAllowed(6)) KontoumsaetzeZeitraumMt940Version6(generator.resetSegmentNumber(2), parameter, bank, customer)
|
else if (result.isAllowed(6)) KontoumsaetzeZeitraumMt940Version6(generator.resetSegmentNumber(2), parameter, bank, customer)
|
||||||
else KontoumsaetzeZeitraumMt940Version5(generator.resetSegmentNumber(2), parameter, bank, customer)
|
else KontoumsaetzeZeitraumMt940Version5(generator.resetSegmentNumber(2), parameter, bank, customer)
|
||||||
|
|
||||||
|
val segments = listOf(
|
||||||
return MessageBuilderResult(createSignedMessage(bank, customer, dialogData, listOf(
|
|
||||||
transactionsJob,
|
transactionsJob,
|
||||||
ZweiSchrittTanEinreichung(generator.getNextSegmentNumber(), TanProcess.TanProcess4, CustomerSegmentId.AccountTransactionsMt940)
|
ZweiSchrittTanEinreichung(generator.getNextSegmentNumber(), TanProcess.TanProcess4, CustomerSegmentId.AccountTransactionsMt940)
|
||||||
)))
|
)
|
||||||
|
|
||||||
|
return createMessageBuilderResult(bank, customer, dialogData, segments)
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
@ -122,24 +124,26 @@ open class MessageBuilder(protected val generator: ISegmentNumberGenerator = Seg
|
||||||
val result = getSupportedVersionsOfJob(CustomerSegmentId.Balance, customer, listOf(5))
|
val result = getSupportedVersionsOfJob(CustomerSegmentId.Balance, customer, listOf(5))
|
||||||
|
|
||||||
if (result.isJobVersionSupported) {
|
if (result.isJobVersionSupported) {
|
||||||
return MessageBuilderResult(createSignedMessage(bank, customer, dialogData, listOf(
|
val segments = listOf(
|
||||||
Saldenabfrage(generator.resetSegmentNumber(2), bank, customer),
|
Saldenabfrage(generator.resetSegmentNumber(2), bank, customer),
|
||||||
ZweiSchrittTanEinreichung(generator.getNextSegmentNumber(), TanProcess.TanProcess4, CustomerSegmentId.Balance)
|
ZweiSchrittTanEinreichung(generator.getNextSegmentNumber(), TanProcess.TanProcess4, CustomerSegmentId.Balance)
|
||||||
)))
|
)
|
||||||
|
|
||||||
|
return createMessageBuilderResult(bank, customer, dialogData, segments)
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
open fun createSendEnteredTanMessage(enteredTan: String, tanResponse: TanResponse, bank: BankData, customer: CustomerData, dialogData: DialogData): MessageBuilderResult {
|
open fun createSendEnteredTanMessage(enteredTan: String, tanResponse: TanResponse, bank: BankData, customer: CustomerData, dialogData: DialogData): String {
|
||||||
|
|
||||||
val tanProcess = if (tanResponse.tanProcess == TanProcess.TanProcess1) TanProcess.TanProcess1 else TanProcess.TanProcess2
|
val tanProcess = if (tanResponse.tanProcess == TanProcess.TanProcess1) TanProcess.TanProcess1 else TanProcess.TanProcess2
|
||||||
|
|
||||||
return MessageBuilderResult(createSignedMessage(bank, customer, dialogData, enteredTan, listOf(
|
return createSignedMessage(bank, customer, dialogData, enteredTan, listOf(
|
||||||
ZweiSchrittTanEinreichung(generator.resetSegmentNumber(2), tanProcess, null,
|
ZweiSchrittTanEinreichung(generator.resetSegmentNumber(2), tanProcess, null,
|
||||||
tanResponse.jobHashValue, tanResponse.jobReference, false, null, tanResponse.tanMediaIdentifier)
|
tanResponse.jobHashValue, tanResponse.jobReference, false, null, tanResponse.tanMediaIdentifier)
|
||||||
)))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -150,10 +154,12 @@ open class MessageBuilder(protected val generator: ISegmentNumberGenerator = Seg
|
||||||
if (result.isJobVersionSupported) {
|
if (result.isJobVersionSupported) {
|
||||||
|
|
||||||
getSepaUrnFor(CustomerSegmentId.SepaAccountInfoParameters, customer, "pain.001.001.03")?.let { urn ->
|
getSepaUrnFor(CustomerSegmentId.SepaAccountInfoParameters, customer, "pain.001.001.03")?.let { urn ->
|
||||||
return MessageBuilderResult(createSignedMessage(bank, customer, dialogData, listOf(
|
val segments = listOf(
|
||||||
SepaEinzelueberweisung(generator.resetSegmentNumber(2), urn, customer, bank.bic, bankTransferData),
|
SepaEinzelueberweisung(generator.resetSegmentNumber(2), urn, customer, bank.bic, bankTransferData),
|
||||||
ZweiSchrittTanEinreichung(generator.getNextSegmentNumber(), TanProcess.TanProcess4, CustomerSegmentId.SepaBankTransfer)
|
ZweiSchrittTanEinreichung(generator.getNextSegmentNumber(), TanProcess.TanProcess4, CustomerSegmentId.SepaBankTransfer)
|
||||||
)))
|
)
|
||||||
|
|
||||||
|
return createMessageBuilderResult(bank, customer, dialogData, segments)
|
||||||
}
|
}
|
||||||
|
|
||||||
return MessageBuilderResult(true, false, result.allowedVersions, result.supportedVersions, null) // TODO: how to tell that we don't support required SEPA pain version?
|
return MessageBuilderResult(true, false, result.allowedVersions, result.supportedVersions, null) // TODO: how to tell that we don't support required SEPA pain version?
|
||||||
|
@ -163,6 +169,29 @@ open class MessageBuilder(protected val generator: ISegmentNumberGenerator = Seg
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
open fun rebuildMessageWithContinuationId(message: MessageBuilderResult, continuationId: String, bank: BankData,
|
||||||
|
customer: CustomerData, dialogData: DialogData): MessageBuilderResult? {
|
||||||
|
|
||||||
|
// val copiedSegments = message.messageBodySegments.map { }
|
||||||
|
val aufsetzpunkte = message.messageBodySegments.flatMap { it.dataElementsAndGroups }.filterIsInstance<Aufsetzpunkt>()
|
||||||
|
|
||||||
|
if (aufsetzpunkte.isEmpty()) {
|
||||||
|
// return MessageBuilderResult(message.isJobAllowed, message.isJobVersionSupported, message.allowedVersions, message.supportedVersions, null)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
aufsetzpunkte.forEach { it.resetContinuationId(continuationId) }
|
||||||
|
|
||||||
|
dialogData.increaseMessageNumber()
|
||||||
|
|
||||||
|
return createMessageBuilderResult(bank, customer, dialogData, message.messageBodySegments)
|
||||||
|
}
|
||||||
|
|
||||||
|
protected open fun createMessageBuilderResult(bank: BankData, customer: CustomerData, dialogData: DialogData, segments: List<Segment>): MessageBuilderResult {
|
||||||
|
return MessageBuilderResult(createSignedMessage(bank, customer, dialogData, segments), segments)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
open fun createSignedMessage(bank: BankData, customer: CustomerData, dialogData: DialogData,
|
open fun createSignedMessage(bank: BankData, customer: CustomerData, dialogData: DialogData,
|
||||||
payloadSegments: List<Segment>): String {
|
payloadSegments: List<Segment>): String {
|
||||||
|
|
||||||
|
|
|
@ -1,17 +1,21 @@
|
||||||
package net.dankito.fints.messages
|
package net.dankito.fints.messages
|
||||||
|
|
||||||
|
import net.dankito.fints.messages.segmente.Segment
|
||||||
|
|
||||||
|
|
||||||
open class MessageBuilderResult(
|
open class MessageBuilderResult(
|
||||||
val isJobAllowed: Boolean,
|
val isJobAllowed: Boolean,
|
||||||
val isJobVersionSupported: Boolean,
|
val isJobVersionSupported: Boolean,
|
||||||
val allowedVersions: List<Int>,
|
val allowedVersions: List<Int>,
|
||||||
val supportedVersions: List<Int>,
|
val supportedVersions: List<Int>,
|
||||||
val createdMessage: String?
|
val createdMessage: String?,
|
||||||
|
val messageBodySegments: List<Segment> = listOf()
|
||||||
) {
|
) {
|
||||||
|
|
||||||
constructor(isJobAllowed: Boolean) : this(isJobAllowed, false, listOf(), listOf(), null)
|
constructor(isJobAllowed: Boolean) : this(isJobAllowed, false, listOf(), listOf(), null)
|
||||||
|
|
||||||
constructor(createdMessage: String) : this(true, true, listOf(), listOf(), createdMessage)
|
constructor(createdMessage: String, messageBodySegments: List<Segment>)
|
||||||
|
: this(true, true, listOf(), listOf(), createdMessage, messageBodySegments)
|
||||||
|
|
||||||
|
|
||||||
open fun isAllowed(version: Int): Boolean {
|
open fun isAllowed(version: Int): Boolean {
|
||||||
|
|
|
@ -14,16 +14,18 @@ abstract class AlphanumerischesDatenelement @JvmOverloads constructor(
|
||||||
override fun validate() {
|
override fun validate() {
|
||||||
super.validate()
|
super.validate()
|
||||||
|
|
||||||
if (writeToOutput && value != null) { // if value is null and value has to be written to output then validation already fails above
|
if (writeToOutput) {
|
||||||
if (value.contains("\r") || value.contains("\n")) {
|
value?.let { value -> // if value is null and value has to be written to output then validation already fails above
|
||||||
throwValidationException("Alphanumerischer Wert '$value' darf kein Carriage Return (\r) oder " +
|
if (value.contains("\r") || value.contains("\n")) {
|
||||||
"Line Feed (\n) enthalten.")
|
throwValidationException("Alphanumerischer Wert '$value' darf kein Carriage Return (\r) oder " +
|
||||||
}
|
"Line Feed (\n) enthalten.")
|
||||||
|
}
|
||||||
|
|
||||||
maxLength?.let {
|
maxLength?.let {
|
||||||
if (value.length > maxLength) {
|
if (value.length > maxLength) {
|
||||||
throwValidationException("Wert '$value' darf maximal $maxLength Zeichen lang sein, " +
|
throwValidationException("Wert '$value' darf maximal $maxLength Zeichen lang sein, " +
|
||||||
"hat aber ${value.length} Zeichen.")
|
"hat aber ${value.length} Zeichen.")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@ open class BinaerDatenelement @JvmOverloads constructor(data: String?, existenzs
|
||||||
if (writeToOutput) {
|
if (writeToOutput) {
|
||||||
checkIfMandatoryValueIsSet()
|
checkIfMandatoryValueIsSet()
|
||||||
|
|
||||||
value?.let { // if value is null and value has to be written to output then validation already fails above
|
value?.let { value -> // if value is null and value has to be written to output then validation already fails above
|
||||||
maxLength?.let {
|
maxLength?.let {
|
||||||
if (value.length > maxLength) {
|
if (value.length > maxLength) {
|
||||||
throwValidationException("Binäre Daten dürfen nur eine maximale Größe von $maxLength Bytes " +
|
throwValidationException("Binäre Daten dürfen nur eine maximale Größe von $maxLength Bytes " +
|
||||||
|
|
|
@ -9,10 +9,11 @@ import net.dankito.fints.messages.datenelemente.Datenelement
|
||||||
/**
|
/**
|
||||||
* Es gilt der vollständige FinTS-Basiszeichensatz.
|
* Es gilt der vollständige FinTS-Basiszeichensatz.
|
||||||
*/
|
*/
|
||||||
abstract class TextDatenelement(val value: String?, existenzstatus: Existenzstatus) : Datenelement(existenzstatus) {
|
abstract class TextDatenelement(var value: String?, existenzstatus: Existenzstatus) : Datenelement(existenzstatus) {
|
||||||
|
|
||||||
|
|
||||||
override val isValueSet = value != null
|
override val isValueSet
|
||||||
|
get() = value != null
|
||||||
|
|
||||||
override fun format(): String {
|
override fun format(): String {
|
||||||
if (writeToOutput) {
|
if (writeToOutput) {
|
||||||
|
|
|
@ -10,4 +10,10 @@ import net.dankito.fints.messages.datenelemente.basisformate.AlphanumerischesDat
|
||||||
* einzigen Auftragssegment erfolgen kann (s. [Formals]).
|
* einzigen Auftragssegment erfolgen kann (s. [Formals]).
|
||||||
*/
|
*/
|
||||||
open class Aufsetzpunkt(continuationId: String?, existenzstatus: Existenzstatus)
|
open class Aufsetzpunkt(continuationId: String?, existenzstatus: Existenzstatus)
|
||||||
: AlphanumerischesDatenelement(continuationId, existenzstatus, 35)
|
: AlphanumerischesDatenelement(continuationId, existenzstatus, 35) {
|
||||||
|
|
||||||
|
open fun resetContinuationId(continuationId: String?) {
|
||||||
|
value = continuationId
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -49,6 +49,9 @@ open class Response constructor(
|
||||||
open val segmentFeedbacks: List<SegmentFeedback>
|
open val segmentFeedbacks: List<SegmentFeedback>
|
||||||
get() = getSegmentsById(InstituteSegmentId.SegmentFeedback)
|
get() = getSegmentsById(InstituteSegmentId.SegmentFeedback)
|
||||||
|
|
||||||
|
open val aufsetzpunkt: String? // TODO: what to do if there are multiple Aufsetzpunkte?
|
||||||
|
get() = segmentFeedbacks.flatMap { it.feedbacks }.filterIsInstance<AufsetzpunktFeedback>().firstOrNull()?.aufsetzpunkt
|
||||||
|
|
||||||
open val errorsToShowToUser: List<String>
|
open val errorsToShowToUser: List<String>
|
||||||
get() {
|
get() {
|
||||||
val errorMessages = segmentFeedbacks
|
val errorMessages = segmentFeedbacks
|
||||||
|
@ -66,6 +69,11 @@ open class Response constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
open var followUpResponse: Response? = null
|
||||||
|
|
||||||
|
open var hasFollowUpMessageButCouldNotReceiveIt: Boolean? = false
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an empty list of response didn't contain any job parameters.
|
* Returns an empty list of response didn't contain any job parameters.
|
||||||
*
|
*
|
||||||
|
|
|
@ -29,13 +29,15 @@ open class ResponseParser @JvmOverloads constructor(
|
||||||
) {
|
) {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val EncryptionDataSegmentHeaderPattern = Pattern.compile("${MessageSegmentId.EncryptionData.id}:\\d{1,3}:\\d{1,3}\\+")
|
val EncryptionDataSegmentHeaderPattern: Pattern = Pattern.compile("${MessageSegmentId.EncryptionData.id}:\\d{1,3}:\\d{1,3}\\+")
|
||||||
|
|
||||||
val JobParametersSegmentPattern = Pattern.compile("HI[A-Z]{3}S")
|
val JobParametersSegmentPattern: Pattern = Pattern.compile("HI[A-Z]{3}S")
|
||||||
|
|
||||||
val FeedbackParametersSeparator = "; "
|
const val FeedbackParametersSeparator = "; "
|
||||||
|
|
||||||
val SupportedTanProceduresForUserResponseCode = 3920
|
const val AufsetzpunktResponseCode = 3040
|
||||||
|
|
||||||
|
const val SupportedTanProceduresForUserResponseCode = 3920
|
||||||
|
|
||||||
private val log = LoggerFactory.getLogger(ResponseParser::class.java)
|
private val log = LoggerFactory.getLogger(ResponseParser::class.java)
|
||||||
}
|
}
|
||||||
|
@ -138,6 +140,9 @@ open class ResponseParser @JvmOverloads constructor(
|
||||||
val supportedProcedures = parseCodeEnum(dataElements.subList(3, dataElements.size), Sicherheitsfunktion.values())
|
val supportedProcedures = parseCodeEnum(dataElements.subList(3, dataElements.size), Sicherheitsfunktion.values())
|
||||||
return SupportedTanProceduresForUserFeedback(supportedProcedures, message)
|
return SupportedTanProceduresForUserFeedback(supportedProcedures, message)
|
||||||
}
|
}
|
||||||
|
else if (responseCode == AufsetzpunktResponseCode) {
|
||||||
|
return AufsetzpunktFeedback(parseString(dataElements[3]), message)
|
||||||
|
}
|
||||||
|
|
||||||
val parameter = if (dataElements.size > 3) dataElements.subList(3, dataElements.size).joinToString(FeedbackParametersSeparator) else null
|
val parameter = if (dataElements.size > 3) dataElements.subList(3, dataElements.size).joinToString(FeedbackParametersSeparator) else null
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
package net.dankito.fints.response.segments
|
||||||
|
|
||||||
|
import net.dankito.fints.response.ResponseParser
|
||||||
|
|
||||||
|
|
||||||
|
open class AufsetzpunktFeedback(
|
||||||
|
val aufsetzpunkt: String,
|
||||||
|
message: String
|
||||||
|
)
|
||||||
|
: Feedback(ResponseParser.AufsetzpunktResponseCode, message)
|
|
@ -1,10 +1,18 @@
|
||||||
package net.dankito.fints.messages
|
package net.dankito.fints.messages
|
||||||
|
|
||||||
import net.dankito.fints.FinTsTestBase
|
import net.dankito.fints.FinTsTestBase
|
||||||
|
import net.dankito.fints.model.AccountData
|
||||||
import net.dankito.fints.model.DialogData
|
import net.dankito.fints.model.DialogData
|
||||||
|
import net.dankito.fints.model.GetTransactionsParameter
|
||||||
|
import net.dankito.fints.response.segments.AccountType
|
||||||
|
import net.dankito.fints.response.segments.JobParameters
|
||||||
import net.dankito.fints.util.FinTsUtils
|
import net.dankito.fints.util.FinTsUtils
|
||||||
|
import net.dankito.utils.datetime.asUtilDate
|
||||||
import org.assertj.core.api.Assertions.assertThat
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
|
import org.junit.After
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
import java.time.LocalDate
|
||||||
|
import java.time.Month
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
|
|
||||||
|
@ -27,6 +35,13 @@ class MessageBuilderTest : FinTsTestBase() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@After
|
||||||
|
fun tearDown() {
|
||||||
|
Bank.supportedJobs = listOf()
|
||||||
|
Customer.accounts = listOf()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun createAnonymousDialogInitMessage() {
|
fun createAnonymousDialogInitMessage() {
|
||||||
|
|
||||||
|
@ -102,4 +117,94 @@ class MessageBuilderTest : FinTsTestBase() {
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun createGetTransactionsMessage_JobIsNotAllowed() {
|
||||||
|
|
||||||
|
// when
|
||||||
|
val result = underTest.createGetTransactionsMessage(GetTransactionsParameter(), Bank, Customer, Product, DialogData.DialogInitDialogData)
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertThat(result.isJobAllowed).isFalse()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun createGetTransactionsMessage_JobVersionIsNotSupported() {
|
||||||
|
|
||||||
|
// given
|
||||||
|
val getTransactionsJob = JobParameters("HKKAZ", 1, 1, null, "HKKAZ:73:5")
|
||||||
|
val getTransactionsJobWithPreviousVersion = JobParameters("HKKAZ", 1, 1, null, "HKKAZ:72:4")
|
||||||
|
Bank.supportedJobs = listOf(getTransactionsJob)
|
||||||
|
val account = AccountData(CustomerId, null, BankCountryCode, BankCode, null, CustomerId, AccountType.Girokonto, "EUR", "", null, null, listOf(getTransactionsJob.jobName), listOf(getTransactionsJobWithPreviousVersion))
|
||||||
|
Customer.accounts = listOf(account)
|
||||||
|
|
||||||
|
// when
|
||||||
|
val result = underTest.createGetTransactionsMessage(GetTransactionsParameter(), Bank, Customer, Product, DialogData.DialogInitDialogData)
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertThat(result.isJobAllowed).isTrue()
|
||||||
|
assertThat(result.isJobVersionSupported).isFalse()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun createGetTransactionsMessage() {
|
||||||
|
|
||||||
|
// given
|
||||||
|
val getTransactionsJob = JobParameters("HKKAZ", 1, 1, null, "HKKAZ:73:5")
|
||||||
|
Bank.supportedJobs = listOf(getTransactionsJob)
|
||||||
|
val account = AccountData(CustomerId, null, BankCountryCode, BankCode, null, CustomerId, AccountType.Girokonto, "EUR", "", null, null, listOf(getTransactionsJob.jobName), listOf(getTransactionsJob))
|
||||||
|
Customer.accounts = listOf(account)
|
||||||
|
|
||||||
|
val fromDate = LocalDate.of(2019, Month.AUGUST, 6).asUtilDate()
|
||||||
|
val toDate = LocalDate.of(2019, Month.OCTOBER, 21).asUtilDate()
|
||||||
|
val maxCountEntries = 99
|
||||||
|
|
||||||
|
// when
|
||||||
|
val result = underTest.createGetTransactionsMessage(GetTransactionsParameter(false, fromDate, toDate, maxCountEntries), Bank, Customer, Product, DialogData.DialogInitDialogData)
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertThat(result.createdMessage).isNotNull()
|
||||||
|
|
||||||
|
assertThat(normalizeBinaryData(result.createdMessage!!)).isEqualTo(normalizeBinaryData(
|
||||||
|
"HNHBK:1:3+000000000362+300+0+1'" +
|
||||||
|
"HNVSK:998:3+PIN:2+998+1+1::0+1:$Date:$Time+2:16:14:@8@ :5:1+280:$BankCode:$CustomerId:V:0:0+0'" +
|
||||||
|
"HNVSD:999:1+@198@" + "HNSHK:2:4+PIN:2+${SecurityFunction.code}+$ControlReference+1+1+1::0+1+1:$Date:$Time+1:999:1+6:10:16+280:$BankCode:$CustomerId:S:0:0'" +
|
||||||
|
"HKKAZ:3:${getTransactionsJob.segmentVersion}+$CustomerId::280:$BankCode+N+${convertDate(fromDate)}+${convertDate(toDate)}+$maxCountEntries'" +
|
||||||
|
"HKTAN:4:6+4+HKKAZ'" +
|
||||||
|
"HNSHA:5:2+$ControlReference++$Pin''" +
|
||||||
|
"HNHBS:6:1+1'"
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun createGetTransactionsMessage_WithContinuationIdSet() {
|
||||||
|
|
||||||
|
// given
|
||||||
|
val getTransactionsJob = JobParameters("HKKAZ", 1, 1, null, "HKKAZ:73:5")
|
||||||
|
Bank.supportedJobs = listOf(getTransactionsJob)
|
||||||
|
val account = AccountData(CustomerId, null, BankCountryCode, BankCode, null, CustomerId, AccountType.Girokonto, "EUR", "", null, null, listOf(getTransactionsJob.jobName), listOf(getTransactionsJob))
|
||||||
|
Customer.accounts = listOf(account)
|
||||||
|
|
||||||
|
val fromDate = LocalDate.of(2019, Month.AUGUST, 6).asUtilDate()
|
||||||
|
val toDate = LocalDate.of(2019, Month.OCTOBER, 21).asUtilDate()
|
||||||
|
val maxCountEntries = 99
|
||||||
|
val continuationId = "9345-10-26-11.52.15.693455"
|
||||||
|
|
||||||
|
// when
|
||||||
|
val result = underTest.createGetTransactionsMessage(GetTransactionsParameter(false, fromDate, toDate, maxCountEntries, false, continuationId), Bank, Customer, Product, DialogData.DialogInitDialogData)
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertThat(result.createdMessage).isNotNull()
|
||||||
|
|
||||||
|
assertThat(normalizeBinaryData(result.createdMessage!!)).isEqualTo(normalizeBinaryData(
|
||||||
|
"HNHBK:1:3+000000000389+300+0+1'" +
|
||||||
|
"HNVSK:998:3+PIN:2+998+1+1::0+1:$Date:$Time+2:16:14:@8@ :5:1+280:$BankCode:$CustomerId:V:0:0+0'" +
|
||||||
|
"HNVSD:999:1+@225@" + "HNSHK:2:4+PIN:2+${SecurityFunction.code}+$ControlReference+1+1+1::0+1+1:$Date:$Time+1:999:1+6:10:16+280:$BankCode:$CustomerId:S:0:0'" +
|
||||||
|
"HKKAZ:3:${getTransactionsJob.segmentVersion}+$CustomerId::280:$BankCode+N+${convertDate(fromDate)}+${convertDate(toDate)}+$maxCountEntries+$continuationId'" +
|
||||||
|
"HKTAN:4:6+4+HKKAZ'" +
|
||||||
|
"HNSHA:5:2+$ControlReference++$Pin''" +
|
||||||
|
"HNHBS:6:1+1'"
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -208,6 +208,19 @@ class ResponseParserTest : FinTsTestBase() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun parseSegmentFeedback_Aufsetzpunkt() {
|
||||||
|
|
||||||
|
// when
|
||||||
|
val result = underTest.parse("HIRMS:4:2:3+0020::Der Auftrag wurde ausgeführt.+0020::Die gebuchten Umsätze wurden übermittelt.+3040::Es liegen weitere Informationen vor.:9345-10-26-11.52.15.693455")
|
||||||
|
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertCouldParseSegment(result, InstituteSegmentId.SegmentFeedback, 4, 2, 3)
|
||||||
|
|
||||||
|
assertThat(result.aufsetzpunkt).isEqualTo("9345-10-26-11.52.15.693455")
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun parseSegmentFeedback_AllowedUserTanProcedures() {
|
fun parseSegmentFeedback_AllowedUserTanProcedures() {
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue