gnunet-svn
[Top][All Lists]
Advanced

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

[libeufin] branch master updated: implement improved ISO20022 camt parsi


From: gnunet
Subject: [libeufin] branch master updated: implement improved ISO20022 camt parsing
Date: Thu, 11 Jun 2020 17:59:30 +0200

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

dold pushed a commit to branch master
in repository libeufin.

The following commit(s) were added to refs/heads/master by this push:
     new 9437d03  implement improved ISO20022 camt parsing
9437d03 is described below

commit 9437d034203690d0f536e428a0025f0416186a5b
Author: Florian Dold <florian.dold@gmail.com>
AuthorDate: Thu Jun 11 21:29:03 2020 +0530

    implement improved ISO20022 camt parsing
---
 .../src/main/kotlin/tech/libeufin/nexus/Helpers.kt |   1 -
 .../main/kotlin/tech/libeufin/nexus/Iso20022.kt    | 321 ++++++++++
 nexus/src/test/kotlin/Iso20022Test.kt              |  25 +
 .../camt.053.001.02.gesamtbeispiel.xml             | 701 +++++++++++++++++++++
 util/src/main/kotlin/XmlCombinators.kt             |  81 ++-
 5 files changed, 1124 insertions(+), 5 deletions(-)

diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/Helpers.kt 
b/nexus/src/main/kotlin/tech/libeufin/nexus/Helpers.kt
index 377c875..062f1d3 100644
--- a/nexus/src/main/kotlin/tech/libeufin/nexus/Helpers.kt
+++ b/nexus/src/main/kotlin/tech/libeufin/nexus/Helpers.kt
@@ -193,7 +193,6 @@ fun ingestBankMessagesIntoAccount(
         }
         acct.highestSeenBankMessageId = lastId
     }
-
 }
 
 /**
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/Iso20022.kt 
b/nexus/src/main/kotlin/tech/libeufin/nexus/Iso20022.kt
new file mode 100644
index 0000000..154c402
--- /dev/null
+++ b/nexus/src/main/kotlin/tech/libeufin/nexus/Iso20022.kt
@@ -0,0 +1,321 @@
+/*
+ * 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.nexus
+
+/**
+ * Parse ISO 20022 messages
+ */
+
+import com.fasterxml.jackson.annotation.JsonInclude
+import org.w3c.dom.Document
+import tech.libeufin.util.XmlElementDestructor
+import tech.libeufin.util.destructXml
+
+enum class CreditDebitIndicator {
+    DBIT, CRDT
+}
+
+enum class TransactionStatus {
+    BOOK, PENDING
+}
+
+data class TransactionDetails(
+    /**
+     * Related parties as JSON.
+     */
+    val relatedParties: RelatedParties,
+    val amountDetails: AmountDetails,
+    val references: References,
+    /**
+     * Unstructured remittance information (=subject line) of the transaction,
+     * or the empty string if missing.
+     */
+    val unstructuredRemittanceInformation: String
+)
+
+data class BankTransaction(
+    val accountIdentifier: String,
+    /**
+     * Scheme used for the account identifier.
+     */
+    val accountScheme: String,
+    val currency: String,
+    val amount: String,
+    /**
+     * Booked, pending, etc.
+     */
+    val status: TransactionStatus,
+    /**
+     * Is this transaction debiting or crediting the account
+     * it is reported for?
+     */
+    val creditDebitIndicator: CreditDebitIndicator,
+    /**
+     * Code that describes the type of bank transaction
+     * in more detail
+     */
+    val bankTransactionCode: BankTransactionCode,
+    /**
+     * Is this a batch booking?
+     */
+    val isBatch: Boolean,
+    val details: List<TransactionDetails>
+)
+
+abstract class TypedEntity(val type: String)
+
+@JsonInclude(JsonInclude.Include.NON_NULL)
+class Agent(
+    val name: String?,
+    val bic: String
+) : TypedEntity("agent")
+
+@JsonInclude(JsonInclude.Include.NON_NULL)
+class Party(
+    val name: String?
+) : TypedEntity("party")
+
+@JsonInclude(JsonInclude.Include.NON_NULL)
+class Account(
+    val iban: String?
+) : TypedEntity("party")
+
+
+@JsonInclude(JsonInclude.Include.NON_NULL)
+data class BankTransactionCode(
+    /**
+     * Standardized bank transaction code, as "$domain/$family/$subfamily"
+     */
+    val iso: String?,
+
+    /**
+     * Proprietary code, as "$issuer/$code".
+     */
+    val proprietary: String?
+)
+
+data class AmountAndCurrencyExchangeDetails(
+    val amount: String,
+    val currency: String
+)
+
+@JsonInclude(JsonInclude.Include.NON_NULL)
+data class AmountDetails(
+    val instructedAmount: AmountAndCurrencyExchangeDetails?,
+    val transactionAmount: AmountAndCurrencyExchangeDetails?
+)
+
+@JsonInclude(JsonInclude.Include.NON_NULL)
+data class References(
+    val endToEndIdentification: String?
+)
+
+/**
+ * This structure captures both "TransactionParties6" and "TransactionAgents5"
+ * of ISO 20022.
+ */
+@JsonInclude(JsonInclude.Include.NON_NULL)
+data class RelatedParties(
+    val debtor: Party?,
+    val debtorAccount: Account?,
+    val debtorAgent: Agent?,
+    val creditor: Party?,
+    val creditorAccount: Account?,
+    val creditorAgent: Agent?
+)
+
+class CamtParsingError(msg: String) : Exception(msg)
+
+private fun XmlElementDestructor.extractAgent(): Agent {
+    return Agent(
+        name = maybeUniqueChildNamed("FinInstnId") {
+            maybeUniqueChildNamed("Nm") {
+                it.textContent
+            }
+        },
+        bic = requireUniqueChildNamed("FinInstnId") {
+            requireUniqueChildNamed("BIC") {
+                it.textContent
+            }
+        }
+    )
+}
+
+private fun XmlElementDestructor.extractAccount(): Account {
+    return Account(
+        iban = requireUniqueChildNamed("Id") {
+            maybeUniqueChildNamed("IBAN") {
+                it.textContent
+            }
+        }
+    )
+}
+
+private fun XmlElementDestructor.extractParty(): Party {
+    return Party(
+        name = maybeUniqueChildNamed("Nm") { it.textContent }
+    )
+}
+
+private fun XmlElementDestructor.extractPartiesAndAgents(): RelatedParties {
+    return RelatedParties(
+        debtor = maybeUniqueChildNamed("RltdPties") {
+            maybeUniqueChildNamed("Dbtr") {
+                extractParty()
+            }
+        },
+        creditor = maybeUniqueChildNamed("RltdPties") {
+            maybeUniqueChildNamed("Cdtr") {
+                extractParty()
+            }
+        },
+        creditorAccount = maybeUniqueChildNamed("RltdPties") {
+            maybeUniqueChildNamed("CdtrAcct") {
+                extractAccount()
+            }
+        },
+        debtorAccount = maybeUniqueChildNamed("RltdPties") {
+            maybeUniqueChildNamed("DbtrAcct") {
+                extractAccount()
+            }
+        },
+        creditorAgent = maybeUniqueChildNamed("RltdAgts") {
+            maybeUniqueChildNamed("CdtrAgt") {
+                extractAgent()
+            }
+        },
+        debtorAgent = maybeUniqueChildNamed("RltdAgts") {
+            maybeUniqueChildNamed("DbtrAgt") {
+                extractAgent()
+            }
+        }
+    )
+}
+
+private fun XmlElementDestructor.extractAmountAndCurrencyExchangeDetails(): 
AmountAndCurrencyExchangeDetails {
+    return AmountAndCurrencyExchangeDetails(
+        amount = requireUniqueChildNamed("Amt") { it.textContent},
+        currency = requireUniqueChildNamed("Amt") { it.getAttribute("Ccy") }
+    )
+}
+
+private fun XmlElementDestructor.extractTransactionDetails(): 
List<TransactionDetails> {
+    return requireUniqueChildNamed("NtryDtls") {
+        mapEachChildNamed("TxDtls") {
+            TransactionDetails(
+                relatedParties = extractPartiesAndAgents(),
+                amountDetails = maybeUniqueChildNamed("AmtDtls") {
+                    AmountDetails(
+                        instructedAmount = maybeUniqueChildNamed("InstrAmt") { 
extractAmountAndCurrencyExchangeDetails() },
+                        transactionAmount = maybeUniqueChildNamed("TxAmt") { 
extractAmountAndCurrencyExchangeDetails() }
+                    )
+                } ?: AmountDetails(null, null),
+                references = maybeUniqueChildNamed("Refs") {
+                    References(
+                        endToEndIdentification = 
maybeUniqueChildNamed("EndToEndId") { it.textContent }
+                    )
+                } ?: References(null),
+                unstructuredRemittanceInformation = 
maybeUniqueChildNamed("RmtInf") {
+                    requireUniqueChildNamed("Ustrd") { it.textContent }
+                } ?: ""
+            )
+        }
+    }
+}
+
+private fun XmlElementDestructor.extractInnerTransactions(): 
List<BankTransaction> {
+    val iban = requireUniqueChildNamed("Acct") {
+        requireUniqueChildNamed("Id") {
+            requireUniqueChildNamed("IBAN") {
+                it.textContent
+            }
+        }
+    }
+
+    return mapEachChildNamed("Ntry") {
+        val amount = requireUniqueChildNamed("Amt") { it.textContent }
+        val currency = requireUniqueChildNamed("Amt") { it.getAttribute("Ccy") 
}
+        val status = requireUniqueChildNamed("Sts") { it.textContent }.let {
+            TransactionStatus.valueOf(it)
+        }
+        val creditDebitIndicator = requireUniqueChildNamed("CdtDbtInd") { 
it.textContent }.let {
+            CreditDebitIndicator.valueOf(it)
+        }
+        val btc = requireUniqueChildNamed("BkTxCd") {
+            BankTransactionCode(
+                proprietary = maybeUniqueChildNamed("Prtry") {
+                    val cd = requireUniqueChildNamed("Cd") { it.textContent }
+                    val issr = requireUniqueChildNamed("Issr") { 
it.textContent }
+                    "$issr:$cd"
+                },
+                iso = maybeUniqueChildNamed("Domn") {
+                    val cd = requireUniqueChildNamed("Cd") { it.textContent }
+                    val r = requireUniqueChildNamed("Fmly") {
+                        object {
+                            val fmlyCd = requireUniqueChildNamed("Cd") { 
it.textContent }
+                            val subFmlyCd = 
requireUniqueChildNamed("SubFmlyCd") { it.textContent }
+                        }
+                    }
+                    "$cd/${r.fmlyCd}/${r.subFmlyCd}"
+                }
+            )
+        }
+        val details = extractTransactionDetails()
+        BankTransaction(
+            accountIdentifier = iban,
+            accountScheme = "iban",
+            amount = amount,
+            currency = currency,
+            status = status,
+            creditDebitIndicator = creditDebitIndicator,
+            bankTransactionCode = btc,
+            details = details,
+            isBatch = details.size > 1
+        )
+    }
+}
+
+/**
+ * Extract a list of transactions from an ISO20022 camt.052 / camt.053 message.
+ */
+fun getTransactions(doc: Document): List<BankTransaction> {
+    return destructXml(doc) {
+        requireRootElement("Document") {
+            // Either bank to customer statement or report
+            requireOnlyChild() {
+                when (it.localName) {
+                    "BkToCstmrAcctRpt" -> {
+                        mapEachChildNamed("Rpt") {
+                            extractInnerTransactions()
+                        }
+                    }
+                    "BkToCstmrStmt" -> {
+                        mapEachChildNamed("Stmt") {
+                            extractInnerTransactions()
+                        }
+                    }
+                    else -> {
+                        throw CamtParsingError("expected statement or report")
+                    }
+                }
+            }
+        }
+    }.flatten()
+}
\ No newline at end of file
diff --git a/nexus/src/test/kotlin/Iso20022Test.kt 
b/nexus/src/test/kotlin/Iso20022Test.kt
new file mode 100644
index 0000000..377c977
--- /dev/null
+++ b/nexus/src/test/kotlin/Iso20022Test.kt
@@ -0,0 +1,25 @@
+package tech.libeufin.nexus
+import com.fasterxml.jackson.databind.ObjectMapper
+import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
+import org.junit.Test
+import org.w3c.dom.Document
+import tech.libeufin.util.XMLUtil
+
+
+fun loadXmlResource(name: String): Document {
+    val classLoader = ClassLoader.getSystemClassLoader()
+    val res = classLoader.getResource(name)
+    if (res == null) {
+        throw Exception("resource $name not found");
+    }
+    return XMLUtil.parseStringIntoDom(res.readText())
+}
+
+class Iso20022Test {
+    @Test
+    fun testTransactionsImport() {
+        val camt53 = 
loadXmlResource("iso20022-samples/camt.053.001.02.gesamtbeispiel.xml")
+        val txs = getTransactions(camt53)
+        
println(jacksonObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(txs))
+    }
+}
\ No newline at end of file
diff --git 
a/nexus/src/test/resources/iso20022-samples/camt.053.001.02.gesamtbeispiel.xml 
b/nexus/src/test/resources/iso20022-samples/camt.053.001.02.gesamtbeispiel.xml
new file mode 100644
index 0000000..109acee
--- /dev/null
+++ 
b/nexus/src/test/resources/iso20022-samples/camt.053.001.02.gesamtbeispiel.xml
@@ -0,0 +1,701 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Mit XMLSpy v2008 rel. 2 sp2 (http://www.altova.com) im Mai 2016 von der 
SIZ GmbH (Wenzel) angepasst hinsichtlich Anlage 3, Version 3.0:  -->
+<!-- 1. BkTxCd Pflicht auf Entryebene, 2. Issuer nun "DK" (Statt "ZKA"), 3. 
Mapping GVC auf Domn, 4. Nichtdrehen bei R-Transaktionen illustriert 5. 
Schluss-Saldo angepasst (Löschung der DTAUS-Umsätze)-->
+<Document xmlns="urn:iso:std:iso:20022:tech:xsd:camt.053.001.02" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xsi:schemaLocation="urn:iso:std:iso:20022:tech:xsd:camt.053.001.02 
camt.053.001.02.xsd">
+       <BkToCstmrStmt>
+               <GrpHdr>
+                       <MsgId>27632364572</MsgId>
+                       <CreDtTm>2016-05-11T19:30:47.0+01:00</CreDtTm>
+                       <MsgRcpt>
+                               <Id>
+                                       <OrgId>
+                                               <Othr>
+                                                       <Id>BCS45678</Id>
+                                               </Othr>
+                                       </OrgId>
+                               </Id>
+                       </MsgRcpt>
+                       <MsgPgntn>
+                               <PgNb>1</PgNb>
+                               <LastPgInd>true</LastPgInd>
+                       </MsgPgntn>
+               </GrpHdr>
+               <Stmt>
+                       <Id>2736482736482</Id>
+                       <ElctrncSeqNb>101</ElctrncSeqNb>
+                       <!--Folgendes Feld ist optional und könnte die 
Papier-KAZ enthalten-->
+                       <LglSeqNb>32</LglSeqNb>
+                       <CreDtTm>2016-05-11T17:30:47.0+01:00</CreDtTm>
+                       <Acct>
+                               <Id>
+                                       <IBAN>DE62210500001234567890</IBAN>
+                               </Id>
+                               <Ccy>EUR</Ccy>
+                               <Ownr>
+                                       <Nm>Name Kontoinhaber</Nm>
+                               </Ownr>
+                               <Svcr>
+                                       <FinInstnId>
+                                               <BIC>BANKDEFFXXX</BIC>
+                                               <Othr>
+                                                       <Id>DE123456789</Id>
+                                                       <Issr>UmsStId</Issr>
+                                               </Othr>
+                                       </FinInstnId>
+                               </Svcr>
+                       </Acct>
+                       <Bal>
+                               <Tp>
+                                       <CdOrPrtry>
+                                               <Cd>PRCD</Cd>
+                                       </CdOrPrtry>
+                               </Tp>
+                               <Amt Ccy="EUR">112.72</Amt>
+                               <CdtDbtInd>CRDT</CdtDbtInd>
+                               <Dt>
+                                       <Dt>2016-05-11</Dt>
+                               </Dt>
+                       </Bal>
+                       <Bal>
+                               <Tp>
+                                       <CdOrPrtry>
+                                               <Cd>CLBD</Cd>
+                                       </CdOrPrtry>
+                               </Tp>
+                               <Amt Ccy="EUR">158530.32</Amt>
+                               <CdtDbtInd>CRDT</CdtDbtInd>
+                               <Dt>
+                                       <Dt>2016-05-11</Dt>
+                               </Dt>
+                       </Bal>
+                       <!-- Beispiel 1: SEPA-Zahlungen (Ueberweisung, 
Lastschrift, R-Nachricht -->
+                       <!--Gutschrift aufgrund eines 
SEPA-Ueberweisungseinganges-->
+                       <Ntry>
+                               <Amt Ccy="EUR">100.00</Amt>
+                               <CdtDbtInd>CRDT</CdtDbtInd>
+                               <Sts>BOOK</Sts>
+                               <BookgDt>
+                                       <Dt>2016-05-11</Dt>
+                               </BookgDt>
+                               <ValDt>
+                                       <Dt>2016-05-11</Dt>
+                               </ValDt>
+                               <AcctSvcrRef>Bankreferenz</AcctSvcrRef>
+                               <BkTxCd>
+                                       <Domn>
+                                          <Cd>PMNT</Cd>
+                                          <Fmly>
+                                                <Cd>RCDT</Cd>
+                                                <SubFmlyCd>ESCT</SubFmlyCd>
+                                               </Fmly>
+                                       </Domn> 
+                                       <Prtry>
+                                               <Cd>166</Cd>
+                                               <Issr>DK</Issr>
+                                       </Prtry>                        
+                               </BkTxCd>
+                               <NtryDtls>
+                                       <TxDtls>
+                                               <Refs>
+                                                       
<EndToEndId>Ende-zu-Ende-Id des Ueberweisenden</EndToEndId>
+                                               </Refs>
+                                               <BkTxCd>
+                                                       <Domn>
+                                                          <Cd>PMNT</Cd>
+                                                          <Fmly>
+                                                                <Cd>RCDT</Cd>
+                                                                
<SubFmlyCd>ESCT</SubFmlyCd>
+                                                               </Fmly>
+                                                       </Domn> 
+                                                       <Prtry>
+                                                               
<Cd>NTRF+166</Cd>
+                                                               <Issr>DK</Issr>
+                                                       </Prtry>
+                                               </BkTxCd>
+                                               <RltdPties>
+                                                       <Dbtr>
+                                                               <Nm>Herr 
Ueberweisender</Nm>
+                                                       </Dbtr>
+                                                       <DbtrAcct>
+                                                               <Id>
+                                                                       
<IBAN>DE21500500001234567897</IBAN>
+                                                               </Id>
+                                                       </DbtrAcct>
+                                                       <UltmtDbtr>
+                                                               <Nm>Herr Debtor 
Reference Party</Nm>
+                                                       </UltmtDbtr>
+                                                       <Cdtr>
+                                                               <Nm>Herr 
Kontoinhaber</Nm>
+                                                       </Cdtr>
+                                                       <UltmtCdtr>
+                                                               <Nm>Herr 
Creditor Reference Party</Nm>
+                                                       </UltmtCdtr>
+                                               </RltdPties>
+                                               <Purp>
+                                                       <Cd>GDDS</Cd>
+                                               </Purp>
+                                               <RmtInf>
+                                                       <Ustrd>Rechnungsnr. 
4711 vom 20.04.2016</Ustrd>
+                                               </RmtInf>
+                                       </TxDtls>
+                               </NtryDtls>
+                               <AddtlNtryInf>SEPA GUTSCHRIFT</AddtlNtryInf>
+                       </Ntry>
+                       <!--Gutschrift aufgrund einer zurueckgekommenen 
SEPA-Ueberweisung-->
+                       <Ntry>
+                               <Amt Ccy="EUR">200.00</Amt>
+                               <CdtDbtInd>CRDT</CdtDbtInd>
+                               <Sts>BOOK</Sts>
+                               <BookgDt>
+                                       <Dt>2016-05-11</Dt>
+                               </BookgDt>
+                               <ValDt>
+                                       <Dt>2016-05-11</Dt>
+                               </ValDt>
+                               <AcctSvcrRef>Bankreferenz</AcctSvcrRef>
+                               <BkTxCd>
+                                       <Domn>
+                                          <Cd>PMNT</Cd>
+                                          <Fmly>
+                                                <Cd>ICDT</Cd>
+                                                <SubFmlyCd>RRTN</SubFmlyCd>
+                                               </Fmly>
+                                       </Domn> 
+                                       <Prtry>
+                                               <Cd>159</Cd>
+                                               <Issr>DK</Issr>
+                                       </Prtry>
+                               </BkTxCd>
+                               <NtryDtls>
+                                       <TxDtls>
+                                               <Refs>
+                                                       <EndToEndId>Urspr. 
E2E-Id der Hintransaktion</EndToEndId>
+                                               </Refs>
+                                               <BkTxCd>
+                                                       <Domn>
+                                                          <Cd>PMNT</Cd>
+                                                          <Fmly>
+                                                                <Cd>ICDT</Cd>
+                                                                
<SubFmlyCd>RRTN</SubFmlyCd>
+                                                               </Fmly>
+                                                       </Domn> 
+                                                       <Prtry>
+                                                               
<Cd>NRTI+159++901</Cd>
+                                                               <Issr>DK</Issr>
+                                                       </Prtry>
+                                               </BkTxCd>
+                                               <RmtInf>
+                                                       <Ustrd>Angabe des 
urspruenglichen Verwendungszweckes</Ustrd>
+                                               </RmtInf>
+                                               <!--Informationen zur 
Originaltransaktion. Da die Belegung von Domain optional ist, kann auch nur 
Prtry (GVC) vorhanden sein-->
+                                               <RtrInf>
+                                                       <OrgnlBkTxCd>
+                                                               <Domn>
+                                                                  <Cd>PMNT</Cd>
+                                                                  <Fmly>
+                                                                        
<Cd>ICDT</Cd>
+                                                                        
<SubFmlyCd>ESCT</SubFmlyCd>
+                                                                       </Fmly>
+                                                               </Domn> 
+                                                               <Prtry>
+                                                                       
<Cd>NTRF+116</Cd>
+                                                                       
<Issr>DK</Issr>
+                                                               </Prtry>
+                                                       </OrgnlBkTxCd>
+                                                       <Orgtr>
+                                                               <Id>
+                                                                       <OrgId>
+                                                                               
<BICOrBEI>BANKDEHH</BICOrBEI>
+                                                                       </OrgId>
+                                                               </Id>
+                                                       </Orgtr>
+                                                       <Rsn>
+                                                               <Cd>AC01</Cd>
+                                                       </Rsn>
+                                                       <AddtlInf>IBAN 
FEHLERHAFT</AddtlInf>
+                                               </RtrInf>
+                                       </TxDtls>
+                               </NtryDtls>
+                               <AddtlNtryInf>SEPA RUECKBUCHUNG</AddtlNtryInf>
+                       </Ntry>
+                       <!--Belastung aufgrund einer SEPA-Lastschrift-->
+                       <Ntry>
+                               <Amt Ccy="EUR">50.00</Amt>
+                               <CdtDbtInd>DBIT</CdtDbtInd>
+                               <Sts>BOOK</Sts>
+                               <BookgDt>
+                                       <Dt>2016-05-11</Dt>
+                               </BookgDt>
+                               <ValDt>
+                                       <Dt>2016-05-11</Dt>
+                               </ValDt>
+                               <AcctSvcrRef>Bankreferenz</AcctSvcrRef>
+                               <BkTxCd>
+                                       <Domn>
+                                          <Cd>PNMT</Cd>
+                                          <Fmly>
+                                                <Cd>RDDT</Cd>
+                                                <SubFmlyCd>ESDD</SubFmlyCd>
+                                               </Fmly>
+                                       </Domn> 
+                                       <Prtry>
+                                               <Cd>105</Cd>
+                                               <Issr>DK</Issr>
+                                       </Prtry>                        
+                               </BkTxCd>
+                               <NtryDtls>
+                                       <TxDtls>
+                                               <Refs>
+                                                       <EndToEndId>E2E-Id 
vergeben vom Glaeubiger</EndToEndId>
+                                                       <MndtId>Ref. des 
SEPA-Lastschriftmandats</MndtId>
+                                               </Refs>
+                                               <BkTxCd>
+                                                       <Domn>
+                                                  <Cd>PNMT</Cd>
+                                                       <Fmly>
+                                                                <Cd>RDDT</Cd>
+                                                                
<SubFmlyCd>ESDD</SubFmlyCd>
+                                                       </Fmly>
+                                                       </Domn> 
+                                                       <Prtry>
+                                                               
<Cd>NDDT+105</Cd>
+                                                               <Issr>DKA</Issr>
+                                                       </Prtry>
+                                               </BkTxCd>
+                                               <RltdPties>
+                                                       <Dbtr>
+                                                               <Nm>Herr 
Zahlungspflichtiger</Nm>
+                                                       </Dbtr>
+                                                       <UltmtDbtr>
+                                                               <Nm>Herr Debtor 
Reference Party</Nm>
+                                                       </UltmtDbtr>
+                                                       <Cdtr>
+                                                               
<Nm>Glaeubigerfirma</Nm>
+                                                               <Id>
+                                                                       <PrvtId>
+                                                                               
<Othr>
+                                                                               
        <Id>Cdtr-Id des Glaeubigers</Id>
+                                                                               
</Othr>
+                                                                       
</PrvtId>
+                                                               </Id>
+                                                       </Cdtr>
+                                               </RltdPties>
+                                               <Purp>
+                                                       <Cd>PHON</Cd>
+                                               </Purp>
+                                               <RmtInf>
+                                                       <Ustrd>Telefonrechnung 
April 2016, Vertragsnummer 3536456345</Ustrd>
+                                               </RmtInf>
+                                       </TxDtls>
+                               </NtryDtls>
+                               <AddtlNtryInf>SEPA LASTSCHRIFT</AddtlNtryInf>
+                       </Ntry>
+                       <!-- Beispiel 2: DTAUS-Zahlungen (Ueberweisung, 
Lastschrift, Rueckgabe) BEISPIEL ENTFERNT  -->
+                       <!-- Beispiel 3a: Sammlerdarstellung mit Aufloesung 
innerhalb der Nachricht -->
+                       <!--Belastung aufgrund von SEPA-Lastschriftrueckgaben 
(Sammelbuchung) mit Sammleraufloesung unter Transaction Details-->
+                       <Ntry>
+                               <Amt Ccy="EUR">276</Amt>
+                               <CdtDbtInd>DBIT</CdtDbtInd>
+                               <Sts>BOOK</Sts>
+                               <BookgDt>
+                                       <Dt>2016-05-11</Dt>
+                               </BookgDt>
+                               <ValDt>
+                                       <Dt>2016-05-11</Dt>
+                               </ValDt>
+                               <AcctSvcrRef>Bankreferenz</AcctSvcrRef>
+                               <BkTxCd>
+                                       <Domn>
+                                          <Cd>PNMT</Cd>
+                                          <Fmly>
+                                                <Cd>IDDT</Cd>
+                                                <SubFmlyCd>UPDD</SubFmlyCd>
+                                               </Fmly>
+                                       </Domn> 
+                                       <Prtry>
+                                               <Cd>109</Cd>
+                                               <Issr>DK</Issr>
+                                       </Prtry>                        
+                               </BkTxCd>
+                               <NtryDtls>
+                                       <Btch>
+                                               <NbOfTxs>3</NbOfTxs>
+                                       </Btch>
+                                       <TxDtls>
+                                               <!-- Ab hier Aufloesung des 
Sammlers bestehend aus 3 Einzelumsaetzen -->                                    
            
+                                               <Refs>
+                                                       
<EndToEndId>79892</EndToEndId>
+                                                       <MndtId>10001</MndtId>
+                                               </Refs>
+                                               <AmtDtls>
+                                                       <TxAmt>
+                                                               <Amt 
Ccy="EUR">76</Amt>
+                                                       </TxAmt>
+                                               </AmtDtls>
+                                               <BkTxCd>
+                                                       <Domn>
+                                                          <Cd>PNMT</Cd>
+                                                          <Fmly>
+                                                                <Cd>IDDT</Cd>
+                                                                
<SubFmlyCd>UPDD</SubFmlyCd>
+                                                               </Fmly>
+                                                       </Domn> 
+                                                       <Prtry>
+                                                               
<Cd>NRTI+109++901</Cd>
+                                                               <Issr>DK</Issr>
+                                                       </Prtry>
+                                               </BkTxCd>
+                                               <!--Weil bei R-Transaktionen 
nicht gedreht wird, stehen hier die Originals-->
+                                               <RltdPties>
+                                                       <Dbtr>
+                                                               <Nm>Herr 
Zahlungspflichtiger 1</Nm>
+                                                       </Dbtr>
+                                                       <DbtrAcct>
+                                                               <Id>
+                                                                        
<IBAN>DE83700202707777777777</IBAN>
+                                                               </Id>
+                                                       </DbtrAcct>
+                                                       <Cdtr>
+                                                               
<Nm>Telefongesellschaft ABC</Nm>
+                                                               <Id>
+                                                                       <PrvtId>
+                                                                               
<Othr>
+                                                                               
        <Id>CdtrId des SEPA-Lastschrifteinr.</Id>
+                                                                               
</Othr>
+                                                                       
</PrvtId>
+                                                               </Id>
+                                                       </Cdtr>
+                                                       <CdtrAcct>
+                                                               <Id>
+                                                                 
<IBAN>DE62210500001234567890</IBAN>
+                                                               </Id>
+                                                       </CdtrAcct>
+                                               </RltdPties>
+                                               <Purp>
+                                                       <Cd>PHON</Cd>
+                                               </Purp>
+                                               <RmtInf>
+                                                       <Ustrd>Telefonrechnung 
April 2016, Vertragsnummer 3536456345</Ustrd>
+                                               </RmtInf>
+                                               <RtrInf>
+                                                       <Rsn>
+                                                               <Cd>AC01</Cd>
+                                                       </Rsn>
+                                                       
<AddtlInf>RUECKLASTSCHRIFT IBAN FEHLERHAFT</AddtlInf>
+                                               </RtrInf>
+                                       </TxDtls>
+                                       <TxDtls>
+                                               <Refs>
+                                                       
<EndToEndId>768768</EndToEndId>
+                                                       <MndtId>10002</MndtId>
+                                               </Refs>
+                                               <AmtDtls>
+                                                       <TxAmt>
+                                                               <Amt 
Ccy="EUR">80</Amt>
+                                                       </TxAmt>
+                                               </AmtDtls>
+                                               <BkTxCd>
+                                                       <Domn>
+                                                          <Cd>PNMT</Cd>
+                                                          <Fmly>
+                                                                <Cd>IDDT</Cd>
+                                                                
<SubFmlyCd>UPDD</SubFmlyCd>
+                                                               </Fmly>
+                                                       </Domn>
+                                                       <Prtry>
+                                                               
<Cd>NRTI+109++901</Cd>
+                                                               <Issr>DK</Issr>
+                                                       </Prtry>
+                                               </BkTxCd>
+                                               <RltdPties>
+                                                       <Dbtr>
+                                                               <Nm>Herr 
Zahlungspflichtiger 2</Nm>
+                                                       </Dbtr>
+                                                       <DbtrAcct>
+                                                               <Id>
+                                                                        
<IBAN>DE83700202704444444444</IBAN>
+                                                               </Id>
+                                                       </DbtrAcct>
+                                                       <Cdtr>
+                                                               
<Nm>Telefongesellschaft ABC</Nm>
+                                                               <Id>
+                                                                       <PrvtId>
+                                                                               
<Othr>
+                                                                               
        <Id>CdtrId des SEPA-Lastschrifteinr.</Id>
+                                                                               
</Othr>
+                                                                       
</PrvtId>
+                                                               </Id>
+                                                       </Cdtr>
+                                                       <CdtrAcct>
+                                                               <Id>
+                                                                 
<IBAN>DE62210500001234567890</IBAN>
+                                                               </Id>
+                                                       </CdtrAcct>
+                                               </RltdPties>
+                                               <Purp>
+                                                       <Cd>PHON</Cd>
+                                               </Purp>
+                                               <RmtInf>
+                                                       <Ustrd>Telefonrechnung 
April 2016, Vertragsnummer 3536456888</Ustrd>
+                                               </RmtInf>
+                                               <RtrInf>
+                                                       <Rsn>
+                                                               <Cd>AC01</Cd>
+                                                       </Rsn>
+                                                       
<AddtlInf>RUECKLASTSCHRIFT IBAN FEHLERHAFT</AddtlInf>
+                                               </RtrInf>
+                                       </TxDtls>
+                                       <TxDtls>
+                                               <Refs>
+                                                       
<EndToEndId>45456465</EndToEndId>
+                                                       <MndtId>10003</MndtId>
+                                               </Refs>
+                                               <AmtDtls>
+                                                       <TxAmt>
+                                                               <Amt 
Ccy="EUR">120</Amt>
+                                                       </TxAmt>
+                                               </AmtDtls>
+                                               <BkTxCd>
+                                                       <Domn>
+                                                          <Cd>PNMT</Cd>
+                                                          <Fmly>
+                                                                <Cd>IDDT</Cd>
+                                                                
<SubFmlyCd>UPDD</SubFmlyCd>
+                                                               </Fmly>
+                                                       </Domn>
+                                                       <Prtry>
+                                                               
<Cd>NRTI+109++901</Cd>
+                                                               <Issr>DK</Issr>
+                                                       </Prtry>
+                                               </BkTxCd>
+                                               <RltdPties>
+                                                       <Dbtr>
+                                                               <Nm>Herr 
Zahlungspflichtiger 3</Nm>
+                                                       </Dbtr>
+                                                       <DbtrAcct>
+                                                               <Id>
+                                                                        
<IBAN>DE83700202703333333333</IBAN>
+                                                               </Id>
+                                                       </DbtrAcct>
+                                                       <Cdtr>
+                                                               
<Nm>Telefongesellschaft ABC</Nm>
+                                                               <Id>
+                                                                       <PrvtId>
+                                                                               
<Othr>
+                                                                               
        <Id>CdtrId des SEPA-Lastschrifteinr.</Id>
+                                                                               
</Othr>
+                                                                       
</PrvtId>
+                                                               </Id>
+                                                       </Cdtr>
+                                                       <CdtrAcct>
+                                                               <Id>
+                                                                 
<IBAN>DE62210500001234567890</IBAN>
+                                                               </Id>
+                                                       </CdtrAcct>
+                                               </RltdPties>
+                                               <Purp>
+                                                       <Cd>PHON</Cd>
+                                               </Purp>
+                                               <RmtInf>
+                                                       <Ustrd>Telefonrechnung 
April 2016, Vertragsnummer 3536456345</Ustrd>
+                                               </RmtInf>
+                                               <RtrInf>
+                                                       <Rsn>
+                                                               <Cd>AC01</Cd>
+                                                       </Rsn>
+                                                       
<AddtlInf>RUECKLASTSCHRIFT IBAN FEHLERHAFT</AddtlInf>
+                                               </RtrInf>
+                                       </TxDtls>
+                               </NtryDtls>                             
+                       </Ntry>
+                       <!-- Beispiel 3b: Sammlerdarstellung mit Verweis auf 
pain-Nachricht und separate camt.054.001.01-Nachricht -->
+                       <!--Belastung aufgrund einer SEPA-Ueberweisung 
(Sammler) mit Verweis auf Original pain-Nachricht-->
+                       <Ntry>
+                               <Amt Ccy="EUR">100876.00</Amt>
+                               <CdtDbtInd>DBIT</CdtDbtInd>
+                               <Sts>BOOK</Sts>
+                               <BookgDt>
+                                       <Dt>2016-05-11</Dt>
+                               </BookgDt>
+                               <ValDt>
+                                       <Dt>2016-05-11</Dt>
+                               </ValDt>
+                               <AcctSvcrRef>Bankreferenz</AcctSvcrRef>
+                               <BkTxCd>
+                                       <Domn>
+                                          <Cd>PNMT</Cd>
+                                          <Fmly>
+                                                <Cd>ICDT</Cd>
+                                                <SubFmlyCd>ESCT</SubFmlyCd>
+                                               </Fmly>
+                                       </Domn> 
+                                       <Prtry>
+                                               <Cd>191</Cd>
+                                               <Issr>DK</Issr>
+                                       </Prtry>                        
+                               </BkTxCd>
+                               <NtryDtls>
+                                       <Btch>
+                                               <MsgId>MsgId der 
pain-Nachricht</MsgId>
+                                               <PmtInfId>Sammler-Id dieser 
pain-Nachricht</PmtInfId>
+                                       </Btch>
+                                       <TxDtls>
+                                               <BkTxCd>
+                                                       <Domn>
+                                                          <Cd>PNMT</Cd>
+                                                          <Fmly>
+                                                                <Cd>ICDT</Cd>
+                                                                
<SubFmlyCd>ESCT</SubFmlyCd>
+                                                               </Fmly>
+                                                       </Domn> 
+                                                       <Prtry>
+                                                               
<Cd>NTRF+191</Cd>
+                                                               <Issr>DK</Issr>
+                                                       </Prtry>
+                                               </BkTxCd>
+                                       </TxDtls>
+                               </NtryDtls>
+                               <AddtlNtryInf>SEPA Credit Transfer 
(Sammler-Soll)</AddtlNtryInf>
+                       </Ntry>
+                       <!--Belastung aufgrund von SEPA-Lastschriftrueckgaben 
(Sammelbuchung) mit Verweis auf separate camt.054.001.01-Nachricht-->
+                       <Ntry>
+                               <Amt Ccy="EUR">276.00</Amt>
+                               <CdtDbtInd>DBIT</CdtDbtInd>
+                               <Sts>BOOK</Sts>
+                               <BookgDt>
+                                       <Dt>2016-05-11</Dt>
+                               </BookgDt>
+                               <ValDt>
+                                       <Dt>2016-05-11</Dt>
+                               </ValDt>
+                               <AcctSvcrRef>Bankreferenz</AcctSvcrRef>
+                               <BkTxCd>
+                                       <Domn>
+                                          <Cd>PNMT</Cd>
+                                          <Fmly>
+                                                <Cd>IDDT</Cd>
+                                                <SubFmlyCd>UPDD</SubFmlyCd>
+                                               </Fmly>
+                                       </Domn> 
+                                       <Prtry>
+                                               <Cd>109</Cd>
+                                               <Issr>DK</Issr>
+                                       </Prtry>                        
+                               </BkTxCd>
+                               <AddtlInfInd>
+                                       <MsgNmId>camt.054.001.01</MsgNmId>
+                                       <MsgId>054-20160511-00034</MsgId>
+                                       <!-- siehe Bsp. camt54 Bsp 3b -->
+                               </AddtlInfInd>
+                               <NtryDtls>
+                                       <TxDtls>
+                                               <BkTxCd>
+                                                       <Domn>
+                                                          <Cd>PNMT</Cd>
+                                                          <Fmly>
+                                                                <Cd>IDDT</Cd>
+                                                                
<SubFmlyCd>UPDD</SubFmlyCd>
+                                                               </Fmly>
+                                                       </Domn>
+                                                       <Prtry>
+                                                               
<Cd>NRTI+109++901</Cd>
+                                                               <Issr>DK</Issr>
+                                                       </Prtry>
+                                               </BkTxCd>
+                                       </TxDtls>
+                               </NtryDtls>                             
+                       </Ntry>
+                       <!-- Beispiel 4: USD-Zahlung mit Gutschrift auf einem 
EUR-Konto -->
+                       <!-- USD-Zahlung mit Gutschrift auf einem EUR-Konto -->
+                       <Ntry>
+                               <Amt Ccy="EUR">259595.60</Amt>
+                               <CdtDbtInd>CRDT</CdtDbtInd>
+                               <Sts>BOOK</Sts>
+                               <BookgDt>
+                                       <Dt>2016-05-11</Dt>
+                               </BookgDt>
+                               <ValDt>
+                                       <Dt>2016-05-11</Dt>
+                               </ValDt>
+                               <AcctSvcrRef>Bankreferenz</AcctSvcrRef>
+                               <BkTxCd>
+                                                       <Domn>
+                                                          <Cd>PMNT</Cd>
+                                                          <Fmly>
+                                                                <Cd>RCDT</Cd>
+                                                                
<SubFmlyCd>XBCT</SubFmlyCd>
+                                                               </Fmly>
+                                                       </Domn> 
+                                                       <Prtry>
+                                                               
<Cd>NTRF+202</Cd>
+                                                               <Issr>DK</Issr>
+                                                       </Prtry>
+                                               </BkTxCd>
+                               <NtryDtls>
+                                       <TxDtls>
+                                               <AmtDtls>
+                                                       <InstdAmt>
+                                                               <Amt 
Ccy="USD">360873.97</Amt>
+                                                       </InstdAmt>
+                                                       <TxAmt>
+                                                               <Amt 
Ccy="EUR">259595.60</Amt>
+                                                       </TxAmt>
+                                                       <CntrValAmt>
+                                                               <Amt 
Ccy="EUR">259621.56</Amt>
+                                                               <CcyXchg>
+                                                                       
<SrcCcy>USD</SrcCcy>
+                                                                       
<TrgtCcy>EUR</TrgtCcy>
+                                                                       
<XchgRate>1.39</XchgRate>
+                                                               </CcyXchg>
+                                                       </CntrValAmt>
+                                               </AmtDtls>
+                                               <BkTxCd>
+                                                       <Domn>
+                                                          <Cd>PMNT</Cd>
+                                                          <Fmly>
+                                                                <Cd>RCDT</Cd>
+                                                                
<SubFmlyCd>XBCT</SubFmlyCd>
+                                                               </Fmly>
+                                                       </Domn> 
+                                                       <Prtry>
+                                                               
<Cd>NTRF+202</Cd>
+                                                               <Issr>DK</Issr>
+                                                       </Prtry>
+                                               </BkTxCd>
+                                               <Chrgs>
+                                                       <Amt 
Ccy="EUR">25.96</Amt>
+                                               </Chrgs>
+                                               <RltdPties>
+                                                       <Dbtr>
+                                                               <Nm>West Coast 
Ltd.</Nm>
+                                                               <PstlAdr>
+                                                                       
<Ctry>US</Ctry>
+                                                                       
<AdrLine>52, Main Street</AdrLine>
+                                                                       
<AdrLine>3733 San Francisco</AdrLine>
+                                                               </PstlAdr>
+                                                       </Dbtr>
+                                                       <DbtrAcct>
+                                                               <Id>
+                                                                       <Othr>
+                                                                               
<Id>546237687</Id>
+                                                                       </Othr>
+                                                               </Id>
+                                                       </DbtrAcct>
+                                               </RltdPties>
+                                               <RltdAgts>
+                                                       <DbtrAgt>
+                                                               <FinInstnId>
+                                                                       
<BIC>BANKUSNY</BIC>
+                                                               </FinInstnId>
+                                                       </DbtrAgt>
+                                               </RltdAgts>
+                                               <RmtInf>
+                                                       <Ustrd>Invoice No. 
4545</Ustrd>
+                                               </RmtInf>
+                                       </TxDtls>
+                               </NtryDtls>
+                               
<AddtlNtryInf>AZV-UEBERWEISUNGSGUTSCHRIFT</AddtlNtryInf>
+                       </Ntry>
+               </Stmt>
+       </BkToCstmrStmt>
+</Document>
diff --git a/util/src/main/kotlin/XmlCombinators.kt 
b/util/src/main/kotlin/XmlCombinators.kt
index d799c57..1c49521 100644
--- a/util/src/main/kotlin/XmlCombinators.kt
+++ b/util/src/main/kotlin/XmlCombinators.kt
@@ -1,6 +1,8 @@
 package tech.libeufin.util
 
 import com.sun.xml.txw2.output.IndentingXMLStreamWriter
+import org.w3c.dom.Document
+import org.w3c.dom.Element
 import java.io.StringWriter
 import javax.xml.stream.XMLOutputFactory
 import javax.xml.stream.XMLStreamWriter
@@ -49,6 +51,7 @@ class XmlDocumentBuilder {
     fun namespace(uri: String) {
         writer.setDefaultNamespace(uri)
     }
+
     fun namespace(prefix: String, uri: String) {
         writer.setPrefix(prefix, uri)
     }
@@ -85,10 +88,80 @@ fun constructXml(indent: Boolean = false, f: 
XmlDocumentBuilder.() -> Unit): Str
     return "<?xml version=\"1.0\" encoding=\"UTF-8\" 
standalone=\"yes\"?>\n${stream.buffer.toString()}"
 }
 
-class XmlDocumentDestructor {
+class DestructionError(m: String) : Exception(m)
+
+private fun Element.getChildElements(ns: String, tag: String): List<Element> {
+    val elements = mutableListOf<Element>()
+    for (i in 0..this.childNodes.length) {
+        val el = this.childNodes.item(i)
+        if (el !is Element) {
+            continue
+        }
+        if (ns != "*" && el.namespaceURI != ns) {
+            continue
+        }
+        if (tag != "*" && el.localName != tag) {
+            continue
+        }
+        elements.add(el)
+    }
+    return elements
+}
+
+class XmlElementDestructor internal constructor(val d: Document, val e: 
Element) {
+    fun <T> requireOnlyChild(f: XmlElementDestructor.(e: Element) -> T): T {
+        val child =
+            e.getChildElements("*", "*").elementAtOrNull(0)
+                ?: throw DestructionError("expected singleton child tag")
+        val destr = XmlElementDestructor(d, child)
+        return f(destr, child)
+    }
+
+    fun <T> mapEachChildNamed(s: String, f: XmlElementDestructor.(e: Element) 
-> T): List<T> {
+        val res = mutableListOf<T>()
+        val els = e.getChildElements("*", s)
+        for (child in els) {
+            val destr = XmlElementDestructor(d, child)
+            res.add(f(destr, child))
+        }
+        return res
+    }
+
+    fun <T> requireUniqueChildNamed(s: String, f: XmlElementDestructor.(e: 
Element) -> T): T {
+        val cl = e.getChildElements("*", s)
+        if (cl.size != 1) {
+            throw DestructionError("expected exactly one unique $s child, got 
${cl.size} instead")
+        }
+        val el = cl[0]
+        val destr = XmlElementDestructor(d, el)
+        return f(destr, el)
+    }
+
+    fun <T> maybeUniqueChildNamed(s: String, f: XmlElementDestructor.(e: 
Element) -> T): T? {
+        val cl = e.getChildElements("*", s)
+        if (cl.size > 1) {
+            throw DestructionError("expected at most one unique $s child, got 
${cl.size} instead")
+        }
+        if (cl.size == 1) {
+            val el = cl[0]
+            val destr = XmlElementDestructor(d, el)
+            println("found child $s")
+            return f(destr, el)
+        }
+        return null
+    }
+}
+
+class XmlDocumentDestructor internal constructor(val d: Document) {
+    fun <T> requireRootElement(name: String, f: XmlElementDestructor.(e: 
Element) -> T): T {
+        if (this.d.documentElement.tagName != name) {
+            throw DestructionError("expected '$name' tag")
+        }
+        val destr = XmlElementDestructor(d, d.documentElement)
+        return f(destr, this.d.documentElement)
+    }
 }
 
-fun <T> destructXml(f: XmlDocumentDestructor.() -> T): T {
-    val d = XmlDocumentDestructor()
-    return f(d)
+fun <T> destructXml(d: Document, f: XmlDocumentDestructor.() -> T): T {
+    return f(XmlDocumentDestructor(d))
 }

-- 
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]