commit 3e3912bfc1e7af67756046379bc62ba4e292e374
parent a63f1ea71e22956cf9a0cd6b905626e254cc9b3f
Author: Florian Dold <florian.dold@gmail.com>
Date: Tue, 7 Jul 2020 13:58:36 +0530
amount format
Diffstat:
4 files changed, 51 insertions(+), 12 deletions(-)
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/bankaccount/BankAccount.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/bankaccount/BankAccount.kt
@@ -156,7 +156,7 @@ fun processCamtMessage(
val rawEntity = NexusBankTransactionEntity.new {
bankAccount = acct
accountTransactionId = "AcctSvcrRef:$acctSvcrRef"
- amount = tx.entryAmount.amount
+ amount = tx.entryAmount.value.toPlainString()
currency = tx.entryAmount.currency
transactionJson = jacksonObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(tx)
creditDebitIndicator = tx.creditDebitIndicator.name
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/iso20022/Iso20022.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/iso20022/Iso20022.kt
@@ -27,6 +27,7 @@ import com.fasterxml.jackson.annotation.JsonValue
import org.w3c.dom.Document
import tech.libeufin.nexus.server.CurrencyAmount
import tech.libeufin.util.*
+import java.math.BigDecimal
import java.time.Instant
import java.time.ZoneId
import java.time.ZonedDateTime
@@ -471,7 +472,7 @@ private fun XmlElementDestructor.extractParty(): PartyIdentification {
private fun XmlElementDestructor.extractCurrencyAmount(): CurrencyAmount {
return CurrencyAmount(
- amount = requireUniqueChildNamed("Amt") { it.textContent },
+ value = BigDecimal(requireUniqueChildNamed("Amt") { it.textContent }),
currency = requireUniqueChildNamed("Amt") { it.getAttribute("Ccy") }
)
}
@@ -479,8 +480,8 @@ private fun XmlElementDestructor.extractCurrencyAmount(): CurrencyAmount {
private fun XmlElementDestructor.maybeExtractCurrencyAmount(): CurrencyAmount? {
return maybeUniqueChildNamed("Amt") {
CurrencyAmount(
- it.textContent,
- it.getAttribute("Ccy")
+ it.getAttribute("Ccy"),
+ BigDecimal(it.textContent)
)
}
}
@@ -624,8 +625,7 @@ private fun XmlElementDestructor.extractInnerBkTxCd(): BankTransactionCode {
private fun XmlElementDestructor.extractInnerTransactions(): CamtReport {
val account = requireUniqueChildNamed("Acct") { extractAccount() }
val entries = mapEachChildNamed("Ntry") {
- val amount = requireUniqueChildNamed("Amt") { it.textContent }
- val currency = requireUniqueChildNamed("Amt") { it.getAttribute("Ccy") }
+ val amount = extractCurrencyAmount()
val status = requireUniqueChildNamed("Sts") { it.textContent }.let {
EntryStatus.valueOf(it)
}
@@ -638,9 +638,9 @@ private fun XmlElementDestructor.extractInnerTransactions(): CamtReport {
val acctSvcrRef = maybeUniqueChildNamed("AcctSvcrRef") { it.textContent }
val entryRef = maybeUniqueChildNamed("NtryRef") { it.textContent }
// For now, only support account servicer reference as id
- val transactionInfos = extractTransactionInfos(CurrencyAmount(currency, amount), creditDebitIndicator)
+ val transactionInfos = extractTransactionInfos(amount, creditDebitIndicator)
CamtBankAccountEntry(
- entryAmount = CurrencyAmount(currency, amount),
+ entryAmount = amount,
status = status,
creditDebitIndicator = creditDebitIndicator,
bankTransactionCode = btc,
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/server/JSON.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/server/JSON.kt
@@ -23,11 +23,21 @@ import com.fasterxml.jackson.annotation.JsonSubTypes
import com.fasterxml.jackson.annotation.JsonTypeInfo
import com.fasterxml.jackson.annotation.JsonTypeName
import com.fasterxml.jackson.annotation.JsonValue
+import com.fasterxml.jackson.core.JsonGenerator
+import com.fasterxml.jackson.core.JsonParser
+import com.fasterxml.jackson.databind.DeserializationContext
import com.fasterxml.jackson.databind.JsonNode
+import com.fasterxml.jackson.databind.SerializerProvider
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize
+import com.fasterxml.jackson.databind.annotation.JsonSerialize
+import com.fasterxml.jackson.databind.deser.std.StdDeserializer
+import com.fasterxml.jackson.databind.ser.std.StdSerializer
import tech.libeufin.nexus.iso20022.CamtBankAccountEntry
import tech.libeufin.nexus.iso20022.CreditDebitIndicator
import tech.libeufin.nexus.iso20022.EntryStatus
import tech.libeufin.util.*
+import java.lang.UnsupportedOperationException
+import java.math.BigDecimal
import java.time.Instant
import java.time.ZoneId
import java.time.ZonedDateTime
@@ -342,12 +352,39 @@ data class ImportBankAccount(
val nexusBankAccountId: String
)
+
+class CurrencyAmountDeserializer(jc: Class<*> = CurrencyAmount::class.java) : StdDeserializer<CurrencyAmount>(jc) {
+ override fun deserialize(p: JsonParser?, ctxt: DeserializationContext?): CurrencyAmount {
+ if (p == null) {
+ throw UnsupportedOperationException();
+ }
+ val s = p.valueAsString
+ val components = s.split(":")
+ // FIXME: error handling!
+ return CurrencyAmount(components[0], BigDecimal(components[1]))
+ }
+}
+
+class CurrencyAmountSerializer(jc: Class<CurrencyAmount> = CurrencyAmount::class.java) : StdSerializer<CurrencyAmount>(jc) {
+ override fun serialize(value: CurrencyAmount?, gen: JsonGenerator?, provider: SerializerProvider?) {
+ if (gen == null) {
+ throw UnsupportedOperationException()
+ }
+ if (value == null) {
+ gen.writeNull()
+ } else {
+ gen.writeString("${value.currency}:${value.value.toPlainString()}")
+ }
+ }
+}
+
+@JsonDeserialize(using = CurrencyAmountDeserializer::class)
+@JsonSerialize(using = CurrencyAmountSerializer::class)
data class CurrencyAmount(
val currency: String,
- val amount: String
+ val value: BigDecimal
)
-
/**
* Account entry item as returned by the /bank-accounts/{acctId}/transactions API.
*/
diff --git a/nexus/src/test/kotlin/Iso20022Test.kt b/nexus/src/test/kotlin/Iso20022Test.kt
@@ -4,7 +4,9 @@ import org.junit.Test
import org.w3c.dom.Document
import tech.libeufin.nexus.iso20022.*
import tech.libeufin.util.XMLUtil
+import java.math.BigDecimal
import kotlin.test.assertEquals
+import kotlin.test.assertTrue
fun loadXmlResource(name: String): Document {
val classLoader = ClassLoader.getSystemClassLoader()
@@ -26,7 +28,7 @@ class Iso20022Test {
assertEquals(1, r.reports.size)
// First Entry
- assertEquals("100.00", r.reports[0].entries[0].entryAmount.amount)
+ assertTrue(BigDecimal(100).compareTo(r.reports[0].entries[0].entryAmount.value) == 0)
assertEquals("EUR", r.reports[0].entries[0].entryAmount.currency)
assertEquals(CreditDebitIndicator.CRDT, r.reports[0].entries[0].creditDebitIndicator)
assertEquals(EntryStatus.BOOK, r.reports[0].entries[0].status)
@@ -39,7 +41,7 @@ class Iso20022Test {
assertEquals("DK", r.reports[0].entries[0].bankTransactionCode.proprietaryIssuer)
assertEquals(1, r.reports[0].entries[0].transactionInfos.size)
assertEquals("EUR", r.reports[0].entries[0].transactionInfos[0].amount.currency)
- assertEquals("100.00", r.reports[0].entries[0].transactionInfos[0].amount.amount)
+ assertTrue(BigDecimal(100).compareTo(r.reports[0].entries[0].transactionInfos[0].amount.value) == 0)
assertEquals(CreditDebitIndicator.CRDT, r.reports[0].entries[0].transactionInfos[0].creditDebitIndicator)
assertEquals("unstructured info one", r.reports[0].entries[0].transactionInfos[0].unstructuredRemittanceInformation)