Implemented adding errors of ResponseParser, Mt940Parser and Mt940AccountTransactionsParser to MessageLog

This commit is contained in:
dankito 2020-12-06 21:51:05 +01:00
parent 55f5603cb9
commit 06ef511892
8 changed files with 105 additions and 25 deletions

View File

@ -3,6 +3,7 @@ package net.dankito.banking.fints
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import net.dankito.banking.fints.callback.FinTsClientCallback
import net.dankito.banking.fints.log.IMessageLogAppender
import net.dankito.banking.fints.log.MessageLogCollector
import net.dankito.banking.fints.messages.MessageBuilder
import net.dankito.banking.fints.messages.MessageBuilderResult
@ -68,6 +69,12 @@ open class FinTsClient(
}
init {
responseParser.logAppender = messageLogAppender
mt940Parser.logAppender = messageLogAppender
}
/**
* Retrieves information about bank (e.g. supported HBCI versions, FinTS server address,
* supported jobs, ...).
@ -394,7 +401,8 @@ open class FinTsClient(
dialogContext.chunkedResponseHandler = { response ->
response.getFirstSegmentById<ReceivedAccountTransactions>(InstituteSegmentId.AccountTransactionsMt940)?.let { transactionsSegment ->
val (chunkTransaction, remainder) = mt940Parser.parseTransactionsChunk(remainingMt940String + transactionsSegment.bookedTransactionsString, parameter.account)
val (chunkTransaction, remainder) = mt940Parser.parseTransactionsChunk(remainingMt940String + transactionsSegment.bookedTransactionsString,
dialogContext.bank, parameter.account)
bookedTransactions.addAll(chunkTransaction)
remainingMt940String = remainder

View File

@ -0,0 +1,11 @@
package net.dankito.banking.fints.log
import net.dankito.banking.fints.model.BankData
import net.dankito.utils.multiplatform.log.Logger
interface IMessageLogAppender {
fun logError(message: String, e: Exception? = null, logger: Logger? = null, bank: BankData? = null)
}

View File

@ -1,5 +1,6 @@
package net.dankito.banking.fints.response
import net.dankito.banking.fints.log.IMessageLogAppender
import net.dankito.banking.fints.messages.Separators
import net.dankito.banking.fints.messages.datenelemente.abgeleiteteformate.Datum
import net.dankito.banking.fints.messages.datenelemente.abgeleiteteformate.Uhrzeit
@ -25,7 +26,8 @@ import net.dankito.utils.multiplatform.log.LoggerFactory
open class ResponseParser(
protected val messageUtils: MessageUtils = MessageUtils()
protected open val messageUtils: MessageUtils = MessageUtils(),
open var logAppender: IMessageLogAppender? = null
) {
companion object {
@ -52,7 +54,7 @@ open class ResponseParser(
return BankResponse(true, response, parsedSegments)
} catch (e: Exception) {
log.error(e) { "Could not parse response '$response'" }
logError("Could not parse response '$response'", e)
return BankResponse(true, response, errorMessage = e.getInnerExceptionMessage())
}
@ -84,7 +86,7 @@ open class ResponseParser(
return parseSegment(segment, segmentId, dataElementGroups)
}
} catch (e: Exception) {
log.error(e) { "Could not parse segment '$segment'" } // TODO: what to do here, how to inform user?
logError("Could not parse segment '$segment'", e) // TODO: what to do here, how to inform user?
}
return null
@ -463,7 +465,7 @@ open class ResponseParser(
return parseCodeEnum(smsAbbuchungskontoErforderlichString, SmsAbbuchungskontoErforderlich.values())
} catch (e: Exception) {
if (isEncodedBooleanValue(smsAbbuchungskontoErforderlichString) == false) {
log.error(e) { "Could not parse '$smsAbbuchungskontoErforderlichString' to SmsAbbuchungskontoErforderlich" }
logError("Could not parse '$smsAbbuchungskontoErforderlichString' to SmsAbbuchungskontoErforderlich", e)
}
}
@ -478,7 +480,7 @@ open class ResponseParser(
return parseCodeEnum(auftraggeberkontoErforderlichString, AuftraggeberkontoErforderlich.values())
} catch (e: Exception) {
if (isEncodedBooleanValue(auftraggeberkontoErforderlichString) == false) {
log.error(e) { "Could not parse '$auftraggeberkontoErforderlichString' to AuftraggeberkontoErforderlich" }
logError("Could not parse '$auftraggeberkontoErforderlichString' to AuftraggeberkontoErforderlich", e)
}
}
@ -708,7 +710,7 @@ open class ResponseParser(
return CreditCardTransaction(amount, transactionDescriptionBase, transactionDescriptionSupplement, bookingDate, valueDate, isCleared)
} catch (e: Exception) {
log.error("Could not parse Credit card transaction '$transactionDataElementGroup'", e)
logError("Could not parse Credit card transaction '$transactionDataElementGroup'", e)
}
return null
@ -978,4 +980,14 @@ open class ResponseParser(
return binaryData
}
protected open fun logError(message: String, e: Exception?) {
logAppender?.let { logAppender ->
logAppender.logError(message, e, log)
}
?: run {
log.error(e) { message }
}
}
}

View File

@ -1,13 +1,18 @@
package net.dankito.banking.fints.transactions
import net.dankito.banking.fints.log.IMessageLogAppender
import net.dankito.banking.fints.model.AccountData
import net.dankito.banking.fints.model.AccountTransaction
import net.dankito.banking.fints.model.BankData
interface IAccountTransactionsParser {
fun parseTransactions(transactionsString: String, account: AccountData): List<AccountTransaction>
var logAppender: IMessageLogAppender?
fun parseTransactionsChunk(transactionsChunk: String, account: AccountData): Pair<List<AccountTransaction>, String>
fun parseTransactions(transactionsString: String, bank: BankData, account: AccountData): List<AccountTransaction>
fun parseTransactionsChunk(transactionsChunk: String, bank: BankData, account: AccountData): Pair<List<AccountTransaction>, String>
}

View File

@ -1,9 +1,7 @@
package net.dankito.banking.fints.transactions
import net.dankito.banking.fints.model.AccountData
import net.dankito.banking.fints.model.AccountTransaction
import net.dankito.banking.fints.model.Amount
import net.dankito.banking.fints.model.Money
import net.dankito.banking.fints.log.IMessageLogAppender
import net.dankito.banking.fints.model.*
import net.dankito.banking.fints.transactions.mt940.IMt940Parser
import net.dankito.banking.fints.transactions.mt940.Mt940Parser
import net.dankito.banking.fints.transactions.mt940.model.AccountStatement
@ -11,10 +9,12 @@ import net.dankito.banking.fints.transactions.mt940.model.Balance
import net.dankito.banking.fints.transactions.mt940.model.Transaction
import net.dankito.banking.fints.transactions.mt940.model.StatementLine
import net.dankito.utils.multiplatform.log.LoggerFactory
import net.dankito.utils.multiplatform.log.Logger
open class Mt940AccountTransactionsParser(
protected val mt940Parser: IMt940Parser = Mt940Parser()
protected val mt940Parser: IMt940Parser = Mt940Parser(),
override var logAppender: IMessageLogAppender? = null
) : IAccountTransactionsParser {
companion object {
@ -22,23 +22,25 @@ open class Mt940AccountTransactionsParser(
}
override fun parseTransactions(transactionsString: String, account: AccountData): List<AccountTransaction> {
override fun parseTransactions(transactionsString: String, bank: BankData, account: AccountData): List<AccountTransaction> {
setLogAppender(bank)
val accountStatements = mt940Parser.parseMt940String(transactionsString)
return accountStatements.flatMap { mapToAccountTransactions(it, account) }
return accountStatements.flatMap { mapToAccountTransactions(it, bank, account) }
}
override fun parseTransactionsChunk(transactionsChunk: String, account: AccountData): Pair<List<AccountTransaction>, String> {
override fun parseTransactionsChunk(transactionsChunk: String, bank: BankData, account: AccountData): Pair<List<AccountTransaction>, String> {
val (accountStatements, remainder) = mt940Parser.parseMt940Chunk(transactionsChunk)
return Pair(accountStatements.flatMap { mapToAccountTransactions(it, account) }, remainder)
return Pair(accountStatements.flatMap { mapToAccountTransactions(it, bank, account) }, remainder)
}
protected open fun mapToAccountTransactions(statement: AccountStatement, account: AccountData): List<AccountTransaction> {
protected open fun mapToAccountTransactions(statement: AccountStatement, bank: BankData, account: AccountData): List<AccountTransaction> {
try {
return statement.transactions.map { mapToAccountTransaction(statement, it, account) }
} catch (e: Exception) {
log.error(e) { "Could not map AccountStatement '$statement' to AccountTransactions" }
logError("Could not map AccountStatement '$statement' to AccountTransactions", e, bank)
}
return listOf()
@ -113,4 +115,27 @@ open class Mt940AccountTransactionsParser(
return positiveAmount
}
protected open fun setLogAppender(bankDataOfCall: BankData) {
// TODO: this does not perfectly work as in parallel calls to Mt940AccountTransactionsParser for different account logAppender gets overwritten by the later call
mt940Parser.logAppender = logAppender?.let { logAppender ->
object : IMessageLogAppender {
override fun logError(message: String, e: Exception?, logger: Logger?, bank: BankData?) {
logAppender.logError(message, e, logger, bank ?: bankDataOfCall)
}
}
}
}
protected open fun logError(message: String, e: Exception?, bank: BankData) {
logAppender?.let { logAppender ->
logAppender.logError(message, e, log, bank)
}
?: run {
log.error(e) { message }
}
}
}

View File

@ -1,10 +1,14 @@
package net.dankito.banking.fints.transactions.mt940
import net.dankito.banking.fints.log.IMessageLogAppender
import net.dankito.banking.fints.transactions.mt940.model.AccountStatement
interface IMt940Parser {
var logAppender: IMessageLogAppender?
/**
* Parses a whole MT 940 statements string, that is one that ends with a "-" line.
*/

View File

@ -1,5 +1,6 @@
package net.dankito.banking.fints.transactions.mt940
import net.dankito.banking.fints.log.IMessageLogAppender
import net.dankito.banking.fints.model.Amount
import net.dankito.banking.fints.transactions.mt940.model.*
import net.dankito.utils.multiplatform.Date
@ -77,6 +78,9 @@ open class Mt940Parser : IMt940Parser {
}
override var logAppender: IMessageLogAppender? = null
/**
* Parses a whole MT 940 statements string, that is one that ends with a "-" line.
*/
@ -108,7 +112,7 @@ open class Mt940Parser : IMt940Parser {
return Pair(transactions, remainder)
} catch (e: Exception) {
log.error(e) { "Could not parse account statements from MT940 string:\n$mt940Chunk" }
logError("Could not parse account statements from MT940 string:\n$mt940Chunk", e)
}
return Pair(listOf(), "")
@ -131,7 +135,7 @@ open class Mt940Parser : IMt940Parser {
return parseAccountStatement(fieldsByCode)
} catch (e: Exception) {
log.error(e) { "Could not parse account statement:\n$accountStatementString" }
logError("Could not parse account statement:\n$accountStatementString", e)
}
return null
@ -301,7 +305,7 @@ open class Mt940Parser : IMt940Parser {
return information
} catch (e: Exception) {
log.error(e) { "Could not parse InformationToAccountOwner from field value '$informationToAccountOwnerString'" }
logError("Could not parse InformationToAccountOwner from field value '$informationToAccountOwnerString'", e)
}
return null
@ -463,7 +467,7 @@ open class Mt940Parser : IMt940Parser {
return Date(year + 2000, month, day) // java.util.Date years start at 1900 at month at 0 not at 1
} catch (e: Exception) {
log.error(e) { "Could not parse dateString '$dateString'" }
logError("Could not parse dateString '$dateString'", e)
}
}
@ -489,4 +493,14 @@ open class Mt940Parser : IMt940Parser {
return Amount(amountString)
}
protected open fun logError(message: String, e: Exception?) {
logAppender?.let { logAppender ->
logAppender.logError(message, e, log)
}
?: run {
log.error(e) { message }
}
}
}

View File

@ -2,6 +2,7 @@ package net.dankito.banking.fints.transactions
import net.dankito.banking.fints.FinTsTestBaseJvm
import net.dankito.banking.fints.model.AccountData
import net.dankito.banking.fints.model.BankData
import org.assertj.core.api.Assertions.assertThat
import org.junit.Test
@ -20,7 +21,7 @@ class Mt940AccountTransactionsParserTest : FinTsTestBaseJvm() {
// when
val result = underTest.parseTransactions(transactionsString, AccountData())
val result = underTest.parseTransactions(transactionsString, BankData(), AccountData())
// then