From 03bdb19668b69f8caf447068d2a7efc603c0b140 Mon Sep 17 00:00:00 2001 From: dankito Date: Thu, 2 Jul 2020 23:08:35 +0200 Subject: [PATCH] Introduced Amount to be able to remove Ionspin BigDecimal dependency --- fints4k/build.gradle | 4 -- .../sepa/SepaBankTransferBase.kt | 2 +- .../banking/fints/model/AccountTransaction.kt | 3 +- .../net/dankito/banking/fints/model/Amount.kt | 34 +++++++++++++++ .../banking/fints/model/BankTransferData.kt | 4 +- .../net/dankito/banking/fints/model/Money.kt | 9 ++-- .../banking/fints/response/ResponseParser.kt | 15 +++---- .../response/client/AddAccountResponse.kt | 3 +- .../fints/response/segments/Balance.kt | 4 +- .../fints/response/segments/BalanceSegment.kt | 6 +-- .../Mt940AccountTransactionsParser.kt | 12 +++--- .../fints/transactions/mt940/Mt940Parser.kt | 7 ++-- .../fints/transactions/mt940/model/Balance.kt | 6 +-- .../transactions/mt940/model/StatementLine.kt | 4 +- .../dankito/banking/fints/FinTsTestBase.kt | 5 --- .../sepa/SepaBankTransferBaseTest.kt | 15 +++---- .../fints/response/ResponseParserTest.kt | 17 ++++---- .../fints/transactions/Mt940ParserTest.kt | 41 +++++++++---------- .../banking/extensions/AmountExtensions.kt | 22 ++++++++++ .../extensions/BigDecimalExtensions.kt | 24 ----------- .../dankito/banking/fints4kBankingClient.kt | 7 ++-- 21 files changed, 127 insertions(+), 117 deletions(-) create mode 100644 fints4k/src/commonMain/kotlin/net/dankito/banking/fints/model/Amount.kt create mode 100644 ui/fints4kBankingClient/src/main/kotlin/net/dankito/banking/extensions/AmountExtensions.kt delete mode 100644 ui/fints4kBankingClient/src/main/kotlin/net/dankito/banking/extensions/BigDecimalExtensions.kt diff --git a/fints4k/build.gradle b/fints4k/build.gradle index 9c393128..59d6597e 100644 --- a/fints4k/build.gradle +++ b/fints4k/build.gradle @@ -53,8 +53,6 @@ kotlin { api "com.soywiz.korlibs.klock:klock:$klockVersion" - api "com.ionspin.kotlin:bignum:$bigNumVersion" - implementation "com.benasher44:uuid:$uuidVersion" } } @@ -129,8 +127,6 @@ kotlin { implementation "com.soywiz.korlibs.klock:klock-js:$klockVersion" - - implementation "com.ionspin.kotlin:bignum-js:$bigNumVersion" } } diff --git a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/messages/segmente/implementierte/sepa/SepaBankTransferBase.kt b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/messages/segmente/implementierte/sepa/SepaBankTransferBase.kt index 3625e14b..733454b0 100644 --- a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/messages/segmente/implementierte/sepa/SepaBankTransferBase.kt +++ b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/messages/segmente/implementierte/sepa/SepaBankTransferBase.kt @@ -32,7 +32,7 @@ open class SepaBankTransferBase( "CreditorName" to messageCreator.convertDiacriticsAndReservedXmlCharacters(data.creditorName), "CreditorIban" to data.creditorIban.replace(" ", ""), "CreditorBic" to data.creditorBic.replace(" ", ""), - "Amount" to data.amount.toStringExpanded(), // TODO: check if ',' or '.' should be used as decimal separator + "Amount" to data.amount.amount.string.replace(',', '.'), // TODO: check if ',' or '.' should be used as decimal separator "Usage" to if (data.usage.isEmpty()) " " else messageCreator.convertDiacriticsAndReservedXmlCharacters(data.usage), "RequestedExecutionDate" to RequestedExecutionDateValueForNotScheduledTransfers ), diff --git a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/model/AccountTransaction.kt b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/model/AccountTransaction.kt index 3a2d7785..4a9d8c41 100644 --- a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/model/AccountTransaction.kt +++ b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/model/AccountTransaction.kt @@ -1,6 +1,5 @@ package net.dankito.banking.fints.model -import com.ionspin.kotlin.bignum.decimal.BigDecimal import com.soywiz.klock.Date import com.soywiz.klock.DateTime @@ -46,7 +45,7 @@ open class AccountTransaction( ) { // for object deserializers - internal constructor() : this(AccountData(), Money(BigDecimal.ZERO, ""), false, "", DateTime.EPOCH.date, null, null, null, null, DateTime.EPOCH.date, 0, null, null, null, + internal constructor() : this(AccountData(), Money(Amount.Zero, ""), false, "", DateTime.EPOCH.date, null, null, null, null, DateTime.EPOCH.date, 0, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, "", "", null, null, "", null) diff --git a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/model/Amount.kt b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/model/Amount.kt new file mode 100644 index 00000000..df2cd723 --- /dev/null +++ b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/model/Amount.kt @@ -0,0 +1,34 @@ +package net.dankito.banking.fints.model + + +open class Amount( + val string: String +) { + + companion object { + val Zero = Amount("0,") + } + + + internal constructor() : this("") // for object deserializers + + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is Amount) return false + + if (string != other.string) return false + + return true + } + + override fun hashCode(): Int { + return string.hashCode() + } + + + override fun toString(): String { + return string + } + +} \ No newline at end of file diff --git a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/model/BankTransferData.kt b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/model/BankTransferData.kt index 83fc35a0..490c207f 100644 --- a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/model/BankTransferData.kt +++ b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/model/BankTransferData.kt @@ -1,13 +1,11 @@ package net.dankito.banking.fints.model -import com.ionspin.kotlin.bignum.decimal.BigDecimal - open class BankTransferData( val creditorName: String, val creditorIban: String, val creditorBic: String, - val amount: BigDecimal, // TODO: use Money + val amount: Money, val usage: String, val instantPayment: Boolean = false ) \ No newline at end of file diff --git a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/model/Money.kt b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/model/Money.kt index ebed5c3a..f9ed5e53 100644 --- a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/model/Money.kt +++ b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/model/Money.kt @@ -1,16 +1,15 @@ package net.dankito.banking.fints.model -import com.ionspin.kotlin.bignum.decimal.BigDecimal - open class Money( - val amount: BigDecimal, + val amount: Amount, val currency: Currency ) { - constructor(amount: BigDecimal, currencyCode: String) : this(amount, Currency(currencyCode)) - internal constructor() : this(BigDecimal.ZERO, "") // for object deserializers + constructor(amount: Amount, currencyCode: String) : this(amount, Currency(currencyCode)) + + internal constructor() : this(Amount.Zero, "") // for object deserializers open val displayString: String diff --git a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/response/ResponseParser.kt b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/response/ResponseParser.kt index 76db415c..984533a9 100644 --- a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/response/ResponseParser.kt +++ b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/response/ResponseParser.kt @@ -1,7 +1,5 @@ package net.dankito.banking.fints.response -import com.ionspin.kotlin.bignum.decimal.BigDecimal -import com.ionspin.kotlin.bignum.decimal.toBigDecimal import com.soywiz.klock.Date import com.soywiz.klock.DateTime import com.soywiz.klock.Time @@ -19,6 +17,7 @@ import net.dankito.banking.fints.messages.datenelementgruppen.implementierte.Kre import net.dankito.banking.fints.messages.datenelementgruppen.implementierte.account.KontoverbindungInternational import net.dankito.banking.fints.messages.datenelementgruppen.implementierte.signatur.Sicherheitsprofil import net.dankito.banking.fints.messages.segmente.id.MessageSegmentId +import net.dankito.banking.fints.model.Amount import net.dankito.banking.fints.response.segments.* import net.dankito.banking.fints.util.MessageUtils import net.dankito.banking.fints.util.log.LoggerFactory @@ -618,7 +617,7 @@ open class ResponseParser( val parsedBalance = parseBalance(dataElementGroup) - if (BigDecimal.ZERO.equals(parsedBalance.amount)) { + if (Amount.Zero.equals(parsedBalance.amount)) { return null } @@ -830,16 +829,14 @@ open class ResponseParser( return null } - protected open fun parseAmount(amountString: String, isPositive: Boolean = true): BigDecimal { - val adjustedAmountString = amountString.replace(',', '.') // Hbci amount format uses comma instead dot as decimal separator - - val amount = adjustedAmountString.toBigDecimal() + protected open fun parseAmount(amountString: String, isPositive: Boolean = true): Amount { + var adjustedAmountString = amountString // Hbci amount format uses comma instead dot as decimal separator if (isPositive == false) { - return amount.negate() + adjustedAmountString = "-" + adjustedAmountString } - return amount + return Amount(adjustedAmountString) } protected open fun parseNullableDateTime(dataElementGroup: String): DateTime? { diff --git a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/response/client/AddAccountResponse.kt b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/response/client/AddAccountResponse.kt index fcf74fd4..df73a0a2 100644 --- a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/response/client/AddAccountResponse.kt +++ b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/response/client/AddAccountResponse.kt @@ -1,6 +1,5 @@ package net.dankito.banking.fints.response.client -import com.ionspin.kotlin.bignum.decimal.BigDecimal import net.dankito.banking.fints.model.* import net.dankito.banking.fints.response.Response @@ -15,4 +14,4 @@ open class AddAccountResponse( val balances: Map = mapOf() ) : GetTransactionsResponse(response, bookedTransactionsOfLast90Days, unbookedTransactionsOfLast90Days, - Money(balances.values.fold(BigDecimal.ZERO) { acc, e -> acc + e.amount }, balances.values.firstOrNull()?.currency?.code ?: "EUR")) \ No newline at end of file + Money(Amount.Zero, balances.values.firstOrNull()?.currency?.code ?: "EUR")) // TODO: sum balances \ No newline at end of file diff --git a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/response/segments/Balance.kt b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/response/segments/Balance.kt index b8c7ac36..47dfc9b5 100644 --- a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/response/segments/Balance.kt +++ b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/response/segments/Balance.kt @@ -1,12 +1,12 @@ package net.dankito.banking.fints.response.segments -import com.ionspin.kotlin.bignum.decimal.BigDecimal import com.soywiz.klock.Date import com.soywiz.klock.Time +import net.dankito.banking.fints.model.Amount open class Balance( - val amount: BigDecimal, + val amount: Amount, val date: Date, val time: Time? ) { diff --git a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/response/segments/BalanceSegment.kt b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/response/segments/BalanceSegment.kt index d8e6c9fe..45dffe68 100644 --- a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/response/segments/BalanceSegment.kt +++ b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/response/segments/BalanceSegment.kt @@ -1,15 +1,15 @@ package net.dankito.banking.fints.response.segments -import com.ionspin.kotlin.bignum.decimal.BigDecimal import com.soywiz.klock.Date +import net.dankito.banking.fints.model.Amount open class BalanceSegment( - val balance: BigDecimal, + val balance: Amount, val currency: String, val date: Date, val accountProductName: String, - val balanceOfPreBookedTransactions: BigDecimal?, + val balanceOfPreBookedTransactions: Amount?, segmentString: String ) : ReceivedSegment(segmentString) \ No newline at end of file diff --git a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/transactions/Mt940AccountTransactionsParser.kt b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/transactions/Mt940AccountTransactionsParser.kt index 217466a7..f9979e28 100644 --- a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/transactions/Mt940AccountTransactionsParser.kt +++ b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/transactions/Mt940AccountTransactionsParser.kt @@ -1,8 +1,8 @@ package net.dankito.banking.fints.transactions -import com.ionspin.kotlin.bignum.decimal.BigDecimal import net.dankito.banking.fints.model.AccountData import net.dankito.banking.fints.model.AccountTransaction +import net.dankito.banking.fints.model.Amount import net.dankito.banking.fints.model.Money import net.dankito.banking.fints.transactions.mt940.IMt940Parser import net.dankito.banking.fints.transactions.mt940.Mt940Parser @@ -91,23 +91,23 @@ open class Mt940AccountTransactionsParser( /** * 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 { + protected open fun mapAmount(balance: Balance): Amount { 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(statementLine: StatementLine): BigDecimal { + protected open fun mapAmount(statementLine: StatementLine): Amount { return mapAmount(statementLine.amount, statementLine.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() + protected open fun mapAmount(positiveAmount: Amount, isCredit: Boolean): Amount { + if (isCredit == false && positiveAmount.string.startsWith('-') == false) { + return Amount("-" + positiveAmount) } return positiveAmount diff --git a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/transactions/mt940/Mt940Parser.kt b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/transactions/mt940/Mt940Parser.kt index e7bf2d81..d5ae5ef8 100644 --- a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/transactions/mt940/Mt940Parser.kt +++ b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/transactions/mt940/Mt940Parser.kt @@ -1,8 +1,7 @@ package net.dankito.banking.fints.transactions.mt940 -import com.ionspin.kotlin.bignum.decimal.BigDecimal -import com.ionspin.kotlin.bignum.decimal.toBigDecimal import com.soywiz.klock.* +import net.dankito.banking.fints.model.Amount import net.dankito.banking.fints.transactions.mt940.model.* import net.dankito.banking.fints.util.log.LoggerFactory @@ -460,8 +459,8 @@ open class Mt940Parser : IMt940Parser { return bookingDate } - protected open fun parseAmount(amountString: String): BigDecimal { - return amountString.replace(',', '.').toBigDecimal() + protected open fun parseAmount(amountString: String): Amount { + return Amount(amountString) } } \ No newline at end of file diff --git a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/transactions/mt940/model/Balance.kt b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/transactions/mt940/model/Balance.kt index 83d5cacb..b833cdd5 100644 --- a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/transactions/mt940/model/Balance.kt +++ b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/transactions/mt940/model/Balance.kt @@ -1,8 +1,8 @@ package net.dankito.banking.fints.transactions.mt940.model -import com.ionspin.kotlin.bignum.decimal.BigDecimal import com.soywiz.klock.Date import com.soywiz.klock.DateTime +import net.dankito.banking.fints.model.Amount open class Balance( @@ -38,11 +38,11 @@ open class Balance( * * Max Length = 15 */ - val amount: BigDecimal + val amount: Amount ) { - internal constructor() : this(false, false, DateTime.EPOCH.date, "", BigDecimal.ZERO) // for object deserializers + internal constructor() : this(false, false, DateTime.EPOCH.date, "", Amount.Zero) // for object deserializers override fun toString(): String { diff --git a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/transactions/mt940/model/StatementLine.kt b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/transactions/mt940/model/StatementLine.kt index b6b408d9..e6b39a16 100644 --- a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/transactions/mt940/model/StatementLine.kt +++ b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/transactions/mt940/model/StatementLine.kt @@ -1,7 +1,7 @@ package net.dankito.banking.fints.transactions.mt940.model -import com.ionspin.kotlin.bignum.decimal.BigDecimal import com.soywiz.klock.Date +import net.dankito.banking.fints.model.Amount open class StatementLine( @@ -48,7 +48,7 @@ open class StatementLine( * * Max length = 15 */ - val amount: BigDecimal, + val amount: Amount, /** * in Kontowährung diff --git a/fints4k/src/commonTest/kotlin/net/dankito/banking/fints/FinTsTestBase.kt b/fints4k/src/commonTest/kotlin/net/dankito/banking/fints/FinTsTestBase.kt index 650addd1..297fb9cd 100644 --- a/fints4k/src/commonTest/kotlin/net/dankito/banking/fints/FinTsTestBase.kt +++ b/fints4k/src/commonTest/kotlin/net/dankito/banking/fints/FinTsTestBase.kt @@ -1,7 +1,6 @@ package net.dankito.banking.fints import com.benasher44.uuid.uuid4 -import com.ionspin.kotlin.bignum.decimal.BigDecimal import com.soywiz.klock.Date import net.dankito.banking.fints.messages.datenelemente.abgeleiteteformate.Datum import net.dankito.banking.fints.messages.datenelemente.abgeleiteteformate.Laenderkennzeichen @@ -68,10 +67,6 @@ abstract class FinTsTestBase { return uuid4().toString().replace("-", "") } - protected open fun convertAmount(amount: BigDecimal): String { - return amount.toStringExpanded().replace('.', ',') - } - protected open fun convertDate(date: Date): String { return Datum.format(date) } diff --git a/fints4k/src/commonTest/kotlin/net/dankito/banking/fints/messages/segmente/implementierte/sepa/SepaBankTransferBaseTest.kt b/fints4k/src/commonTest/kotlin/net/dankito/banking/fints/messages/segmente/implementierte/sepa/SepaBankTransferBaseTest.kt index 19fa2417..e2318f00 100644 --- a/fints4k/src/commonTest/kotlin/net/dankito/banking/fints/messages/segmente/implementierte/sepa/SepaBankTransferBaseTest.kt +++ b/fints4k/src/commonTest/kotlin/net/dankito/banking/fints/messages/segmente/implementierte/sepa/SepaBankTransferBaseTest.kt @@ -2,11 +2,8 @@ package net.dankito.banking.fints.messages.segmente.implementierte.sepa import ch.tutteli.atrium.api.fluent.en_GB.contains import ch.tutteli.atrium.api.verbs.expect -import com.ionspin.kotlin.bignum.decimal.toBigDecimal import net.dankito.banking.fints.messages.segmente.id.CustomerSegmentId -import net.dankito.banking.fints.model.AccountData -import net.dankito.banking.fints.model.BankTransferData -import net.dankito.banking.fints.model.CustomerData +import net.dankito.banking.fints.model.* import kotlin.test.Test @@ -21,7 +18,7 @@ class SepaBankTransferBaseTest { val creditorName = "Mahatma Gandhi" val creditorIban = "IN123456780987654321" val creditorBic = "ABCDINEFXXX" - val amount = 1234.56.toBigDecimal() + val amount = Amount("1234,56") val usage = "What should Mahatma Gandhi want with money?" } @@ -36,7 +33,7 @@ class SepaBankTransferBaseTest { CustomerData("", "", "", debitorName), AccountData("", null, 0, "", debitorIban, "", null, null, "", null, null, listOf()), debitorBic, - BankTransferData(creditorName, creditorIban, creditorBic, amount, usage) + BankTransferData(creditorName, creditorIban, creditorBic, Money(amount, "EUR"), usage) ) @@ -46,7 +43,7 @@ class SepaBankTransferBaseTest { // then expect(result).contains(debitorName, debitorIban, debitorBic, creditorName, creditorIban, creditorBic, - amount.toString(), usage, "urn?:iso?:std?:iso?:20022?:tech?:xsd?:pain.001.001.03") + amount.toString().replace(',', '.'), usage, "urn?:iso?:std?:iso?:20022?:tech?:xsd?:pain.001.001.03") } @Test @@ -58,7 +55,7 @@ class SepaBankTransferBaseTest { CustomerData("", "", "", debitorName), AccountData("", null, 0, "", debitorIban, "", null, null, "", null, null, listOf()), debitorBic, - BankTransferData(creditorName, creditorIban, creditorBic, amount, usage) + BankTransferData(creditorName, creditorIban, creditorBic, Money(amount, "EUR"), usage) ) @@ -68,7 +65,7 @@ class SepaBankTransferBaseTest { // then expect(result).contains(debitorName, debitorIban, debitorBic, creditorName, creditorIban, creditorBic, - amount.toString(), usage, "urn?:iso?:std?:iso?:20022?:tech?:xsd?:pain.001.003.03") + amount.toString().replace(',', '.'), usage, "urn?:iso?:std?:iso?:20022?:tech?:xsd?:pain.001.003.03") } } \ No newline at end of file diff --git a/fints4k/src/commonTest/kotlin/net/dankito/banking/fints/response/ResponseParserTest.kt b/fints4k/src/commonTest/kotlin/net/dankito/banking/fints/response/ResponseParserTest.kt index 004daa27..857f97f0 100644 --- a/fints4k/src/commonTest/kotlin/net/dankito/banking/fints/response/ResponseParserTest.kt +++ b/fints4k/src/commonTest/kotlin/net/dankito/banking/fints/response/ResponseParserTest.kt @@ -13,10 +13,9 @@ import net.dankito.banking.fints.messages.segmente.id.ISegmentId import net.dankito.banking.fints.messages.segmente.id.MessageSegmentId import net.dankito.banking.fints.response.segments.* import ch.tutteli.atrium.api.verbs.expect -import com.ionspin.kotlin.bignum.decimal.BigDecimal -import com.ionspin.kotlin.bignum.decimal.toBigDecimal import net.dankito.banking.fints.extensions.isFalse import net.dankito.banking.fints.extensions.isTrue +import net.dankito.banking.fints.model.Amount import kotlin.test.Test import kotlin.test.fail @@ -965,7 +964,7 @@ class ResponseParserTest : FinTsTestBase() { fun parseBalance() { // given - val balance = 1234.56.toBigDecimal() + val balance = "1234,56" val date = com.soywiz.klock.Date(1988, 3, 27) val bankCode = "12345678" val accountId = "0987654321" @@ -973,13 +972,13 @@ class ResponseParserTest : FinTsTestBase() { // when val result = underTest.parse("HISAL:8:5:3+$accountId::280:$bankCode+$accountProductName+EUR+" + - "C:${convertAmount(balance)}:EUR:${convertDate(date)}+C:0,:EUR:20191006++${convertAmount(balance)}:EUR") + "C:$balance:EUR:${convertDate(date)}+C:0,:EUR:20191006++$balance:EUR") // then assertSuccessfullyParsedSegment(result, InstituteSegmentId.Balance, 8, 5, 3) result.getFirstSegmentById(InstituteSegmentId.Balance)?.let { segment -> - expect(segment.balance).toBe(balance) + expect(segment.balance).toBe(Amount(balance)) expect(segment.currency).toBe("EUR") expect(segment.date).toBe(date) expect(segment.accountProductName).toBe(accountProductName) @@ -992,7 +991,7 @@ class ResponseParserTest : FinTsTestBase() { fun parseBalance_BalanceOfPreBookedTransactionsIsZero() { // given - val balance = BigDecimal.ZERO + val balance = Amount.Zero val date = com.soywiz.klock.Date(2020, 6, 11) val bankCode = "12345678" val accountId = "0987654321" @@ -1000,7 +999,7 @@ class ResponseParserTest : FinTsTestBase() { // when // "HISAL:7:5:3+0987654321:Girokonto:280:12345678+Girokonto+EUR+C:0,:EUR:20200511:204204'" - val result = underTest.parse("HISAL:7:5:3+$accountId:$accountProductName:280:$bankCode+$accountProductName+EUR+C:0,:EUR:${convertDate(date)}:204204'") + val result = underTest.parse("HISAL:7:5:3+$accountId:$accountProductName:280:$bankCode+$accountProductName+EUR+C:$balance:EUR:${convertDate(date)}:204204'") // then assertSuccessfullyParsedSegment(result, InstituteSegmentId.Balance, 7, 5, 3) @@ -1019,7 +1018,7 @@ class ResponseParserTest : FinTsTestBase() { fun parseBalance_BalanceOfPreBookedTransactionsIsEmpty() { // given - val balance = BigDecimal.ZERO + val balance = Amount.Zero val date = com.soywiz.klock.Date(2020, 6, 11) val bankCode = "12345678" val accountId = "0987654321" @@ -1027,7 +1026,7 @@ class ResponseParserTest : FinTsTestBase() { // when // "HISAL:7:5:3+0987654321:Girokonto:280:12345678+Girokonto+EUR++0,:EUR'" - val result = underTest.parse("HISAL:7:5:3+$accountId:$accountProductName:280:$bankCode+$accountProductName+EUR+C:0,:EUR:${convertDate(date)}:204204++0,:EUR'") + val result = underTest.parse("HISAL:7:5:3+$accountId:$accountProductName:280:$bankCode+$accountProductName+EUR+C:0,:EUR:${convertDate(date)}:204204++$balance:EUR'") // then assertSuccessfullyParsedSegment(result, InstituteSegmentId.Balance, 7, 5, 3) diff --git a/fints4k/src/commonTest/kotlin/net/dankito/banking/fints/transactions/Mt940ParserTest.kt b/fints4k/src/commonTest/kotlin/net/dankito/banking/fints/transactions/Mt940ParserTest.kt index 2a08108d..c9e4a88f 100644 --- a/fints4k/src/commonTest/kotlin/net/dankito/banking/fints/transactions/Mt940ParserTest.kt +++ b/fints4k/src/commonTest/kotlin/net/dankito/banking/fints/transactions/Mt940ParserTest.kt @@ -9,12 +9,11 @@ import net.dankito.banking.fints.transactions.mt940.model.Balance import net.dankito.banking.fints.transactions.mt940.model.InformationToAccountOwner import net.dankito.banking.fints.transactions.mt940.model.StatementLine import ch.tutteli.atrium.api.verbs.expect -import com.ionspin.kotlin.bignum.decimal.BigDecimal -import com.ionspin.kotlin.bignum.decimal.toBigDecimal import kotlin.test.Test import com.soywiz.klock.Date import com.soywiz.klock.DateFormat import net.dankito.banking.fints.extensions.isFalse +import net.dankito.banking.fints.model.Amount class Mt940ParserTest : FinTsTestBase() { @@ -26,20 +25,20 @@ class Mt940ParserTest : FinTsTestBase() { val AccountStatement1PreviousStatementBookingDate = Date(1988, 2, 26) val AccountStatement1BookingDate = Date(1988, 2, 27) - val AccountStatement1OpeningBalanceAmount = 12345.67.toBigDecimal() + val AccountStatement1OpeningBalanceAmount = Amount("12345,67") - val AccountStatement1Transaction1Amount = 1234.56.toBigDecimal() + val AccountStatement1Transaction1Amount = Amount("1234,56") val AccountStatement1Transaction1OtherPartyName = "Sender1" val AccountStatement1Transaction1OtherPartyBankCode = "AAAADE12" val AccountStatement1Transaction1OtherPartyAccountId = "DE99876543210987654321" - val AccountStatement1Transaction2Amount = 432.10.toBigDecimal() + val AccountStatement1Transaction2Amount = Amount("432,10") val AccountStatement1Transaction2OtherPartyName = "Receiver2" val AccountStatement1Transaction2OtherPartyBankCode = "BBBBDE56" val AccountStatement1Transaction2OtherPartyAccountId = "DE77987654321234567890" - val AccountStatement1ClosingBalanceAmount = AccountStatement1OpeningBalanceAmount + AccountStatement1Transaction1Amount - val AccountStatement1With2TransactionsClosingBalanceAmount = AccountStatement1OpeningBalanceAmount + AccountStatement1Transaction1Amount - AccountStatement1Transaction2Amount + val AccountStatement1ClosingBalanceAmount = Amount("13580,23") + val AccountStatement1With2TransactionsClosingBalanceAmount = Amount("13148,13") } private val underTest = Mt940Parser() @@ -74,7 +73,7 @@ class Mt940ParserTest : FinTsTestBase() { fun accountStatementWithSingleTransaction_SheetNumberOmitted() { // given - val amount = BigDecimal.parseString("15.00") + val amount = Amount("15,00") val isCredit = false val bookingDate = Date(2020, 5, 11) @@ -92,7 +91,7 @@ class Mt940ParserTest : FinTsTestBase() { expect(statement.statementNumber).toBe(0) expect(statement.sequenceNumber).toBe(null) - assertBalance(statement.openingBalance, true, bookingDate, BigDecimal.parseString("0.00")) + assertBalance(statement.openingBalance, true, bookingDate, Amount("0,00")) assertBalance(statement.closingBalance, isCredit, bookingDate, amount) expect(statement.transactions).hasSize(1) @@ -276,14 +275,14 @@ class Mt940ParserTest : FinTsTestBase() { } - private fun assertBalance(balance: Balance, isCredit: Boolean, bookingDate: Date, amount: BigDecimal) { + private fun assertBalance(balance: Balance, isCredit: Boolean, bookingDate: Date, amount: Amount) { expect(balance.isCredit).toBe(isCredit) expect(balance.bookingDate).toBe(bookingDate) expect(balance.amount).toBe(amount) expect(balance.currency).toBe(Currency) } - private fun assertTurnover(statementLine: StatementLine, valueDate: Date, amount: BigDecimal, isCredit: Boolean = true, + private fun assertTurnover(statementLine: StatementLine, valueDate: Date, amount: Amount, isCredit: Boolean = true, bookingDate: Date? = valueDate) { expect(statementLine.isCredit).toBe(isCredit) @@ -308,12 +307,12 @@ class Mt940ParserTest : FinTsTestBase() { :20:STARTUMSE :25:$BankCode/$CustomerId :28C:00000/001 - :60F:C${convertMt940Date(AccountStatement1PreviousStatementBookingDate)}EUR${convertAmount(AccountStatement1OpeningBalanceAmount)} - :61:${convertMt940Date(AccountStatement1BookingDate)}${convertToShortBookingDate(AccountStatement1BookingDate)}CR${convertAmount(AccountStatement1Transaction1Amount)}N062NONREF + :60F:C${convertMt940Date(AccountStatement1PreviousStatementBookingDate)}EUR$AccountStatement1OpeningBalanceAmount + :61:${convertMt940Date(AccountStatement1BookingDate)}${convertToShortBookingDate(AccountStatement1BookingDate)}CR${AccountStatement1Transaction1Amount}N062NONREF :86:166?00GUTSCHR. UEBERWEISUNG?109249?20EREF+674?21SVWZ+1908301/ - EUR ${convertAmount(AccountStatement1Transaction1Amount)}/20?2219-10-02/...?30$AccountStatement1Transaction1OtherPartyBankCode?31$AccountStatement1Transaction1OtherPartyAccountId + EUR ${AccountStatement1Transaction1Amount}/20?2219-10-02/...?30$AccountStatement1Transaction1OtherPartyBankCode?31$AccountStatement1Transaction1OtherPartyAccountId ?32$AccountStatement1Transaction1OtherPartyName - :62F:C${convertMt940Date(AccountStatement1BookingDate)}EUR${convertAmount(AccountStatement1ClosingBalanceAmount)} + :62F:C${convertMt940Date(AccountStatement1BookingDate)}EUR$AccountStatement1ClosingBalanceAmount - """.trimIndent() @@ -321,16 +320,16 @@ class Mt940ParserTest : FinTsTestBase() { :20:STARTUMSE :25:$BankCode/$CustomerId :28C:00000/001 - :60F:C${convertMt940Date(AccountStatement1PreviousStatementBookingDate)}EUR${convertAmount(AccountStatement1OpeningBalanceAmount)} - :61:${convertMt940Date(AccountStatement1BookingDate)}${convertToShortBookingDate(AccountStatement1BookingDate)}CR${convertAmount(AccountStatement1Transaction1Amount)}N062NONREF + :60F:C${convertMt940Date(AccountStatement1PreviousStatementBookingDate)}EUR$AccountStatement1OpeningBalanceAmount + :61:${convertMt940Date(AccountStatement1BookingDate)}${convertToShortBookingDate(AccountStatement1BookingDate)}CR${AccountStatement1Transaction1Amount}N062NONREF :86:166?00GUTSCHR. UEBERWEISUNG?109249?20EREF+674?21SVWZ+1908301/ - EUR ${convertAmount(AccountStatement1Transaction1Amount)}/20?2219-10-02/...?30$AccountStatement1Transaction1OtherPartyBankCode?31$AccountStatement1Transaction1OtherPartyAccountId + EUR ${AccountStatement1Transaction1Amount}/20?2219-10-02/...?30$AccountStatement1Transaction1OtherPartyBankCode?31$AccountStatement1Transaction1OtherPartyAccountId ?32$AccountStatement1Transaction1OtherPartyName - :61:${convertMt940Date(AccountStatement1BookingDate)}${convertToShortBookingDate(AccountStatement1BookingDate)}DR${convertAmount(AccountStatement1Transaction2Amount)}N062NONREF + :61:${convertMt940Date(AccountStatement1BookingDate)}${convertToShortBookingDate(AccountStatement1BookingDate)}DR${AccountStatement1Transaction2Amount}N062NONREF :86:166?00ONLINE-UEBERWEISUNG?109249?20EREF+674?21SVWZ+1908301/ - EUR ${convertAmount(AccountStatement1Transaction2Amount)}/20?2219-10-02/...?30$AccountStatement1Transaction2OtherPartyBankCode?31$AccountStatement1Transaction2OtherPartyAccountId + EUR ${AccountStatement1Transaction2Amount}/20?2219-10-02/...?30$AccountStatement1Transaction2OtherPartyBankCode?31$AccountStatement1Transaction2OtherPartyAccountId ?32$AccountStatement1Transaction2OtherPartyName - :62F:C${convertMt940Date(AccountStatement1BookingDate)}EUR${convertAmount(AccountStatement1With2TransactionsClosingBalanceAmount)} + :62F:C${convertMt940Date(AccountStatement1BookingDate)}EUR${AccountStatement1With2TransactionsClosingBalanceAmount} - """.trimIndent() diff --git a/ui/fints4kBankingClient/src/main/kotlin/net/dankito/banking/extensions/AmountExtensions.kt b/ui/fints4kBankingClient/src/main/kotlin/net/dankito/banking/extensions/AmountExtensions.kt new file mode 100644 index 00000000..9e7d2f35 --- /dev/null +++ b/ui/fints4kBankingClient/src/main/kotlin/net/dankito/banking/extensions/AmountExtensions.kt @@ -0,0 +1,22 @@ +package net.dankito.banking.extensions + +import net.dankito.banking.fints.model.Amount +import net.dankito.banking.fints.model.Money +import java.math.BigDecimal + + +fun BigDecimal.toAmount(): Amount { + return Amount(this.toString()) +} + +fun BigDecimal.toMoney(): Money { + return Money(this.toAmount(), "EUR") +} + +fun Amount.toJavaBigDecimal(): BigDecimal { + return BigDecimal(this.string) +} + +fun Money.toJavaBigDecimal(): BigDecimal { + return this.amount.toJavaBigDecimal() +} \ No newline at end of file diff --git a/ui/fints4kBankingClient/src/main/kotlin/net/dankito/banking/extensions/BigDecimalExtensions.kt b/ui/fints4kBankingClient/src/main/kotlin/net/dankito/banking/extensions/BigDecimalExtensions.kt deleted file mode 100644 index 27d74d82..00000000 --- a/ui/fints4kBankingClient/src/main/kotlin/net/dankito/banking/extensions/BigDecimalExtensions.kt +++ /dev/null @@ -1,24 +0,0 @@ -package net.dankito.banking.extensions - -import com.ionspin.kotlin.bignum.integer.Sign -import net.dankito.banking.fints.model.Money -import java.math.BigDecimal - - -fun BigDecimal.toIonspinBigDecimal(): com.ionspin.kotlin.bignum.decimal.BigDecimal { - return com.ionspin.kotlin.bignum.decimal.BigDecimal.parseString(this.toString()) // TODO: couldn't figure out how to create BigDecimal from unscaledValue and scale -} - -fun com.ionspin.kotlin.bignum.decimal.BigDecimal.toJavaBigDecimal(): BigDecimal { - val converted = BigDecimal.valueOf(this.significand.longValue(), (this.precision - this.exponent - 1).toInt()) - - if (this.significand.sign == Sign.NEGATIVE) { - return converted.negate() - } - - return converted -} - -fun Money.toJavaBigDecimal(): BigDecimal { - return this.amount.toJavaBigDecimal() -} \ No newline at end of file diff --git a/ui/fints4kBankingClient/src/main/kotlin/net/dankito/banking/fints4kBankingClient.kt b/ui/fints4kBankingClient/src/main/kotlin/net/dankito/banking/fints4kBankingClient.kt index 66f1a890..8a5ad060 100644 --- a/ui/fints4kBankingClient/src/main/kotlin/net/dankito/banking/fints4kBankingClient.kt +++ b/ui/fints4kBankingClient/src/main/kotlin/net/dankito/banking/fints4kBankingClient.kt @@ -1,7 +1,5 @@ package net.dankito.banking -import net.dankito.banking.extensions.toIonspinBigDecimal -import net.dankito.banking.extensions.toJavaBigDecimal import com.soywiz.klock.jvm.toDate import net.dankito.banking.extensions.toKlockDate import net.dankito.banking.ui.BankingClientCallback @@ -25,8 +23,11 @@ import net.dankito.utils.serialization.JacksonJsonSerializer import net.dankito.banking.fints.webclient.IWebClient import net.dankito.banking.fints.webclient.KtorWebClient import net.dankito.banking.bankfinder.BankInfo +import net.dankito.banking.extensions.toAmount +import net.dankito.banking.extensions.toMoney import org.slf4j.LoggerFactory import java.io.File +import java.math.BigDecimal open class fints4kBankingClient( @@ -133,7 +134,7 @@ open class fints4kBankingClient( callback(BankingClientResponse(false, "Cannot find account for ${bankAccount.identifier}")) // TODO: translate } else { - val mappedData = BankTransferData(data.creditorName, data.creditorIban, data.creditorBic, data.amount.toIonspinBigDecimal(), data.usage, data.instantPayment) + val mappedData = BankTransferData(data.creditorName, data.creditorIban, data.creditorBic, data.amount.toMoney(), data.usage, data.instantPayment) client.doBankTransferAsync(mappedData, account) { response -> saveData()