From b16390d0ebbfeaf5c54a954af38e82b5f78bf573 Mon Sep 17 00:00:00 2001 From: dankito Date: Thu, 19 Nov 2020 20:03:47 +0100 Subject: [PATCH] Fixed that ?, got treated as field code leading to that parsing whole information to account owner failed --- .../fints/transactions/mt940/Mt940Parser.kt | 30 ++++++++-------- .../fints/transactions/Mt940ParserTest.kt | 35 +++++++++++++++++++ 2 files changed, 51 insertions(+), 14 deletions(-) diff --git a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/transactions/mt940/Mt940Parser.kt b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/transactions/mt940/Mt940Parser.kt index 9a6180aa..24aa3a3e 100644 --- a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/transactions/mt940/Mt940Parser.kt +++ b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/transactions/mt940/Mt940Parser.kt @@ -58,6 +58,8 @@ open class Mt940Parser : IMt940Parser { val ReferenceTypeRegex = Regex("[A-Z]{4}\\+") + val InformationToAccountOwnerSubFieldRegex = Regex("\\?\\d\\d") + const val EndToEndReferenceKey = "EREF+" const val CustomerReferenceKey = "KREF+" @@ -318,21 +320,21 @@ open class Mt940Parser : IMt940Parser { var primaNotaNumber: String? = null var textKeySupplement: String? = null - informationToAccountOwnerString.substring(3).split('?').forEach { subField -> - if (subField.isNotEmpty()) { - val fieldCode = subField.substring(0, 2).toInt() - val fieldValue = subField.substring(2) + val subFieldMatches = InformationToAccountOwnerSubFieldRegex.findAll(informationToAccountOwnerString).toList() + subFieldMatches.forEachIndexed { index, matchResult -> + val fieldCode = matchResult.value.substring(1, 3).toInt() + val endIndex = if (index + 1 < subFieldMatches.size) subFieldMatches[index + 1].range.start else informationToAccountOwnerString.length + val fieldValue = informationToAccountOwnerString.substring(matchResult.range.last + 1, endIndex) - when (fieldCode) { - 0 -> bookingText = fieldValue - 10 -> primaNotaNumber = fieldValue - in 20..29 -> referenceParts.add(fieldValue) - 30 -> otherPartyBankCode = fieldValue - 31 -> otherPartyAccountId = fieldValue - 32, 33 -> otherPartyName.append(fieldValue) - 34 -> textKeySupplement = fieldValue - in 60..63 -> referenceParts.add(fieldValue) - } + when (fieldCode) { + 0 -> bookingText = fieldValue + 10 -> primaNotaNumber = fieldValue + in 20..29 -> referenceParts.add(fieldValue) + 30 -> otherPartyBankCode = fieldValue + 31 -> otherPartyAccountId = fieldValue + 32, 33 -> otherPartyName.append(fieldValue) + 34 -> textKeySupplement = fieldValue + in 60..63 -> referenceParts.add(fieldValue) } } diff --git a/fints4k/src/commonTest/kotlin/net/dankito/banking/fints/transactions/Mt940ParserTest.kt b/fints4k/src/commonTest/kotlin/net/dankito/banking/fints/transactions/Mt940ParserTest.kt index 3513b131..574d47bd 100644 --- a/fints4k/src/commonTest/kotlin/net/dankito/banking/fints/transactions/Mt940ParserTest.kt +++ b/fints4k/src/commonTest/kotlin/net/dankito/banking/fints/transactions/Mt940ParserTest.kt @@ -11,6 +11,7 @@ import net.dankito.banking.fints.transactions.mt940.model.StatementLine import ch.tutteli.atrium.api.verbs.expect import kotlin.test.Test import net.dankito.banking.fints.extensions.isFalse +import net.dankito.banking.fints.extensions.isTrue import net.dankito.banking.fints.model.Amount import net.dankito.utils.multiplatform.Date import net.dankito.utils.multiplatform.DateFormatter @@ -277,6 +278,40 @@ class Mt940ParserTest : FinTsTestBase() { } } + @Test + fun `Fix that ?, gets detected as field code`() { + val transactionsString = """ + :20:STARTUMS + :25:$BankCode/$CustomerId + :28C:0 + :60F:C200511EUR0,00 + :61:200511D15,00NMSCNONREF + :86:105?00BASISLASTSCHRIFT?10931?20EREF+6MKL2OT30QENNLIU + ?21MREF+?,3SQNdUbxm9z7dB)+gKYD?22JAKzCM0G?23CRED+DE94ZZZ00000123456 + ?24SVWZ+306-4991422-2405949 NI?25LE Mktp DE 6MKL2OT30QENNLIU?26 + EREF: 6MKL2OT30QENNLIU MRE?27F: ?,3SQNdUbxm9z7dB)+gKYDJA?28KzCM0G + CRED: DE94ZZZ0000012?293456 IBAN: DE87300308801234?30TUBDDEDD?31DE87300308801234567890?32NILE PAYMENTS EUROPE S.C.?33A.?34992?60567890 BIC: TUBDDEDD + :62F:D200511EUR15,00 + - + """.trimIndent() + + + // when + val result = underTest.parseMt940String(transactionsString) + + + // then + expect(result).hasSize(1) + expect(result.first().transactions).hasSize(1) + + expect(result.first().transactions[0].information?.bookingText).toBe("BASISLASTSCHRIFT") + expect(result.first().transactions[0].information?.otherPartyBankCode).toBe("TUBDDEDD") + expect(result.first().transactions[0].information?.otherPartyAccountId).toBe("DE87300308801234567890") + expect(result.first().transactions[0].information?.endToEndReference).toBe("6MKL2OT30QENNLIU") + expect(result.first().transactions[0].information?.mandateReference).toBe("?,3SQNdUbxm9z7dB)+gKYDJAKzCM0G") + expect(result.first().transactions[0].information?.sepaReference?.contains("IBAN: DE87300308801234567890 BIC: TUBDDEDD") ?: false).isTrue() + } + private fun assertBalance(balance: Balance, isCredit: Boolean, bookingDate: Date, amount: Amount) { expect(balance.isCredit).toBe(isCredit)