Applied adjusted values from MT 940 to AccountTransaction
This commit is contained in:
parent
47e2b851b9
commit
bf76de4f23
|
@ -41,7 +41,7 @@ open class CsvWriter {
|
|||
protected open suspend fun writeToFile(stream: AsyncStream, valueSeparator: String, customer: CustomerAccount, account: BankAccount, transaction: AccountTransaction) {
|
||||
val amount = if (valueSeparator == ";") transaction.amount.amount.string.replace('.', ',') else transaction.amount.amount.string.replace(',', '.')
|
||||
|
||||
stream.writeString(listOf(customer.bankName, account.identifier, transaction.valueDate, amount, transaction.amount.currency, ensureNotNull(transaction.bookingText), wrap(transaction.reference),
|
||||
stream.writeString(listOf(customer.bankName, account.identifier, transaction.valueDate, amount, transaction.amount.currency, ensureNotNull(transaction.postingText), wrap(transaction.reference),
|
||||
ensureNotNull(transaction.otherPartyName), ensureNotNull(transaction.otherPartyBankCode), ensureNotNull(transaction.otherPartyAccountId)).joinToString(valueSeparator))
|
||||
|
||||
stream.writeString(NewLine)
|
||||
|
|
|
@ -227,7 +227,7 @@ open class FinTsJobExecutor(
|
|||
|
||||
response.getFirstSegmentById<ReceivedCreditCardTransactionsAndBalance>(InstituteSegmentId.CreditCardTransactions)?.let { creditCardTransactionsSegment ->
|
||||
balance = Money(creditCardTransactionsSegment.balance.amount, creditCardTransactionsSegment.balance.currency ?: "EUR")
|
||||
bookedTransactions.addAll(creditCardTransactionsSegment.transactions.map { AccountTransaction(parameter.account, it.amount, it.description, it.bookingDate, it.transactionDescriptionBase ?: "", null, null, "", it.valueDate) })
|
||||
bookedTransactions.addAll(creditCardTransactionsSegment.transactions.map { AccountTransaction(parameter.account, it.amount, it.description, it.bookingDate, it.valueDate, it.transactionDescriptionBase ?: "", null, null) })
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -111,14 +111,23 @@ open class FinTsModelMapper {
|
|||
}
|
||||
|
||||
open fun map(transaction: net.codinux.banking.fints.model.AccountTransaction): AccountTransaction {
|
||||
return AccountTransaction(transaction.amount, transaction.unparsedReference, transaction.bookingDate,
|
||||
transaction.otherPartyName, transaction.otherPartyBankCode, transaction.otherPartyAccountId, transaction.bookingText, transaction.valueDate,
|
||||
transaction.statementNumber, transaction.sequenceNumber, transaction.openingBalance, transaction.closingBalance,
|
||||
transaction.endToEndReference, transaction.customerReference, transaction.mandateReference, transaction.creditorIdentifier, transaction.originatorsIdentificationCode,
|
||||
return AccountTransaction(
|
||||
transaction.amount, transaction.unparsedReference,
|
||||
transaction.bookingDate, transaction.valueDate,
|
||||
transaction.otherPartyName, transaction.otherPartyBankCode, transaction.otherPartyAccountId,
|
||||
|
||||
transaction.postingText, transaction.statementNumber, transaction.sheetNumber,
|
||||
transaction.openingBalance, transaction.closingBalance,
|
||||
|
||||
transaction.customerReference, transaction.bankReference, transaction.furtherInformation,
|
||||
|
||||
transaction.endToEndReference, transaction.mandateReference, transaction.creditorIdentifier, transaction.originatorsIdentificationCode,
|
||||
transaction.compensationAmount, transaction.originalAmount, transaction.sepaReference, transaction.deviantOriginator, transaction.deviantRecipient,
|
||||
transaction.referenceWithNoSpecialType, transaction.primaNotaNumber, transaction.textKeySupplement,
|
||||
transaction.currencyType, transaction.bookingKey, transaction.referenceForTheAccountOwner, transaction.referenceOfTheAccountServicingInstitution, transaction.supplementaryDetails,
|
||||
transaction.transactionReferenceNumber, transaction.relatedReferenceNumber)
|
||||
transaction.referenceWithNoSpecialType,
|
||||
|
||||
transaction.journalNumber, transaction.textKeyAddition,
|
||||
transaction.orderReferenceNumber, transaction.referenceNumber
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -7,51 +7,118 @@ import net.codinux.banking.fints.extensions.UnixEpochStart
|
|||
open class AccountTransaction(
|
||||
val account: AccountData,
|
||||
val amount: Money,
|
||||
val isReversal: Boolean,
|
||||
val unparsedReference: String,
|
||||
|
||||
val bookingDate: LocalDate,
|
||||
val otherPartyName: String?,
|
||||
val otherPartyBankCode: String?,
|
||||
val otherPartyAccountId: String?,
|
||||
val bookingText: String?,
|
||||
val valueDate: LocalDate,
|
||||
|
||||
/**
|
||||
* Name des Überweisenden oder Zahlungsempfängers
|
||||
*/
|
||||
val otherPartyName: String?,
|
||||
/**
|
||||
* BIC des Überweisenden / Zahlungsempfängers
|
||||
*/
|
||||
val otherPartyBankCode: String?,
|
||||
/**
|
||||
* IBAN des Überweisenden oder Zahlungsempfängers
|
||||
*/
|
||||
val otherPartyAccountId: String?,
|
||||
|
||||
/**
|
||||
* Buchungstext, z. B. DAUERAUFTRAG, BARGELDAUSZAHLUNG, ONLINE-UEBERWEISUNG, FOLGELASTSCHRIFT, ...
|
||||
*/
|
||||
val postingText: String?,
|
||||
/**
|
||||
* Auszugsnummer
|
||||
*/
|
||||
val statementNumber: Int,
|
||||
val sequenceNumber: Int?,
|
||||
/**
|
||||
* Blattnummer
|
||||
*/
|
||||
val sheetNumber: Int?,
|
||||
|
||||
val openingBalance: Money?,
|
||||
val closingBalance: Money?,
|
||||
|
||||
val endToEndReference: String?,
|
||||
/**
|
||||
* Kundenreferenz.
|
||||
*/
|
||||
val customerReference: String?,
|
||||
/**
|
||||
* Bankreferenz
|
||||
*/
|
||||
val bankReference: String?,
|
||||
/**
|
||||
* Währungsart und Umsatzbetrag in Ursprungswährung
|
||||
*/
|
||||
val furtherInformation: String?,
|
||||
|
||||
|
||||
/* Remittance information */
|
||||
|
||||
val endToEndReference: String?,
|
||||
val mandateReference: String?,
|
||||
val creditorIdentifier: String?,
|
||||
val originatorsIdentificationCode: String?,
|
||||
/**
|
||||
* Summe aus Auslagenersatz und Bearbeitungsprovision bei einer nationalen Rücklastschrift
|
||||
* sowie optionalem Zinsausgleich.
|
||||
*/
|
||||
val compensationAmount: String?,
|
||||
/**
|
||||
* Betrag der ursprünglichen Lastschrift
|
||||
*/
|
||||
val originalAmount: String?,
|
||||
val sepaReference: String?,
|
||||
/**
|
||||
* Abweichender Überweisender oder Zahlungsempfänger
|
||||
*/
|
||||
val deviantOriginator: String?,
|
||||
/**
|
||||
* Abweichender Zahlungsempfänger oder Zahlungspflichtiger
|
||||
*/
|
||||
val deviantRecipient: String?,
|
||||
val referenceWithNoSpecialType: String?,
|
||||
val primaNotaNumber: String?,
|
||||
val textKeySupplement: String?,
|
||||
|
||||
val currencyType: String?,
|
||||
val bookingKey: String,
|
||||
val referenceForTheAccountOwner: String,
|
||||
val referenceOfTheAccountServicingInstitution: String?,
|
||||
val supplementaryDetails: String?,
|
||||
/**
|
||||
* Primanoten-Nr.
|
||||
*/
|
||||
val journalNumber: String?,
|
||||
/**
|
||||
* Bei R-Transaktionen siehe Tabelle der
|
||||
* SEPA-Rückgabecodes, bei SEPALastschriften siehe optionale Belegung
|
||||
* bei GVC 104 und GVC 105 (GVC = Geschäftsvorfallcode)
|
||||
*/
|
||||
val textKeyAddition: String?,
|
||||
|
||||
val transactionReferenceNumber: String,
|
||||
val relatedReferenceNumber: String?
|
||||
/**
|
||||
* Referenznummer, die vom Sender als eindeutige Kennung für die Nachricht vergeben wurde
|
||||
* (z.B. als Referenz auf stornierte Nachrichten).
|
||||
*/
|
||||
val orderReferenceNumber: String?,
|
||||
/**
|
||||
* Bezugsreferenz
|
||||
*/
|
||||
val referenceNumber: String?,
|
||||
|
||||
/**
|
||||
* Storno, ob die Buchung storniert wurde(?).
|
||||
* Aus:
|
||||
* „RC“ = Storno Haben
|
||||
* „RD“ = Storno Soll
|
||||
*/
|
||||
val isReversal: Boolean
|
||||
) {
|
||||
|
||||
// for object deserializers
|
||||
internal constructor() : this(AccountData(), Money(Amount.Zero, ""), "", UnixEpochStart, null, null, null, null, UnixEpochStart)
|
||||
internal constructor() : this(AccountData(), Money(Amount.Zero, ""), "", UnixEpochStart, UnixEpochStart, null, null, null, null)
|
||||
|
||||
constructor(account: AccountData, amount: Money, unparsedReference: String, bookingDate: LocalDate, otherPartyName: String?, otherPartyBankCode: String?, otherPartyAccountId: String?, bookingText: String?, valueDate: LocalDate)
|
||||
: this(account, amount, false, unparsedReference, bookingDate, otherPartyName, otherPartyBankCode, otherPartyAccountId, bookingText, valueDate,
|
||||
constructor(account: AccountData, amount: Money, unparsedReference: String, bookingDate: LocalDate, valueDate: LocalDate, otherPartyName: String?, otherPartyBankCode: String?, otherPartyAccountId: String?, postingText: String? = null)
|
||||
: this(account, amount, unparsedReference, bookingDate, valueDate, otherPartyName, otherPartyBankCode, otherPartyAccountId, postingText,
|
||||
0, null, null, null,
|
||||
null, null, null, null, null, null, null, null, null, null, null, null, null,
|
||||
null, "", "", null, null, "", null)
|
||||
null, null, null, null, null, null, null, null, null, null, null, null,
|
||||
"", null, null, "", null, false)
|
||||
|
||||
|
||||
open val showOtherPartyName: Boolean
|
||||
|
@ -72,7 +139,7 @@ open class AccountTransaction(
|
|||
if (otherPartyName != other.otherPartyName) return false
|
||||
if (otherPartyBankCode != other.otherPartyBankCode) return false
|
||||
if (otherPartyAccountId != other.otherPartyAccountId) return false
|
||||
if (bookingText != other.bookingText) return false
|
||||
if (postingText != other.postingText) return false
|
||||
if (valueDate != other.valueDate) return false
|
||||
|
||||
return true
|
||||
|
@ -86,7 +153,7 @@ open class AccountTransaction(
|
|||
result = 31 * result + (otherPartyName?.hashCode() ?: 0)
|
||||
result = 31 * result + (otherPartyBankCode?.hashCode() ?: 0)
|
||||
result = 31 * result + (otherPartyAccountId?.hashCode() ?: 0)
|
||||
result = 31 * result + (bookingText?.hashCode() ?: 0)
|
||||
result = 31 * result + (postingText?.hashCode() ?: 0)
|
||||
result = 31 * result + valueDate.hashCode()
|
||||
return result
|
||||
}
|
||||
|
|
|
@ -44,24 +44,33 @@ open class Mt940AccountTransactionsParser(
|
|||
protected open fun mapToAccountTransaction(statement: AccountStatement, transaction: Transaction, account: AccountData): AccountTransaction {
|
||||
val currency = statement.closingBalance.currency
|
||||
|
||||
// may parse postingKey to postingText (Buchungstext) according to table in 8.2.3 Buchungsschlüssel (Feld 61), S. 654 ff.
|
||||
|
||||
return AccountTransaction(
|
||||
account,
|
||||
Money(mapAmount(transaction.statementLine), currency),
|
||||
transaction.statementLine.isReversal,
|
||||
transaction.information?.unparsedReference ?: "",
|
||||
|
||||
transaction.statementLine.bookingDate ?: statement.closingBalance.bookingDate,
|
||||
transaction.statementLine.valueDate,
|
||||
|
||||
transaction.information?.otherPartyName,
|
||||
transaction.information?.otherPartyBankCode,
|
||||
transaction.information?.otherPartyAccountId,
|
||||
|
||||
transaction.information?.postingText,
|
||||
transaction.statementLine.valueDate,
|
||||
statement.statementNumber,
|
||||
statement.sheetNumber,
|
||||
Money(mapAmount(statement.openingBalance), currency), // TODO: that's not true, these are the opening and closing balance of
|
||||
Money(mapAmount(statement.closingBalance), currency), // all transactions of this day, not this specific transaction's ones
|
||||
|
||||
Money(mapAmount(statement.openingBalance), currency),
|
||||
Money(mapAmount(statement.closingBalance), currency),
|
||||
|
||||
// :60: customer reference: Wenn „KREF+“ eingestellt ist, dann erfolgt die Angabe der Referenznummer in Tag :86: .
|
||||
transaction.information?.customerReference ?: transaction.statementLine.customerReference,
|
||||
transaction.statementLine.bankReference,
|
||||
transaction.statementLine.furtherInformationOriginalAmountAndCharges,
|
||||
|
||||
transaction.information?.endToEndReference,
|
||||
transaction.information?.customerReference,
|
||||
transaction.information?.mandateReference,
|
||||
transaction.information?.creditorIdentifier,
|
||||
transaction.information?.originatorsIdentificationCode,
|
||||
|
@ -74,14 +83,10 @@ open class Mt940AccountTransactionsParser(
|
|||
transaction.information?.journalNumber,
|
||||
transaction.information?.textKeyAddition,
|
||||
|
||||
transaction.statementLine.currencyType,
|
||||
transaction.statementLine.postingKey,
|
||||
transaction.statementLine.customerReference,
|
||||
transaction.statementLine.bankReference,
|
||||
transaction.statementLine.furtherInformationOriginalAmountAndCharges,
|
||||
|
||||
statement.orderReferenceNumber,
|
||||
statement.referenceNumber
|
||||
statement.referenceNumber,
|
||||
|
||||
transaction.statementLine.isReversal,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -273,7 +273,7 @@ open class Mt940Parser(
|
|||
val postingKey = fieldValue.substring(postingKeyStart, postingKeyStart + 3) // TODO: parse codes, p. 178
|
||||
|
||||
val customerAndBankReference = fieldValue.substring(postingKeyStart + 3).split("//")
|
||||
val customerReference = customerAndBankReference[0]
|
||||
val customerReference = customerAndBankReference[0].takeIf { it != "NONREF" }
|
||||
|
||||
/**
|
||||
* The content of this subfield is the account servicing institution's own reference for the transaction.
|
||||
|
@ -281,14 +281,14 @@ open class Mt940Parser(
|
|||
* reference may be identical to subfield 7, Reference for the Account Owner. If this is
|
||||
* the case, Reference of the Account Servicing Institution, subfield 8 may be omitted.
|
||||
*/
|
||||
var bankReference = if (customerAndBankReference.size > 1) customerAndBankReference[1] else customerReference // TODO: or use null?
|
||||
var bankReference = if (customerAndBankReference.size > 1) customerAndBankReference[1] else null
|
||||
var furtherInformation: String? = null
|
||||
|
||||
val bankReferenceAndSupplementaryDetails = bankReference.split("\n")
|
||||
if (bankReferenceAndSupplementaryDetails.size > 1) {
|
||||
bankReference = bankReferenceAndSupplementaryDetails[0].trim()
|
||||
if (bankReference != null && bankReference.contains('\n')) {
|
||||
val bankReferenceAndFurtherInformation = bankReference.split("\n")
|
||||
bankReference = bankReferenceAndFurtherInformation[0].trim()
|
||||
// TODO: parse /OCMT/ and /CHGS/, see page 518
|
||||
furtherInformation = bankReferenceAndSupplementaryDetails[1].trim()
|
||||
furtherInformation = bankReferenceAndFurtherInformation[1].trim()
|
||||
}
|
||||
|
||||
return StatementLine(!!!isDebit, isCancellation, valueDate, bookingDate, null, amount, postingKey,
|
||||
|
|
|
@ -58,17 +58,11 @@ open class StatementLine(
|
|||
val postingKey: String,
|
||||
|
||||
/**
|
||||
* Kundenreferenz. Bei
|
||||
* Nichtbelegung wird
|
||||
* „NONREF“ eingestellt,
|
||||
* zum Beispiel bei Schecknummer
|
||||
* Wenn „KREF+“ eingestellt
|
||||
* ist, dann erfolgt die
|
||||
* Angabe der
|
||||
* Referenznummer in Tag
|
||||
* :86: .
|
||||
* Kundenreferenz.
|
||||
* Bei Nichtbelegung wird „NONREF“ eingestellt, zum Beispiel bei Schecknummer
|
||||
* Wenn „KREF+“ eingestellt ist, dann erfolgt die Angabe der Referenznummer in Tag :86: .
|
||||
*/
|
||||
val customerReference: String,
|
||||
val customerReference: String?,
|
||||
|
||||
/**
|
||||
* Bankreferenz
|
||||
|
|
|
@ -11,19 +11,26 @@ import net.codinux.banking.fints.extensions.UnixEpochStart
|
|||
open class AccountTransaction(
|
||||
val amount: Money, // TODO: if we decide to stick with Money, create own type, don't use that one from fints.model (or move over from)
|
||||
val unparsedReference: String, // alternative names: purpose, reason
|
||||
|
||||
val bookingDate: LocalDate,
|
||||
val valueDate: LocalDate,
|
||||
|
||||
val otherPartyName: String?,
|
||||
val otherPartyBankCode: String?,
|
||||
val otherPartyAccountId: String?,
|
||||
val bookingText: String?,
|
||||
val valueDate: LocalDate,
|
||||
|
||||
val postingText: String?,
|
||||
val statementNumber: Int,
|
||||
val sequenceNumber: Int?,
|
||||
val sheetNumber: Int?,
|
||||
|
||||
val openingBalance: Money?,
|
||||
val closingBalance: Money?,
|
||||
|
||||
val endToEndReference: String?,
|
||||
val customerReference: String?,
|
||||
val bankReference: String?,
|
||||
val furtherInformation: String?,
|
||||
|
||||
val endToEndReference: String?,
|
||||
val mandateReference: String?,
|
||||
val creditorIdentifier: String?,
|
||||
val originatorsIdentificationCode: String?,
|
||||
|
@ -36,24 +43,18 @@ open class AccountTransaction(
|
|||
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?
|
||||
val orderReferenceNumber: String?,
|
||||
val referenceNumber: String?
|
||||
) {
|
||||
|
||||
// for object deserializers
|
||||
internal constructor() : this(Money(Amount.Zero, ""), "", UnixEpochStart, null, null, null, null, UnixEpochStart)
|
||||
internal constructor() : this(Money(Amount.Zero, ""), "", UnixEpochStart, UnixEpochStart, null, null, null, null)
|
||||
|
||||
constructor(amount: Money, unparsedReference: String, bookingDate: LocalDate, otherPartyName: String?, otherPartyBankCode: String?, otherPartyAccountId: String?, bookingText: String?, valueDate: LocalDate)
|
||||
: this(amount, unparsedReference, bookingDate, otherPartyName, otherPartyBankCode, otherPartyAccountId, bookingText, valueDate,
|
||||
constructor(amount: Money, unparsedReference: String, bookingDate: LocalDate, valueDate: LocalDate, otherPartyName: String?, otherPartyBankCode: String?, otherPartyAccountId: String?, postingText: String?)
|
||||
: this(amount, unparsedReference, bookingDate, valueDate, otherPartyName, otherPartyBankCode, otherPartyAccountId, postingText,
|
||||
0, null, null, null,
|
||||
null, null, null, null, null, null, null, null, null, null, null, null, null,
|
||||
null, "", "", null, null, "", null)
|
||||
null, null, null, null)
|
||||
|
||||
|
||||
open val showOtherPartyName: Boolean
|
||||
|
@ -73,7 +74,7 @@ open class AccountTransaction(
|
|||
if (otherPartyName != other.otherPartyName) return false
|
||||
if (otherPartyBankCode != other.otherPartyBankCode) return false
|
||||
if (otherPartyAccountId != other.otherPartyAccountId) return false
|
||||
if (bookingText != other.bookingText) return false
|
||||
if (postingText != other.postingText) return false
|
||||
if (valueDate != other.valueDate) return false
|
||||
|
||||
return true
|
||||
|
@ -86,7 +87,7 @@ open class AccountTransaction(
|
|||
result = 31 * result + (otherPartyName?.hashCode() ?: 0)
|
||||
result = 31 * result + (otherPartyBankCode?.hashCode() ?: 0)
|
||||
result = 31 * result + (otherPartyAccountId?.hashCode() ?: 0)
|
||||
result = 31 * result + (bookingText?.hashCode() ?: 0)
|
||||
result = 31 * result + (postingText?.hashCode() ?: 0)
|
||||
result = 31 * result + valueDate.hashCode()
|
||||
return result
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ package net.codinux.banking.fints.transactions
|
|||
import net.codinux.banking.fints.FinTsTestBase
|
||||
import net.codinux.banking.fints.transactions.mt940.Mt940Parser
|
||||
import net.codinux.banking.fints.transactions.mt940.model.Balance
|
||||
import net.codinux.banking.fints.transactions.mt940.model.InformationToAccountOwner
|
||||
import net.codinux.banking.fints.transactions.mt940.model.RemittanceInformationField
|
||||
import net.codinux.banking.fints.transactions.mt940.model.StatementLine
|
||||
import kotlinx.datetime.LocalDate
|
||||
import net.codinux.banking.fints.extensions.*
|
||||
|
@ -90,7 +90,7 @@ class Mt940ParserTest : FinTsTestBase() {
|
|||
assertEquals(BankCode, statement.bankCodeBicOrIban)
|
||||
assertEquals(CustomerId, statement.accountIdentifier)
|
||||
assertEquals(0, statement.statementNumber)
|
||||
assertNull(statement.sequenceNumber)
|
||||
assertNull(statement.sheetNumber)
|
||||
|
||||
assertBalance(statement.openingBalance, true, bookingDate, Amount("0,00"))
|
||||
assertBalance(statement.closingBalance, isCredit, bookingDate, amount)
|
||||
|
@ -306,7 +306,7 @@ class Mt940ParserTest : FinTsTestBase() {
|
|||
assertSize(1, result.first().transactions)
|
||||
|
||||
result.first().transactions[0].information?.apply {
|
||||
assertEquals("BASISLASTSCHRIFT", bookingText)
|
||||
assertEquals("BASISLASTSCHRIFT", postingText)
|
||||
assertEquals("TUBDDEDD", otherPartyBankCode)
|
||||
assertEquals("DE87300308801234567890", otherPartyAccountId)
|
||||
assertEquals("6MKL2OT30QENNLIU", endToEndReference)
|
||||
|
@ -362,7 +362,7 @@ class Mt940ParserTest : FinTsTestBase() {
|
|||
assertEquals(amount, statementLine.amount)
|
||||
}
|
||||
|
||||
private fun assertTransactionDetails(details: InformationToAccountOwner?, otherPartyName: String,
|
||||
private fun assertTransactionDetails(details: RemittanceInformationField?, otherPartyName: String,
|
||||
otherPartyBankCode: String, otherPartyAccountId: String) {
|
||||
|
||||
assertNotNull(details)
|
||||
|
|
Loading…
Reference in New Issue