BankingClient/hbci4jBankingClient/src/main/kotlin/net/dankito/banking/util/AccountTransactionMapper.kt
2020-01-26 12:23:02 +01:00

162 lines
No EOL
7.9 KiB
Kotlin

package net.dankito.banking.util
import net.dankito.banking.ui.model.AccountTransaction
import net.dankito.banking.ui.model.BankAccount
import org.kapott.hbci.GV_Result.GVRKUms
import org.slf4j.LoggerFactory
import java.math.BigDecimal
import java.text.SimpleDateFormat
open class AccountTransactionMapper {
companion object {
protected val DateStartString = "DATUM "
protected val DateEndString = " UHR"
protected val DateTimeFormat = SimpleDateFormat("dd.MM.yyyy,HH.mm")
protected val DateFormat = SimpleDateFormat("dd.MM.yyyy,")
private val log = LoggerFactory.getLogger(AccountTransactionMapper::class.java)
}
open fun mapAccountTransactions(bankAccount: BankAccount, result: GVRKUms): List<AccountTransaction> {
val entries = ArrayList<AccountTransaction>()
result.flatData.forEach { transaction ->
entries.add(mapAccountingEntry(bankAccount, transaction))
}
log.debug("Retrieved ${result.flatData.size} accounting entries")
return entries.sortedByDescending { it.bookingDate }
}
protected open fun mapAccountingEntry(bankAccount: BankAccount, transaction: GVRKUms.UmsLine): AccountTransaction {
val result = AccountTransaction(BigDecimal.valueOf(transaction.value.longValue).divide(BigDecimal.valueOf(100)), transaction.bdate, transaction.usage.joinToString(""),
if (transaction.other.name2.isNullOrBlank() == false) transaction.other.name + " " + transaction.other.name2 else transaction.other.name,
if (transaction.other.bic != null) transaction.other.bic else transaction.other.blz,
if (transaction.other.iban != null) transaction.other.iban else transaction.other.number,
transaction.text, BigDecimal.valueOf(transaction.saldo.value.longValue), transaction.value.curr, bankAccount)
// mapUsage(transaction, result)
return result
}
/**
* From https://sites.google.com/a/crem-solutions.de/doku/version-2012-neu/buchhaltung/03-zahlungsverkehr/05-e-banking/technische-beschreibung-der-mt940-sta-datei:
*
* Weitere 4 Verwendungszwecke können zu den Feldschlüsseln 60 bis 63 eingestellt werden.
* Jeder Bezeichner [z.B. EREF+] muss am Anfang eines Subfeldes [z. B. ?21] stehen.
* Bei Längenüberschreitung wird im nachfolgenden Subfeld ohne Wiederholung des Bezeichners fortgesetzt. Bei Wechsel des Bezeichners ist ein neues Subfeld zu beginnen.
* Belegung in der nachfolgenden Reihenfolge, wenn vorhanden:
* EREF+[ Ende-zu-Ende Referenz ] (DD-AT10; CT-AT41 - Angabe verpflichtend; NOTPROVIDED wird nicht eingestellt.)
* KREF+[Kundenreferenz]
* MREF+[Mandatsreferenz] (DD-AT01 - Angabe verpflichtend)
* CRED+[Creditor Identifier] (DD-AT02 - Angabe verpflichtend bei SEPA-Lastschriften, nicht jedoch bei SEPA-Rücklastschriften)
* DEBT+[Originators Identification Code](CT-AT10- Angabe verpflichtend,)
* Entweder CRED oder DEBT
*
* optional zusätzlich zur Einstellung in Feld 61, Subfeld 9:
*
* COAM+ [Compensation Amount / Summe aus Auslagenersatz und Bearbeitungsprovision bei einer nationalen Rücklastschrift sowie optionalem Zinsausgleich.]
* OAMT+[Original Amount] Betrag der ursprünglichen Lastschrift
*
* SVWZ+[SEPA-Verwendungszweck] (DD-AT22; CT-AT05 -Angabe verpflichtend, nicht jedoch bei R-Transaktionen)
* ABWA+[Abweichender Überweisender] (CT-AT08) / Abweichender Zahlungsempfänger (DD-AT38) ] (optional)
* ABWE+[Abweichender Zahlungsemp-fänger (CT-AT28) / Abweichender Zahlungspflichtiger ((DD-AT15)] (optional)
*/
// protected open fun mapUsage(buchung: GVRKUms.UmsLine, entry: AccountingEntry) {
// var lastUsageLineType = UsageLineType.ContinuationFromLastLine
// var typeValue = ""
//
// buchung.usage.forEach { line ->
// val (type, adjustedString) = getUsageLineType(line, entry)
//
// if (type == UsageLineType.ContinuationFromLastLine) {
// typeValue += (if(adjustedString[0].isUpperCase()) " " else "") + adjustedString
// }
// else if (lastUsageLineType != type) {
// if (lastUsageLineType != UsageLineType.ContinuationFromLastLine) {
// setUsageLineValue(entry, lastUsageLineType, typeValue)
// }
//
// typeValue = adjustedString
// lastUsageLineType = type
// }
//
// tryToParseBookingDateFromUsageLine(entry, adjustedString, typeValue)
// }
//
// if(lastUsageLineType != UsageLineType.ContinuationFromLastLine) {
// setUsageLineValue(entry, lastUsageLineType, typeValue)
// }
// }
//
// protected open fun setUsageLineValue(entry: AccountingEntry, lastUsageLineType: UsageLineType, typeValue: String) {
// entry.parsedUsages.add(typeValue)
//
// when (lastUsageLineType) {
// UsageLineType.EREF -> entry.endToEndReference = typeValue
// UsageLineType.KREF -> entry.kundenreferenz = typeValue
// UsageLineType.MREF -> entry.mandatsreferenz = typeValue
// UsageLineType.CRED -> entry.creditorIdentifier = typeValue
// UsageLineType.DEBT -> entry.originatorsIdentificationCode = typeValue
// UsageLineType.COAM -> entry.compensationAmount = typeValue
// UsageLineType.OAMT -> entry.originalAmount = typeValue
// UsageLineType.SVWZ -> entry.sepaVerwendungszweck = typeValue
// UsageLineType.ABWA -> entry.abweichenderAuftraggeber = typeValue
// UsageLineType.ABWE -> entry.abweichenderZahlungsempfaenger = typeValue
// UsageLineType.NoSpecialType -> entry.usageWithNoSpecialType = typeValue
// }
// }
//
// protected open fun getUsageLineType(line: String, entry: AccountingEntry): Pair<UsageLineType, String> {
// return when {
// line.startsWith("EREF+") -> Pair(UsageLineType.EREF, line.substring(5))
// line.startsWith("KREF+") -> Pair(UsageLineType.KREF, line.substring(5))
// line.startsWith("MREF+") -> Pair(UsageLineType.MREF, line.substring(5))
// line.startsWith("CRED+") -> Pair(UsageLineType.CRED, line.substring(5))
// line.startsWith("DEBT+") -> Pair(UsageLineType.DEBT, line.substring(5))
// line.startsWith("COAM+") -> Pair(UsageLineType.COAM, line.substring(5))
// line.startsWith("OAMT+") -> Pair(UsageLineType.OAMT, line.substring(5))
// line.startsWith("SVWZ+") -> Pair(UsageLineType.SVWZ, line.substring(5))
// line.startsWith("ABWA+") -> Pair(UsageLineType.ABWA, line.substring(5))
// line.startsWith("ABWE+") -> Pair(UsageLineType.ABWE, line.substring(5))
// entry.usage.startsWith(line) -> Pair(UsageLineType.NoSpecialType, line)
// else -> Pair(UsageLineType.ContinuationFromLastLine, line)
// }
// }
//
// protected open fun tryToParseBookingDateFromUsageLine(entry: AccountingEntry, currentLine: String, typeLine: String) {
// if (currentLine.startsWith(DateStartString)) {
// tryToParseBookingDateFromUsageLine(entry, currentLine)
// }
// else if (typeLine.startsWith(DateStartString)) {
// tryToParseBookingDateFromUsageLine(entry, typeLine)
// }
// }
//
// protected open fun tryToParseBookingDateFromUsageLine(entry: AccountingEntry, line: String) {
// var dateString = line.replace(DateStartString, "")
// val index = dateString.indexOf(DateEndString)
// if (index > 0) {
// dateString = dateString.substring(0, index)
// }
//
// try {
// entry.bookingDate = DateTimeFormat.parse(dateString)
// } catch (e: Exception) {
// try {
// entry.bookingDate = DateFormat.parse(dateString)
// } catch (secondException: Exception) {
// log.debug("Could not parse '$dateString' from '$line' to a Date", e)
// }
// }
// }
}