From 7fcc8db798ad04051bc46db8cdfe7f4597bc13b2 Mon Sep 17 00:00:00 2001 From: dankl Date: Sun, 13 Oct 2019 21:19:11 +0200 Subject: [PATCH] Implemented checking if allowed jobs are supported --- .../kotlin/net/dankito/fints/FinTsClient.kt | 15 +++- .../fints/extensions/CollectionExtensions.kt | 12 +++ .../dankito/fints/messages/MessageBuilder.kt | 73 +++++++++++++++---- .../fints/messages/MessageBuilderResult.kt | 21 ++++++ .../KontoumsaetzeZeitraumMt940Version6.kt | 32 ++++++++ .../net/dankito/fints/response/Response.kt | 9 ++- .../response/client/FinTsClientResponse.kt | 13 +++- 7 files changed, 153 insertions(+), 22 deletions(-) create mode 100644 fints4javaLib/src/main/kotlin/net/dankito/fints/extensions/CollectionExtensions.kt create mode 100644 fints4javaLib/src/main/kotlin/net/dankito/fints/messages/MessageBuilderResult.kt create mode 100644 fints4javaLib/src/main/kotlin/net/dankito/fints/messages/segmente/implementierte/umsaetze/KontoumsaetzeZeitraumMt940Version6.kt diff --git a/fints4javaLib/src/main/kotlin/net/dankito/fints/FinTsClient.kt b/fints4javaLib/src/main/kotlin/net/dankito/fints/FinTsClient.kt index 90249ff3..19b1e4c7 100644 --- a/fints4javaLib/src/main/kotlin/net/dankito/fints/FinTsClient.kt +++ b/fints4javaLib/src/main/kotlin/net/dankito/fints/FinTsClient.kt @@ -1,6 +1,7 @@ package net.dankito.fints import net.dankito.fints.messages.MessageBuilder +import net.dankito.fints.messages.MessageBuilderResult import net.dankito.fints.messages.datenelemente.implementierte.Dialogsprache import net.dankito.fints.messages.datenelemente.implementierte.KundensystemID import net.dankito.fints.messages.datenelemente.implementierte.KundensystemStatusWerte @@ -157,7 +158,7 @@ open class FinTsClient @JvmOverloads constructor( if (parameter.alsoRetrieveBalance) { val balanceResponse = getBalanceAfterDialogInit(bank, customer, dialogData) - if (balanceResponse.successful == false) { + if (balanceResponse.successful == false && balanceResponse.couldCreateMessage == true) { // don't break here if required HKSAL message is not implemented return GetTransactionsResponse(balanceResponse) } @@ -169,9 +170,9 @@ open class FinTsClient @JvmOverloads constructor( dialogData.increaseMessageNumber() - val requestBody = messageBuilder.createGetTransactionsMessage(parameter, bank, customer, product, dialogData) + val message = messageBuilder.createGetTransactionsMessage(parameter, bank, customer, product, dialogData) - val response = getAndHandleResponseForMessage(requestBody, bank) + val response = getAndHandleResponseForMessage(message, bank) closeDialog(bank, customer, dialogData) @@ -302,6 +303,14 @@ open class FinTsClient @JvmOverloads constructor( } + protected open fun getAndHandleResponseForMessage(message: MessageBuilderResult, bank: BankData): Response { + message.createdMessage?.let { requestBody -> + return getAndHandleResponseForMessage(requestBody, bank) + } + + return Response(false, messageCreationError = message) + } + protected open fun getAndHandleResponseForMessage(requestBody: String, bank: BankData): Response { val webResponse = getResponseForMessage(requestBody, bank) diff --git a/fints4javaLib/src/main/kotlin/net/dankito/fints/extensions/CollectionExtensions.kt b/fints4javaLib/src/main/kotlin/net/dankito/fints/extensions/CollectionExtensions.kt new file mode 100644 index 00000000..360a6c0f --- /dev/null +++ b/fints4javaLib/src/main/kotlin/net/dankito/fints/extensions/CollectionExtensions.kt @@ -0,0 +1,12 @@ +package net.dankito.fints.extensions + + +fun Collection.containsAny(otherCollection: Collection): Boolean { + for (otherItem in otherCollection) { + if (this.contains(otherItem)) { + return true + } + } + + return false +} \ No newline at end of file diff --git a/fints4javaLib/src/main/kotlin/net/dankito/fints/messages/MessageBuilder.kt b/fints4javaLib/src/main/kotlin/net/dankito/fints/messages/MessageBuilder.kt index 2fcf2901..f846a04b 100644 --- a/fints4javaLib/src/main/kotlin/net/dankito/fints/messages/MessageBuilder.kt +++ b/fints4javaLib/src/main/kotlin/net/dankito/fints/messages/MessageBuilder.kt @@ -1,5 +1,6 @@ package net.dankito.fints.messages +import net.dankito.fints.extensions.containsAny import net.dankito.fints.messages.datenelemente.implementierte.Synchronisierungsmodus import net.dankito.fints.messages.datenelemente.implementierte.tan.TanProcess import net.dankito.fints.messages.segmente.ISegmentNumberGenerator @@ -10,6 +11,8 @@ import net.dankito.fints.messages.segmente.id.CustomerSegmentId import net.dankito.fints.messages.segmente.implementierte.* import net.dankito.fints.messages.segmente.implementierte.sepa.SepaEinzelueberweisung import net.dankito.fints.messages.segmente.implementierte.umsaetze.KontoumsaetzeZeitraumMt940Version5 +import net.dankito.fints.messages.segmente.implementierte.umsaetze.KontoumsaetzeZeitraumMt940Version6 +import net.dankito.fints.messages.segmente.implementierte.umsaetze.KontoumsaetzeZeitraumMt940Version7 import net.dankito.fints.messages.segmente.implementierte.umsaetze.Saldenabfrage import net.dankito.fints.model.* import net.dankito.fints.util.FinTsUtils @@ -86,29 +89,53 @@ open class MessageBuilder(protected val generator: ISegmentNumberGenerator = Seg open fun createGetTransactionsMessage(parameter: GetTransactionsParameter, bank: BankData, customer: CustomerData, - product: ProductData, dialogData: DialogData): String { + product: ProductData, dialogData: DialogData): MessageBuilderResult { - return createSignedMessage(bank, customer, dialogData, listOf( - KontoumsaetzeZeitraumMt940Version5(generator.resetSegmentNumber(2), parameter, bank, customer), - ZweiSchrittTanEinreichung(generator.getNextSegmentNumber(), TanProcess.TanProcess4, CustomerSegmentId.AccountTransactionsMt940) - )) + val result = getSupportedVersionOfJob(CustomerSegmentId.AccountTransactionsMt940, customer, listOf(5, 6, 7)) + + if (result.isJobVersionSupported) { + val transactionsJob = if (result.isAllowed(7)) KontoumsaetzeZeitraumMt940Version7(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) + + + return MessageBuilderResult(createSignedMessage(bank, customer, dialogData, listOf( + transactionsJob, + ZweiSchrittTanEinreichung(generator.getNextSegmentNumber(), TanProcess.TanProcess4, CustomerSegmentId.AccountTransactionsMt940) + ))) + } + + return result } - open fun createGetBalanceMessage(bank: BankData, customer: CustomerData, product: ProductData, dialogData: DialogData): String { + open fun createGetBalanceMessage(bank: BankData, customer: CustomerData, product: ProductData, dialogData: DialogData): MessageBuilderResult { - return createSignedMessage(bank, customer, dialogData, listOf( - Saldenabfrage(generator.resetSegmentNumber(2), bank, customer), - ZweiSchrittTanEinreichung(generator.getNextSegmentNumber(), TanProcess.TanProcess4, CustomerSegmentId.Balance) - )) + val result = getSupportedVersionOfJob(CustomerSegmentId.Balance, customer, listOf(5)) + + if (result.isJobVersionSupported) { + return MessageBuilderResult(createSignedMessage(bank, customer, dialogData, listOf( + Saldenabfrage(generator.resetSegmentNumber(2), bank, customer), + ZweiSchrittTanEinreichung(generator.getNextSegmentNumber(), TanProcess.TanProcess4, CustomerSegmentId.Balance) + ))) + } + + return result } - open fun createBankTransferMessage(bankTransferData: BankTransferData, bank: BankData, customer: CustomerData, dialogData: DialogData): String { + open fun createBankTransferMessage(bankTransferData: BankTransferData, bank: BankData, customer: CustomerData, dialogData: DialogData): MessageBuilderResult { - return createSignedMessage(bank, customer, dialogData, listOf( - SepaEinzelueberweisung(generator.resetSegmentNumber(2), customer, bank.bic!!, bankTransferData), - ZweiSchrittTanEinreichung(generator.getNextSegmentNumber(), TanProcess.TanProcess4, CustomerSegmentId.SepaBankTransfer) - )) + val result = getSupportedVersionOfJob(CustomerSegmentId.SepaBankTransfer, customer, listOf(1)) + + if (result.isJobVersionSupported) { + + return MessageBuilderResult(createSignedMessage(bank, customer, dialogData, listOf( + SepaEinzelueberweisung(generator.resetSegmentNumber(2), customer, bank.bic!!, bankTransferData), + ZweiSchrittTanEinreichung(generator.getNextSegmentNumber(), TanProcess.TanProcess4, CustomerSegmentId.SepaBankTransfer) + ))) + } + + return result } @@ -183,4 +210,20 @@ open class MessageBuilder(protected val generator: ISegmentNumberGenerator = Seg return payload.joinToString(Separators.SegmentSeparator) { it.format() } } + + protected open fun getSupportedVersionOfJob(segmentId: CustomerSegmentId, customer: CustomerData, + supportedVersions: List): MessageBuilderResult { + + customer.accounts.firstOrNull()?.let { account -> // TODO: find a better solution / make more generic + val allowedVersions = account.allowedJobs.filter { it.jobName == segmentId.id } + .map { it.segmentVersion } + .sortedDescending() + + return MessageBuilderResult(allowedVersions.isNotEmpty(), allowedVersions.containsAny(supportedVersions), + allowedVersions, supportedVersions, null) + } + + return MessageBuilderResult(false) + } + } \ No newline at end of file diff --git a/fints4javaLib/src/main/kotlin/net/dankito/fints/messages/MessageBuilderResult.kt b/fints4javaLib/src/main/kotlin/net/dankito/fints/messages/MessageBuilderResult.kt new file mode 100644 index 00000000..ab2be4ab --- /dev/null +++ b/fints4javaLib/src/main/kotlin/net/dankito/fints/messages/MessageBuilderResult.kt @@ -0,0 +1,21 @@ +package net.dankito.fints.messages + + +open class MessageBuilderResult( + val isJobAllowed: Boolean, + val isJobVersionSupported: Boolean, + val allowedVersions: List, + val supportedVersions: List, + val createdMessage: String? +) { + + constructor(isJobAllowed: Boolean) : this(isJobAllowed, false, listOf(), listOf(), null) + + constructor(createdMessage: String) : this(true, true, listOf(), listOf(), createdMessage) + + + open fun isAllowed(version: Int): Boolean { + return allowedVersions.contains(version) + } + +} \ No newline at end of file diff --git a/fints4javaLib/src/main/kotlin/net/dankito/fints/messages/segmente/implementierte/umsaetze/KontoumsaetzeZeitraumMt940Version6.kt b/fints4javaLib/src/main/kotlin/net/dankito/fints/messages/segmente/implementierte/umsaetze/KontoumsaetzeZeitraumMt940Version6.kt new file mode 100644 index 00000000..d2790f9c --- /dev/null +++ b/fints4javaLib/src/main/kotlin/net/dankito/fints/messages/segmente/implementierte/umsaetze/KontoumsaetzeZeitraumMt940Version6.kt @@ -0,0 +1,32 @@ +package net.dankito.fints.messages.segmente.implementierte.umsaetze + +import net.dankito.fints.messages.datenelementgruppen.implementierte.account.Kontoverbindung +import net.dankito.fints.model.BankData +import net.dankito.fints.model.CustomerData +import net.dankito.fints.model.GetTransactionsParameter + + +/** + * Die Lösung bietet dem Kunden die Möglichkeit, auf seinem System verlorengegangene Buchungen erneut zu erhalten. + * + * Die maximale Anzahl der rückzumeldenden Buchungspositionen kann begrenzt werden. Eine Buchungsposition besteht + * aus einem :61:/:86:-Block eines MT 940-Formats. Es muss davon unabhängig immer ein gültiges MT 940-Format + * zurückgemeldet werden, d.h. die Felder :20: bis :60: und :62: bis :86: sind obligatorischer Bestandteil der Rückmeldung. + * + * Der maximale Zeitraum, für den rückwirkend Buchungen beim Kreditinstitut gespeichert sind, wird in den + * Bankparameterdaten übermittelt. + */ +open class KontoumsaetzeZeitraumMt940Version6( + segmentNumber: Int, + parameter: GetTransactionsParameter, + bank: BankData, + customer: CustomerData, + subAccountAttribute: String? = null + +) + : KontoumsaetzeZeitraumMt940Base( + 6, + segmentNumber, + Kontoverbindung(bank.countryCode, bank.bankCode, customer.customerId, subAccountAttribute), + parameter + ) \ No newline at end of file diff --git a/fints4javaLib/src/main/kotlin/net/dankito/fints/response/Response.kt b/fints4javaLib/src/main/kotlin/net/dankito/fints/response/Response.kt index 1e74eb05..48ea9e66 100644 --- a/fints4javaLib/src/main/kotlin/net/dankito/fints/response/Response.kt +++ b/fints4javaLib/src/main/kotlin/net/dankito/fints/response/Response.kt @@ -1,5 +1,6 @@ package net.dankito.fints.response +import net.dankito.fints.messages.MessageBuilderResult import net.dankito.fints.messages.Separators import net.dankito.fints.messages.segmente.id.ISegmentId import net.dankito.fints.messages.segmente.id.MessageSegmentId @@ -14,14 +15,18 @@ open class Response constructor( /** * When a serious error occurred during web request or response parsing. */ - val exception: Exception? = null + val exception: Exception? = null, + val messageCreationError: MessageBuilderResult? = null ) { + open val couldCreateMessage: Boolean + get() = messageCreationError == null + open val responseContainsErrors: Boolean get() = exception == null && messageFeedback?.isError == true open val successful: Boolean - get() = didReceiveResponse && responseContainsErrors == false + get() = couldCreateMessage && didReceiveResponse && responseContainsErrors == false open val isStrongAuthenticationRequired: Boolean get() = tanResponse?.isStrongAuthenticationRequired == true diff --git a/fints4javaLib/src/main/kotlin/net/dankito/fints/response/client/FinTsClientResponse.kt b/fints4javaLib/src/main/kotlin/net/dankito/fints/response/client/FinTsClientResponse.kt index 5357c7b2..9b183aa2 100644 --- a/fints4javaLib/src/main/kotlin/net/dankito/fints/response/client/FinTsClientResponse.kt +++ b/fints4javaLib/src/main/kotlin/net/dankito/fints/response/client/FinTsClientResponse.kt @@ -16,11 +16,20 @@ open class FinTsClientResponse( /** * When a serious error occurred during web request or response parsing. */ - val exception: Exception? = null + val exception: Exception? = null, + + val isJobAllowed: Boolean = true, + val isJobVersionSupported: Boolean = true, + val allowedVersions: List = listOf(), + val supportedVersions: List = listOf() ) { constructor(response: Response) : this(response.successful, response.isStrongAuthenticationRequired, - response.tanResponse, response.errorsToShowToUser, response.exception) + response.tanResponse, response.errorsToShowToUser, response.exception, + response.messageCreationError?.isJobAllowed ?: true, + response.messageCreationError?.isJobVersionSupported ?: true, + response.messageCreationError?.allowedVersions ?: listOf(), + response.messageCreationError?.supportedVersions ?: listOf()) } \ No newline at end of file