Decided against parsing Mt942 creationTime and smallest amount (should rarely be used and may only cause parsing errors)
This commit is contained in:
parent
90a7543641
commit
7ddeb88475
|
@ -1,6 +1,5 @@
|
|||
package net.codinux.banking.fints.transactions.mt940
|
||||
|
||||
import kotlinx.datetime.Instant
|
||||
import net.codinux.banking.fints.log.IMessageLogAppender
|
||||
import net.codinux.banking.fints.transactions.mt940.model.AmountAndCurrency
|
||||
import net.codinux.banking.fints.transactions.mt940.model.InterimAccountStatement
|
||||
|
@ -42,9 +41,12 @@ open class Mt942Parser(
|
|||
transactions: List<Transaction>,
|
||||
fieldsByCode: List<Pair<String, String>>
|
||||
): InterimAccountStatement {
|
||||
val smallestAmounts = fieldsByCode.filter { it.first.startsWith(SmallestAmountCode) } // should we parse it? i see no use in it
|
||||
.mapIndexed { index, field -> parseAmountAndCurrency(field.second, index == 0) }
|
||||
val creationTime = fieldsByCode.first { it.first == CreationTimeCode || it.first.startsWith(CreationTimeStartCode) } // should we parse it? i see no use in it
|
||||
// also decided against parsing smallest amounts, i don't think they ever going to be used
|
||||
// val smallestAmounts = fieldsByCode.filter { it.first.startsWith(SmallestAmountCode) } // should we parse it? i see no use in it
|
||||
// .mapIndexed { index, field -> parseAmountAndCurrency(field.second, index == 0) }
|
||||
|
||||
// decided against parsing creation time as there are so many non specification confirm time formats that parsing is likely to fail 'cause of this unused value
|
||||
// val creationTime = parseDateTime(fieldsByCode.first { it.first == CreationTimeCode || it.first.startsWith(CreationTimeStartCode) }.second)
|
||||
|
||||
val numberAndTotalOfDebitPostings = fieldsByCode.firstOrNull { it.first.equals(AmountOfDebitPostingsCode) }
|
||||
?.let { parseNumberAndTotalOfPostings(it.second) }
|
||||
|
@ -55,9 +57,6 @@ open class Mt942Parser(
|
|||
orderReferenceNumber, referenceNumber,
|
||||
bankCodeBicOrIban, accountIdentifier,
|
||||
statementNumber, sheetNumber,
|
||||
smallestAmounts.first(),
|
||||
if (smallestAmounts.size > 1) smallestAmounts[1] else null,
|
||||
Instant.DISTANT_PAST,
|
||||
transactions,
|
||||
numberAndTotalOfDebitPostings,
|
||||
numberAndTotalOfCreditPostings
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package net.codinux.banking.fints.transactions.mt940
|
||||
|
||||
import kotlinx.datetime.LocalDate
|
||||
import kotlinx.datetime.Month
|
||||
import kotlinx.datetime.*
|
||||
import net.codinux.banking.fints.extensions.EuropeBerlin
|
||||
import net.codinux.log.logger
|
||||
import net.codinux.banking.fints.log.IMessageLogAppender
|
||||
import net.codinux.banking.fints.model.Amount
|
||||
|
@ -469,7 +469,7 @@ abstract class Mt94xParserBase<T: AccountStatementCommon>(
|
|||
}
|
||||
|
||||
|
||||
protected open fun parseMt940Date(dateString: String): LocalDate {
|
||||
open fun parseMt940Date(dateString: String): LocalDate {
|
||||
// TODO: this should be necessary anymore, isn't it?
|
||||
|
||||
// SimpleDateFormat is not thread-safe. Before adding another library i decided to parse
|
||||
|
@ -526,6 +526,30 @@ abstract class Mt94xParserBase<T: AccountStatementCommon>(
|
|||
return bookingDate
|
||||
}
|
||||
|
||||
open fun parseTime(timeString: String): LocalTime {
|
||||
val hour = timeString.substring(0, 2).toInt()
|
||||
val minute = timeString.substring(2, 4).toInt()
|
||||
|
||||
return LocalTime(hour, minute)
|
||||
}
|
||||
|
||||
open fun parseDateTime(dateTimeString: String): Instant {
|
||||
val date = parseMt940Date(dateTimeString.substring(0, 6))
|
||||
|
||||
val time = parseTime(dateTimeString.substring(6, 10))
|
||||
|
||||
val dateTime = LocalDateTime(date, time)
|
||||
|
||||
return if (dateTimeString.length == 15) { // actually mandatory, but by far not always stated: the time zone
|
||||
val plus = dateTimeString[10] == '+'
|
||||
val timeDifference = parseTime(dateTimeString.substring(11))
|
||||
|
||||
dateTime.toInstant(UtcOffset(if (plus) timeDifference.hour else timeDifference.hour * -1, timeDifference.minute))
|
||||
} else { // we then assume the server states the DateTime in FinTS's default time zone, Europe/Berlin
|
||||
dateTime.toInstant(TimeZone.EuropeBerlin)
|
||||
}
|
||||
}
|
||||
|
||||
protected open fun parseAmount(amountString: String): Amount {
|
||||
return Amount(amountString)
|
||||
}
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
package net.codinux.banking.fints.transactions.mt940.model
|
||||
|
||||
import kotlinx.datetime.Instant
|
||||
|
||||
open class InterimAccountStatement(
|
||||
orderReferenceNumber: String,
|
||||
referenceNumber: String?,
|
||||
|
@ -12,11 +10,12 @@ open class InterimAccountStatement(
|
|||
statementNumber: Int,
|
||||
sheetNumber: Int?,
|
||||
|
||||
val smallestAmountOfReportedTransactions: AmountAndCurrency,
|
||||
|
||||
val smallestAmountOfReportedCreditTransactions: AmountAndCurrency? = null,
|
||||
|
||||
val creationTime: Instant,
|
||||
// decided against parsing them, see Mt942Parser
|
||||
// val smallestAmountOfReportedTransactions: AmountAndCurrency,
|
||||
//
|
||||
// val smallestAmountOfReportedCreditTransactions: AmountAndCurrency? = null,
|
||||
//
|
||||
// val creationTime: Instant,
|
||||
|
||||
transactions: List<Transaction>,
|
||||
|
||||
|
@ -27,11 +26,11 @@ open class InterimAccountStatement(
|
|||
) : AccountStatementCommon(orderReferenceNumber, referenceNumber, bankCodeBicOrIban, accountIdentifier, statementNumber, sheetNumber, transactions) {
|
||||
|
||||
// for object deserializers
|
||||
private constructor() : this("", "", "", null, 0, null, AmountAndCurrency(), null, Instant.DISTANT_PAST, listOf())
|
||||
private constructor() : this("", "", "", null, 0, null, listOf())
|
||||
|
||||
|
||||
override fun toString(): String {
|
||||
return "$smallestAmountOfReportedTransactions ${super.toString()}"
|
||||
return "${amountAndTotalOfDebitPostings?.amount} ${super.toString()}"
|
||||
}
|
||||
|
||||
}
|
|
@ -103,13 +103,13 @@ class Mt942ParserTest {
|
|||
assertEquals(5, statement.statementNumber)
|
||||
assertEquals(1, statement.sheetNumber)
|
||||
|
||||
assertEquals("20,50", statement.smallestAmountOfReportedTransactions.amount)
|
||||
assertEquals("EUR", statement.smallestAmountOfReportedTransactions.currency)
|
||||
assertEquals(false, statement.smallestAmountOfReportedTransactions.isCredit)
|
||||
|
||||
assertEquals("155,34", statement.smallestAmountOfReportedCreditTransactions?.amount)
|
||||
assertEquals("EUR", statement.smallestAmountOfReportedCreditTransactions?.currency)
|
||||
assertEquals(true, statement.smallestAmountOfReportedCreditTransactions?.isCredit)
|
||||
// assertEquals("20,50", statement.smallestAmountOfReportedTransactions.amount)
|
||||
// assertEquals("EUR", statement.smallestAmountOfReportedTransactions.currency)
|
||||
// assertEquals(false, statement.smallestAmountOfReportedTransactions.isCredit)
|
||||
//
|
||||
// assertEquals("155,34", statement.smallestAmountOfReportedCreditTransactions?.amount)
|
||||
// assertEquals("EUR", statement.smallestAmountOfReportedCreditTransactions?.currency)
|
||||
// assertEquals(true, statement.smallestAmountOfReportedCreditTransactions?.isCredit)
|
||||
|
||||
assertEquals(1, statement.amountAndTotalOfDebitPostings?.numberOfPostings)
|
||||
assertEquals("20,50", statement.amountAndTotalOfDebitPostings?.amount)
|
||||
|
@ -167,10 +167,10 @@ class Mt942ParserTest {
|
|||
assertEquals(0, statement.statementNumber)
|
||||
assertEquals(1, statement.sheetNumber)
|
||||
|
||||
assertEquals("60,77", statement.smallestAmountOfReportedTransactions.amount)
|
||||
assertEquals("EUR", statement.smallestAmountOfReportedTransactions.currency)
|
||||
assertEquals(false, statement.smallestAmountOfReportedTransactions.isCredit)
|
||||
assertNull(statement.smallestAmountOfReportedCreditTransactions)
|
||||
// assertEquals("60,77", statement.smallestAmountOfReportedTransactions.amount)
|
||||
// assertEquals("EUR", statement.smallestAmountOfReportedTransactions.currency)
|
||||
// assertEquals(false, statement.smallestAmountOfReportedTransactions.isCredit)
|
||||
// assertNull(statement.smallestAmountOfReportedCreditTransactions)
|
||||
|
||||
assertEquals(1, statement.amountAndTotalOfDebitPostings?.numberOfPostings)
|
||||
assertEquals("60,77", statement.amountAndTotalOfDebitPostings?.amount)
|
||||
|
@ -199,8 +199,8 @@ class Mt942ParserTest {
|
|||
assertEquals(0, statement.statementNumber)
|
||||
assertEquals(1, statement.sheetNumber)
|
||||
|
||||
assertEquals("0,", statement.smallestAmountOfReportedTransactions.amount)
|
||||
assertEquals("EUR", statement.smallestAmountOfReportedTransactions.currency)
|
||||
// assertEquals("0,", statement.smallestAmountOfReportedTransactions.amount)
|
||||
// assertEquals("EUR", statement.smallestAmountOfReportedTransactions.currency)
|
||||
|
||||
assertSize(0, statement.transactions)
|
||||
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
package net.codinux.banking.fints.transactions
|
||||
|
||||
import kotlinx.datetime.LocalDateTime
|
||||
import kotlinx.datetime.TimeZone
|
||||
import kotlinx.datetime.toLocalDateTime
|
||||
import net.codinux.banking.fints.extensions.EuropeBerlin
|
||||
import net.codinux.banking.fints.test.assertEquals
|
||||
import net.codinux.banking.fints.transactions.mt940.Mt94xParserBase
|
||||
import net.codinux.banking.fints.transactions.mt940.model.AccountStatement
|
||||
import net.codinux.banking.fints.transactions.mt940.model.Transaction
|
||||
import kotlin.test.Test
|
||||
|
||||
class Mt94xParserBaseTest {
|
||||
|
||||
private val underTest = object : Mt94xParserBase<AccountStatement>() {
|
||||
override fun createAccountStatement(orderReferenceNumber: String, referenceNumber: String?, bankCodeBicOrIban: String, accountIdentifier: String?, statementNumber: Int, sheetNumber: Int?, transactions: List<Transaction>, fieldsByCode: List<Pair<String, String>>): AccountStatement {
|
||||
throw IllegalStateException("We are testing base functionality, not parsing (Interim)AccountStatements")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
fun parseDateTimeWithTimeZoneUtc() {
|
||||
val result = underTest.parseDateTime("1311130945+0000")
|
||||
|
||||
val resultAtEuropeBerlin = result.toLocalDateTime(TimeZone.EuropeBerlin)
|
||||
|
||||
assertEquals(LocalDateTime(2013, 11, 13, 10, 45), resultAtEuropeBerlin)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun parseDateTimeWithTimeZoneEuropeBerlin() {
|
||||
val result = underTest.parseDateTime("2408210742+0200")
|
||||
|
||||
val resultAtEuropeBerlin = result.toLocalDateTime(TimeZone.EuropeBerlin)
|
||||
|
||||
assertEquals(LocalDateTime(2024, 8, 21, 7, 42), resultAtEuropeBerlin)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun parseDateTimeWithoutTimeZone() { // actually the time zone is mandatory, but by far not all banks add it
|
||||
val result = underTest.parseDateTime("2408232156")
|
||||
|
||||
val resultAtEuropeBerlin = result.toLocalDateTime(TimeZone.EuropeBerlin)
|
||||
|
||||
assertEquals(LocalDateTime(2024, 8, 23, 21, 56), resultAtEuropeBerlin)
|
||||
}
|
||||
|
||||
// @Test
|
||||
// fun parseDateTimeStartingWithCharacter() {
|
||||
// // really don't know where's the 'C' at the start is coming from, but this is an example from DFÜ-Abkommen PDF, p. 674
|
||||
// val result = underTest.parseDateTime("C1311130945+0000")
|
||||
//
|
||||
// val resultAtEuropeBerlin = result.toLocalDateTime(TimeZone.EuropeBerlin)
|
||||
//
|
||||
// assertEquals(LocalDateTime(2024, 8, 23, 21, 56), resultAtEuropeBerlin)
|
||||
// }
|
||||
|
||||
}
|
Loading…
Reference in New Issue