Implemented parsing received transactions string as a whole as sometimes banks breaks MT940 data sets in the middle when sending transactions in multiple messages so that this data set cannot be parsed if received messages get parsed immediately

This commit is contained in:
dankl 2019-12-31 17:27:17 +01:00 committed by dankito
parent 2951445390
commit 9798b39807
4 changed files with 30 additions and 21 deletions

View File

@ -18,6 +18,8 @@ import net.dankito.fints.response.client.FinTsClientResponse
import net.dankito.fints.response.client.GetTanMediaListResponse import net.dankito.fints.response.client.GetTanMediaListResponse
import net.dankito.fints.response.client.GetTransactionsResponse import net.dankito.fints.response.client.GetTransactionsResponse
import net.dankito.fints.response.segments.* import net.dankito.fints.response.segments.*
import net.dankito.fints.transactions.IAccountTransactionsParser
import net.dankito.fints.transactions.Mt940AccountTransactionsParser
import net.dankito.fints.util.IBase64Service import net.dankito.fints.util.IBase64Service
import net.dankito.utils.IThreadPool import net.dankito.utils.IThreadPool
import net.dankito.utils.ThreadPool import net.dankito.utils.ThreadPool
@ -36,6 +38,7 @@ open class FinTsClient @JvmOverloads constructor(
protected val webClient: IWebClient = OkHttpWebClient(), protected val webClient: IWebClient = OkHttpWebClient(),
protected val messageBuilder: MessageBuilder = MessageBuilder(), protected val messageBuilder: MessageBuilder = MessageBuilder(),
protected val responseParser: ResponseParser = ResponseParser(), protected val responseParser: ResponseParser = ResponseParser(),
protected val mt940Parser: IAccountTransactionsParser = Mt940AccountTransactionsParser(),
protected val threadPool: IThreadPool = ThreadPool(), protected val threadPool: IThreadPool = ThreadPool(),
protected val product: ProductData = ProductData("15E53C26816138699C7B6A3E8", "0.1") // TODO: get version dynamically protected val product: ProductData = ProductData("15E53C26816138699C7B6A3E8", "0.1") // TODO: get version dynamically
) { ) {
@ -261,7 +264,7 @@ open class FinTsClient @JvmOverloads constructor(
// TODO: that should not work. Find out in which method transactions are retrieved after entering TAN // TODO: that should not work. Find out in which method transactions are retrieved after entering TAN
// just retrieved all transactions -> check if retrieving that ones of last 90 days is possible without entering TAN // just retrieved all transactions -> check if retrieving that ones of last 90 days is possible without entering TAN
if (customer.supportsRetrievingTransactionsOfLast90DaysWithoutTan == null && if (customer.supportsRetrievingTransactionsOfLast90DaysWithoutTan == null &&
response.successful && transactions.bookedTransactions.isNotEmpty() && parameter.fromDate == null) { response.successful && transactions.bookedTransactionsString.isNotEmpty() && parameter.fromDate == null) {
tryGetTransactionsOfLast90DaysWithoutTan(bank, customer) tryGetTransactionsOfLast90DaysWithoutTan(bank, customer)
} }
@ -277,22 +280,31 @@ open class FinTsClient @JvmOverloads constructor(
} }
protected open fun getTransactionsFromResponse(response: Response, transactions: ReceivedAccountTransactions): Pair<List<AccountTransaction>, List<Any>> { protected open fun getTransactionsFromResponse(response: Response, transactions: ReceivedAccountTransactions): Pair<List<AccountTransaction>, List<Any>> {
val bookedTransactions = mutableListOf<AccountTransaction>() val bookedTransactionsString = StringBuilder()
val unbookedTransactions = mutableListOf<Any>() val unbookedTransactionsString = StringBuilder()
bookedTransactions.addAll(transactions.bookedTransactions) getTransactionsFromResponse(response, transactions, bookedTransactionsString, unbookedTransactionsString)
unbookedTransactions.addAll(transactions.unbookedTransactions)
val bookedTransactions = mt940Parser.parseTransactions(bookedTransactionsString.toString())
val unbookedTransactions = listOf<Any>() // TODO: implement parsing MT942
return Pair(bookedTransactions, unbookedTransactions)
}
protected open fun getTransactionsFromResponse(response: Response, transactions: ReceivedAccountTransactions,
bookedTransactionsString: StringBuilder, unbookedTransactionsString: StringBuilder) {
bookedTransactionsString.append(transactions.bookedTransactionsString)
transactions.unbookedTransactionsString?.let {
unbookedTransactionsString.append(transactions.unbookedTransactionsString)
}
response.followUpResponse?.let { followUpResponse -> response.followUpResponse?.let { followUpResponse ->
followUpResponse.getFirstSegmentById<ReceivedAccountTransactions>(InstituteSegmentId.AccountTransactionsMt940)?.let { followUpTransactions -> followUpResponse.getFirstSegmentById<ReceivedAccountTransactions>(InstituteSegmentId.AccountTransactionsMt940)?.let { followUpTransactions ->
val followUpBookedAndUnbookedTransactions = getTransactionsFromResponse(followUpResponse, followUpTransactions) getTransactionsFromResponse(followUpResponse, followUpTransactions, bookedTransactionsString, unbookedTransactionsString)
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,

View File

@ -7,6 +7,8 @@ import net.dankito.fints.response.ResponseParser
import net.dankito.fints.response.client.AddAccountResponse import net.dankito.fints.response.client.AddAccountResponse
import net.dankito.fints.response.client.FinTsClientResponse import net.dankito.fints.response.client.FinTsClientResponse
import net.dankito.fints.response.client.GetTransactionsResponse import net.dankito.fints.response.client.GetTransactionsResponse
import net.dankito.fints.transactions.IAccountTransactionsParser
import net.dankito.fints.transactions.Mt940AccountTransactionsParser
import net.dankito.fints.util.IBase64Service import net.dankito.fints.util.IBase64Service
import net.dankito.utils.IThreadPool import net.dankito.utils.IThreadPool
import net.dankito.utils.ThreadPool import net.dankito.utils.ThreadPool
@ -22,11 +24,12 @@ open class FinTsClientForCustomer(
webClient: IWebClient = OkHttpWebClient(), webClient: IWebClient = OkHttpWebClient(),
messageBuilder: MessageBuilder = MessageBuilder(), messageBuilder: MessageBuilder = MessageBuilder(),
responseParser: ResponseParser = ResponseParser(), responseParser: ResponseParser = ResponseParser(),
mt940Parser: IAccountTransactionsParser = Mt940AccountTransactionsParser(),
threadPool: IThreadPool = ThreadPool(), threadPool: IThreadPool = ThreadPool(),
product: ProductData = ProductData("15E53C26816138699C7B6A3E8", "0.1") // TODO: get version dynamically product: ProductData = ProductData("15E53C26816138699C7B6A3E8", "0.1") // TODO: get version dynamically
) { ) {
protected val client = FinTsClient(callback, base64Service, webClient, messageBuilder, responseParser, threadPool, product) protected val client = FinTsClient(callback, base64Service, webClient, messageBuilder, responseParser, mt940Parser, threadPool, product)
open fun addAccountAsync(callback: (AddAccountResponse) -> Unit) { open fun addAccountAsync(callback: (AddAccountResponse) -> Unit) {

View File

@ -14,8 +14,6 @@ import net.dankito.fints.messages.datenelementgruppen.implementierte.Kreditinsti
import net.dankito.fints.messages.datenelementgruppen.implementierte.signatur.Sicherheitsprofil import net.dankito.fints.messages.datenelementgruppen.implementierte.signatur.Sicherheitsprofil
import net.dankito.fints.messages.segmente.id.MessageSegmentId import net.dankito.fints.messages.segmente.id.MessageSegmentId
import net.dankito.fints.response.segments.* import net.dankito.fints.response.segments.*
import net.dankito.fints.transactions.IAccountTransactionsParser
import net.dankito.fints.transactions.Mt940AccountTransactionsParser
import net.dankito.fints.util.MessageUtils import net.dankito.fints.util.MessageUtils
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import java.math.BigDecimal import java.math.BigDecimal
@ -24,7 +22,6 @@ import java.util.regex.Pattern
open class ResponseParser @JvmOverloads constructor( open class ResponseParser @JvmOverloads constructor(
protected val mt940Parser: IAccountTransactionsParser = Mt940AccountTransactionsParser(),
protected val messageUtils: MessageUtils = MessageUtils() protected val messageUtils: MessageUtils = MessageUtils()
) { ) {
@ -504,10 +501,9 @@ open class ResponseParser @JvmOverloads constructor(
protected open fun parseMt940AccountTransactions(segment: String, dataElementGroups: List<String>): ReceivedAccountTransactions { protected open fun parseMt940AccountTransactions(segment: String, dataElementGroups: List<String>): ReceivedAccountTransactions {
val bookedTransactionsString = extractBinaryData(dataElementGroups[1]) val bookedTransactionsString = extractBinaryData(dataElementGroups[1])
// TODO: implement parsing MT942
val unbookedTransactionsString = if (dataElementGroups.size > 2) extractBinaryData(dataElementGroups[2]) else null val unbookedTransactionsString = if (dataElementGroups.size > 2) extractBinaryData(dataElementGroups[2]) else null
return ReceivedAccountTransactions(mt940Parser.parseTransactions(bookedTransactionsString), listOf(), segment) return ReceivedAccountTransactions(bookedTransactionsString, unbookedTransactionsString, segment)
} }

View File

@ -1,11 +1,9 @@
package net.dankito.fints.response.segments package net.dankito.fints.response.segments
import net.dankito.fints.model.AccountTransaction
open class ReceivedAccountTransactions( open class ReceivedAccountTransactions(
val bookedTransactions: List<AccountTransaction>, val bookedTransactionsString: String,
val unbookedTransactions: List<Any>, // TODO val unbookedTransactionsString: String?, // TODO
segmentString: String segmentString: String
) )