Implemented mapping all account transaction fields; Renamed usage to unparsedUsage, isCancellation to isReversal, customerReference to referenceForTheAccountOwner, bankReference to referenceOfTheAccountServicingInstitution and referenceReferenceNumber to relatedReferenceNumber

This commit is contained in:
dankito 2020-05-23 19:00:43 +02:00
parent ac78758262
commit a16cf630b4
13 changed files with 228 additions and 171 deletions

View File

@ -6,27 +6,54 @@ import java.util.*
open class AccountTransaction( open class AccountTransaction(
val account: AccountData,
val amount: BigDecimal, val amount: BigDecimal,
val currency: String, val currency: String,
val usage: String, val isReversal: Boolean,
val unparsedUsage: String,
val bookingDate: Date, val bookingDate: Date,
val otherPartyName: String?, val otherPartyName: String?,
val otherPartyBankCode: String?, val otherPartyBankCode: String?,
val otherPartyAccountId: String?, val otherPartyAccountId: String?,
val bookingText: String?, val bookingText: String?,
val valueDate: Date?, val valueDate: Date,
val statementNumber: Int,
val sequenceNumber: Int?,
val openingBalance: BigDecimal?, val openingBalance: BigDecimal?,
val closingBalance: BigDecimal?, val closingBalance: BigDecimal?,
val account: AccountData
// TODO: may also add other values from parsed usage lines val endToEndReference: String?,
val customerReference: String?,
val mandateReference: String?,
val creditorIdentifier: String?,
val originatorsIdentificationCode: String?,
val compensationAmount: String?,
val originalAmount: String?,
val sepaUsage: String?,
val deviantOriginator: String?,
val deviantRecipient: String?,
val usageWithNoSpecialType: String?,
val primaNotaNumber: String?,
val textKeySupplement: String?,
val currencyType: String?,
val bookingKey: String,
val referenceForTheAccountOwner: String,
val referenceOfTheAccountServicingInstitution: String?,
val supplementaryDetails: String?,
val transactionReferenceNumber: String,
val relatedReferenceNumber: String?
) { ) {
// for object deserializers // for object deserializers
internal constructor() : this(0.toBigDecimal(),"", "", Date(), null, null, null, null, null, null, null, AccountData()) internal constructor() : this(AccountData(), 0.toBigDecimal(),"", false, "", Date(), null, null, null, null, Date(), 0, null, null, null,
null, null, null, null, null, null, null, null, null, null, null, null, null,
null, "", "", null, null, "", null)
override fun toString(): String { override fun toString(): String {
return "${DateFormat.getDateInstance(DateFormat.MEDIUM).format(bookingDate)} $amount $otherPartyName: $usage" return "${DateFormat.getDateInstance(DateFormat.MEDIUM).format(bookingDate)} $amount $otherPartyName: $unparsedUsage"
} }
} }

View File

@ -45,18 +45,44 @@ open class Mt940AccountTransactionsParser @JvmOverloads constructor(
protected open fun mapToAccountTransaction(statement: AccountStatement, transaction: Transaction, account: AccountData): AccountTransaction { protected open fun mapToAccountTransaction(statement: AccountStatement, transaction: Transaction, account: AccountData): AccountTransaction {
return AccountTransaction( return AccountTransaction(
account,
mapAmount(transaction.statementLine), mapAmount(transaction.statementLine),
statement.closingBalance.currency, statement.closingBalance.currency,
transaction.information?.sepaUsage ?: transaction.information?.usage ?: "", transaction.statementLine.isReversal,
transaction.information?.unparsedUsage ?: "",
transaction.statementLine.bookingDate ?: statement.closingBalance.bookingDate, transaction.statementLine.bookingDate ?: statement.closingBalance.bookingDate,
transaction.information?.otherPartyName, transaction.information?.otherPartyName,
transaction.information?.otherPartyBankCode, transaction.information?.otherPartyBankCode,
transaction.information?.otherPartyAccountId, transaction.information?.otherPartyAccountId,
transaction.information?.bookingText, transaction.information?.bookingText,
transaction.statementLine.valueDate, transaction.statementLine.valueDate,
statement.statementNumber,
statement.sequenceNumber,
mapAmount(statement.openingBalance), // TODO: that's not true, these are the opening and closing balance of mapAmount(statement.openingBalance), // TODO: that's not true, these are the opening and closing balance of
mapAmount(statement.closingBalance), // all transactions of this day, not this specific transaction's ones mapAmount(statement.closingBalance), // all transactions of this day, not this specific transaction's ones
account
transaction.information?.endToEndReference,
transaction.information?.customerReference,
transaction.information?.mandateReference,
transaction.information?.creditorIdentifier,
transaction.information?.originatorsIdentificationCode,
transaction.information?.compensationAmount,
transaction.information?.originalAmount,
transaction.information?.sepaUsage,
transaction.information?.deviantOriginator,
transaction.information?.deviantRecipient,
transaction.information?.usageWithNoSpecialType,
transaction.information?.primaNotaNumber,
transaction.information?.textKeySupplement,
transaction.statementLine.currencyType,
transaction.statementLine.bookingKey,
transaction.statementLine.referenceForTheAccountOwner,
transaction.statementLine.referenceOfTheAccountServicingInstitution,
transaction.statementLine.supplementaryDetails,
statement.transactionReferenceNumber,
statement.relatedReferenceNumber
) )
} }

View File

@ -57,6 +57,18 @@ open class Mt940Parser : IMt940Parser {
val UsageTypePattern = Pattern.compile("\\w{4}\\+") val UsageTypePattern = Pattern.compile("\\w{4}\\+")
const val EndToEndReferenceUsageKey = "EREF+"
const val CustomerReferenceUsageKey = "KREF+"
const val MandateReferenceUsageKey = "MREF+"
const val CreditorIdentifierUsageKey = "CRED+"
const val OriginatorsIdentificationCodeUsageKey = "DEBT+"
const val CompensationAmountUsageKey = "COAM+"
const val OriginalAmountUsageKey = "OAMT+"
const val SepaUsageUsageKey = "SVWZ+"
const val DeviantOriginatorUsageKey = "ABWA+"
const val DeviantRecipientUsageKey = "ABWE+"
private val log = LoggerFactory.getLogger(Mt940Parser::class.java) private val log = LoggerFactory.getLogger(Mt940Parser::class.java)
} }
@ -362,36 +374,35 @@ open class Mt940Parser : IMt940Parser {
* Weitere 4 Verwendungszwecke können zu den Feldschlüsseln 60 bis 63 eingestellt werden. * Weitere 4 Verwendungszwecke können zu den Feldschlüsseln 60 bis 63 eingestellt werden.
*/ */
protected open fun mapUsage(information: InformationToAccountOwner) { protected open fun mapUsage(information: InformationToAccountOwner) {
val usageParts = getUsageParts(information) val usageParts = getUsageParts(information.unparsedUsage)
usageParts.forEach { pair -> usageParts.forEach { entry ->
setUsageLineValue(information, pair.first, pair.second) setUsageLineValue(information, entry.key, entry.value)
} }
} }
protected open fun getUsageParts(information: InformationToAccountOwner): MutableList<Pair<String, String>> { open fun getUsageParts(unparsedUsage: String): Map<String, String> {
val usage = information.usage
var previousMatchType = "" var previousMatchType = ""
var previousMatchEnd = 0 var previousMatchEnd = 0
val usageParts = mutableListOf<Pair<String, String>>() val usageParts = mutableMapOf<String, String>()
val matcher = UsageTypePattern.matcher(information.usage) val matcher = UsageTypePattern.matcher(unparsedUsage)
while (matcher.find()) { while (matcher.find()) {
if (previousMatchEnd > 0) { if (previousMatchEnd > 0) {
val typeValue = usage.substring(previousMatchEnd, matcher.start()) val typeValue = unparsedUsage.substring(previousMatchEnd, matcher.start())
usageParts.add(Pair(previousMatchType, typeValue)) usageParts[previousMatchType] = typeValue
} }
previousMatchType = usage.substring(matcher.start(), matcher.end()) previousMatchType = unparsedUsage.substring(matcher.start(), matcher.end())
previousMatchEnd = matcher.end() previousMatchEnd = matcher.end()
} }
if (previousMatchEnd > 0) { if (previousMatchEnd > 0) {
val typeValue = usage.substring(previousMatchEnd, usage.length) val typeValue = unparsedUsage.substring(previousMatchEnd, unparsedUsage.length)
usageParts.add(Pair(previousMatchType, typeValue)) usageParts[previousMatchType] = typeValue
} }
return usageParts return usageParts
@ -399,16 +410,16 @@ open class Mt940Parser : IMt940Parser {
protected open fun setUsageLineValue(information: InformationToAccountOwner, usageType: String, typeValue: String) { protected open fun setUsageLineValue(information: InformationToAccountOwner, usageType: String, typeValue: String) {
when (usageType) { when (usageType) {
"EREF+" -> information.endToEndReference = typeValue EndToEndReferenceUsageKey -> information.endToEndReference = typeValue
"KREF+" -> information.customerReference = typeValue CustomerReferenceUsageKey -> information.customerReference = typeValue
"MREF+" -> information.mandateReference = typeValue MandateReferenceUsageKey -> information.mandateReference = typeValue
"CRED+" -> information.creditorIdentifier = typeValue CreditorIdentifierUsageKey -> information.creditorIdentifier = typeValue
"DEBT+" -> information.originatorsIdentificationCode = typeValue OriginatorsIdentificationCodeUsageKey -> information.originatorsIdentificationCode = typeValue
"COAM+" -> information.compensationAmount = typeValue CompensationAmountUsageKey -> information.compensationAmount = typeValue
"OAMT+" -> information.originalAmount = typeValue OriginalAmountUsageKey -> information.originalAmount = typeValue
"SVWZ+" -> information.sepaUsage = typeValue SepaUsageUsageKey -> information.sepaUsage = typeValue
"ABWA+" -> information.deviantOriginator = typeValue DeviantOriginatorUsageKey -> information.deviantOriginator = typeValue
"ABWE+" -> information.deviantRecipient = typeValue DeviantRecipientUsageKey -> information.deviantRecipient = typeValue
else -> information.usageWithNoSpecialType = typeValue else -> information.usageWithNoSpecialType = typeValue
} }
} }

View File

@ -20,7 +20,7 @@ open class AccountStatement(
* *
* Max length = 16 * Max length = 16
*/ */
val referenceReferenceNumber: String?, val relatedReferenceNumber: String?,
/** /**
* xxxxxxxxxxx/Konto-Nr. oder yyyyyyyy/Konto-Nr. * xxxxxxxxxxx/Konto-Nr. oder yyyyyyyy/Konto-Nr.

View File

@ -2,7 +2,7 @@ package net.dankito.banking.fints.transactions.mt940.model
open class InformationToAccountOwner( open class InformationToAccountOwner(
val usage: String, val unparsedUsage: String,
val otherPartyName: String?, val otherPartyName: String?,
val otherPartyBankCode: String?, val otherPartyBankCode: String?,
val otherPartyAccountId: String?, val otherPartyAccountId: String?,
@ -35,7 +35,7 @@ open class InformationToAccountOwner(
override fun toString(): String { override fun toString(): String {
return "$otherPartyName $usage" return "$otherPartyName $unparsedUsage"
} }
} }

View File

@ -19,7 +19,7 @@ open class StatementLine(
*/ */
val isCredit: Boolean, val isCredit: Boolean,
val isCancellation: Boolean, val isReversal: Boolean,
/** /**
* Valuta (JJMMTT) * Valuta (JJMMTT)
@ -58,9 +58,9 @@ open class StatementLine(
*/ */
val bookingKey: String, val bookingKey: String,
val customerReference: String, val referenceForTheAccountOwner: String,
val bankReference: String?, val referenceOfTheAccountServicingInstitution: String?,
val supplementaryDetails: String? = null val supplementaryDetails: String? = null

View File

@ -249,7 +249,7 @@ class Mt940ParserTest : FinTsTestBase() {
bookingDate: Date? = valueDate) { bookingDate: Date? = valueDate) {
assertThat(statementLine.isCredit).isEqualTo(isCredit) assertThat(statementLine.isCredit).isEqualTo(isCredit)
assertThat(statementLine.isCancellation).isFalse() assertThat(statementLine.isReversal).isFalse()
assertThat(statementLine.valueDate).isEqualTo(valueDate) assertThat(statementLine.valueDate).isEqualTo(valueDate)
assertThat(statementLine.bookingDate).isEqualTo(bookingDate) assertThat(statementLine.bookingDate).isEqualTo(bookingDate)
assertThat(statementLine.amount).isEqualTo(amount) assertThat(statementLine.amount).isEqualTo(amount)

View File

@ -72,9 +72,9 @@ open class LuceneBankingPersistence(
fields.storedField(BookingDateFieldName, transaction.bookingDate), fields.storedField(BookingDateFieldName, transaction.bookingDate),
fields.storedField(AmountFieldName, transaction.amount), fields.storedField(AmountFieldName, transaction.amount),
fields.storedField(CurrencyFieldName, transaction.currency), fields.storedField(CurrencyFieldName, transaction.currency),
fields.nullableStoredField(BalanceFieldName, transaction.balance), fields.nullableStoredField(BalanceFieldName, transaction.closingBalance), // TODO: remove
fields.sortField(BookingDateSortFieldName, transaction.bookingDate) fields.sortField(BookingDateSortFieldName, transaction.bookingDate) // TODO: sort by valueDate
) )
} }

View File

@ -211,7 +211,7 @@ class LuceneRemitteeSearcherTest {
otherPartyName: String = randomString(), otherPartyBankCode: String = randomString(), otherPartyName: String = randomString(), otherPartyBankCode: String = randomString(),
otherPartyAccountId: String = randomString(), usage: String = randomString()): AccountTransaction { otherPartyAccountId: String = randomString(), usage: String = randomString()): AccountTransaction {
return AccountTransaction(amount, bookingDate, usage, otherPartyName, otherPartyBankCode, otherPartyAccountId, null, null, "EUR", bankAccount) return AccountTransaction(bankAccount, amount, usage, bookingDate, otherPartyName, otherPartyBankCode, otherPartyAccountId, null, bookingDate)
} }
private fun randomString(): String { private fun randomString(): String {

View File

@ -72,7 +72,7 @@ open class AccountTransactionsTable @JvmOverloads constructor(
} }
} }
label(it.usage ?: "") { label(it.usage) {
vboxConstraints { vboxConstraints {
margin = LabelMargin margin = LabelMargin
} }

View File

@ -9,20 +9,57 @@ import java.util.*
@JsonIdentityInfo(property = "id", generator = ObjectIdGenerators.PropertyGenerator::class) // to avoid stack overflow due to circular references @JsonIdentityInfo(property = "id", generator = ObjectIdGenerators.PropertyGenerator::class) // to avoid stack overflow due to circular references
open class AccountTransaction( open class AccountTransaction(
val bankAccount: BankAccount,
val amount: BigDecimal, val amount: BigDecimal,
val currency: String,
val isReversal: Boolean,
val unparsedUsage: String,
val bookingDate: Date, val bookingDate: Date,
val usage: String,
val otherPartyName: String?, val otherPartyName: String?,
val otherPartyBankCode: String?, val otherPartyBankCode: String?,
val otherPartyAccountId: String?, val otherPartyAccountId: String?,
val bookingText: String?, val bookingText: String?,
val balance: BigDecimal?, val valueDate: Date,
val currency: String, val statementNumber: Int,
val bankAccount: BankAccount val sequenceNumber: Int?,
val openingBalance: BigDecimal?,
val closingBalance: BigDecimal?,
val endToEndReference: String?,
val customerReference: String?,
val mandateReference: String?,
val creditorIdentifier: String?,
val originatorsIdentificationCode: String?,
val compensationAmount: String?,
val originalAmount: String?,
val sepaUsage: String?,
val deviantOriginator: String?,
val deviantRecipient: String?,
val usageWithNoSpecialType: String?,
val primaNotaNumber: String?,
val textKeySupplement: String?,
val currencyType: String?,
val bookingKey: String,
val referenceForTheAccountOwner: String,
val referenceOfTheAccountServicingInstitution: String?,
val supplementaryDetails: String?,
val transactionReferenceNumber: String,
val relatedReferenceNumber: String?
) { ) {
constructor(bankAccount: BankAccount, amount: BigDecimal, unparsedUsage: String, bookingDate: Date,
otherPartyName: String?, otherPartyBankCode: String?, otherPartyAccountId: String?,
bookingText: String?, valueDate: Date)
: this(bankAccount, amount, "EUR", false, unparsedUsage, bookingDate,
otherPartyName, otherPartyBankCode, otherPartyAccountId, bookingText, valueDate,
0, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, "", "", null, null, "", null)
// for object deserializers // for object deserializers
internal constructor() : this(BigDecimal.ZERO, Date(),"", null, null, null, null, BigDecimal.ZERO, "", BankAccount()) internal constructor() : this(BankAccount(), BigDecimal.ZERO, "", false,"", Date(), null, null, null, null, Date(), 0, null, BigDecimal.ZERO, BigDecimal.ZERO,
null, null, null, null, null, null, null, null, null, null, null, null, null,
null, "", "", null, null, "", null)
var id: String = UUID.randomUUID().toString() var id: String = UUID.randomUUID().toString()
@ -32,6 +69,9 @@ open class AccountTransaction(
val showOtherPartyName: Boolean val showOtherPartyName: Boolean
get() = otherPartyName.isNullOrBlank() == false /* && type != "ENTGELTABSCHLUSS" && type != "AUSZAHLUNG" */ // TODO get() = otherPartyName.isNullOrBlank() == false /* && type != "ENTGELTABSCHLUSS" && type != "AUSZAHLUNG" */ // TODO
val usage: String
get() = sepaUsage ?: unparsedUsage
override fun equals(other: Any?): Boolean { override fun equals(other: Any?): Boolean {
if (this === other) return true if (this === other) return true
@ -39,7 +79,7 @@ open class AccountTransaction(
if (amount.compareTo(other.amount) != 0) return false if (amount.compareTo(other.amount) != 0) return false
if (currency != other.currency) return false if (currency != other.currency) return false
if (usage != other.usage) return false if (unparsedUsage != other.unparsedUsage) return false
if (bookingDate != other.bookingDate) return false if (bookingDate != other.bookingDate) return false
if (otherPartyName != other.otherPartyName) return false if (otherPartyName != other.otherPartyName) return false
if (otherPartyBankCode != other.otherPartyBankCode) return false if (otherPartyBankCode != other.otherPartyBankCode) return false
@ -53,7 +93,7 @@ open class AccountTransaction(
override fun hashCode(): Int { override fun hashCode(): Int {
var result = amount.hashCode() var result = amount.hashCode()
result = 31 * result + currency.hashCode() result = 31 * result + currency.hashCode()
result = 31 * result + usage.hashCode() result = 31 * result + unparsedUsage.hashCode()
result = 31 * result + bookingDate.hashCode() result = 31 * result + bookingDate.hashCode()
result = 31 * result + (otherPartyName?.hashCode() ?: 0) result = 31 * result + (otherPartyName?.hashCode() ?: 0)
result = 31 * result + (otherPartyBankCode?.hashCode() ?: 0) result = 31 * result + (otherPartyBankCode?.hashCode() ?: 0)

View File

@ -175,16 +175,44 @@ open class fints4kModelMapper {
open fun mapTransaction(bankAccount: BankAccount, transaction: net.dankito.banking.fints.model.AccountTransaction): AccountTransaction { open fun mapTransaction(bankAccount: BankAccount, transaction: net.dankito.banking.fints.model.AccountTransaction): AccountTransaction {
return AccountTransaction( return AccountTransaction(
bankAccount,
transaction.amount, transaction.amount,
transaction.currency,
transaction.isReversal,
transaction.unparsedUsage,
transaction.bookingDate, transaction.bookingDate,
transaction.usage,
transaction.otherPartyName, transaction.otherPartyName,
transaction.otherPartyBankCode, transaction.otherPartyBankCode,
transaction.otherPartyAccountId, transaction.otherPartyAccountId,
transaction.bookingText, transaction.bookingText,
transaction.valueDate,
transaction.statementNumber,
transaction.sequenceNumber,
transaction.openingBalance,
transaction.closingBalance, transaction.closingBalance,
transaction.currency,
bankAccount transaction.endToEndReference,
transaction.customerReference,
transaction.mandateReference,
transaction.creditorIdentifier,
transaction.originatorsIdentificationCode,
transaction.compensationAmount,
transaction.originalAmount,
transaction.sepaUsage,
transaction.deviantOriginator,
transaction.deviantRecipient,
transaction.usageWithNoSpecialType,
transaction.primaNotaNumber,
transaction.textKeySupplement,
transaction.currencyType,
transaction.bookingKey,
transaction.referenceForTheAccountOwner,
transaction.referenceOfTheAccountServicingInstitution,
transaction.supplementaryDetails,
transaction.transactionReferenceNumber,
transaction.relatedReferenceNumber
) )
} }

View File

@ -1,8 +1,10 @@
package net.dankito.banking.util package net.dankito.banking.util
import net.dankito.banking.fints.transactions.mt940.Mt940Parser
import net.dankito.banking.ui.model.AccountTransaction import net.dankito.banking.ui.model.AccountTransaction
import net.dankito.banking.ui.model.BankAccount import net.dankito.banking.ui.model.BankAccount
import org.kapott.hbci.GV_Result.GVRKUms import org.kapott.hbci.GV_Result.GVRKUms
import org.kapott.hbci.structures.Value
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import java.math.BigDecimal import java.math.BigDecimal
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
@ -25,8 +27,10 @@ open class AccountTransactionMapper {
open fun mapAccountTransactions(bankAccount: BankAccount, result: GVRKUms): List<AccountTransaction> { open fun mapAccountTransactions(bankAccount: BankAccount, result: GVRKUms): List<AccountTransaction> {
val entries = ArrayList<AccountTransaction>() val entries = ArrayList<AccountTransaction>()
result.flatData.forEach { transaction -> result.dataPerDay.forEach { btag ->
entries.add(mapAccountingEntry(bankAccount, transaction)) btag.lines.forEach { transaction ->
entries.add(mapAccountingEntry(bankAccount, btag, transaction))
}
} }
log.debug("Retrieved ${result.flatData.size} accounting entries") log.debug("Retrieved ${result.flatData.size} accounting entries")
@ -34,129 +38,50 @@ open class AccountTransactionMapper {
return entries.sortedByDescending { it.bookingDate } return entries.sortedByDescending { it.bookingDate }
} }
protected open fun mapAccountingEntry(bankAccount: BankAccount, transaction: GVRKUms.UmsLine): AccountTransaction { protected open fun mapAccountingEntry(bankAccount: BankAccount, btag: GVRKUms.BTag, transaction: GVRKUms.UmsLine): AccountTransaction {
val unparsedUsage = transaction.usage.joinToString("")
val parsedUsage = Mt940Parser().getUsageParts(unparsedUsage)
val statementAndMaySequenceNumber = btag.counter.split('/')
val result = AccountTransaction(BigDecimal.valueOf(transaction.value.longValue).divide(BigDecimal.valueOf(100)), transaction.bdate, transaction.usage.joinToString(""), val result = AccountTransaction(bankAccount,
if (transaction.other.name2.isNullOrBlank() == false) transaction.other.name + " " + transaction.other.name2 else transaction.other.name, mapValue(transaction.value), transaction.value.curr, transaction.isStorno, unparsedUsage, transaction.bdate,
if (transaction.other.bic != null) transaction.other.bic else transaction.other.blz, transaction.other.name + (transaction.other.name2 ?: ""),
if (transaction.other.iban != null) transaction.other.iban else transaction.other.number, transaction.other.bic ?: transaction.other.blz,
transaction.text, BigDecimal.valueOf(transaction.saldo.value.longValue), transaction.value.curr, bankAccount) transaction.other.iban ?: transaction.other.number,
transaction.text, transaction.valuta,
statementAndMaySequenceNumber[0].toInt(),
if (statementAndMaySequenceNumber.size > 1) statementAndMaySequenceNumber[1].toInt() else null,
mapValue(btag.start.value), mapValue(btag.end.value),
// mapUsage(transaction, result) parsedUsage[Mt940Parser.EndToEndReferenceUsageKey],
parsedUsage[Mt940Parser.CustomerReferenceUsageKey],
parsedUsage[Mt940Parser.MandateReferenceUsageKey],
parsedUsage[Mt940Parser.CreditorIdentifierUsageKey],
parsedUsage[Mt940Parser.OriginatorsIdentificationCodeUsageKey],
parsedUsage[Mt940Parser.CompensationAmountUsageKey],
parsedUsage[Mt940Parser.OriginalAmountUsageKey],
parsedUsage[Mt940Parser.SepaUsageUsageKey],
parsedUsage[Mt940Parser.DeviantOriginatorUsageKey],
parsedUsage[Mt940Parser.DeviantRecipientUsageKey],
parsedUsage[""],
transaction.primanota,
transaction.addkey,
null,
"",
transaction.customerref,
transaction.instref,
transaction.additional,
"",
null
)
return result return result
} }
/** protected open fun mapValue(value: Value): BigDecimal {
* 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: return BigDecimal.valueOf(value.longValue).divide(BigDecimal.valueOf(100))
* }
* 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)
// }
// }
// }
} }