Implemented Mt940AccountTransactionsParser

This commit is contained in:
dankl 2019-10-12 13:57:06 +02:00 committed by dankito
parent 7544c9c666
commit 4b731d83c3
3 changed files with 124 additions and 0 deletions

View File

@ -0,0 +1,10 @@
package net.dankito.fints.transactions
import net.dankito.fints.model.AccountTransaction
interface IAccountTransactionsParser {
fun parseTransactions(transactionsString: String): List<AccountTransaction>
}

View File

@ -0,0 +1,80 @@
package net.dankito.fints.transactions
import net.dankito.fints.model.AccountTransaction
import net.dankito.fints.transactions.mt940.IMt940Parser
import net.dankito.fints.transactions.mt940.Mt940Parser
import net.dankito.fints.transactions.mt940.model.AccountStatement
import net.dankito.fints.transactions.mt940.model.Balance
import net.dankito.fints.transactions.mt940.model.Transaction
import net.dankito.fints.transactions.mt940.model.Turnover
import org.slf4j.LoggerFactory
import java.math.BigDecimal
open class Mt940AccountTransactionsParser @JvmOverloads constructor(
protected val mt940Parser: IMt940Parser = Mt940Parser()
) : IAccountTransactionsParser {
companion object {
private val log = LoggerFactory.getLogger(Mt940AccountTransactionsParser::class.java)
}
override fun parseTransactions(transactionsString: String): List<AccountTransaction> {
val accountStatements = mt940Parser.parseMt940String(transactionsString)
return accountStatements.flatMap { mapToAccountTransactions(it) }
}
protected open fun mapToAccountTransactions(statement: AccountStatement): List<AccountTransaction> {
try {
return statement.transactions.map { mapToAccountTransaction(statement, it) }
} catch (e: Exception) {
log.error("Could not map AccountStatement '$statement' to AccountTransactions", e)
}
return listOf()
}
protected open fun mapToAccountTransaction(statement: AccountStatement, transaction: Transaction): AccountTransaction {
return AccountTransaction(
mapAmount(transaction.turnover),
statement.closingBalance.currency,
transaction.details?.sepaUsage ?: transaction.details?.usage ?: "",
transaction.turnover.bookingDate ?: statement.closingBalance.bookingDate,
transaction.details?.otherPartyName,
transaction.details?.otherPartyBankCode,
transaction.details?.otherPartyAccountId,
transaction.details?.bookingText,
transaction.turnover.valueDate,
mapAmount(statement.openingBalance),
mapAmount(statement.closingBalance)
)
}
/**
* In MT940 amounts are always stated as a positive number and flag isCredit decides if it's a credit or debit.
*/
protected open fun mapAmount(balance: Balance): BigDecimal {
return mapAmount(balance.amount, balance.isCredit)
}
/**
* In MT940 amounts are always stated as a positive number and flag isCredit decides if it's a credit or debit.
*/
protected open fun mapAmount(turnover: Turnover): BigDecimal {
return mapAmount(turnover.amount, turnover.isCredit)
}
/**
* In MT940 amounts are always stated as a positive number and flag isCredit decides if it's a credit or debit.
*/
protected open fun mapAmount(positiveAmount: BigDecimal, isCredit: Boolean): BigDecimal {
if (isCredit == false) {
return positiveAmount.negate()
}
return positiveAmount
}
}

View File

@ -0,0 +1,34 @@
package net.dankito.fints.transactions
import org.assertj.core.api.Assertions.assertThat
import org.junit.Test
class Mt940AccountTransactionsParserTest {
companion object {
const val TestFilesFolderName = "test_files/"
const val TransactionsMt940FileRelativePath = TestFilesFolderName + "TransactionsMt940.txt" // TODO: place in common file
}
private val underTest = Mt940AccountTransactionsParser()
@Test
fun parseTransactions() {
// given
val fileStream = Mt940ParserTest::class.java.classLoader.getResourceAsStream(TransactionsMt940FileRelativePath)
val transactionsString = fileStream.reader().readText()
// when
val result = underTest.parseTransactions(transactionsString)
// then
assertThat(result).hasSize(55)
}
}