gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[libeufin] 02/02: parse balances and batches correctly


From: gnunet
Subject: [libeufin] 02/02: parse balances and batches correctly
Date: Tue, 07 Jul 2020 22:15:14 +0200

This is an automated email from the git hooks/post-receive script.

dold pushed a commit to branch master
in repository libeufin.

commit da0c0cdc71d27670aba52dc566fb146046bffdc9
Author: Florian Dold <florian.dold@gmail.com>
AuthorDate: Wed Jul 8 01:38:56 2020 +0530

    parse balances and batches correctly
---
 nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt  |  19 +-
 .../tech/libeufin/nexus/iso20022/Iso20022.kt       | 261 +++++++++++++++++----
 .../camt.053/de.camt.053.001.02.xml                | 128 +++++++++-
 util/src/main/kotlin/ISO20022.kt                   |  69 ------
 4 files changed, 357 insertions(+), 120 deletions(-)

diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt 
b/nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt
index a5b7ac5..9d009f7 100644
--- a/nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt
+++ b/nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt
@@ -33,9 +33,11 @@ import org.slf4j.Logger
 import org.slf4j.LoggerFactory
 import tech.libeufin.nexus.server.serverMain
 import tech.libeufin.util.CryptoUtil.hashpw
-import ch.qos.logback.classic.Level
-import ch.qos.logback.classic.LoggerContext
+import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
+import tech.libeufin.nexus.iso20022.parseCamtMessage
+import tech.libeufin.util.XMLUtil
 import tech.libeufin.util.setLogLevel
+import java.io.File
 
 val logger: Logger = LoggerFactory.getLogger("tech.libeufin.nexus")
 
@@ -58,6 +60,17 @@ class Serve : CliktCommand("Run nexus HTTP server") {
     }
 }
 
+class ParseCamt : CliktCommand("Parse a camt file") {
+    private val logLevel by option()
+    private val filename by argument()
+    override fun run() {
+        setLogLevel(logLevel)
+        val camtText = File(filename).readText(Charsets.UTF_8)
+        val res = parseCamtMessage(XMLUtil.parseStringIntoDom(camtText))
+        
println(jacksonObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(res))
+    }
+}
+
 class Superuser : CliktCommand("Add superuser or change pw") {
     private val dbName by option().default("libeufin-nexus.sqlite3")
     private val username by argument()
@@ -85,6 +98,6 @@ class Superuser : CliktCommand("Add superuser or change pw") {
 
 fun main(args: Array<String>) {
     NexusCommand()
-        .subcommands(Serve(), Superuser())
+        .subcommands(Serve(), Superuser(), ParseCamt())
         .main(args)
 }
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/iso20022/Iso20022.kt 
b/nexus/src/main/kotlin/tech/libeufin/nexus/iso20022/Iso20022.kt
index 4f8beaf..6958ea8 100644
--- a/nexus/src/main/kotlin/tech/libeufin/nexus/iso20022/Iso20022.kt
+++ b/nexus/src/main/kotlin/tech/libeufin/nexus/iso20022/Iso20022.kt
@@ -60,7 +60,16 @@ enum class CashManagementResponseType(@get:JsonValue val 
jsonName: String) {
 
 @JsonInclude(JsonInclude.Include.NON_NULL)
 data class CamtReport(
+    val id: String,
+    val creationDateTime: String?,
+    val legalSequenceNumber: Int?,
+    val electronicSequenceNumber: Int?,
+    val fromDate: String?,
+    val toDate: String?,
+    val reportingSource: String?,
+    val proprietaryReportingSource: String?,
     val account: CashAccount,
+    val balances: List<Balance>,
     val entries: List<CamtBankAccountEntry>
 )
 
@@ -80,6 +89,7 @@ data class CashAccount(
     val otherId: GenericId?
 )
 
+@JsonInclude(JsonInclude.Include.NON_NULL)
 data class Balance(
     val type: String?,
     val subtype: String?,
@@ -97,7 +107,6 @@ data class CamtParseResult(
     val messageType: CashManagementResponseType,
     val messageId: String,
     val creationDateTime: String,
-    val balances: List<Balance>,
     val reports: List<CamtReport>
 )
 
@@ -127,6 +136,7 @@ data class PartyIdentification(
     val countryOfResidence: String?,
     val privateId: PrivateIdentification?,
     val organizationId: OrganizationIdentification?,
+    val postalAddress: PostalAddress?,
 
     /**
      * Identification that applies to both private parties and organizations.
@@ -134,10 +144,48 @@ data class PartyIdentification(
     val otherId: GenericId?
 )
 
+@JsonInclude(JsonInclude.Include.NON_NULL)
+data class PostalAddress(
+    val addressCode: String?,
+    val addressProprietaryId: String?,
+    val addressProprietarySchemeName: String?,
+    val addressProprietaryIssuer: String?,
+    val department: String?,
+    val subDepartment: String?,
+    val streetName: String?,
+    val buildingNumber: String?,
+    val buildingName: String?,
+    val floor: String?,
+    val postBox: String?,
+    val room: String?,
+    val postCode: String?,
+    val townName: String?,
+    val townLocationName: String?,
+    val districtName: String?,
+    val countrySubDivision: String?,
+    val country: String?,
+    val addressLines: List<String>
+)
+
 @JsonInclude(JsonInclude.Include.NON_NULL)
 data class AgentIdentification(
     val name: String?,
+
     val bic: String?,
+
+    /**
+     * Legal entity identification.
+     */
+    val lei: String?,
+
+    val clearingSystemMemberId: String?,
+
+    val clearingSystemCode: String?,
+
+    val proprietaryClearingSystemCode: String?,
+
+    val postalAddress: PostalAddress?,
+
     val otherId: GenericId?
 )
 
@@ -159,11 +207,16 @@ data class TransactionDetails(
     val creditor: PartyIdentification?,
     val creditorAccount: CashAccount?,
     val creditorAgent: AgentIdentification?,
+    val ultimateCreditor: PartyIdentification?,
+    val ultimateDebtor: PartyIdentification?,
 
     val endToEndId: String? = null,
     val paymentInformationId: String? = null,
     val messageId: String? = null,
 
+    val purpose: String?,
+    val proprietaryPurpose: String?,
+
     /**
      * Currency exchange information for the transaction's amount.
      */
@@ -219,11 +272,11 @@ data class BatchTransaction(
     val details: TransactionDetails
 )
 
-
+@JsonInclude(JsonInclude.Include.NON_NULL)
 data class Batch(
-    val batchTransactions: List<BatchTransaction>,
     val messageId: String?,
-    val paymentInformationId: String?
+    val paymentInformationId: String?,
+    val batchTransactions: List<BatchTransaction>
 )
 
 @JsonInclude(JsonInclude.Include.NON_NULL)
@@ -263,9 +316,16 @@ data class CamtBankAccountEntry(
 
     /**
      * Value before/after currency exchange before charges have been applied.
+     * Only present if currency exchange happened at the entry level.
      */
     val counterValueAmount: CurrencyAmount?,
 
+    /**
+     * Instructed amount.
+     * Only present if currency exchange happens at the entry level.
+     */
+    val instructedAmount: CurrencyAmount?,
+
     /**
      * Details of the underlying transaction for type=Simple.
      */
@@ -419,19 +479,74 @@ private fun XmlElementDestructor.extractDateOrDateTime(): 
String {
     }
 }
 
+private fun XmlElementDestructor.extractInnerPostalAddress(): PostalAddress {
+    return PostalAddress(
+        addressCode = maybeUniqueChildNamed("AdrTp") { 
maybeUniqueChildNamed("Cd") { it.textContent } },
+        addressProprietaryIssuer = maybeUniqueChildNamed("AdrTp") {
+            maybeUniqueChildNamed("Prtry") {
+                maybeUniqueChildNamed("Issr") { it.textContent }
+            }
+        },
+        addressProprietarySchemeName = maybeUniqueChildNamed("AdrTp") {
+            maybeUniqueChildNamed("Prtry") {
+                maybeUniqueChildNamed("SchmeNm") { it.textContent }
+            }
+        },
+        addressProprietaryId = maybeUniqueChildNamed("AdrTp") {
+            maybeUniqueChildNamed("Prtry") {
+                maybeUniqueChildNamed("Id") { it.textContent }
+            }
+        },
+        buildingName = maybeUniqueChildNamed("BldgNm") { it.textContent },
+        buildingNumber = maybeUniqueChildNamed("BldgNb") { it.textContent },
+        country = maybeUniqueChildNamed("Ctry") { it.textContent },
+        countrySubDivision = maybeUniqueChildNamed("CtrySubDvsn") { 
it.textContent },
+        department = maybeUniqueChildNamed("Dept") { it.textContent },
+        districtName = maybeUniqueChildNamed("DstrctNm") { it.textContent },
+        floor = maybeUniqueChildNamed("Flr") { it.textContent },
+        postBox = maybeUniqueChildNamed("PstBx") { it.textContent },
+        postCode = maybeUniqueChildNamed("PstCd") { it.textContent },
+        room = maybeUniqueChildNamed("Room") { it.textContent },
+        streetName = maybeUniqueChildNamed("StrtNm") { it.textContent },
+        subDepartment = maybeUniqueChildNamed("SubDept") { it.textContent },
+        townLocationName = maybeUniqueChildNamed("TwnLctnNm") { it.textContent 
},
+        townName = maybeUniqueChildNamed("TwnNm") { it.textContent },
+        addressLines = mapEachChildNamed("AdrLine") { it.textContent }
+    )
+}
+
 private fun XmlElementDestructor.extractAgent(): AgentIdentification {
     return AgentIdentification(
         name = maybeUniqueChildNamed("FinInstnId") {
-            maybeUniqueChildNamed("Nm") {
-                it.textContent
-            }
+            maybeUniqueChildNamed("Nm") { it.textContent }
         },
         bic = requireUniqueChildNamed("FinInstnId") {
-            requireUniqueChildNamed("BIC") {
-                it.textContent
+            maybeUniqueChildNamed("BIC") { it.textContent }
+        },
+        lei = requireUniqueChildNamed("FinInstnId") {
+            maybeUniqueChildNamed("LEI") { it.textContent }
+        },
+        clearingSystemCode = requireUniqueChildNamed("FinInstnId") {
+            maybeUniqueChildNamed("ClrSysMmbId") {
+                maybeUniqueChildNamed("ClrSysId") {
+                    maybeUniqueChildNamed("Cd") { it.textContent }
+                }
             }
         },
-        otherId = null
+        proprietaryClearingSystemCode = requireUniqueChildNamed("FinInstnId") {
+            maybeUniqueChildNamed("ClrSysMmbId") {
+                maybeUniqueChildNamed("ClrSysId") {
+                    maybeUniqueChildNamed("Prtry") { it.textContent }
+                }
+            }
+        },
+        clearingSystemMemberId = requireUniqueChildNamed("FinInstnId") {
+            maybeUniqueChildNamed("ClrSysMmbId") {
+                maybeUniqueChildNamed("MmbId") { it.textContent }
+            }
+        },
+        otherId = requireUniqueChildNamed("FinInstnId") { 
maybeUniqueChildNamed("Othr") { extractGenericId() } },
+        postalAddress = requireUniqueChildNamed("FinInstnId") { 
maybeUniqueChildNamed("PstlAdr") { extractInnerPostalAddress() } }
     )
 }
 
@@ -506,7 +621,8 @@ private fun XmlElementDestructor.extractParty(): 
PartyIdentification {
         otherId = otherId,
         privateId = privateId,
         organizationId = organizationId,
-        countryOfResidence = maybeUniqueChildNamed("CtryOfRes") { 
it.textContent }
+        countryOfResidence = maybeUniqueChildNamed("CtryOfRes") { 
it.textContent },
+        postalAddress = maybeUniqueChildNamed("PstlAdr") { 
extractInnerPostalAddress() }
     )
 }
 
@@ -548,10 +664,27 @@ private fun XmlElementDestructor.extractBatches(
         var amount = maybeExtractCurrencyAmount()
         var creditDebitIndicator = maybeExtractCreditDebitIndicator()
 
-        if (amount == null && numDtls == 1) {
+        val ttlAmt = maybeUniqueChildNamed("Btch") {
+            maybeUniqueChildNamed("TtlAmt") {
+                CurrencyAmount(
+                    value =  BigDecimal(it.textContent),
+                    currency = it.getAttribute("Ccy")
+                )
+            }
+        }
+
+        val ttlCreditDebitIndicator = maybeUniqueChildNamed("Btch") {
+            maybeExtractCreditDebitIndicator()
+        }
+
+        if (amount == null && ttlAmt != null && ttlCreditDebitIndicator != 
null) {
+            amount = ttlAmt
+            creditDebitIndicator = ttlCreditDebitIndicator
+        } else if (amount == null && numDtls == 1) {
             amount = outerAmount
             creditDebitIndicator = outerCreditDebitIndicator
         }
+
         if (amount == null || creditDebitIndicator == null) {
             throw Error("no amount for inner transaction")
         }
@@ -559,7 +692,7 @@ private fun XmlElementDestructor.extractBatches(
             val details = extractTransactionDetails(outerAmount, 
outerCreditDebitIndicator, false)
             BatchTransaction(amount, creditDebitIndicator, details)
         }
-        Batch(txs, null, null)
+        Batch(null, null, txs)
     }
 }
 
@@ -581,8 +714,8 @@ private fun XmlElementDestructor.extractTransactionDetails(
     val creditDebitIndicator = maybeExtractCreditDebitIndicator() ?: 
outerCreditDebitIndicator
 
     val currencyExchange = maybeUniqueChildNamed("AmtDtls") {
-        val cxCntrVal =  maybeUniqueChildNamed("CntrValAmt") { 
extractMaybeCurrencyExchange() }
-        val cxTx =  maybeUniqueChildNamed("TxAmt") { 
extractMaybeCurrencyExchange() }
+        val cxCntrVal = maybeUniqueChildNamed("CntrValAmt") { 
extractMaybeCurrencyExchange() }
+        val cxTx = maybeUniqueChildNamed("TxAmt") { 
extractMaybeCurrencyExchange() }
         val cxInstr = maybeUniqueChildNamed("InstdAmt") { 
extractMaybeCurrencyExchange() }
         cxCntrVal ?: cxTx ?: cxInstr
     }
@@ -605,7 +738,7 @@ private fun XmlElementDestructor.extractTransactionDetails(
             maybeUniqueChildNamed("PmtInfId") { it.textContent }
         },
         unstructuredRemittanceInformation = maybeUniqueChildNamed("RmtInf") {
-            val chunks = mapEachChildNamed("Ustrd", { it.textContent })
+            val chunks = mapEachChildNamed("Ustrd") { it.textContent }
             if (chunks.isEmpty()) {
                 null
             } else {
@@ -614,10 +747,14 @@ private fun 
XmlElementDestructor.extractTransactionDetails(
         } ?: "",
         creditorAgent = maybeUniqueChildNamed("RltdAgts") { 
maybeUniqueChildNamed("CdtrAgt") { extractAgent() } },
         debtorAgent = maybeUniqueChildNamed("RltdAgts") { 
maybeUniqueChildNamed("DbtrAgt") { extractAgent() } },
-        debtorAccount = maybeUniqueChildNamed("RltdPties") { 
maybeUniqueChildNamed("DbtrAgt") { extractAccount() } },
-        creditorAccount = maybeUniqueChildNamed("RltdPties") { 
maybeUniqueChildNamed("CdtrAgt") { extractAccount() } },
+        debtorAccount = maybeUniqueChildNamed("RltdPties") { 
maybeUniqueChildNamed("DbtrAcct") { extractAccount() } },
+        creditorAccount = maybeUniqueChildNamed("RltdPties") { 
maybeUniqueChildNamed("CdtrAcct") { extractAccount() } },
         debtor = maybeUniqueChildNamed("RltdPties") { 
maybeUniqueChildNamed("Dbtr") { extractParty() } },
         creditor = maybeUniqueChildNamed("RltdPties") { 
maybeUniqueChildNamed("Cdtr") { extractParty() } },
+        proprietaryPurpose = maybeUniqueChildNamed("Purp") { 
maybeUniqueChildNamed("Prtry") { it.textContent } },
+        purpose = maybeUniqueChildNamed("Purp") { maybeUniqueChildNamed("Cd") 
{ it.textContent } },
+        ultimateCreditor = maybeUniqueChildNamed("RltdPties") { 
maybeUniqueChildNamed("UltmtCdtr") { extractParty() } },
+        ultimateDebtor = maybeUniqueChildNamed("RltdPties") { 
maybeUniqueChildNamed("UltmtDbtr") { extractParty() } },
         returnInfo = maybeUniqueChildNamed("RtrInf") {
             ReturnInfo(
                 originalBankTransactionCode = 
maybeUniqueChildNamed("OrgnlBkTxCd") {
@@ -637,7 +774,6 @@ private fun XmlElementDestructor.extractTransactionDetails(
     )
 }
 
-
 private fun XmlElementDestructor.extractSingleDetails(
     outerAmount: CurrencyAmount,
     outerCreditDebitIndicator: CreditDebitIndicator
@@ -687,6 +823,33 @@ private fun 
XmlElementDestructor.extractInnerBkTxCd(creditDebitIndicator: Credit
 
 private fun XmlElementDestructor.extractInnerTransactions(): CamtReport {
     val account = requireUniqueChildNamed("Acct") { extractAccount() }
+
+    val balances = mapEachChildNamed("Bal") {
+        Balance(
+            type = maybeUniqueChildNamed("Tp") {
+                maybeUniqueChildNamed("CdOrPrtry") {
+                    maybeUniqueChildNamed("Cd") { it.textContent }
+                }
+            },
+            proprietaryType = maybeUniqueChildNamed("Tp") {
+                maybeUniqueChildNamed("CdOrPrtry") {
+                    maybeUniqueChildNamed("Prtry") { it.textContent }
+                }
+            },
+            date = requireUniqueChildNamed("Dt") { extractDateOrDateTime() },
+            creditDebitIndicator = requireUniqueChildNamed("CdtDbtInd") { 
it.textContent }.let {
+                CreditDebitIndicator.valueOf(it)
+            },
+            subtype = maybeUniqueChildNamed("Tp") {
+                maybeUniqueChildNamed("SubTp") { maybeUniqueChildNamed("Cd") { 
it.textContent } }
+            },
+            proprietarySubtype = maybeUniqueChildNamed("Tp") {
+                maybeUniqueChildNamed("SubTp") { 
maybeUniqueChildNamed("Prtry") { it.textContent } }
+            },
+            amount = extractCurrencyAmount()
+        )
+    }
+
     val entries = mapEachChildNamed("Ntry") {
         val amount = extractCurrencyAmount()
         val status = requireUniqueChildNamed("Sts") { it.textContent }.let {
@@ -701,13 +864,19 @@ private fun 
XmlElementDestructor.extractInnerTransactions(): CamtReport {
         val acctSvcrRef = maybeUniqueChildNamed("AcctSvcrRef") { 
it.textContent }
         val entryRef = maybeUniqueChildNamed("NtryRef") { it.textContent }
 
-        val numNtryDtls = mapEachChildNamed("NtryDtls") {
-            Unit
-        }.count()
+        val numInnerTxs = mapEachChildNamed("NtryDtls") {
+            mapEachChildNamed("TxDtls") { Unit }
+        }.flatten().count()
+
+        val numBatches = mapEachChildNamed("NtryDtls") {
+            mapEachChildNamed("Btch") { Unit }
+        }.flatten().count()
+
+        val isBatch = numBatches > 0 || numInnerTxs > 1
 
         val currencyExchange = maybeUniqueChildNamed("AmtDtls") {
-            val cxCntrVal =  maybeUniqueChildNamed("CntrValAmt") { 
extractMaybeCurrencyExchange() }
-            val cxTx =  maybeUniqueChildNamed("TxAmt") { 
extractMaybeCurrencyExchange() }
+            val cxCntrVal = maybeUniqueChildNamed("CntrValAmt") { 
extractMaybeCurrencyExchange() }
+            val cxTx = maybeUniqueChildNamed("TxAmt") { 
extractMaybeCurrencyExchange() }
             val cxInstr = maybeUniqueChildNamed("InstrAmt") { 
extractMaybeCurrencyExchange() }
             cxCntrVal ?: cxTx ?: cxInstr
         }
@@ -716,6 +885,10 @@ private fun 
XmlElementDestructor.extractInnerTransactions(): CamtReport {
             maybeUniqueChildNamed("CntrValAmt") { extractCurrencyAmount() }
         }
 
+        val instructedAmount = maybeUniqueChildNamed("AmtDtls") {
+            maybeUniqueChildNamed("InstdAmt") { extractCurrencyAmount() }
+        }
+
         // For now, only support account servicer reference as id
 
         CamtBankAccountEntry(
@@ -723,14 +896,15 @@ private fun 
XmlElementDestructor.extractInnerTransactions(): CamtReport {
             status = status,
             currencyExchange = currencyExchange,
             counterValueAmount = counterValueAmount,
+            instructedAmount = instructedAmount,
             creditDebitIndicator = creditDebitIndicator,
             bankTransactionCode = btc,
-            details = if (numNtryDtls == 1) {
-                extractSingleDetails(amount, creditDebitIndicator)
-            } else {
+            details = if (isBatch) {
                 null
+            } else {
+                extractSingleDetails(amount, creditDebitIndicator)
             },
-            batches = if (numNtryDtls > 1) {
+            batches = if (isBatch) {
                 extractBatches(amount, creditDebitIndicator)
             } else {
                 null
@@ -741,7 +915,19 @@ private fun 
XmlElementDestructor.extractInnerTransactions(): CamtReport {
             entryRef = entryRef
         )
     }
-    return CamtReport(account, entries)
+    return CamtReport(
+        account = account,
+        entries = entries,
+        creationDateTime = maybeUniqueChildNamed("CreDtTm") { it.textContent },
+        balances = balances,
+        electronicSequenceNumber = maybeUniqueChildNamed("ElctrncSeqNb") { 
it.textContent.toInt() },
+        legalSequenceNumber = maybeUniqueChildNamed("LglSeqNb") { 
it.textContent.toInt() },
+        fromDate = maybeUniqueChildNamed("FrToDt") { 
maybeUniqueChildNamed("FrDtTm") { it.textContent } },
+        toDate = maybeUniqueChildNamed("FrToDt") { 
maybeUniqueChildNamed("ToDtTm") { it.textContent } },
+        id = requireUniqueChildNamed("Id") { it.textContent },
+        proprietaryReportingSource = maybeUniqueChildNamed("RptgSrc") { 
maybeUniqueChildNamed("Prtry") { it.textContent } },
+        reportingSource = maybeUniqueChildNamed("RptgSrc") { 
maybeUniqueChildNamed("Cd") { it.textContent } }
+    )
 }
 
 /**
@@ -769,22 +955,6 @@ fun parseCamtMessage(doc: Document): CamtParseResult {
                 }
             }
 
-            val balances = requireOnlyChild {
-                mapEachChildNamed("Bal") {
-                    Balance(
-                        type = maybeUniqueChildNamed("Tp") { 
maybeUniqueChildNamed("Cd") { it.textContent } },
-                        proprietaryType = maybeUniqueChildNamed("Tp") { 
maybeUniqueChildNamed("Prtry") { it.textContent } },
-                        date = extractDateOrDateTime(),
-                        creditDebitIndicator = 
requireUniqueChildNamed("CdtDbtInd") { it.textContent }.let {
-                            CreditDebitIndicator.valueOf(it)
-                        },
-                        subtype = maybeUniqueChildNamed("SubTp") { 
maybeUniqueChildNamed("Cd") { it.textContent } },
-                        proprietarySubtype = maybeUniqueChildNamed("SubTp") { 
maybeUniqueChildNamed("Prtry") { it.textContent } },
-                        amount = extractCurrencyAmount()
-                    )
-                }
-            }
-
             val messageId = requireOnlyChild {
                 requireUniqueChildNamed("GrpHdr") {
                     requireUniqueChildNamed("MsgId") { it.textContent }
@@ -806,7 +976,6 @@ fun parseCamtMessage(doc: Document): CamtParseResult {
             }
             CamtParseResult(
                 reports = reports,
-                balances = balances,
                 messageId = messageId,
                 messageType = messageType,
                 creationDateTime = creationDateTime
diff --git 
a/nexus/src/test/resources/iso20022-samples/camt.053/de.camt.053.001.02.xml 
b/nexus/src/test/resources/iso20022-samples/camt.053/de.camt.053.001.02.xml
index dc3511e..14a36eb 100644
--- a/nexus/src/test/resources/iso20022-samples/camt.053/de.camt.053.001.02.xml
+++ b/nexus/src/test/resources/iso20022-samples/camt.053/de.camt.053.001.02.xml
@@ -233,7 +233,7 @@
                                 </Id>
                             </DbtrAcct>
                             <Cdtr>
-                                <Nm>Nonexistant Creditor</Nm>
+                                <Nm>Nonexistent Creditor</Nm>
                             </Cdtr>
                             <CdtrAcct>
                                 <Id>
@@ -330,7 +330,7 @@
                         </Chrgs>
                         <RltdPties>
                             <Dbtr>
-                                <Nm>Some US Bank</Nm>
+                                <Nm>Mr USA</Nm>
                                 <PstlAdr>
                                     <Ctry>US</Ctry>
                                     <AdrLine>42 Some Street</AdrLine>
@@ -359,6 +359,130 @@
                 </NtryDtls>
                 <AddtlNtryInf>AZV-UEBERWEISUNGSGUTSCHRIFT</AddtlNtryInf>
             </Ntry>
+
+            <Ntry>
+                <Amt Ccy="EUR">48.42</Amt>
+                <CdtDbtInd>DBIT</CdtDbtInd>
+                <Sts>BOOK</Sts>
+                <BookgDt>
+                    <Dt>2020-07-07</Dt>
+                </BookgDt>
+                <ValDt>
+                    <Dt>2020-07-07</Dt>
+                </ValDt>
+                <AcctSvcrRef>acctsvcrref-005</AcctSvcrRef>
+                <BkTxCd>
+                    <Domn>
+                        <Cd>PMNT</Cd>
+                        <Fmly>
+                            <Cd>ICDT</Cd>
+                            <SubFmlyCd>ESCT</SubFmlyCd>
+                        </Fmly>
+                    </Domn>
+                </BkTxCd>
+                <AmtDtls>
+                    <TxAmt>
+                        <Amt Ccy="CHF">46.3</Amt>
+                    </TxAmt>
+                </AmtDtls>
+                <NtryDtls>
+                    <Btch>
+                        <MsgId>UXC20070700006</MsgId>
+                        <PmtInfId>UXC20070700006PI00001</PmtInfId>
+                        <NbOfTxs>2</NbOfTxs>
+                        <TtlAmt Ccy="EUR">46.3</TtlAmt>
+                        <CdtDbtInd>DBIT</CdtDbtInd>
+                    </Btch>
+                    <TxDtls>
+                        <AmtDtls>
+                            <TxAmt>
+                                <Amt Ccy="EUR">23.1</Amt>
+                            </TxAmt>
+                        </AmtDtls>
+                        <BkTxCd>
+                            <Domn>
+                                <Cd>PMNT</Cd>
+                                <Fmly>
+                                    <Cd>ICDT</Cd>
+                                    <SubFmlyCd>ESCT</SubFmlyCd>
+                                </Fmly>
+                            </Domn>
+                        </BkTxCd>
+                        <RltdPties>
+                            <Cdtr>
+                                <Nm>Zahlungsempfaenger 23, ZA 5, DE</Nm>
+                                <PstlAdr>
+                                    <Ctry>DE</Ctry>
+                                    <AdrLine>DE Adresszeile 1</AdrLine>
+                                    <AdrLine>DE Adresszeile 2</AdrLine>
+                                </PstlAdr>
+                            </Cdtr>
+                            <CdtrAcct>
+                                <Id>
+                                    <IBAN>DE32733516350012345678</IBAN>
+                                </Id>
+                            </CdtrAcct>
+                        </RltdPties>
+                        <RltdAgts>
+                            <CdtrAgt>
+                                <FinInstnId>
+                                    <BIC>BYLADEM1ALR</BIC>
+                                </FinInstnId>
+                            </CdtrAgt>
+                        </RltdAgts>
+                    </TxDtls>
+                    <TxDtls>
+                        <Refs>
+                            <MsgId>asdfasdf</MsgId>
+                            <AcctSvcrRef>5j3k453k45</AcctSvcrRef>
+                            <PmtInfId>6j564l56</PmtInfId>
+                            <InstrId>6jl5lj65afasdf</InstrId>
+                            <EndToEndId>jh45k34h5l</EndToEndId>
+                        </Refs>
+                        <AmtDtls>
+                            <TxAmt>
+                                <Amt Ccy="EUR">23.2</Amt>
+                            </TxAmt>
+                        </AmtDtls>
+                        <BkTxCd>
+                            <Domn>
+                                <Cd>PMNT</Cd>
+                                <Fmly>
+                                    <Cd>ICDT</Cd>
+                                    <SubFmlyCd>ESCT</SubFmlyCd>
+                                </Fmly>
+                            </Domn>
+                            <Prtry>
+                                <Cd>K25</Cd>
+                            </Prtry>
+                        </BkTxCd>
+                        <RltdPties>
+                            <Cdtr>
+                                <Nm>Zahlungsempfaenger 23, ZA 5, AT</Nm>
+                                <PstlAdr>
+                                    <Ctry>AT</Ctry>
+                                    <AdrLine>AT Adresszeile 1</AdrLine>
+                                    <AdrLine>AT Adresszeile 2</AdrLine>
+                                </PstlAdr>
+                            </Cdtr>
+                            <CdtrAcct>
+                                <Id>
+                                    <IBAN>AT071100000012345678</IBAN>
+                                </Id>
+                            </CdtrAcct>
+                        </RltdPties>
+                        <RltdAgts>
+                            <CdtrAgt>
+                                <FinInstnId>
+                                    <BIC>BKAUATWW</BIC>
+                                </FinInstnId>
+                            </CdtrAgt>
+                        </RltdAgts>
+                    </TxDtls>
+                </NtryDtls>
+                <AddtlNtryInf>Order</AddtlNtryInf>
+            </Ntry>
+
         </Stmt>
     </BkToCstmrStmt>
 </Document>
diff --git a/util/src/main/kotlin/ISO20022.kt b/util/src/main/kotlin/ISO20022.kt
deleted file mode 100644
index 3f2cc8b..0000000
--- a/util/src/main/kotlin/ISO20022.kt
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * This file is part of LibEuFin.
- * Copyright (C) 2020 Taler Systems S.A.
- *
- * LibEuFin is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation; either version 3, or
- * (at your option) any later version.
- *
- * LibEuFin is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero General
- * Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public
- * License along with LibEuFin; see the file COPYING.  If not, see
- * <http://www.gnu.org/licenses/>
- */
-
-package tech.libeufin.util
-
-import org.w3c.dom.Document
-
-/*
- * This file is part of LibEuFin.
- * Copyright (C) 2019 Stanisci and Dold.
-
- * LibEuFin is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation; either version 3, or
- * (at your option) any later version.
-
- * LibEuFin is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero General
- * Public License for more details.
-
- * You should have received a copy of the GNU Affero General Public
- * License along with LibEuFin; see the file COPYING.  If not, see
- * <http://www.gnu.org/licenses/>
- */
-
-data class CamtData(
-    val bookingDate: Long,
-    val subject: String,
-    val txType: String, /* only "DBIT" / "CRDT" are admitted */
-    val currency: String,
-    val amount: String,
-    val status: String, /* only "BOOK" is admitted */
-    val counterpartIban: String,
-    val counterpartBic: String,
-    val counterpartName: String
-)
-
-fun parseCamt(camtDoc: Document): CamtData {
-    val txType = 
camtDoc.pickString("//*[local-name()='Ntry']//*[local-name()='CdtDbtInd']")
-    val bd = 
parseDashedDate(camtDoc.pickString("//*[local-name()='BookgDt']//*[local-name()='Dt']"))
-    return CamtData(
-        txType = txType,
-        bookingDate = bd.millis(),
-        subject = 
camtDoc.pickString("//*[local-name()='Ntry']//*[local-name()='Ustrd']"),
-        currency = 
camtDoc.pickString("//*[local-name()='Ntry']//*[local-name()='Amt']/@Ccy"),
-        amount = 
camtDoc.pickString("//*[local-name()='Ntry']//*[local-name()='Amt']"),
-        status = 
camtDoc.pickString("//*[local-name()='Ntry']//*[local-name()='Sts']"),
-        counterpartBic = 
camtDoc.pickString("//*[local-name()='RltdAgts']//*[local-name()='BIC']"),
-        counterpartIban = camtDoc.pickString("//*[local-name()='${if (txType 
== "DBIT") "CdtrAcct" else "DbtrAcct"}']//*[local-name()='IBAN']"),
-        counterpartName = 
camtDoc.pickString("//*[local-name()='RltdPties']//*[local-name()='${if (txType 
== "DBIT") "Cdtr" else "Dbtr"}']//*[local-name()='Nm']")
-    )
-}
\ No newline at end of file

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]