diff --git a/fints4k/src/main/kotlin/net/dankito/banking/fints/transactions/mt940/Mt940Parser.kt b/fints4k/src/main/kotlin/net/dankito/banking/fints/transactions/mt940/Mt940Parser.kt index a4b730c5..600cbb24 100644 --- a/fints4k/src/main/kotlin/net/dankito/banking/fints/transactions/mt940/Mt940Parser.kt +++ b/fints4k/src/main/kotlin/net/dankito/banking/fints/transactions/mt940/Mt940Parser.kt @@ -232,7 +232,7 @@ open class Mt940Parser : IMt940Parser { val bookingDateString = if (creditMarkMatcher.start() > 6) fieldValue.substring(6, 10) else null val bookingDate = bookingDateString?.let { // bookingDateString has format MMdd -> add year from valueDateString - parseMt940Date(valueDateString.substring(0, 2) + bookingDateString) + parseMt940BookingDate(bookingDateString, valueDateString, valueDate) } val amountMatcher = AmountPattern.matcher(fieldValue) @@ -418,6 +418,20 @@ open class Mt940Parser : IMt940Parser { return DateFormat.parse(dateString) // fallback to not thread-safe SimpleDateFormat. Works in most cases but not all } + /** + * Booking date string consists only of MMDD -> we need to take the year from value date string. + */ + protected open fun parseMt940BookingDate(bookingDateString: String, valueDateString: String, valueDate: Date): Date { + val bookingDate = parseMt940Date(valueDateString.substring(0, 2) + bookingDateString) + + // there are rare cases that booking date is e.g. on 31.12.2019 and value date on 01.01.2020 -> booking date would be on 31.12.2020 (and therefore in the future) + if (bookingDate.month != valueDate.month && bookingDate.month == 11) { + return parseMt940Date("" + (valueDate.year - 1 - 100) + bookingDateString) + } + + return bookingDate + } + protected open fun parseAmount(amountString: String): BigDecimal { return amountString.replace(',', '.').toBigDecimal() } diff --git a/fints4k/src/test/kotlin/net/dankito/banking/fints/transactions/Mt940ParserTest.kt b/fints4k/src/test/kotlin/net/dankito/banking/fints/transactions/Mt940ParserTest.kt index f19932e8..ccdc3080 100644 --- a/fints4k/src/test/kotlin/net/dankito/banking/fints/transactions/Mt940ParserTest.kt +++ b/fints4k/src/test/kotlin/net/dankito/banking/fints/transactions/Mt940ParserTest.kt @@ -127,6 +127,37 @@ class Mt940ParserTest : FinTsTestBase() { AccountStatement1Transaction2OtherPartyBankCode, AccountStatement1Transaction2OtherPartyAccountId) } + @Test + fun `Fix annual jump from booking date to value date`() { + + val transactionsString = ":20:STARTUMSE\n" + + ":25:72051210/0560165557\n" + + ":28C:00000/001\n" + + ":60F:C191227EUR104501,86\n" + + ":61:2001011230DR3,99N024NONREF\n" + + ":86:809?00ENTGELTABSCHLUSS?106666?20Entgeltabrechnung?21siehe Anl\n" + + "age?3072051210\n" + + ":61:2001011230CR0,00N066NONREF\n" + + ":86:805?00ABSCHLUSS?106666?20Abrechnung 30.12.2019?21siehe Anlage\n" + + "?3072051210\n" + + ":62F:C191230EUR104490,88\n" + + "-" + + + // when + val result = underTest.parseMt940String(transactionsString) + + + // then + assertThat(result).hasSize(1) + assertThat(result.first().transactions).hasSize(2) + + assertThat(result.first().transactions[0].turnover.bookingDate).isEqualTo(Date(119, 11, 30)) + assertThat(result.first().transactions[0].turnover.valueDate).isEqualTo(Date(120, 0, 1)) + assertThat(result.first().transactions[1].turnover.bookingDate).isEqualTo(Date(119, 11, 30)) + assertThat(result.first().transactions[1].turnover.valueDate).isEqualTo(Date(120, 0, 1)) + } + @Test fun parseTransactions() {