gnunet-svn
[Top][All Lists]
Advanced

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

[libeufin] 03/03: Introducing the "pf" dialect.


From: gnunet
Subject: [libeufin] 03/03: Introducing the "pf" dialect.
Date: Wed, 17 May 2023 14:23:52 +0200

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

ms pushed a commit to branch master
in repository libeufin.

commit 213256b16aab1b1e8ae6fac98f886a14d4537860
Author: MS <ms@taler.net>
AuthorDate: Wed May 17 14:16:11 2023 +0200

    Introducing the "pf" dialect.
    
    This dialect was tested on the PostFinance test platform.
    Along the core changes, the handling of dialects themselves
    was also introduced.
---
 cli/bin/libeufin-cli                               |    8 +-
 .../main/kotlin/tech/libeufin/nexus/Anastasis.kt   |    7 +-
 nexus/src/main/kotlin/tech/libeufin/nexus/DB.kt    |    7 +-
 nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt  |   47 +-
 nexus/src/main/kotlin/tech/libeufin/nexus/Taler.kt |    4 +-
 .../tech/libeufin/nexus/bankaccount/BankAccount.kt |   34 +-
 .../tech/libeufin/nexus/ebics/EbicsClient.kt       |   39 +-
 .../kotlin/tech/libeufin/nexus/ebics/EbicsNexus.kt |  220 +++-
 .../tech/libeufin/nexus/iso20022/Iso20022.kt       |  244 +++-
 .../kotlin/tech/libeufin/nexus/server/Helpers.kt   |   27 +-
 .../main/kotlin/tech/libeufin/nexus/server/JSON.kt |   17 +-
 .../tech/libeufin/nexus/server/NexusServer.kt      |   52 +-
 .../nexus/xlibeufinbank/XLibeufinBankNexus.kt      |    1 +
 nexus/src/test/kotlin/Iso20022Test.kt              |   78 ++
 nexus/src/test/kotlin/MakeEnv.kt                   |  197 +++-
 nexus/src/test/kotlin/PostFinance.kt               |  100 ++
 nexus/src/test/kotlin/TalerTest.kt                 |    1 +
 util/src/main/kotlin/CamtJsonMapping.kt            |   59 +-
 util/src/main/kotlin/Ebics.kt                      |   16 +-
 util/src/main/kotlin/JSON.kt                       |    3 +-
 util/src/main/kotlin/XMLUtil.kt                    |    3 +-
 util/src/main/kotlin/ebics_h004/EbicsRequest.kt    |    6 +-
 .../main/resources/xsd/pain.001.001.03.ch.02.xsd   | 1212 ++++++++++++++++++++
 23 files changed, 2197 insertions(+), 185 deletions(-)

diff --git a/cli/bin/libeufin-cli b/cli/bin/libeufin-cli
index ff30d62a..04ac85fd 100755
--- a/cli/bin/libeufin-cli
+++ b/cli/bin/libeufin-cli
@@ -542,10 +542,15 @@ def new_xlibeufinbank_connection(obj, bank_url, username, 
password, connection_n
 @click.option("--host-id", help="Host ID", required=True)
 @click.option("--partner-id", help="Partner ID", required=True)
 @click.option("--ebics-user-id", help="Ebics user ID", required=True)
+@click.option(
+  "--dialect",
+  help="EBICS dialect of this connection",
+  required=False
+)
 @click.argument("connection-name")
 @click.pass_obj
 def new_ebics_connection(
-    obj, connection_name, ebics_url, host_id, partner_id, ebics_user_id
+    obj, connection_name, ebics_url, host_id, partner_id, ebics_user_id, 
dialect
 ):
     url = urljoin_nodrop(obj.nexus_base_url, "/bank-connections")
     body = dict(
@@ -557,6 +562,7 @@ def new_ebics_connection(
             hostID=host_id,
             partnerID=partner_id,
             userID=ebics_user_id,
+            dialect=dialect
         ),
     )
     try:
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/Anastasis.kt 
b/nexus/src/main/kotlin/tech/libeufin/nexus/Anastasis.kt
index b75755ef..684229d4 100644
--- a/nexus/src/main/kotlin/tech/libeufin/nexus/Anastasis.kt
+++ b/nexus/src/main/kotlin/tech/libeufin/nexus/Anastasis.kt
@@ -15,6 +15,7 @@ import io.ktor.server.application.*
 import io.ktor.server.response.*
 import io.ktor.server.routing.*
 import tech.libeufin.util.buildIbanPaytoUri
+import tech.libeufin.util.internalServerError
 
 data class AnastasisIncomingBankTransaction(
     val row_id: Long,
@@ -59,9 +60,13 @@ fun anastasisFilter(payment: NexusBankTransactionEntity, 
txDtls: TransactionDeta
         logger.warn("Not allowing transactions missing the BIC.  IBAN and 
name: ${debtorIban}, $debtorName")
         return
     }
+    val paymentSubject = txDtls.unstructuredRemittanceInformation
+    if (paymentSubject == null) {
+        throw internalServerError("Nexus payment 
'${payment.accountTransactionId}' has no subject.")
+    }
     AnastasisIncomingPaymentEntity.new {
         this.payment = payment
-        subject = txDtls.unstructuredRemittanceInformation
+        subject = paymentSubject
         timestampMs = System.currentTimeMillis()
         debtorPaytoUri = buildIbanPaytoUri(
             debtorIban,
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/DB.kt 
b/nexus/src/main/kotlin/tech/libeufin/nexus/DB.kt
index 2f54626b..086d6fe6 100644
--- a/nexus/src/main/kotlin/tech/libeufin/nexus/DB.kt
+++ b/nexus/src/main/kotlin/tech/libeufin/nexus/DB.kt
@@ -28,6 +28,7 @@ import org.jetbrains.exposed.dao.id.LongIdTable
 import org.jetbrains.exposed.sql.*
 import org.jetbrains.exposed.sql.transactions.TransactionManager
 import org.jetbrains.exposed.sql.transactions.transaction
+import tech.libeufin.nexus.server.FetchLevel
 import tech.libeufin.util.*
 import java.sql.Connection
 import kotlin.reflect.typeOf
@@ -163,7 +164,7 @@ object NexusBankMessagesTable : LongIdTable() {
     val bankConnection = reference("bankConnection", NexusBankConnectionsTable)
     val message = blob("message")
     val messageId = text("messageId").nullable()
-    val code = text("code").nullable()
+    val fetchLevel = enumerationByName("fetchLevel", 16, FetchLevel::class)
     // true when the parser could not ingest one message:
     val errors = bool("errors").default(false)
 }
@@ -172,7 +173,7 @@ class NexusBankMessageEntity(id: EntityID<Long>) : 
LongEntity(id) {
     companion object : 
LongEntityClass<NexusBankMessageEntity>(NexusBankMessagesTable)
     var bankConnection by NexusBankConnectionEntity referencedOn 
NexusBankMessagesTable.bankConnection
     var messageId by NexusBankMessagesTable.messageId
-    var code by NexusBankMessagesTable.code
+    var fetchLevel by NexusBankMessagesTable.fetchLevel
     var message by NexusBankMessagesTable.message
     var errors by NexusBankMessagesTable.errors
 }
@@ -405,6 +406,7 @@ class NexusUserEntity(id: EntityID<Long>) : LongEntity(id) {
 object NexusBankConnectionsTable : LongIdTable() {
     val connectionId = text("connectionId")
     val type = text("type")
+    val dialect = text("dialect").nullable()
     val owner = reference("user", NexusUsersTable)
 }
 
@@ -417,6 +419,7 @@ class NexusBankConnectionEntity(id: EntityID<Long>) : 
LongEntity(id) {
 
     var connectionId by NexusBankConnectionsTable.connectionId
     var type by NexusBankConnectionsTable.type
+    var dialect by NexusBankConnectionsTable.dialect
     var owner by NexusUserEntity referencedOn NexusBankConnectionsTable.owner
 }
 
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt 
b/nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt
index 5ba89ad4..a63e6503 100644
--- a/nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt
+++ b/nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt
@@ -34,6 +34,8 @@ import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.launch
 import startServer
+import tech.libeufin.nexus.iso20022.NexusPaymentInitiationData
+import tech.libeufin.nexus.iso20022.createPain001document
 import tech.libeufin.nexus.iso20022.parseCamtMessage
 import tech.libeufin.nexus.server.client
 import tech.libeufin.nexus.server.nexusApp
@@ -94,10 +96,51 @@ class Serve : CliktCommand("Run nexus HTTP server") {
     }
 }
 
-class ParseCamt : CliktCommand("Parse CAMT file, outputs JSON in libEufin 
internal representation.") {
+/**
+ * This command purpose is to let the user then _manually_
+ * tune the pain.001, to upload it to online verifiers.
+ */
+class GenPain : CliktCommand(
+    "Generate random pain.001 document for 'pf' dialect, printing to STDOUT."
+) {
     private val logLevel by option(
         help = "Set the log level to: 'off', 'error', 'warn', 'info', 'debug', 
'trace', 'all'"
     )
+    private val dialect by option(
+        help = "EBICS dialect using the pain.001 being generated.  Defaults to 
'pf' (PostFinance)",
+    ).default("pf")
+    override fun run() {
+        setLogLevel(logLevel)
+        val pain001 = createPain001document(
+            NexusPaymentInitiationData(
+                debtorIban = "CH0889144371988976754",
+                debtorBic = "POFICHBEXXX",
+                debtorName = "Sample Debtor Name",
+                currency = "CHF",
+                amount = "5.00",
+                creditorIban = "CH9789144829733648596",
+                creditorName = "Sample Creditor Name",
+                creditorBic = "POFICHBEXXX",
+                paymentInformationId = "8aae7a2ded2f",
+                preparationTimestamp = getNow().toInstant().toEpochMilli(),
+                subject = "Unstructured remittance information",
+                instructionId = "InstructionId",
+                endToEndId = "71cfbdaf901f",
+                messageId = "2a16b35ed69c"
+            ),
+            dialect = this.dialect
+        )
+        println(pain001)
+    }
+}
+class ParseCamt : CliktCommand("Parse camt.05x file, outputs JSON in libEufin 
internal representation.") {
+    private val logLevel by option(
+        help = "Set the log level to: 'off', 'error', 'warn', 'info', 'debug', 
'trace', 'all'"
+    )
+    private val withC54 by option(
+        help = "Treats the input as camt.054.  Without this option, the" +
+                " parser expects a camt.052 or camt.053 and handles them 
equally."
+    ).flag(default = false)
     private val filename by argument("FILENAME", "File in CAMT format")
     override fun run() {
         setLogLevel(logLevel)
@@ -151,6 +194,6 @@ class Superuser : CliktCommand("Add superuser or change 
pw") {
 
 fun main(args: Array<String>) {
     NexusCommand()
-        .subcommands(Serve(), Superuser(), ParseCamt(), ResetTables())
+        .subcommands(Serve(), Superuser(), ParseCamt(), ResetTables(), 
GenPain())
         .main(args)
 }
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/Taler.kt 
b/nexus/src/main/kotlin/tech/libeufin/nexus/Taler.kt
index 35ff1819..36379094 100644
--- a/nexus/src/main/kotlin/tech/libeufin/nexus/Taler.kt
+++ b/nexus/src/main/kotlin/tech/libeufin/nexus/Taler.kt
@@ -239,7 +239,8 @@ fun talerFilter(
     txDtls: TransactionDetails
 ) {
     var isInvalid = false // True when pub is invalid or duplicate.
-    val subject = txDtls.unstructuredRemittanceInformation
+    val subject = txDtls.unstructuredRemittanceInformation ?: throw
+            internalServerError("Payment '${payment.accountTransactionId}' has 
no subject, can't extract reserve pub.")
     val debtorName = txDtls.debtor?.name
     if (debtorName == null) {
         logger.warn("empty debtor name")
@@ -380,6 +381,7 @@ fun maybeTalerRefunds(bankAccount: NexusBankAccountEntity, 
lastSeenId: Long) {
                         it[NexusBankTransactionsTable.bankAccount] == 
bankAccount.id,
                 "Cannot refund an _outgoing_ payment!"
             )
+
             // FIXME #7116
             addPaymentInitiation(
                 Pain001Data(
diff --git 
a/nexus/src/main/kotlin/tech/libeufin/nexus/bankaccount/BankAccount.kt 
b/nexus/src/main/kotlin/tech/libeufin/nexus/bankaccount/BankAccount.kt
index 9c1c8f9f..a1576a05 100644
--- a/nexus/src/main/kotlin/tech/libeufin/nexus/bankaccount/BankAccount.kt
+++ b/nexus/src/main/kotlin/tech/libeufin/nexus/bankaccount/BankAccount.kt
@@ -206,20 +206,26 @@ fun ingestBankMessagesIntoAccount(
         ).forEach {
             val processingResult: IngestedTransactionsCount = 
when(BankConnectionType.parseBankConnectionType(conn.type)) {
                 BankConnectionType.EBICS -> {
-                    val doc = 
XMLUtil.parseStringIntoDom(it.message.bytes.toString(Charsets.UTF_8))
+                    val camtString = it.message.bytes.toString(Charsets.UTF_8)
+                    val doc = XMLUtil.parseStringIntoDom(camtString)
                     /**
                      * Calling the CaMt handler.  After its return, all the 
Neuxs-meaningful
                      * payment data got stored into the database and is ready 
to being further
                      * processed by any facade OR simply be communicated to 
the CLI via JSON.
                      */
-                    processCamtMessage(
-                        bankAccountId,
-                        doc,
-                        it.code ?: throw internalServerError(
-                            "Bank message with ID ${it.id.value} in DB table" +
-                                    " NexusBankMessagesTable has no code, but 
one is expected."
+                    try {
+                        processCamtMessage(
+                            bankAccountId,
+                            doc,
+                            it.fetchLevel,
+                            conn.dialect
                         )
-                    )
+                    }
+                    catch (e: Exception) {
+                        logger.error("Could not parse the following camt 
document:\n${camtString}")
+                        // rethrowing. Here just to log the failing document
+                        throw e
+                    }
                 }
                 BankConnectionType.X_LIBEUFIN_BANK -> {
                     val jMessage = try { 
jacksonObjectMapper().readTree(it.message.bytes) }
@@ -287,7 +293,8 @@ fun getPaymentInitiation(uuid: Long): 
PaymentInitiationEntity {
 
 data class LastMessagesTimes(
     val lastStatement: ZonedDateTime?,
-    val lastReport: ZonedDateTime?
+    val lastReport: ZonedDateTime?,
+    val lastNotification: ZonedDateTime?
 )
 /**
  * Get the last timestamps where a report and
@@ -306,6 +313,9 @@ fun getLastMessagesTimes(acct: NexusBankAccountEntity): 
LastMessagesTimes {
         },
         lastStatement = acct.lastStatementCreationTimestamp?.let {
             ZonedDateTime.ofInstant(Instant.ofEpochMilli(it), ZoneOffset.UTC)
+        },
+        lastNotification = acct.lastNotificationCreationTimestamp?.let {
+            ZonedDateTime.ofInstant(Instant.ofEpochMilli(it), ZoneOffset.UTC)
         }
     )
 }
@@ -336,11 +346,13 @@ fun addPaymentInitiation(
     debtorAccount: NexusBankAccountEntity
 ): PaymentInitiationEntity {
     return transaction {
+
         val now = Instant.now().toEpochMilli()
         val nowHex = now.toString(16)
         val painCounter = debtorAccount.pain001Counter++
         val painHex = painCounter.toString(16)
         val acctHex = debtorAccount.id.value.toString(16)
+
         PaymentInitiationEntity.new {
             currency = paymentData.currency
             bankAccount = debtorAccount
@@ -350,9 +362,9 @@ fun addPaymentInitiation(
             creditorBic = paymentData.creditorBic
             creditorIban = paymentData.creditorIban
             preparationDate = now
-            endToEndId = "leuf-e-$nowHex-$painHex-$acctHex"
+            endToEndId = paymentData.endToEndId ?: 
"leuf-e-$nowHex-$painHex-$acctHex"
             messageId = "leuf-mp1-$nowHex-$painHex-$acctHex"
-            paymentInformationId = paymentData.pmtInfId ?: 
"leuf-p-$nowHex-$painHex-$acctHex"
+            paymentInformationId = "leuf-p-$nowHex-$painHex-$acctHex"
             instructionId = "leuf-i-$nowHex-$painHex-$acctHex"
         }
     }
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/EbicsClient.kt 
b/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/EbicsClient.kt
index 85006012..382aefc8 100644
--- a/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/EbicsClient.kt
+++ b/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/EbicsClient.kt
@@ -81,6 +81,11 @@ class EbicsDownloadSuccessResult(
     val orderData: ByteArray
 ) : EbicsDownloadResult()
 
+class EbicsDownloadEmptyResult(
+    val orderData: ByteArray = ByteArray(0)
+) : EbicsDownloadResult()
+
+
 /**
  * A bank-technical error occurred.
  */
@@ -126,20 +131,16 @@ suspend fun doEbicsDownloadTransaction(
             )
         }
     }
-    /**
-     * At this point, the EBICS init phase went through,
-     * therefore the message should carry a transaction ID!
-     */
-    if (transactionID == null) throw NexusError(
-        HttpStatusCode.BadGateway,
-        "EBICS-correct init response should contain" +
-                " a transaction ID, $orderType did not!"
-    )
     // Checking the 'bank technical' code.
     when (initResponse.bankReturnCode) {
         EbicsReturnCode.EBICS_OK -> {
             // Success, nothing to do!
         }
+        EbicsReturnCode.EBICS_NO_DOWNLOAD_DATA_AVAILABLE -> {
+            // The 'pf' dialect might respond this value here (at init phase),
+            // in contrast to what the default dialect does (waiting the 
transfer phase)
+            return EbicsDownloadEmptyResult()
+        }
         else -> {
             logger.error(
                 "Bank-technical error at init phase: 
${initResponse.bankReturnCode}" +
@@ -175,7 +176,12 @@ suspend fun doEbicsDownloadTransaction(
     // Transfer phase
     for (x in 2 .. numSegments) {
         val transferReqStr =
-            createEbicsRequestForDownloadTransferPhase(subscriberDetails, 
transactionID, x, numSegments)
+            createEbicsRequestForDownloadTransferPhase(
+                subscriberDetails,
+                transactionID,
+                x,
+                numSegments
+            )
         logger.debug("EBICS download transfer phase of ${transactionID}: 
sending segment $x")
         val transferResponseStr = 
client.postToBank(subscriberDetails.ebicsUrl, transferReqStr)
         val transferResponse = 
parseAndValidateEbicsResponse(subscriberDetails, transferResponseStr)
@@ -216,7 +222,10 @@ suspend fun doEbicsDownloadTransaction(
     val respPayload = decryptAndDecompressResponse(subscriberDetails, 
encryptionInfo, payloadChunks)
 
     // Acknowledgement phase
-    val ackRequest = createEbicsRequestForDownloadReceipt(subscriberDetails, 
transactionID)
+    val ackRequest = createEbicsRequestForDownloadReceipt(
+        subscriberDetails,
+        transactionID
+    )
     val ackResponseStr = client.postToBank(
         subscriberDetails.ebicsUrl,
         ackRequest
@@ -253,6 +262,7 @@ suspend fun doEbicsUploadTransaction(
     }
     val preparedUploadData = prepareUploadPayload(subscriberDetails, payload)
     val req = createEbicsRequestForUploadInitialization(subscriberDetails, 
orderType, orderParams, preparedUploadData)
+    logger.debug("EBICS upload message to: ${subscriberDetails.ebicsUrl}")
     val responseStr = client.postToBank(subscriberDetails.ebicsUrl, req)
 
     val initResponse = parseAndValidateEbicsResponse(subscriberDetails, 
responseStr)
@@ -266,15 +276,12 @@ suspend fun doEbicsUploadTransaction(
     }
     // The bank did NOT indicate any error, but the response
     // lacks required information, blame the bank.
-    val transactionID = initResponse.transactionID ?: throw NexusError(
-            HttpStatusCode.BadGateway,
-            "Init response must have transaction ID"
-        )
+    val transactionID = initResponse.transactionID
     if (initResponse.bankReturnCode != EbicsReturnCode.EBICS_OK) {
         throw NexusError(
             HttpStatusCode.InternalServerError,
             reason = "Bank-technical error at init phase:" +
-                    " ${initResponse.technicalReturnCode}"
+                    " ${initResponse.bankReturnCode}"
         )
     }
     logger.debug("Bank acknowledges EBICS upload initialization. " +
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/EbicsNexus.kt 
b/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/EbicsNexus.kt
index 04150eaf..e84e9846 100644
--- a/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/EbicsNexus.kt
+++ b/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/EbicsNexus.kt
@@ -72,10 +72,32 @@ private data class EbicsFetchSpec(
     val orderParams: EbicsOrderParams
 )
 
-fun storeCamt(bankConnectionId: String, camt: String, historyType: String) {
+/**
+ * Maps EBICS specific history types to their camt
+ * counterparts.  That allows the database to store
+ * camt types per-se, without any reference to the
+ * EBICS message that brought them.  For example, a
+ * EBICS "Z52" and "C52" will both bring a camt.052.
+ * Such camt.052 is associated with the more generic
+ * type of FetchLevel.REPORT.
+ */
+private fun getFetchLevelFromEbicsOrder(ebicsHistoryType: String): FetchLevel {
+    return when(ebicsHistoryType) {
+        "C52", "Z52" -> FetchLevel.REPORT
+        "C53", "Z53" -> FetchLevel.STATEMENT
+        "C54", "Z54" -> FetchLevel.NOTIFICATION
+        else -> throw internalServerError("EBICS history type 
'$ebicsHistoryType' not supported")
+    }
+}
+
+fun storeCamt(
+    bankConnectionId: String,
+    camt: String,
+    fetchLevel: FetchLevel
+) {
     val camt53doc = XMLUtil.parseStringIntoDom(camt)
     val msgId = 
camt53doc.pickStringWithRootNs("/*[1]/*[1]/root:GrpHdr/root:MsgId")
-    logger.info("Camt document '$msgId' received via $historyType.")
+    logger.info("Camt document '$msgId' received via $fetchLevel.")
     transaction {
         val conn = NexusBankConnectionEntity.findByName(bankConnectionId)
         if (conn == null) {
@@ -85,13 +107,12 @@ fun storeCamt(bankConnectionId: String, camt: String, 
historyType: String) {
         if (oldMsg == null) {
             NexusBankMessageEntity.new {
                 this.bankConnection = conn
-                this.code = historyType
+                this.fetchLevel = fetchLevel
                 this.messageId = msgId
                 this.message = ExposedBlob(camt.toByteArray(Charsets.UTF_8))
             }
         }
     }
-
 }
 
 /**
@@ -125,17 +146,29 @@ private suspend fun fetchEbicsC5x(
     }
 
     when (historyType) {
+        // default dialect
         "C52" -> {}
         "C53" -> {}
+        // 'pf' dialect
+        "Z52" -> {}
+        "Z53" -> {}
+        "Z54" -> {}
         else -> {
-            throw NexusError(HttpStatusCode.BadRequest, "history type 
'$historyType' not supported")
+            throw NexusError(
+                HttpStatusCode.BadRequest,
+                "history type '$historyType' not supported"
+            )
         }
     }
     when (response) {
         is EbicsDownloadSuccessResult -> {
             response.orderData.unzipWithLambda {
                 // logger.debug("Camt entry (filename (in the Zip archive): 
${it.first}): ${it.second}")
-                storeCamt(bankConnectionId, it.second, historyType)
+                storeCamt(
+                    bankConnectionId,
+                    it.second,
+                    getFetchLevelFromEbicsOrder(historyType)
+                )
             }
         }
         is EbicsDownloadBankErrorResult -> {
@@ -144,6 +177,9 @@ private suspend fun fetchEbicsC5x(
                 response.returnCode.errorCode
             )
         }
+        is EbicsDownloadEmptyResult -> {
+            // no-op
+        }
     }
 }
 
@@ -194,7 +230,10 @@ fun getEbicsSubscriberDetails(bankConnectionId: String): 
EbicsClientSubscriberDe
     val subscriber = getSubscriberFromConnection(transport)
 
     // transport exists and belongs to caller.
-    return getEbicsSubscriberDetailsInternal(subscriber)
+    val ret = getEbicsSubscriberDetailsInternal(subscriber)
+    if (transport.dialect != null)
+        ret.dialect = transport.dialect
+    return ret
 }
 
 fun Route.ebicsBankProtocolRoutes(client: HttpClient) {
@@ -283,6 +322,10 @@ fun Route.ebicsBankConnectionRoutes(client: HttpClient) {
             client, subscriberDetails, "HTD", EbicsStandardOrderParams()
         )
         when (response) {
+            is EbicsDownloadEmptyResult -> {
+                // no-op
+                logger.warn("HTD response was empty.")
+            }
             is EbicsDownloadBankErrorResult -> {
                 throw NexusError(
                     HttpStatusCode.BadGateway,
@@ -325,7 +368,7 @@ fun Route.ebicsBankConnectionRoutes(client: HttpClient) {
         if (orderType.length != 3) {
             throw NexusError(HttpStatusCode.BadRequest, "ebics order type must 
be three characters")
         }
-        val paramsJson = 
call.receiveNullable<EbicsStandardOrderParamsDateJson>()
+        val paramsJson = 
call.receiveNullable<EbicsStandardOrderParamsEmptyJson>()
         val orderParams = paramsJson?.toOrderParams() ?: 
EbicsStandardOrderParams()
         val subscriberDetails = transaction {
             val conn = requireBankConnection(call, "connid")
@@ -341,6 +384,9 @@ fun Route.ebicsBankConnectionRoutes(client: HttpClient) {
             orderParams
         )
         when (response) {
+            is EbicsDownloadEmptyResult -> {
+                logger.info(orderType + " response was empty.") // no op
+            }
             is EbicsDownloadSuccessResult -> {
                 call.respondText(
                     response.orderData.toString(Charsets.UTF_8),
@@ -405,6 +451,34 @@ fun formatHex(ba: ByteArray): String {
     return out
 }
 
+private fun getSubmissionTypeAfterDialect(dialect: String? = null): String {
+    return when (dialect) {
+        "pf" -> "XE2"
+        else -> "CCT"
+    }
+}
+private fun getReportTypeAfterDialect(dialect: String? = null): String {
+    return when (dialect) {
+        "pf" -> "Z52"
+        else -> "C52"
+    }
+}
+private fun getStatementTypeAfterDialect(dialect: String? = null): String {
+    return when (dialect) {
+        "pf" -> "Z53"
+        else -> "C53"
+    }
+}
+
+private fun getNotificationTypeAfterDialect(dialect: String? = null): String {
+    return when (dialect) {
+        "pf" -> "Z54"
+        else -> throw NotImplementedError(
+            "Notifications not implemented in the 'default' EBICS dialect"
+        )
+    }
+}
+
 /**
  * This function returns a possibly empty list of Exception.
  * That helps not to stop fetching if ONE operation fails.  Notably,
@@ -433,14 +507,17 @@ class EbicsBankConnectionProtocol: BankConnectionProtocol 
{
         fun addForLevel(l: FetchLevel, p: EbicsOrderParams) {
             when (l) {
                 FetchLevel.ALL -> {
-                    specs.add(EbicsFetchSpec("C52", p))
-                    specs.add(EbicsFetchSpec("C53", p))
+                    
specs.add(EbicsFetchSpec(getReportTypeAfterDialect(subscriberDetails.dialect), 
p))
+                    
specs.add(EbicsFetchSpec(getStatementTypeAfterDialect(subscriberDetails.dialect),
 p))
                 }
                 FetchLevel.REPORT -> {
-                    specs.add(EbicsFetchSpec("C52", p))
+                    
specs.add(EbicsFetchSpec(getReportTypeAfterDialect(subscriberDetails.dialect), 
p))
                 }
                 FetchLevel.STATEMENT -> {
-                    specs.add(EbicsFetchSpec("C53", p))
+                    
specs.add(EbicsFetchSpec(getStatementTypeAfterDialect(subscriberDetails.dialect),
 p))
+                }
+                FetchLevel.NOTIFICATION -> {
+                    
specs.add(EbicsFetchSpec(getNotificationTypeAfterDialect(subscriberDetails.dialect),
 p))
                 }
             }
         }
@@ -462,7 +539,9 @@ class EbicsBankConnectionProtocol: BankConnectionProtocol {
             /**
              * This branch differentiates the last date of reports and
              * statements and builds the fetch instructions for each of
-             * them.
+             * them.  For this reason, it does not use the "addForLevel()"
+             * helper, since that uses the same date for all the messages
+             * falling in the ALL level.
              */
             is FetchSpecSinceLastJson -> {
                 val pRep = EbicsStandardOrderParams(
@@ -481,21 +560,42 @@ class EbicsBankConnectionProtocol: BankConnectionProtocol 
{
                         ), ZonedDateTime.now(ZoneOffset.UTC)
                     )
                 )
+                val pNtfn = EbicsStandardOrderParams(
+                    EbicsDateRange(
+                        lastTimes.lastNotification ?: ZonedDateTime.ofInstant(
+                            Instant.EPOCH,
+                            ZoneOffset.UTC
+                        ), ZonedDateTime.now(ZoneOffset.UTC)
+                    )
+                )
                 when (fetchSpec.level) {
-                    /**
-                     * This branch doesn't call the "addForLevel()" helper 
because
-                     * that takes only ONE time range and would use it for both
-                     * statements and reports.
-                     */
                     FetchLevel.ALL -> {
-                        specs.add(EbicsFetchSpec("C52", pRep))
-                        specs.add(EbicsFetchSpec("C53", pStmt))
+                        specs.add(EbicsFetchSpec(
+                            orderType = getReportTypeAfterDialect(dialect = 
subscriberDetails.dialect),
+                            orderParams = pRep
+                        ))
+                        specs.add(EbicsFetchSpec(
+                            orderType = getStatementTypeAfterDialect(dialect = 
subscriberDetails.dialect),
+                            orderParams = pStmt
+                        ))
                     }
                     FetchLevel.REPORT -> {
-                        specs.add(EbicsFetchSpec("C52", pRep))
+                        specs.add(EbicsFetchSpec(
+                            orderType = getReportTypeAfterDialect(dialect = 
subscriberDetails.dialect),
+                            orderParams = pRep
+                        ))
                     }
                     FetchLevel.STATEMENT -> {
-                        specs.add(EbicsFetchSpec("C53", pStmt))
+                        specs.add(EbicsFetchSpec(
+                            orderType = getStatementTypeAfterDialect(dialect = 
subscriberDetails.dialect),
+                            orderParams = pStmt
+                        ))
+                    }
+                    FetchLevel.NOTIFICATION -> {
+                        specs.add(EbicsFetchSpec(
+                            orderType = 
getNotificationTypeAfterDialect(dialect = subscriberDetails.dialect),
+                            orderParams = pNtfn
+                        ))
                     }
                 }
             }
@@ -520,6 +620,7 @@ class EbicsBankConnectionProtocol: BankConnectionProtocol {
             return errors
         return null
     }
+
     // Submit one Pain.001 for one payment initiations.
     override suspend fun submitPaymentInitiation(httpClient: HttpClient, 
paymentInitiationId: Long) {
         val dbData = transaction {
@@ -545,7 +646,8 @@ class EbicsBankConnectionProtocol: BankConnectionProtocol {
                     instructionId = preparedPayment.instructionId,
                     endToEndId = preparedPayment.endToEndId,
                     messageId = preparedPayment.messageId
-                )
+                ),
+                dialect = subscriberDetails.dialect
             )
             object {
                 val painXml = painMessage
@@ -568,7 +670,7 @@ class EbicsBankConnectionProtocol: BankConnectionProtocol {
         doEbicsUploadTransaction(
             httpClient,
             dbData.subscriberDetails,
-            "CCT",
+            getSubmissionTypeAfterDialect(dbData.subscriberDetails.dialect),
             dbData.painXml.toByteArray(Charsets.UTF_8),
             EbicsStandardOrderParams()
         )
@@ -648,6 +750,7 @@ class EbicsBankConnectionProtocol: BankConnectionProtocol {
         val subscriber = transaction { 
getEbicsSubscriberDetails(bankConnectionId) }
         val ret = EbicsKeysBackupJson(
             type = "ebics",
+            dialect = subscriber.dialect,
             userID = subscriber.userId,
             hostID = subscriber.hostId,
             partnerID = subscriber.partnerId,
@@ -669,7 +772,19 @@ class EbicsBankConnectionProtocol: BankConnectionProtocol {
                     subscriber.customerSignPriv.encoded,
                     passphrase
                 )
-            )
+            ),
+            bankAuthBlob = run {
+                val maybeBankAuthPub = subscriber.bankAuthPub
+                if (maybeBankAuthPub != null)
+                    return@run bytesToBase64(maybeBankAuthPub.encoded)
+                null
+            },
+            bankEncBlob = run {
+                val maybeBankEncPub = subscriber.bankEncPub
+                if (maybeBankEncPub != null)
+                    return@run bytesToBase64(maybeBankEncPub.encoded)
+                null
+            }
         )
         val mapper = ObjectMapper()
         return mapper.valueToTree(ret)
@@ -683,7 +798,6 @@ class EbicsBankConnectionProtocol: BankConnectionProtocol {
         details.put("ebicsHostId", ebicsSubscriber.hostId)
         details.put("partnerId", ebicsSubscriber.partnerId)
         details.put("userId", ebicsSubscriber.userId)
-
         details.put(
             "customerAuthKeyHash",
             CryptoUtil.getEbicsPublicKeyHash(
@@ -717,16 +831,22 @@ class EbicsBankConnectionProtocol: BankConnectionProtocol 
{
         node.set<JsonNode>("details", details)
         return node
     }
-    override fun createConnection(connId: String, user: NexusUserEntity, data: 
JsonNode) {
+    override fun createConnection(
+        connId: String,
+        user: NexusUserEntity,
+        data: JsonNode
+    ) {
+        val newTransportData = jacksonObjectMapper()
+            .treeToValue(data, EbicsNewTransport::class.java) ?: throw 
NexusError(
+            HttpStatusCode.BadRequest,
+            "Ebics details not found in request"
+        )
         val bankConn = NexusBankConnectionEntity.new {
             this.connectionId = connId
             owner = user
             type = "ebics"
+            this.dialect = newTransportData.dialect
         }
-        val newTransportData = jacksonObjectMapper(
-        ).treeToValue(data, EbicsNewTransport::class.java) ?: throw NexusError(
-            HttpStatusCode.BadRequest, "Ebics details not found in request"
-        )
         val pairA = CryptoUtil.generateRsaKeyPair(2048)
         val pairB = CryptoUtil.generateRsaKeyPair(2048)
         val pairC = CryptoUtil.generateRsaKeyPair(2048)
@@ -752,14 +872,18 @@ class EbicsBankConnectionProtocol: BankConnectionProtocol 
{
         backup: JsonNode
     ) {
         if (passphrase === null) {
-            throw NexusError(HttpStatusCode.BadRequest, "EBICS backup needs 
passphrase")
+            throw NexusError(
+                HttpStatusCode.BadRequest,
+                "EBICS backup needs passphrase"
+            )
         }
+        val ebicsBackup = jacksonObjectMapper().treeToValue(backup, 
EbicsKeysBackupJson::class.java)
         val bankConn = NexusBankConnectionEntity.new {
             connectionId = connId
             owner = user
             type = "ebics"
+            this.dialect = ebicsBackup.dialect
         }
-        val ebicsBackup = jacksonObjectMapper().treeToValue(backup, 
EbicsKeysBackupJson::class.java)
         val (authKey, encKey, sigKey) = try {
             Triple(
                 CryptoUtil.decryptKey(
@@ -795,7 +919,31 @@ class EbicsBankConnectionProtocol: BankConnectionProtocol {
                 nexusBankConnection = bankConn
                 ebicsIniState = EbicsInitState.UNKNOWN
                 ebicsHiaState = EbicsInitState.UNKNOWN
-            }
+                if (ebicsBackup.bankAuthBlob != null) {
+                    val keyBlob = base64ToBytes(ebicsBackup.bankAuthBlob)
+                    try { CryptoUtil.loadRsaPublicKey(keyBlob) }
+                    catch (e: Exception) {
+                        logger.error("Could not restore bank's auth public 
key")
+                        throw NexusError(
+                            HttpStatusCode.BadRequest,
+                            "Bad bank's auth pub"
+                        )
+                    }
+                    bankAuthenticationPublicKey = ExposedBlob(keyBlob)
+                }
+                if (ebicsBackup.bankEncBlob != null) {
+                    val keyBlob = base64ToBytes(ebicsBackup.bankEncBlob)
+                    try { CryptoUtil.loadRsaPublicKey(keyBlob) }
+                    catch (e: Exception) {
+                        logger.error("Could not restore bank's enc public key")
+                        throw NexusError(
+                            HttpStatusCode.BadRequest,
+                            "Bad bank's enc pub"
+                        )
+                    }
+                    bankEncryptionPublicKey = ExposedBlob(keyBlob)
+                }
+             }
         } catch (e: Exception) {
             throw NexusError(
                 HttpStatusCode.BadRequest,
@@ -811,6 +959,10 @@ class EbicsBankConnectionProtocol: BankConnectionProtocol {
             client, subscriberDetails, "HTD", EbicsStandardOrderParams()
         )
         when (response) {
+            is EbicsDownloadEmptyResult -> {
+                // no-op
+                logger.warn("HTD response was empty.")
+            }
             is EbicsDownloadBankErrorResult -> {
                 throw NexusError(
                     HttpStatusCode.BadGateway,
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 9d7ed3ea..fb65f0c5 100644
--- a/nexus/src/main/kotlin/tech/libeufin/nexus/iso20022/Iso20022.kt
+++ b/nexus/src/main/kotlin/tech/libeufin/nexus/iso20022/Iso20022.kt
@@ -37,7 +37,6 @@ import PostalAddress
 import PrivateIdentification
 import ReturnInfo
 import TransactionDetails
-import com.fasterxml.jackson.annotation.JsonIgnore
 import com.fasterxml.jackson.annotation.JsonInclude
 import com.fasterxml.jackson.annotation.JsonValue
 import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
@@ -49,16 +48,22 @@ import org.w3c.dom.Document
 import tech.libeufin.nexus.*
 import tech.libeufin.nexus.bankaccount.IngestedTransactionsCount
 import tech.libeufin.nexus.bankaccount.findDuplicate
+import tech.libeufin.nexus.server.EbicsDialects
+import tech.libeufin.nexus.server.FetchLevel
+import tech.libeufin.nexus.server.PaymentUidQualifiers
 import tech.libeufin.util.*
 import toPlainString
 import java.time.Instant
+import java.time.LocalDateTime
 import java.time.ZoneId
 import java.time.ZonedDateTime
 import java.time.format.DateTimeFormatter
 
 
 enum class CashManagementResponseType(@get:JsonValue val jsonName: String) {
-    Report("report"), Statement("statement"), Notification("notification")
+    Report("report"),
+    Statement("statement"),
+    Notification("notification")
 }
 
 @JsonInclude(JsonInclude.Include.NON_NULL)
@@ -124,30 +129,40 @@ data class NexusPaymentInitiationData(
     val instructionId: String? = null
 )
 
+data class Pain001Namespaces(
+    val fullNamespace: String,
+    val xsdFilename: String
+)
+
 /**
  * Create a PAIN.001 XML document according to the input data.
  * Needs to be called within a transaction block.
  */
-fun createPain001document(paymentData: NexusPaymentInitiationData): String {
-    // Every PAIN.001 document contains at least three IDs:
-    //
-    // 1) MsgId: a unique id for the message itself
-    // 2) PmtInfId: the unique id for the payment's set of information
-    // 3) EndToEndId: a unique id to be shared between the debtor and
-    //    creditor that uniquely identifies the transaction
-    //
-    // For now and for simplicity, since every PAIN entry in the database
-    // has a unique ID, and the three values aren't required to be mutually 
different,
-    // we'll assign the SAME id (= the row id) to all the three aforementioned
-    // PAIN id types.
+fun createPain001document(
+    paymentData: NexusPaymentInitiationData,
+    dialect: String? = null
+): String {
+
+    val namespace: Pain001Namespaces = if (dialect == "pf")
+        Pain001Namespaces(
+            fullNamespace = 
"http://www.six-interbank-clearing.com/de/pain.001.001.03.ch.02.xsd";,
+            xsdFilename = "pain.001.001.03.ch.02.xsd"
+        )
+    else Pain001Namespaces(
+        fullNamespace = "urn:iso:std:iso:20022:tech:xsd:pain.001.001.03",
+        xsdFilename = "pain.001.001.03.xsd"
+    )
+
+    val paymentMethod = if (dialect == "pf")
+        "SDVA" else "SEPA"
 
     val s = constructXml(indent = true) {
         root("Document") {
-            attribute("xmlns", 
"urn:iso:std:iso:20022:tech:xsd:pain.001.001.03")
+            attribute("xmlns", namespace.fullNamespace)
             attribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance";)
             attribute(
                 "xsi:schemaLocation",
-                "urn:iso:std:iso:20022:tech:xsd:pain.001.001.03 
pain.001.001.03.xsd"
+                "${namespace.fullNamespace} ${namespace.xsdFilename}"
             )
             element("CstmrCdtTrfInitn") {
                 element("GrpHdr") {
@@ -188,7 +203,7 @@ fun createPain001document(paymentData: 
NexusPaymentInitiationData): String {
                         text(paymentData.amount)
                     }
                     element("PmtTpInf/SvcLvl/Cd") {
-                        text("SEPA")
+                        text(paymentMethod)
                     }
                     element("ReqdExctnDt") {
                         val dateMillis = paymentData.preparationTimestamp
@@ -484,7 +499,6 @@ private fun XmlElementDestructor.extractTransactionDetails(
             maybeUniqueChildNamed("CntrValAmt") { extractCurrencyAmount() }
         },
         currencyExchange = currencyExchange,
-        // FIXME: implement
         interBankSettlementAmount = null,
         endToEndId = maybeUniqueChildNamed("Refs") {
             maybeUniqueChildNamed("EndToEndId") { focusElement.textContent }
@@ -492,6 +506,9 @@ private fun XmlElementDestructor.extractTransactionDetails(
         paymentInformationId = maybeUniqueChildNamed("Refs") {
             maybeUniqueChildNamed("PmtInfId") { focusElement.textContent }
         },
+        accountServicerRef = maybeUniqueChildNamed("Refs") {
+            maybeUniqueChildNamed("AcctSvcrRef") { focusElement.textContent }
+        },
         unstructuredRemittanceInformation = maybeUniqueChildNamed("RmtInf") {
             val chunks = mapEachChildNamed("Ustrd") { focusElement.textContent 
}
             if (chunks.isEmpty()) {
@@ -499,7 +516,7 @@ private fun XmlElementDestructor.extractTransactionDetails(
             } else {
                 chunks.joinToString(separator = "")
             }
-        } ?: "",
+        },
         creditorAgent = maybeUniqueChildNamed("RltdAgts") { 
maybeUniqueChildNamed("CdtrAgt") { extractAgent() } },
         debtorAgent = maybeUniqueChildNamed("RltdAgts") { 
maybeUniqueChildNamed("DbtrAgt") { extractAgent() } },
         debtorAccount = maybeUniqueChildNamed("RltdPties") { 
maybeUniqueChildNamed("DbtrAcct") { extractAccount() } },
@@ -676,6 +693,11 @@ fun parseCamtMessage(doc: Document): CamtParseResult {
                             extractInnerTransactions()
                         }
                     }
+                    "BkToCstmrDbtCdtNtfctn" -> {
+                        mapEachChildNamed("Ntfctn") {
+                            extractInnerTransactions()
+                        }
+                    }
                     else -> {
                         throw CamtParsingError("expected statement or report")
                     }
@@ -695,6 +717,7 @@ fun parseCamtMessage(doc: Document): CamtParseResult {
                 when (focusElement.localName) {
                     "BkToCstmrAcctRpt" -> CashManagementResponseType.Report
                     "BkToCstmrStmt" -> CashManagementResponseType.Statement
+                    "BkToCstmrDbtCdtNtfctn" -> 
CashManagementResponseType.Notification
                     else -> {
                         throw CamtParsingError("expected statement or report")
                     }
@@ -710,6 +733,104 @@ fun parseCamtMessage(doc: Document): CamtParseResult {
     }
 }
 
+// Get timestamp in milliseconds, according to the EBICS+camt dialect.
+fun getTimestampInMillis(
+    dateTimeFromCamt: String,
+    dialect: String? = null
+): Long {
+    return when(dialect) {
+        EbicsDialects.POSTFINANCE.dialectName -> {
+            val withoutTimezone = LocalDateTime.parse(
+                dateTimeFromCamt,
+                DateTimeFormatter.ISO_LOCAL_DATE_TIME
+            )
+            ZonedDateTime.of(
+                withoutTimezone,
+                ZoneId.of("Europe/Zurich")).toInstant().toEpochMilli()
+        }
+        else -> {
+            ZonedDateTime.parse(
+                dateTimeFromCamt,
+                DateTimeFormatter.ISO_DATE_TIME
+            ).toInstant().toEpochMilli()
+        }
+    }
+}
+
+/**
+ * Extracts the UID from the payment, according to dialect
+ * and direction.  It returns the _qualified_ string from such
+ * ID.  A qualified string has the format "$qualifier:$extracted_id".
+ * $qualifier is a constant that gives more context about the
+ * actual $extracted_id;  for example, it may indicate that the
+ * ID was assigned by the bank, or by Nexus when it uploaded
+ * the payment initiation in the first place.
+ *
+ * NOTE: this version _still_ expect only singleton transactions
+ * in the input.  That means _only one_ element is expected at the
+ * lowest level of the camt.05x report.  This may/should change in
+ * future versions.
+ */
+fun extractPaymentUidFromSingleton(
+    ntry: CamtBankAccountEntry,
+    camtMessageId: String, // used to print errors.
+    dialect: String?
+    ): String {
+    // First check if the input is a singleton.
+    val batchTransactions: List<BatchTransaction>? = 
ntry.batches?.get(0)?.batchTransactions
+    val tx: BatchTransaction = if (ntry.batches?.size != 1 || 
batchTransactions?.size != 1) {
+        logger.error("camt message ${camtMessageId} has non singleton 
transactions.")
+        throw internalServerError("Dialect $dialect sent camt with non 
singleton transactions.")
+    } else
+        batchTransactions[0]
+
+    when(dialect) {
+        EbicsDialects.POSTFINANCE.dialectName -> {
+            if (tx.creditDebitIndicator == CreditDebitIndicator.DBIT) {
+                val expectedEndToEndId = tx.details.endToEndId
+                /**
+                 * Because this is an outgoing transaction, and because
+                 * Nexus should have included the EndToEndId in the original
+                 * pain.001, this transaction must have it (recall: EndToEndId
+                 * is mandatory in the pain.001).  A null value means therefore
+                 * that the payment was done via another mean than pain.001.
+                 */
+                if (expectedEndToEndId == null) {
+                    logger.error("Camt '$camtMessageId' shows outgoing payment 
_without_ the EndToEndId." +
+                            "  This likely wasn't initiated via pain.001"
+                    )
+                    throw internalServerError("Internal reconciliation error 
(no EndToEndId)")
+                }
+                return 
"${PaymentUidQualifiers.NEXUS_GIVEN}:$expectedEndToEndId"
+            }
+            // Didn't return/throw before, it must be an incoming payment.
+            val maybeAcctSvcrRef = tx.details.accountServicerRef
+            // Expecting this value to be at the lowest level, as observed on 
the test platform.
+            val expectedAcctSvcrRef = tx.details.accountServicerRef
+            if (expectedAcctSvcrRef == null) {
+                logger.error("AcctSvcrRef was expected at the lowest tx level 
for dialect: $dialect, but wasn't found")
+                throw internalServerError("Internal reconciliation error (no 
AcctSvcrRef at lowest tx level)")
+            }
+            return "${PaymentUidQualifiers.BANK_GIVEN}:$expectedAcctSvcrRef"
+        }
+        // This is the default dialect, the one tested with GLS.
+        null -> {
+            /**
+             * This dialect has shown the AcctSvcrRef to be always given
+             * at the level that _contains_ the (singleton) transaction(s).
+             * This occurs _regardless_ of the payment direction.
+             */
+            val expectedAcctSvcrRef = ntry.accountServicerRef
+            if (expectedAcctSvcrRef == null) {
+                logger.error("AcctSvcrRef was expected at the outer tx level 
for dialect: GLS, but wasn't found.")
+                throw internalServerError("Internal reconciliation error: 
AcctSvcrRef not found at outer level.")
+            }
+            return "${PaymentUidQualifiers.BANK_GIVEN}:$expectedAcctSvcrRef"
+        }
+        else -> throw internalServerError("Dialect $dialect is not supported.")
+    }
+}
+
 /**
  * Given that every CaMt is a collection of reports/statements
  * where each of them carries the bank account balance and a list
@@ -720,7 +841,7 @@ fun parseCamtMessage(doc: Document): CamtParseResult {
  *   report/statement.
  * - finds which transactions were already downloaded.
  * - stores a new NexusBankTransactionEntity for each new tx
-accounted in the report/statement.
+ *   accounted in the report/statement.
  * - tries to link the new transaction with a submitted one, in
  *   case of DBIT transaction.
  * - returns a IngestedTransactionCount object.
@@ -728,12 +849,16 @@ accounted in the report/statement.
 fun processCamtMessage(
     bankAccountId: String,
     camtDoc: Document,
+    fetchLevel: FetchLevel,
+    dialect: String? = null
+): IngestedTransactionsCount {
     /**
-     * FIXME: should NOT be C52/C53 but "report" or "statement".
-     * The reason is that C52/C53 are NOT CaMt, they are EBICS names.
+     * Ensure that the level is not ALL, as the parser expects
+     * the exact type for the one message being parsed.
      */
-    code: String
-): IngestedTransactionsCount {
+    if (fetchLevel == FetchLevel.ALL)
+        throw internalServerError("Parser needs exact camt type (ALL not 
permitted).")
+
     var newTransactions = 0
     var downloadedTransactions = 0
     transaction {
@@ -742,7 +867,7 @@ fun processCamtMessage(
             throw NexusError(HttpStatusCode.NotFound, "user not found")
         }
         val res = try { parseCamtMessage(camtDoc) } catch (e: 
CamtParsingError) {
-            logger.warn("Invalid CAMT received from bank: $e")
+            logger.warn("Invalid CAMT received from bank: ${e.message}")
             newTransactions = -1
             return@transaction
         }
@@ -774,31 +899,28 @@ fun processCamtMessage(
             }
         }
         // Updating the local bank account state timestamps according to the 
current document.
-        val stamp = ZonedDateTime.parse(
-            res.creationDateTime,
-            DateTimeFormatter.ISO_DATE_TIME
-        ).toInstant().toEpochMilli()
-        when (code) {
-            "C52" -> {
+        val stamp = getTimestampInMillis(res.creationDateTime, dialect = 
dialect)
+        when (fetchLevel) {
+            FetchLevel.REPORT -> {
                 val s = acct.lastReportCreationTimestamp
-                /**
-                 * FIXME.
-                 * The following check seems broken, as it ONLY sets the value 
when
-                 * s is non-null BUT s gets never set; not even with a default 
value.
-                 * That didn't break so far because the timestamp gets only 
used when
-                 * the fetch specification has "since-last" for the time 
range.  Never
-                 * used.
-                 */
-                if (s != null && stamp > s) {
+                if (s == null || stamp > s) {
                     acct.lastReportCreationTimestamp = stamp
                 }
             }
-            "C53" -> {
+            FetchLevel.STATEMENT -> {
                 val s = acct.lastStatementCreationTimestamp
-                if (s != null && stamp > s) {
+                if (s == null || stamp > s) {
                     acct.lastStatementCreationTimestamp = stamp
                 }
             }
+            FetchLevel.NOTIFICATION -> {
+                val s = acct.lastNotificationCreationTimestamp
+                if (s == null || stamp > s) {
+                    acct.lastNotificationCreationTimestamp = stamp
+                }
+            }
+            // Silencing the compiler: the 'ALL' case was checked at the top 
of this function.
+            else -> {}
         }
         val entries: List<CamtBankAccountEntry> = res.reports.map { it.entries 
}.flatten()
         var newPaymentsLog = ""
@@ -809,22 +931,26 @@ fun processCamtMessage(
                     HttpStatusCode.InternalServerError,
                     "Singleton money movements policy wasn't respected"
                 )
-            val acctSvcrRef = entry.accountServicerRef
-            if (acctSvcrRef == null) {
-                // FIXME(dold): Report this!
-                logger.error("missing account servicer reference in 
transaction")
+            if (entry.status != EntryStatus.BOOK) {
+                logger.info("camt message '${res.messageId}' has a " +
+                        "non-BOOK transaction, ignoring it."
+                )
                 continue
             }
-            val duplicate = findDuplicate(bankAccountId, acctSvcrRef)
+            val paymentUid = extractPaymentUidFromSingleton(
+                ntry = entry,
+                camtMessageId = res.messageId,
+                dialect = dialect
+            )
+            val duplicate = findDuplicate(bankAccountId, paymentUid)
             if (duplicate != null) {
-                logger.info("Found a duplicate (acctSvcrRef): $acctSvcrRef")
-                // FIXME(dold): See if an old transaction needs to be 
superseded by this one
+                logger.info("Found a duplicate, UID is $paymentUid")
                 // https://bugs.gnunet.org/view.php?id=6381
                 continue@txloop
             }
             val rawEntity = NexusBankTransactionEntity.new {
                 bankAccount = acct
-                accountTransactionId = acctSvcrRef
+                accountTransactionId = paymentUid
                 amount = singletonBatchedTransaction.amount.value
                 currency = singletonBatchedTransaction.amount.currency
                 transactionJson = 
jacksonObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(entry)
@@ -833,29 +959,35 @@ fun processCamtMessage(
             }
             rawEntity.flush()
             newTransactions++
-            newPaymentsLog += "\n- " + entry.getSingletonSubject()
+            newPaymentsLog += "\n- ${entry.getSingletonSubject()}"
+
             // This block tries to acknowledge a former outgoing payment as 
booked.
             if (singletonBatchedTransaction.creditDebitIndicator == 
CreditDebitIndicator.DBIT) {
                 val t0 = singletonBatchedTransaction.details
-                val pmtInfId = t0.paymentInformationId
-                if (pmtInfId != null) {
+                val endToEndId = t0.endToEndId
+                if (endToEndId != null) {
+                    logger.debug("Reconciling outgoing payment with 
EndToEndId: $endToEndId")
                     val paymentInitiation = PaymentInitiationEntity.find {
                         PaymentInitiationsTable.bankAccount eq acct.id and (
                                 // pmtInfId is a value that the payment 
submitter
                                 // asked the bank to associate with the 
payment to be made.
-                                PaymentInitiationsTable.paymentInformationId 
eq pmtInfId)
+                                PaymentInitiationsTable.endToEndId eq 
endToEndId)
 
                     }.firstOrNull()
                     if (paymentInitiation != null) {
-                        logger.info("Could confirm one initiated payment: 
$pmtInfId")
+                        logger.info("Could confirm one initiated payment: 
$endToEndId")
                         paymentInitiation.confirmationTransaction = rawEntity
                     }
                 }
+                // Every payment initiated by Nexus has EndToEndId.  Warn if 
not found.
+                else
+                    logger.warn("Camt ${res.messageId} has outgoing payment 
without EndToEndId..")
             }
         }
         if (newTransactions > 0)
-            logger.debug("Camt $code '${res.messageId}' has new 
payments:${newPaymentsLog}")
+            logger.debug("Camt $fetchLevel '${res.messageId}' has new 
payments:${newPaymentsLog}")
     }
+
     return IngestedTransactionsCount(
         newTransactions = newTransactions,
         downloadedTransactions = downloadedTransactions
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/server/Helpers.kt 
b/nexus/src/main/kotlin/tech/libeufin/nexus/server/Helpers.kt
index 52069270..5e386c84 100644
--- a/nexus/src/main/kotlin/tech/libeufin/nexus/server/Helpers.kt
+++ b/nexus/src/main/kotlin/tech/libeufin/nexus/server/Helpers.kt
@@ -58,10 +58,35 @@ fun unknownBankAccount(bankAccountLabel: String): 
NexusError {
  * strings.
  */
 
+enum class EbicsDialects(val dialectName: String) {
+    POSTFINANCE("pf")
+}
+
+/**
+ * Nexus needs to uniquely identify a payment, in order
+ * to spot the same payment to be ingested more than once.
+ * For example, payment X may have been already ingested
+ * (and possibly led to a Taler withdrawal) via a EBICS C52
+ * order, and might be later again downloaded via another
+ * EBICS order (e.g. C53).  The second time this payment
+ * reaches Nexus, it must NOT be considered new, therefore
+ * Nexus needs a UID to check its database for the presence
+ * of known payments.  Every bank assigns UIDs in a different
+ * fashion, sometimes even differentiating between incoming and
+ * outgoing payments; Nexus therefore classifies those UIDs
+ * by assigning them one of the names defined in the following
+ * enum class.  This way, Nexus has more control when it tries
+ * to locally reconcile payments.
+ */
+enum class PaymentUidQualifiers(qualifierName: String) {
+    BANK_GIVEN("bank_given"),
+    NEXUS_GIVEN("nexus_given")
+}
+
 // Valid connection types.
 enum class BankConnectionType(val typeName: String) {
     EBICS("ebics"),
-    X_LIBEUFIN_BANK("x-taler-bank");
+    X_LIBEUFIN_BANK("x-libeufin-bank");
     companion object {
         /**
          * This method takes legacy bank connection type names as input
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/server/JSON.kt 
b/nexus/src/main/kotlin/tech/libeufin/nexus/server/JSON.kt
index 312961c2..bb0ece5e 100644
--- a/nexus/src/main/kotlin/tech/libeufin/nexus/server/JSON.kt
+++ b/nexus/src/main/kotlin/tech/libeufin/nexus/server/JSON.kt
@@ -20,7 +20,6 @@
 package tech.libeufin.nexus.server
 
 import CamtBankAccountEntry
-import CurrencyAmount
 import EntryStatus
 import com.fasterxml.jackson.annotation.JsonSubTypes
 import com.fasterxml.jackson.annotation.JsonTypeInfo
@@ -143,7 +142,10 @@ data class EbicsKeysBackupJson(
     val ebicsURL: String,
     val authBlob: String,
     val encBlob: String,
-    val sigBlob: String
+    val sigBlob: String,
+    val bankAuthBlob: String?,
+    val bankEncBlob: String?,
+    val dialect: String? = null
 )
 
 enum class PermissionChangeAction(@get:JsonValue val jsonName: String) {
@@ -170,7 +172,10 @@ data class ChangePermissionsRequest(
 )
 
 enum class FetchLevel(@get:JsonValue val jsonName: String) {
-    REPORT("report"), STATEMENT("statement"), ALL("all");
+    REPORT("report"),
+    STATEMENT("statement"),
+    NOTIFICATION("notification"),
+    ALL("all");
 }
 
 /**
@@ -232,6 +237,7 @@ class CreateBankConnectionFromBackupRequestJson(
 class CreateBankConnectionFromNewRequestJson(
     name: String,
     val type: String,
+    val dialect: String? = null,
     val data: JsonNode
 ) : CreateBankConnectionRequestJson(name)
 
@@ -240,7 +246,8 @@ data class EbicsNewTransport(
     val partnerID: String,
     val hostID: String,
     val ebicsURL: String,
-    val systemID: String?
+    val systemID: String?,
+    val dialect: String? = null
 )
 
 /**
@@ -386,7 +393,7 @@ data class Pain001Data(
     val sum: String,
     val currency: String,
     val subject: String,
-    val pmtInfId: String? = null
+    val endToEndId: String? = null
 )
 
 data class AccountTask(
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/server/NexusServer.kt 
b/nexus/src/main/kotlin/tech/libeufin/nexus/server/NexusServer.kt
index 5b9a0bd7..fca81b51 100644
--- a/nexus/src/main/kotlin/tech/libeufin/nexus/server/NexusServer.kt
+++ b/nexus/src/main/kotlin/tech/libeufin/nexus/server/NexusServer.kt
@@ -25,28 +25,20 @@ import io.ktor.server.plugins.contentnegotiation.*
 import com.fasterxml.jackson.core.util.DefaultIndenter
 import com.fasterxml.jackson.core.util.DefaultPrettyPrinter
 import com.fasterxml.jackson.databind.JsonNode
-import com.fasterxml.jackson.core.JsonParseException
 import com.fasterxml.jackson.databind.DeserializationFeature
 import com.fasterxml.jackson.databind.JsonMappingException
 import com.fasterxml.jackson.databind.SerializationFeature
-import com.fasterxml.jackson.databind.exc.MismatchedInputException
 import com.fasterxml.jackson.module.kotlin.*
 import io.ktor.client.*
 import io.ktor.http.*
-import io.ktor.network.sockets.*
 import io.ktor.server.application.*
-import io.ktor.server.engine.*
-import io.ktor.server.netty.*
 import io.ktor.server.plugins.*
 import io.ktor.server.plugins.callloging.*
 import io.ktor.server.plugins.statuspages.*
 import io.ktor.server.request.*
 import io.ktor.server.response.*
 import io.ktor.server.routing.*
-import io.ktor.util.*
-import org.jetbrains.exposed.exceptions.ExposedSQLException
 import org.jetbrains.exposed.sql.and
-import org.jetbrains.exposed.sql.transactions.TransactionManager
 import org.jetbrains.exposed.sql.transactions.transaction
 import org.slf4j.event.Level
 import tech.libeufin.nexus.*
@@ -54,9 +46,7 @@ import tech.libeufin.nexus.bankaccount.*
 import tech.libeufin.nexus.ebics.*
 import tech.libeufin.nexus.iso20022.processCamtMessage
 import tech.libeufin.util.*
-import java.net.BindException
 import java.net.URLEncoder
-import kotlin.system.exitProcess
 
 // Return facade state depending on the type.
 fun getFacadeState(type: String, facade: FacadeEntity): JsonNode {
@@ -439,10 +429,24 @@ val nexusApp: Application.() -> Unit = {
         }
         post("/bank-accounts/{accountId}/test-camt-ingestion/{type}") {
             requireSuperuser(call.request)
+            val accountId = ensureNonNull(call.parameters["accountId"])
+            val bankAccount = getBankAccount(accountId)
+            val connId = transaction { 
bankAccount.defaultBankConnection?.connectionId }
+            val dialect = if (connId != null) {
+                val defaultConn = getBankConnection(connId)
+                defaultConn.dialect
+            } else null
+            val msgType = ensureNonNull(call.parameters["type"])
             processCamtMessage(
-                ensureNonNull(call.parameters["accountId"]),
+                ensureNonNull(accountId),
                 XMLUtil.parseStringIntoDom(call.receiveText()),
-                ensureNonNull(call.parameters["type"])
+                when(msgType) {
+                    "C52", "Z52" -> { FetchLevel.REPORT }
+                    "C53", "Z53" -> { FetchLevel.STATEMENT }
+                    "C54", "Z54" -> { FetchLevel.NOTIFICATION }
+                    else -> throw badRequest("Message type: '$msgType', not 
supported")
+                },
+                dialect = dialect
             )
             call.respond(object {})
             return@post
@@ -693,7 +697,7 @@ val nexusApp: Application.() -> Unit = {
             if (body.uid != null) {
                 val maybeExists: PaymentInitiationEntity? = transaction {
                     PaymentInitiationEntity.find {
-                        PaymentInitiationsTable.paymentInformationId eq 
body.uid
+                        PaymentInitiationsTable.endToEndId eq body.uid
                     }.firstOrNull()
                 }
                 // If submitted payment looks exactly the same as the one
@@ -733,7 +737,7 @@ val nexusApp: Application.() -> Unit = {
                         sum = amount.amount,
                         currency = amount.currency,
                         subject = body.subject,
-                        pmtInfId = body.uid
+                        endToEndId = body.uid
                     ),
                     bankAccount
                 )
@@ -850,14 +854,26 @@ val nexusApp: Application.() -> Unit = {
                     is CreateBankConnectionFromBackupRequestJson -> {
                         val type = body.data.get("type")
                         if (type == null || !type.isTextual) {
-                            throw NexusError(HttpStatusCode.BadRequest, 
"backup needs type")
+                            throw NexusError(
+                                HttpStatusCode.BadRequest,
+                                "backup needs type"
+                            )
                         }
                         val plugin = getConnectionPlugin(type.textValue())
-                        plugin.createConnectionFromBackup(body.name, user, 
body.passphrase, body.data)
+                        plugin.createConnectionFromBackup(
+                            body.name,
+                            user,
+                            body.passphrase,
+                            body.data
+                        )
                     }
                     is CreateBankConnectionFromNewRequestJson -> {
                         val plugin = getConnectionPlugin(body.type)
-                        plugin.createConnection(body.name, user, body.data)
+                        plugin.createConnection(
+                            body.name,
+                            user,
+                            body.data
+                        )
                     }
                 }
             }
@@ -946,7 +962,7 @@ val nexusApp: Application.() -> Unit = {
                     list.bankMessages.add(
                         BankMessageInfo(
                             messageId = it.messageId,
-                            code = it.code,
+                            code = it.fetchLevel.jsonName,
                             length = it.message.bytes.size.toLong()
                         )
                     )
diff --git 
a/nexus/src/main/kotlin/tech/libeufin/nexus/xlibeufinbank/XLibeufinBankNexus.kt 
b/nexus/src/main/kotlin/tech/libeufin/nexus/xlibeufinbank/XLibeufinBankNexus.kt
index 22c07e38..a6193a14 100644
--- 
a/nexus/src/main/kotlin/tech/libeufin/nexus/xlibeufinbank/XLibeufinBankNexus.kt
+++ 
b/nexus/src/main/kotlin/tech/libeufin/nexus/xlibeufinbank/XLibeufinBankNexus.kt
@@ -303,6 +303,7 @@ class XlibeufinBankConnectionProtocol : 
BankConnectionProtocol {
             NexusBankMessageEntity.new {
                 bankConnection = conn
                 message = ExposedBlob(respBlob)
+                fetchLevel = fetchSpec.level
             }
         }
         return null
diff --git a/nexus/src/test/kotlin/Iso20022Test.kt 
b/nexus/src/test/kotlin/Iso20022Test.kt
index 18502881..58777cba 100644
--- a/nexus/src/test/kotlin/Iso20022Test.kt
+++ b/nexus/src/test/kotlin/Iso20022Test.kt
@@ -1,14 +1,33 @@
 package tech.libeufin.nexus
 import CamtBankAccountEntry
 import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
+import io.ktor.client.request.*
+import io.ktor.http.*
+import io.ktor.server.testing.*
+import org.jetbrains.exposed.sql.transactions.transaction
 import org.junit.Ignore
 import org.junit.Test
 import org.w3c.dom.Document
+import poFiCamt052
+import poFiCamt054
+import prepNexusDb
+import tech.libeufin.nexus.bankaccount.getBankAccount
 import tech.libeufin.nexus.iso20022.*
+import tech.libeufin.nexus.server.EbicsDialects
+import tech.libeufin.nexus.server.FetchLevel
+import tech.libeufin.nexus.server.getBankConnection
+import tech.libeufin.nexus.server.nexusApp
 import tech.libeufin.util.DestructionError
 import tech.libeufin.util.XMLUtil
 import tech.libeufin.util.destructXml
+import withTestDatabase
 import java.math.BigDecimal
+import java.time.LocalDateTime
+import java.time.ZoneId
+import java.time.ZoneOffset
+import java.time.ZonedDateTime
+import java.time.format.DateTimeFormatter
+import java.util.TimeZone
 import kotlin.test.assertEquals
 import kotlin.test.assertNotNull
 import kotlin.test.assertTrue
@@ -85,4 +104,63 @@ class Iso20022Test {
 
         
println(jacksonObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(r))
     }
+
+    /**
+     * PoFi timestamps aren't zoned, therefore the usual ZonedDateTime
+     * doesn't cover it.  They must switch to (java.time.)LocalDateTime.
+     */
+    @Test
+    fun parsePostFinanceDate() {
+        // 2011-12-03T10:15:30 from Java Doc as ISO_LOCAL_DATE_TIME.
+        // 2023-05-09T11:04:09 from PoFi
+
+        getTimestampInMillis(
+            "2011-12-03T10:15:30",
+            EbicsDialects.POSTFINANCE.dialectName
+        )
+        getTimestampInMillis(
+            "2011-12-03T10:15:30Z" // ! with timezone
+        )
+    }
+
+    @Test
+    fun parsePoFiCamt054() {
+        val doc = XMLUtil.parseStringIntoDom(poFiCamt054)
+        parseCamtMessage(doc)
+    }
+
+    @Test
+    fun ingestPoFiCamt054() {
+        val doc = XMLUtil.parseStringIntoDom(poFiCamt054)
+        withTestDatabase { prepNexusDb()
+            processCamtMessage(
+                "foo",
+                doc,
+                FetchLevel.NOTIFICATION,
+                dialect = "pf"
+            )
+        }
+    }
+
+    @Test
+    fun parsePostFinanceCamt052() {
+        withTestDatabase {
+            prepNexusDb()
+            // Adjusting the MakeEnv.kt values to PoFi
+            val fooBankAccount = getBankAccount("foo")
+            val fooConnection = getBankConnection("foo")
+            transaction {
+                fooBankAccount.iban = "CH9789144829733648596"
+                fooConnection.dialect = "pf"
+            }
+            testApplication {
+                application(nexusApp)
+                client.post("/bank-accounts/foo/test-camt-ingestion/C52") {
+                    basicAuth("foo", "foo")
+                    contentType(ContentType.Application.Xml)
+                    setBody(poFiCamt052)
+                }
+            }
+        }
+    }
 }
diff --git a/nexus/src/test/kotlin/MakeEnv.kt b/nexus/src/test/kotlin/MakeEnv.kt
index daad7447..c64d20e8 100644
--- a/nexus/src/test/kotlin/MakeEnv.kt
+++ b/nexus/src/test/kotlin/MakeEnv.kt
@@ -69,11 +69,13 @@ inline fun <reified ExceptionType> assertException(
  * Run a block after connecting to the test database.
  * Cleans up the DB file afterwards.
  */
-fun withTestDatabase(f: () -> Unit) {
+fun withTestDatabase(keepData: Boolean = false, f: () -> Unit) {
     Database.connect(TEST_DB_CONN, user = currentUser)
     TransactionManager.manager.defaultIsolationLevel = 
java.sql.Connection.TRANSACTION_SERIALIZABLE
-    dbDropTables(TEST_DB_CONN)
-    tech.libeufin.sandbox.dbDropTables(TEST_DB_CONN)
+    if (!keepData) {
+        dbDropTables(TEST_DB_CONN)
+        tech.libeufin.sandbox.dbDropTables(TEST_DB_CONN)
+    }
     f()
 }
 
@@ -195,11 +197,16 @@ fun prepNexusDb() {
     }
 }
 
-fun prepSandboxDb(usersDebtLimit: Int = 1000, currency: String = "TESTKUDOS") {
+fun prepSandboxDb(
+    usersDebtLimit: Int = 1000,
+    currency: String = "TESTKUDOS",
+    cashoutCurrency: String = "EUR"
+) {
     tech.libeufin.sandbox.dbCreateTables(TEST_DB_CONN)
     transaction {
         val config = DemobankConfig(
             currency = currency,
+            cashoutCurrency = cashoutCurrency,
             bankDebtLimit = 10000,
             usersDebtLimit = usersDebtLimit,
             allowRegistrations = true,
@@ -321,6 +328,7 @@ fun withSandboxTestDatabase(f: () -> Unit) {
         transaction {
             val config = DemobankConfig(
                 currency = "TESTKUDOS",
+                cashoutCurrency = "NOTUSED",
                 bankDebtLimit = 10000,
                 usersDebtLimit = 1000,
                 allowRegistrations = true,
@@ -486,3 +494,184 @@ fun genNexusIncomingCamt(
             )
         )
     )
+
+val poFiCamt054: String = """
+    <?xml version="1.0" encoding="UTF-8"?>
+    <Document xmlns="urn:iso:std:iso:20022:tech:xsd:camt.054.001.04" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xsi:schemaLocation="urn:iso:std:iso:20022:tech:xsd:camt.054.001.04 
camt.054.001.04.xsd">
+      <BkToCstmrDbtCdtNtfctn>
+        <GrpHdr>
+          <MsgId>286494ADFK/132157/448798</MsgId>
+          <CreDtTm>2023-05-10T13:21:57</CreDtTm>
+          <MsgPgntn>
+            <PgNb>1</PgNb>
+            <LastPgInd>true</LastPgInd>
+          </MsgPgntn>
+          <AddtlInf>SPS/1.7/TEST</AddtlInf>
+        </GrpHdr>
+        <Ntfctn>
+          <Id>286494ADFK/132157/448798</Id>
+          <CreDtTm>2023-05-10T13:21:57</CreDtTm>
+          <RptgSrc>
+            <Prtry>OTHR</Prtry>
+          </RptgSrc>
+          <Acct>
+            <Id>
+              <IBAN>${FOO_USER_IBAN}</IBAN>
+            </Id>
+          </Acct>
+          <Ntry>
+            <Amt Ccy="CHF">5.00</Amt>
+            <CdtDbtInd>DBIT</CdtDbtInd>
+            <Sts>BOOK</Sts>
+            <BookgDt>
+              <Dt>2023-05-10</Dt>
+            </BookgDt>
+            <ValDt>
+              <Dt>2023-05-10</Dt>
+            </ValDt>
+            <BkTxCd>
+              <Domn>
+                <Cd>PMNT</Cd>
+                <Fmly>
+                  <Cd>ICDT</Cd>
+                  <SubFmlyCd>AUTT</SubFmlyCd>
+                </Fmly>
+              </Domn>
+            </BkTxCd>
+            <NtryDtls>
+              <TxDtls>
+                <Refs>
+                  <MsgId>478b-9e7e-2a16b35ed69c</MsgId>
+                  <PmtInfId>4f4-b65d-8aae7a2ded2f</PmtInfId>
+                  <InstrId>InstructionId</InstrId>
+                  <EndToEndId>4c3d-a74b-71cfbdaf901f</EndToEndId>
+                </Refs>
+                <Amt Ccy="CHF">5.00</Amt>
+                <CdtDbtInd>DBIT</CdtDbtInd>
+                <BkTxCd>
+                  <Domn>
+                    <Cd>PMNT</Cd>
+                    <Fmly>
+                      <Cd>ICDT</Cd>
+                      <SubFmlyCd>BOOK</SubFmlyCd>
+                    </Fmly>
+                  </Domn>
+                </BkTxCd>
+                <RltdPties>
+                  <DbtrAcct>
+                    <Id>
+                      <IBAN>CH0889144371988976754</IBAN>
+                    </Id>
+                  </DbtrAcct>
+                  <Cdtr>
+                    <Nm>Sample Creditor Name</Nm>
+                  </Cdtr>
+                  <CdtrAcct>
+                    <Id>
+                      <IBAN>CH9789144829733648596</IBAN>
+                    </Id>
+                  </CdtrAcct>
+                </RltdPties>
+                <RmtInf>
+                  <Ustrd>Unstructured remittance information</Ustrd>
+                </RmtInf>
+              </TxDtls>
+            </NtryDtls>
+          </Ntry>
+        </Ntfctn>
+      </BkToCstmrDbtCdtNtfctn>
+    </Document>
+""".trimIndent()
+
+val poFiCamt052: String = """
+    <?xml version="1.0"?>
+    <Document xmlns="urn:iso:std:iso:20022:tech:xsd:camt.052.001.04" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xsi:schemaLocation="urn:iso:std:iso:20022:tech:xsd:camt.052.001.04 
camt.052.001.04.xsd">
+      <BkToCstmrAcctRpt>
+        <GrpHdr>
+          <MsgId>2827403ADFJ/110409/997113</MsgId>
+          <CreDtTm>2023-05-09T11:04:09</CreDtTm>
+          <MsgPgntn>
+            <PgNb>1</PgNb>
+            <LastPgInd>true</LastPgInd>
+          </MsgPgntn>
+          <AddtlInf>SPS/1.7/TEST</AddtlInf>
+        </GrpHdr>
+        <Rpt>
+          <Id>2827403ADFJ/110409/997113</Id>
+          <ElctrncSeqNb>129</ElctrncSeqNb>
+          <CreDtTm>2023-05-09T11:04:09</CreDtTm>
+          <FrToDt>
+            <FrDtTm>2023-05-09T00:00:00</FrDtTm>
+            <ToDtTm>2023-05-09T10:00:00</ToDtTm>
+          </FrToDt>
+          <Acct>
+            <Id>
+              <IBAN>CH9789144829733648596</IBAN>
+            </Id>
+            <Ownr>
+              <Nm>LibEuFin</Nm>
+            </Ownr>
+          </Acct>
+          <Bal>
+            <Tp>
+              <CdOrPrtry>
+                <Cd>OPBD</Cd>
+              </CdOrPrtry>
+            </Tp>
+            <Amt Ccy="CHF">500000.00</Amt>
+            <CdtDbtInd>CRDT</CdtDbtInd>
+            <Dt>
+              <Dt>2023-05-09</Dt>
+            </Dt>
+          </Bal>
+          <Bal>
+            <Tp>
+              <CdOrPrtry>
+                <Cd>CLBD</Cd>
+              </CdOrPrtry>
+            </Tp>
+            <Amt Ccy="CHF">499998.00</Amt>
+            <CdtDbtInd>CRDT</CdtDbtInd>
+            <Dt>
+              <Dt>2023-05-09</Dt>
+            </Dt>
+          </Bal>
+          <Ntry>
+            <Amt Ccy="CHF">2.00</Amt>
+            <CdtDbtInd>DBIT</CdtDbtInd>
+            <RvslInd>false</RvslInd>
+            <Sts>BOOK</Sts>
+            <BookgDt>
+              <Dt>2023-05-09</Dt>
+            </BookgDt>
+            <ValDt>
+              <Dt>2023-05-09</Dt>
+            </ValDt>
+            <BkTxCd>
+              <Domn>
+                <Cd>PMNT</Cd>
+                <Fmly>
+                  <Cd>ICDT</Cd>
+                  <SubFmlyCd>AUTT</SubFmlyCd>
+                </Fmly>
+              </Domn>
+            </BkTxCd>
+            <NtryDtls>
+              <TxDtls>
+                <Refs>
+                  <MsgId>leuf-mp1-187ffc0f021-1-1</MsgId>
+                  <AcctSvcrRef>032663184998070600000003</AcctSvcrRef>
+                  <PmtInfId>Zufall</PmtInfId>
+                  <InstrId>leuf-i-187ffc0f021-1-1</InstrId>
+                  <EndToEndId>leuf-e-187ffc0f021-1-1</EndToEndId>
+                </Refs>
+                <Amt Ccy="CHF">2.00</Amt>
+                <CdtDbtInd>DBIT</CdtDbtInd>
+              </TxDtls>
+            </NtryDtls>
+            <AddtlNtryInf>EZAG ISO 20022 SAMMELAUFTRAG E-FINANCE Zufall 
leuf-mp1-187ffc0f021-1-1</AddtlNtryInf>
+          </Ntry>
+        </Rpt>
+      </BkToCstmrAcctRpt>
+    </Document>
+""".trimIndent()
\ No newline at end of file
diff --git a/nexus/src/test/kotlin/PostFinance.kt 
b/nexus/src/test/kotlin/PostFinance.kt
new file mode 100644
index 00000000..5b93f677
--- /dev/null
+++ b/nexus/src/test/kotlin/PostFinance.kt
@@ -0,0 +1,100 @@
+import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
+import io.ktor.client.*
+import kotlinx.coroutines.runBlocking
+import org.jetbrains.exposed.sql.transactions.transaction
+import tech.libeufin.nexus.bankaccount.addPaymentInitiation
+import tech.libeufin.nexus.bankaccount.fetchBankAccountTransactions
+import tech.libeufin.nexus.bankaccount.getBankAccount
+import tech.libeufin.nexus.ebics.doEbicsUploadTransaction
+import tech.libeufin.nexus.ebics.getEbicsSubscriberDetails
+import tech.libeufin.nexus.getConnectionPlugin
+import tech.libeufin.nexus.getNexusUser
+import tech.libeufin.nexus.server.*
+import tech.libeufin.util.EbicsStandardOrderParams
+import java.io.BufferedReader
+import java.io.File
+
+
+private fun downloadPayment() {
+    val httpClient = HttpClient()
+    runBlocking {
+        fetchBankAccountTransactions(
+            client = httpClient,
+            fetchSpec = FetchSpecLatestJson(
+                level = FetchLevel.NOTIFICATION,
+                bankConnection = null
+            ),
+            accountId = "foo"
+        )
+    }
+}
+
+// Causes one CRDT payment to show up in the camt.054.
+private fun uploadQrrPayment() {
+    val httpClient = HttpClient()
+    val qrr = """
+        
Product;Channel;Account;Currency;Amount;Reference;Name;Street;Number;Postcode;City;Country;DebtorAddressLine;DebtorAddressLine;DebtorAccount;ReferenceType;UltimateDebtorName;UltimateDebtorStreet;UltimateDebtorNumber;UltimateDebtorPostcode;UltimateDebtorTownName;UltimateDebtorCountry;UltimateDebtorAddressLine;UltimateDebtorAddressLine;RemittanceInformationText
+        
QRR;PO;CH9789144829733648596;CHF;33;;D009;Musterstrasse;1;1111;Musterstadt;CH;;;;NON;D009;Musterstrasse;1;1111;Musterstadt;CH;;;Taler-Demo
+    """.trimIndent()
+    runBlocking {
+        doEbicsUploadTransaction(
+            httpClient,
+            getEbicsSubscriberDetails("postfinance"),
+            "XTC",
+            qrr.toByteArray(Charsets.UTF_8),
+            EbicsStandardOrderParams()
+        )
+    }
+}
+
+/**
+ * Causes one DBIT payment to show up in the camt.054.  This one
+ * however lacks the AcctSvcrRef, so other ways to pin it are needed.
+ * Notably, EndToEndId is mandatory in pain.001 _and_ is controlled
+ * by the sender.  Hence, the sender can itself ensure the EndToEndId
+ * uniqueness.
+ */
+private fun uploadPain001Payment() {
+    transaction {
+        addPaymentInitiation(
+            Pain001Data(
+                creditorIban = "CH9300762011623852957",
+                creditorBic = "POFICHBEXXX",
+                creditorName = "Muster Frau",
+                sum = "2",
+                currency = "CHF",
+                subject = "Muster Zahlung 0",
+                endToEndId = "Zufall"
+            ),
+            getBankAccount("foo")
+        )
+    }
+    val ebicsConn = getConnectionPlugin("ebics")
+    val httpClient = HttpClient()
+    runBlocking {
+        ebicsConn.submitPaymentInitiation(httpClient, 1L)
+    }
+}
+fun main() {
+    // Load EBICS subscriber's keys from disk.
+    val bufferedReader: BufferedReader = 
File("/tmp/pofi.json").bufferedReader()
+    val accessDataTxt = bufferedReader.use { it.readText() }
+    val ebicsConn = getConnectionPlugin("ebics")
+    val accessDataJson = jacksonObjectMapper().readTree(accessDataTxt)
+    withTestDatabase {
+        prepNexusDb()
+        transaction {
+            ebicsConn.createConnectionFromBackup(
+                connId = "postfinance",
+                user = getNexusUser("foo"),
+                passphrase = "foo",
+                accessDataJson
+            )
+            val fooBankAccount = getBankAccount("foo")
+            fooBankAccount.defaultBankConnection = 
getBankConnection("postfinance")
+            fooBankAccount.iban = "CH9789144829733648596"
+        }
+    }
+    // uploadPayment()
+    downloadPayment()
+}
\ No newline at end of file
diff --git a/nexus/src/test/kotlin/TalerTest.kt 
b/nexus/src/test/kotlin/TalerTest.kt
index ecaa7a0a..cd8b1776 100644
--- a/nexus/src/test/kotlin/TalerTest.kt
+++ b/nexus/src/test/kotlin/TalerTest.kt
@@ -86,6 +86,7 @@ class TalerTest {
                     contentType(ContentType.Application.Json)
                     basicAuth(testedAccount, testedAccount)
                 }
+                assert(r.status.value == HttpStatusCode.OK.value)
                 val j = mapper.readTree(r.readBytes())
                 val wtidFromTwg = 
j.get("outgoing_transactions").get(0).get("wtid").asText()
                 assert(wtidFromTwg == "T0")
diff --git a/util/src/main/kotlin/CamtJsonMapping.kt 
b/util/src/main/kotlin/CamtJsonMapping.kt
index 06a042a6..fcf992c5 100644
--- a/util/src/main/kotlin/CamtJsonMapping.kt
+++ b/util/src/main/kotlin/CamtJsonMapping.kt
@@ -8,6 +8,7 @@ import com.fasterxml.jackson.databind.annotation.JsonDeserialize
 import com.fasterxml.jackson.databind.annotation.JsonSerialize
 import com.fasterxml.jackson.databind.deser.std.StdDeserializer
 import com.fasterxml.jackson.databind.ser.std.StdSerializer
+import org.jetbrains.exposed.sql.Transaction
 import tech.libeufin.util.internalServerError
 
 enum class CreditDebitIndicator {
@@ -184,6 +185,7 @@ data class TransactionDetails(
     val endToEndId: String? = null,
     val paymentInformationId: String? = null,
     val messageId: String? = null,
+    val accountServicerRef: String? = null,
 
     val purpose: String?,
     val proprietaryPurpose: String?,
@@ -214,11 +216,8 @@ data class TransactionDetails(
      */
     val interBankSettlementAmount: CurrencyAmount?,
 
-    /**
-     * Unstructured remittance information (=subject line) of the transaction,
-     * or the empty string if missing.
-     */
-    val unstructuredRemittanceInformation: String,
+    // PoFi shown entries lacking it.
+    val unstructuredRemittanceInformation: String?,
     val returnInfo: ReturnInfo?
 )
 
@@ -286,23 +285,15 @@ data class CamtBankAccountEntry(
     // list of sub-transactions participating in this money movement.
     val batches: List<Batch>?
 ) {
-    /**
-     * This function returns the subject of the unique transaction
-     * accounted in this object.  If the transaction is not unique,
-     * it throws an exception.  NOTE: the caller has the responsibility
-     * of not passing an empty report; those usually should be discarded
-     * and never participate in the application logic.
-     */
-    @JsonIgnore
-    fun getSingletonSubject(): String {
-        // Checks that the given list contains only one element and returns it.
-        fun <T>checkAndGetSingleton(maybeTxs: List<T>?): T {
-            if (maybeTxs == null || maybeTxs.size > 1) throw 
internalServerError(
-                "Only a singleton transaction is " +
-                        "allowed inside ${this.javaClass}."
-            )
-            return maybeTxs[0]
-        }
+    // Checks that the given list contains only one element and returns it.
+    private fun <T>checkAndGetSingleton(maybeTxs: List<T>?): T {
+        if (maybeTxs == null || maybeTxs.size > 1) throw internalServerError(
+            "Only a singleton transaction is " +
+                    "allowed inside ${this.javaClass}."
+        )
+        return maybeTxs[0]
+    }
+    private fun getSingletonTxDtls(): TransactionDetails {
         /**
          * Types breakdown until the meaningful payment information is reached.
          *
@@ -329,6 +320,28 @@ data class CamtBankAccountEntry(
         val batchTransactions = batch.batchTransactions
         val tx: BatchTransaction = checkAndGetSingleton(batchTransactions)
         val details: TransactionDetails = tx.details
-        return details.unstructuredRemittanceInformation
+        return details
+    }
+    /**
+     * This function returns the subject of the unique transaction
+     * accounted in this object.  If the transaction is not unique,
+     * it throws an exception.  NOTE: the caller has the responsibility
+     * of not passing an empty report; those usually should be discarded
+     * and never participate in the application logic.
+     */
+    @JsonIgnore
+    fun getSingletonSubject(): String {
+        val maybeSubject = 
getSingletonTxDtls().unstructuredRemittanceInformation
+        if (maybeSubject == null) {
+            throw internalServerError(
+                "The parser let in a transaction without subject" +
+                        ", acctSvcrRef: ${this.getSingletonAcctSvcrRef()}."
+            )
+        }
+        return maybeSubject
+    }
+    @JsonIgnore
+    fun getSingletonAcctSvcrRef(): String? {
+        return getSingletonTxDtls().accountServicerRef
     }
 }
\ No newline at end of file
diff --git a/util/src/main/kotlin/Ebics.kt b/util/src/main/kotlin/Ebics.kt
index 182a02bf..737039a6 100644
--- a/util/src/main/kotlin/Ebics.kt
+++ b/util/src/main/kotlin/Ebics.kt
@@ -87,7 +87,8 @@ data class EbicsClientSubscriberDetails(
     val customerAuthPriv: RSAPrivateCrtKey,
     val customerSignPriv: RSAPrivateCrtKey,
     val ebicsIniState: EbicsInitState,
-    val ebicsHiaState: EbicsInitState
+    val ebicsHiaState: EbicsInitState,
+    var dialect: String? = null
 )
 
 /**
@@ -158,9 +159,12 @@ private fun signOrder(
 
 fun createEbicsRequestForDownloadReceipt(
     subscriberDetails: EbicsClientSubscriberDetails,
-    transactionID: String
+    transactionID: String?
 ): String {
-    val req = EbicsRequest.createForDownloadReceiptPhase(transactionID, 
subscriberDetails.hostId)
+    val req = EbicsRequest.createForDownloadReceiptPhase(
+        transactionID,
+        subscriberDetails.hostId
+    )
     val doc = XMLUtil.convertJaxbToDocument(req)
     XMLUtil.signEbicsDocument(doc, subscriberDetails.customerAuthPriv)
     return XMLUtil.convertDomToString(doc)
@@ -300,7 +304,7 @@ fun createEbicsRequestForDownloadInitialization(
 
 fun createEbicsRequestForDownloadTransferPhase(
     subscriberDetails: EbicsClientSubscriberDetails,
-    transactionID: String,
+    transactionID: String?,
     segmentNumber: Int,
     numSegments: Int
 ): String {
@@ -317,7 +321,7 @@ fun createEbicsRequestForDownloadTransferPhase(
 
 fun createEbicsRequestForUploadTransferPhase(
     subscriberDetails: EbicsClientSubscriberDetails,
-    transactionID: String,
+    transactionID: String?,
     preparedUploadData: PreparedUploadData,
     chunkIndex: Int
 ): String {
@@ -363,10 +367,12 @@ enum class EbicsReturnCode(val errorCode: String) {
     EBICS_DOWNLOAD_POSTPROCESS_DONE("011000"),
     EBICS_DOWNLOAD_POSTPROCESS_SKIPPED("011001"),
     EBICS_TX_SEGMENT_NUMBER_UNDERRUN("011101"),
+    EBICS_AUTHENTICATION_FAILED ("061001"),
     EBICS_INVALID_USER_OR_USER_STATE("091002"),
     EBICS_PROCESSING_ERROR("091116"),
     EBICS_ACCOUNT_AUTHORISATION_FAILED("091302"),
     EBICS_AMOUNT_CHECK_FAILED("091303"),
+    EBICS_EBICS_AUTHORISATION_ORDER_IDENTIFIER_FAILED("090003"),
     EBICS_NO_DOWNLOAD_DATA_AVAILABLE("090005");
 
     companion object {
diff --git a/util/src/main/kotlin/JSON.kt b/util/src/main/kotlin/JSON.kt
index b2ad4a05..2be1f3d0 100644
--- a/util/src/main/kotlin/JSON.kt
+++ b/util/src/main/kotlin/JSON.kt
@@ -93,7 +93,8 @@ data class XLibeufinBankTransaction(
      * along every API call using this object.
      */
     val pmtInfId: String? = null,
-    val msgId: String? = null
+    val msgId: String? = null,
+    val endToEndId: String? = null
 )
 data class IncomingPaymentInfo(
     val debtorIban: String,
diff --git a/util/src/main/kotlin/XMLUtil.kt b/util/src/main/kotlin/XMLUtil.kt
index c20a969a..e9074cb4 100644
--- a/util/src/main/kotlin/XMLUtil.kt
+++ b/util/src/main/kotlin/XMLUtil.kt
@@ -231,7 +231,8 @@ class XMLUtil private constructor() {
                 "xsd/camt.052.001.02.xsd",
                 "xsd/camt.053.001.02.xsd",
                 "xsd/camt.054.001.02.xsd",
-                "xsd/pain.001.001.03.xsd"
+                "xsd/pain.001.001.03.xsd",
+                "xsd/pain.001.001.03.ch.02.xsd"
             ).map {
                 val stream =
                     classLoader.getResourceAsStream(it) ?: throw 
FileNotFoundException("Schema file $it not found.")
diff --git a/util/src/main/kotlin/ebics_h004/EbicsRequest.kt 
b/util/src/main/kotlin/ebics_h004/EbicsRequest.kt
index c5d053ea..7041f5f2 100644
--- a/util/src/main/kotlin/ebics_h004/EbicsRequest.kt
+++ b/util/src/main/kotlin/ebics_h004/EbicsRequest.kt
@@ -289,7 +289,7 @@ class EbicsRequest {
     companion object {
 
         fun createForDownloadReceiptPhase(
-            transactionId: String,
+            transactionId: String?,
             hostId: String
 
         ): EbicsRequest {
@@ -444,7 +444,7 @@ class EbicsRequest {
 
         fun createForUploadTransferPhase(
             hostId: String,
-            transactionId: String,
+            transactionId: String?,
             segNumber: BigInteger,
             encryptedData: String
         ): EbicsRequest {
@@ -477,7 +477,7 @@ class EbicsRequest {
 
         fun createForDownloadTransferPhase(
             hostID: String,
-            transactionID: String,
+            transactionID: String?,
             segmentNumber: Int,
             numSegments: Int
         ): EbicsRequest {
diff --git a/util/src/main/resources/xsd/pain.001.001.03.ch.02.xsd 
b/util/src/main/resources/xsd/pain.001.001.03.ch.02.xsd
new file mode 100644
index 00000000..b8ecce02
--- /dev/null
+++ b/util/src/main/resources/xsd/pain.001.001.03.ch.02.xsd
@@ -0,0 +1,1212 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!--
+(C) Copyright 2010, SKSF, www.sksf.ch
+CH Version fuer pain.001 Credit Transfer: xmlns="http://www.iso-payments.ch";
+.ch.:              Identification for this CH version
+Last part (.02):   Version of this scheme
+
+Based on ISO pain.001.001.03 (urn:iso:std:iso:20022:tech:xsd:pain.001.001.03)
+
+Anregungen und Fragen zu diesem Dokument können an das jeweilige 
Finanzinstitut gerichtet werden.
+Allgemeine Anregungen können auch bei der SIX Interbank Clearing AG unter 
folgender Adresse angebracht werden:
+pm@six-group.com
+
+History
+15.02.2010  V01  initial version, 
targetNamespace="http://www.six-interbank-clearing.com/de/pain.001.001.03.ch.01.xsd";
  File:pain.001.001.03.ch.01.xsd
+30.04.2010  V02  added: element Initiating Party/Contact Details contains 
Software name and Version of producing application
+                                                changed: name in 
"PartyIdentification32-CH_Name" mandatory
+-->
+<!-- V01: changed:
+-->
+<xs:schema 
xmlns="http://www.six-interbank-clearing.com/de/pain.001.001.03.ch.02.xsd"; 
xmlns:xs="http://www.w3.org/2001/XMLSchema"; 
targetNamespace="http://www.six-interbank-clearing.com/de/pain.001.001.03.ch.02.xsd";
 elementFormDefault="qualified">
+       <xs:element name="Document" type="Document"/>
+       <!-- V01: changed: CH version changes applied -->
+       <xs:complexType name="AccountIdentification4Choice-CH">
+               <xs:sequence>
+                       <xs:choice>
+                               <xs:element name="IBAN" 
type="IBAN2007Identifier"/>
+                               <xs:element name="Othr" 
type="GenericAccountIdentification1-CH"/>
+                       </xs:choice>
+               </xs:sequence>
+       </xs:complexType>
+       <!-- V01: unused
+       <xs:complexType name="AccountSchemeName1Choice">
+               <xs:sequence>
+                       <xs:choice>
+                               <xs:element name="Cd" 
type="ExternalAccountIdentification1Code"/>
+                               <xs:element name="Prtry" type="Max35Text"/>
+                       </xs:choice>
+               </xs:sequence>
+       </xs:complexType>
+    -->
+       <xs:simpleType name="ActiveOrHistoricCurrencyAndAmount_SimpleType">
+               <xs:restriction base="xs:decimal">
+                       <xs:minInclusive value="0"/>
+                       <xs:fractionDigits value="5"/>
+                       <xs:totalDigits value="18"/>
+               </xs:restriction>
+       </xs:simpleType>
+       <xs:complexType name="ActiveOrHistoricCurrencyAndAmount">
+               <xs:simpleContent>
+                       <xs:extension 
base="ActiveOrHistoricCurrencyAndAmount_SimpleType">
+                               <xs:attribute name="Ccy" 
type="ActiveOrHistoricCurrencyCode" use="required"/>
+                       </xs:extension>
+               </xs:simpleContent>
+       </xs:complexType>
+       <xs:simpleType name="ActiveOrHistoricCurrencyCode">
+               <xs:restriction base="xs:string">
+                       <xs:pattern value="[A-Z]{3,3}"/>
+               </xs:restriction>
+       </xs:simpleType>
+       <xs:simpleType name="AddressType2Code">
+               <xs:restriction base="xs:string">
+                       <xs:enumeration value="ADDR"/>
+                       <xs:enumeration value="PBOX"/>
+                       <xs:enumeration value="HOME"/>
+                       <xs:enumeration value="BIZZ"/>
+                       <xs:enumeration value="MLTO"/>
+                       <xs:enumeration value="DLVY"/>
+               </xs:restriction>
+       </xs:simpleType>
+       <xs:complexType name="AmountType3Choice">
+               <xs:sequence>
+                       <xs:choice>
+                               <xs:element name="InstdAmt" 
type="ActiveOrHistoricCurrencyAndAmount"/>
+                               <xs:element name="EqvtAmt" 
type="EquivalentAmount2"/>
+                       </xs:choice>
+               </xs:sequence>
+       </xs:complexType>
+       <xs:simpleType name="AnyBICIdentifier">
+               <xs:restriction base="xs:string">
+                       <xs:pattern 
value="[A-Z]{6,6}[A-Z2-9][A-NP-Z0-9]([A-Z0-9]{3,3}){0,1}"/>
+               </xs:restriction>
+       </xs:simpleType>
+       <!-- V01: unused: type Authorisation1Choice is not allowed or used in 
CH Version
+       <xs:complexType name="Authorisation1Choice">
+               <xs:sequence>
+                       <xs:choice>
+                               <xs:element name="Cd" 
type="Authorisation1Code"/>
+                               <xs:element name="Prtry" type="Max128Text"/>
+                       </xs:choice>
+               </xs:sequence>
+       </xs:complexType>
+       <xs:simpleType name="Authorisation1Code">
+               <xs:restriction base="xs:string">
+                       <xs:enumeration value="AUTH"/>
+                       <xs:enumeration value="FDET"/>
+                       <xs:enumeration value="FSUM"/>
+                       <xs:enumeration value="ILEV"/>
+               </xs:restriction>
+       </xs:simpleType>
+       -->
+       <!-- V01: added: CH version supports only this character set. All text 
fields use this type -->
+       <xs:simpleType name="BasicText-CH">
+               <xs:restriction base="xs:string">
+                       <xs:pattern 
value="([a-zA-Z0-9\.,;:'\+\-/\(\)?\*\[\]\{\}\\`´~ 
]|[!&quot;#%&amp;&lt;&gt;÷=@_$£]|[àáâäçèéêëìíîïñòóôöùúûüýßÀÁÂÄÇÈÉÊËÌÍÎÏÒÓÔÖÙÚÛÜÑ])*"/>
+               </xs:restriction>
+       </xs:simpleType>
+       <!-- V01: added: This is the SWIFT character set -->
+       <xs:simpleType name="BasicText-Swift">
+               <xs:restriction base="xs:string">
+                       <xs:pattern 
value="([A-Za-z0-9]|[+|\?|/|\-|:|\(|\)|\.|,|'|\p{Zs}])*"/>
+               </xs:restriction>
+       </xs:simpleType>
+       <xs:simpleType name="BICIdentifier">
+               <xs:restriction base="xs:string">
+                       <xs:pattern 
value="[A-Z]{6,6}[A-Z2-9][A-NP-Z0-9]([A-Z0-9]{3,3}){0,1}"/>
+               </xs:restriction>
+       </xs:simpleType>
+       <xs:simpleType name="BaseOneRate">
+               <xs:restriction base="xs:decimal">
+                       <xs:fractionDigits value="10"/>
+                       <xs:totalDigits value="11"/>
+               </xs:restriction>
+       </xs:simpleType>
+       <xs:simpleType name="BatchBookingIndicator">
+               <xs:restriction base="xs:boolean"/>
+       </xs:simpleType>
+       <xs:complexType name="BranchAndFinancialInstitutionIdentification4">
+               <xs:sequence>
+                       <xs:element name="FinInstnId" 
type="FinancialInstitutionIdentification7"/>
+                       <xs:element name="BrnchId" type="BranchData2" 
minOccurs="0"/>
+               </xs:sequence>
+       </xs:complexType>
+       <!-- VO1: added: definition of FI where only BIC or Clearing Id is 
allowed, but no branch data -->
+       <xs:complexType 
name="BranchAndFinancialInstitutionIdentification4-CH_BicOrClrId">
+               <xs:sequence>
+                       <xs:element name="FinInstnId" 
type="FinancialInstitutionIdentification7-CH_BicOrClrId"/>
+                       <!-- V01: unused
+                       <xs:element name="BrnchId" type="BranchData2" 
minOccurs="0"/>
+                       -->
+               </xs:sequence>
+       </xs:complexType>
+       <!-- VO1: added: definition of FI where all elements are allowed, but 
no branch data -->
+       <xs:complexType name="BranchAndFinancialInstitutionIdentification4-CH">
+               <xs:sequence>
+                       <xs:element name="FinInstnId" 
type="FinancialInstitutionIdentification7-CH"/>
+                       <!-- V01: unused
+                       <xs:element name="BrnchId" type="BranchData2" 
minOccurs="0"/>
+                       -->
+               </xs:sequence>
+       </xs:complexType>
+       <xs:complexType name="BranchData2">
+               <xs:sequence>
+                       <xs:element name="Id" type="Max35Text" minOccurs="0"/>
+                       <xs:element name="Nm" type="Max140Text" minOccurs="0"/>
+                       <xs:element name="PstlAdr" type="PostalAddress6" 
minOccurs="0"/>
+               </xs:sequence>
+       </xs:complexType>
+       <!-- V01: changed: CH version changes applied  -->
+       <xs:complexType name="CashAccount16-CH_IdAndCurrency">
+               <xs:sequence>
+                       <xs:element name="Id" 
type="AccountIdentification4Choice-CH"/>
+                       <xs:element name="Ccy" 
type="ActiveOrHistoricCurrencyCode" minOccurs="0"/>
+                       <!-- V01: unused
+                       <xs:element name="Tp" type="CashAccountType2" 
minOccurs="0"/>
+                       <xs:element name="Nm" type="Max70Text" minOccurs="0"/>
+                       -->
+               </xs:sequence>
+       </xs:complexType>
+       <!-- V01: added -->
+       <xs:complexType name="CashAccount16-CH_IdTpCcy">
+               <xs:sequence>
+                       <xs:element name="Id" 
type="AccountIdentification4Choice-CH"/>
+                       <xs:element name="Tp" type="CashAccountType2" 
minOccurs="0"/>
+                       <xs:element name="Ccy" 
type="ActiveOrHistoricCurrencyCode" minOccurs="0"/>
+                       <!-- V01: unused
+                       <xs:element name="Nm" type="Max70Text" minOccurs="0"/>
+                       -->
+               </xs:sequence>
+       </xs:complexType>
+       <!-- V01: added -->
+       <xs:complexType name="CashAccount16-CH_Id">
+               <xs:sequence>
+                       <xs:element name="Id" 
type="AccountIdentification4Choice-CH"/>
+                       <!-- V01: unused
+                       <xs:element name="Tp" type="CashAccountType2" 
minOccurs="0"/>
+                       <xs:element name="Ccy" 
type="ActiveOrHistoricCurrencyCode" minOccurs="0"/>
+                       <xs:element name="Nm" type="Max70Text" minOccurs="0"/>
+                       -->
+               </xs:sequence>
+       </xs:complexType>
+       <xs:complexType name="CashAccountType2">
+               <xs:sequence>
+                       <xs:choice>
+                               <xs:element name="Cd" 
type="CashAccountType4Code"/>
+                               <xs:element name="Prtry" type="Max35Text"/>
+                       </xs:choice>
+               </xs:sequence>
+       </xs:complexType>
+       <xs:simpleType name="CashAccountType4Code">
+               <xs:restriction base="xs:string">
+                       <xs:enumeration value="CASH"/>
+                       <xs:enumeration value="CHAR"/>
+                       <xs:enumeration value="COMM"/>
+                       <xs:enumeration value="TAXE"/>
+                       <xs:enumeration value="CISH"/>
+                       <xs:enumeration value="TRAS"/>
+                       <xs:enumeration value="SACC"/>
+                       <xs:enumeration value="CACC"/>
+                       <xs:enumeration value="SVGS"/>
+                       <xs:enumeration value="ONDP"/>
+                       <xs:enumeration value="MGLD"/>
+                       <xs:enumeration value="NREX"/>
+                       <xs:enumeration value="MOMA"/>
+                       <xs:enumeration value="LOAN"/>
+                       <xs:enumeration value="SLRY"/>
+                       <xs:enumeration value="ODFT"/>
+               </xs:restriction>
+       </xs:simpleType>
+       <!-- V01: changed: Only element Code allowed in Ch version -->
+       <xs:complexType name="CategoryPurpose1-CH_Code">
+               <xs:sequence>
+                       <xs:element name="Cd" 
type="ExternalCategoryPurpose1Code"/>
+                       <!-- V01: unused
+                               <xs:element name="Prtry" type="Max35Text"/>
+                               -->
+               </xs:sequence>
+       </xs:complexType>
+       <!-- -->
+       <xs:simpleType name="ChargeBearerType1Code">
+               <xs:restriction base="xs:string">
+                       <xs:enumeration value="DEBT"/>
+                       <xs:enumeration value="CRED"/>
+                       <xs:enumeration value="SHAR"/>
+                       <xs:enumeration value="SLEV"/>
+               </xs:restriction>
+       </xs:simpleType>
+       <!-- V01: unused
+       <xs:complexType name="Cheque6">
+               <xs:sequence>
+                       <xs:element name="ChqTp" type="ChequeType2Code" 
minOccurs="0"/>
+                       <xs:element name="ChqNb" type="Max35Text" 
minOccurs="0"/>
+                       <xs:element name="ChqFr" type="NameAndAddress10" 
minOccurs="0"/>
+                       <xs:element name="DlvryMtd" 
type="ChequeDeliveryMethod1Choice" minOccurs="0"/>
+                       <xs:element name="DlvrTo" type="NameAndAddress10" 
minOccurs="0"/>
+                       <xs:element name="InstrPrty" type="Priority2Code" 
minOccurs="0"/>
+                       <xs:element name="ChqMtrtyDt" type="ISODate" 
minOccurs="0"/>
+                       <xs:element name="FrmsCd" type="Max35Text" 
minOccurs="0"/>
+                       <xs:element name="MemoFld" type="Max35Text" 
minOccurs="0" maxOccurs="2"/>
+                       <xs:element name="RgnlClrZone" type="Max35Text" 
minOccurs="0"/>
+                       <xs:element name="PrtLctn" type="Max35Text" 
minOccurs="0"/>
+               </xs:sequence>
+       </xs:complexType>
+    -->
+       <!-- V01: added -->
+       <xs:complexType name="Cheque6-CH">
+               <xs:sequence>
+                       <xs:element name="ChqTp" type="ChequeType2Code" 
minOccurs="0"/>
+                       <xs:element name="DlvryMtd" 
type="ChequeDeliveryMethod1Choice" minOccurs="0"/>
+                       <!-- V01: unused
+                       <xs:element name="ChqNb" type="Max35Text" 
minOccurs="0"/>
+                       <xs:element name="ChqFr" type="NameAndAddress10" 
minOccurs="0"/>
+                       <xs:element name="DlvrTo" type="NameAndAddress10" 
minOccurs="0"/>
+                       <xs:element name="InstrPrty" type="Priority2Code" 
minOccurs="0"/>
+                       <xs:element name="ChqMtrtyDt" type="ISODate" 
minOccurs="0"/>
+                       <xs:element name="FrmsCd" type="Max35Text" 
minOccurs="0"/>
+                       <xs:element name="MemoFld" type="Max35Text" 
minOccurs="0" maxOccurs="2"/>
+                       <xs:element name="RgnlClrZone" type="Max35Text" 
minOccurs="0"/>
+                       <xs:element name="PrtLctn" type="Max35Text" 
minOccurs="0"/>
+                       -->
+               </xs:sequence>
+       </xs:complexType>
+       <xs:simpleType name="ChequeDelivery1Code">
+               <xs:restriction base="xs:string">
+                       <xs:enumeration value="MLDB"/>
+                       <xs:enumeration value="MLCD"/>
+                       <xs:enumeration value="MLFA"/>
+                       <xs:enumeration value="CRDB"/>
+                       <xs:enumeration value="CRCD"/>
+                       <xs:enumeration value="CRFA"/>
+                       <xs:enumeration value="PUDB"/>
+                       <xs:enumeration value="PUCD"/>
+                       <xs:enumeration value="PUFA"/>
+                       <xs:enumeration value="RGDB"/>
+                       <xs:enumeration value="RGCD"/>
+                       <xs:enumeration value="RGFA"/>
+               </xs:restriction>
+       </xs:simpleType>
+       <xs:complexType name="ChequeDeliveryMethod1Choice">
+               <xs:sequence>
+                       <xs:choice>
+                               <xs:element name="Cd" 
type="ChequeDelivery1Code"/>
+                               <xs:element name="Prtry" type="Max35Text"/>
+                       </xs:choice>
+               </xs:sequence>
+       </xs:complexType>
+       <xs:simpleType name="ChequeType2Code">
+               <xs:restriction base="xs:string">
+                       <xs:enumeration value="CCHQ"/>
+                       <xs:enumeration value="CCCH"/>
+                       <xs:enumeration value="BCHQ"/>
+                       <xs:enumeration value="DRFT"/>
+                       <xs:enumeration value="ELDR"/>
+               </xs:restriction>
+       </xs:simpleType>
+       <xs:complexType name="ClearingSystemIdentification2Choice">
+               <xs:sequence>
+                       <xs:choice>
+                               <xs:element name="Cd" 
type="ExternalClearingSystemIdentification1Code"/>
+                               <xs:element name="Prtry" type="Max35Text"/>
+                       </xs:choice>
+               </xs:sequence>
+       </xs:complexType>
+       <xs:complexType name="ClearingSystemMemberIdentification2">
+               <xs:sequence>
+                       <xs:element name="ClrSysId" 
type="ClearingSystemIdentification2Choice" minOccurs="0"/>
+                       <xs:element name="MmbId" type="Max35Text"/>
+               </xs:sequence>
+       </xs:complexType>
+       <xs:complexType name="ContactDetails2">
+               <xs:sequence>
+                       <xs:element name="NmPrfx" type="NamePrefix1Code" 
minOccurs="0"/>
+                       <xs:element name="Nm" type="Max140Text" minOccurs="0"/>
+                       <xs:element name="PhneNb" type="PhoneNumber" 
minOccurs="0"/>
+                       <xs:element name="MobNb" type="PhoneNumber" 
minOccurs="0"/>
+                       <xs:element name="FaxNb" type="PhoneNumber" 
minOccurs="0"/>
+                       <xs:element name="EmailAdr" type="Max2048Text" 
minOccurs="0"/>
+                       <xs:element name="Othr" type="Max35Text" minOccurs="0"/>
+               </xs:sequence>
+       </xs:complexType>
+       <!-- V02: changed: include Contact Details for Software name and 
version -->
+       <xs:complexType name="ContactDetails2-CH">
+               <xs:sequence>
+                       <xs:element name="Nm" type="Max70Text" minOccurs="0"/>
+                       <xs:element name="Othr" type="Max35Text" minOccurs="0"/>
+                       <!-- V02: unused
+                       <xs:element name="NmPrfx" type="NamePrefix1Code" 
minOccurs="0"/>
+                       <xs:element name="PhneNb" type="PhoneNumber" 
minOccurs="0"/>
+                       <xs:element name="MobNb" type="PhoneNumber" 
minOccurs="0"/>
+                       <xs:element name="FaxNb" type="PhoneNumber" 
minOccurs="0"/>
+                       <xs:element name="EmailAdr" type="Max2048Text" 
minOccurs="0"/>
+                       -->
+               </xs:sequence>
+       </xs:complexType>
+       <xs:simpleType name="CountryCode">
+               <xs:restriction base="xs:string">
+                       <xs:pattern value="[A-Z]{2,2}"/>
+               </xs:restriction>
+       </xs:simpleType>
+       <xs:simpleType name="CreditDebitCode">
+               <xs:restriction base="xs:string">
+                       <xs:enumeration value="CRDT"/>
+                       <xs:enumeration value="DBIT"/>
+               </xs:restriction>
+       </xs:simpleType>
+       <xs:complexType name="CreditTransferTransactionInformation10-CH">
+               <xs:sequence>
+                       <xs:element name="PmtId" type="PaymentIdentification1"/>
+                       <xs:element name="PmtTpInf" 
type="PaymentTypeInformation19-CH" minOccurs="0"/>
+                       <xs:element name="Amt" type="AmountType3Choice"/>
+                       <xs:element name="XchgRateInf" 
type="ExchangeRateInformation1" minOccurs="0"/>
+                       <xs:element name="ChrgBr" type="ChargeBearerType1Code" 
minOccurs="0"/>
+                       <xs:element name="ChqInstr" type="Cheque6-CH" 
minOccurs="0"/>
+                       <xs:element name="UltmtDbtr" 
type="PartyIdentification32-CH" minOccurs="0"/>
+                       <xs:element name="IntrmyAgt1" 
type="BranchAndFinancialInstitutionIdentification4-CH" minOccurs="0"/>
+                       <xs:element name="CdtrAgt" 
type="BranchAndFinancialInstitutionIdentification4-CH" minOccurs="0"/>
+                       <!-- V02: changed:  element Name mandatory -->
+                       <xs:element name="Cdtr" 
type="PartyIdentification32-CH_Name" minOccurs="0"/>
+                       <xs:element name="CdtrAcct" type="CashAccount16-CH_Id" 
minOccurs="0"/>
+                       <!-- V02: changed:  element Name mandatory -->
+                       <xs:element name="UltmtCdtr" 
type="PartyIdentification32-CH_Name" minOccurs="0"/>
+                       <xs:element name="InstrForCdtrAgt" 
type="InstructionForCreditorAgent1" minOccurs="0" maxOccurs="unbounded"/>
+                       <xs:element name="InstrForDbtrAgt" type="Max140Text" 
minOccurs="0"/>
+                       <xs:element name="Purp" type="Purpose2-CH_Code" 
minOccurs="0"/>
+                       <xs:element name="RgltryRptg" 
type="RegulatoryReporting3" minOccurs="0" maxOccurs="10"/>
+                       <xs:element name="RmtInf" 
type="RemittanceInformation5-CH" minOccurs="0"/>
+                       <!-- V01: usused
+                       <xs:element name="IntrmyAgt1Acct" type="CashAccount16" 
minOccurs="0"/>
+                       <xs:element name="IntrmyAgt2" 
type="BranchAndFinancialInstitutionIdentification4" minOccurs="0"/>
+                       <xs:element name="IntrmyAgt2Acct" type="CashAccount16" 
minOccurs="0"/>
+                       <xs:element name="IntrmyAgt3" 
type="BranchAndFinancialInstitutionIdentification4" minOccurs="0"/>
+                       <xs:element name="IntrmyAgt3Acct" type="CashAccount16" 
minOccurs="0"/>
+                       <xs:element name="CdtrAgtAcct" 
type="CashAccount16-CH_Id" minOccurs="0"/>
+                       <xs:element name="Tax" type="TaxInformation3" 
minOccurs="0"/>
+                       <xs:element name="RltdRmtInf" 
type="RemittanceLocation2" minOccurs="0" maxOccurs="10"/>
+                       -->
+               </xs:sequence>
+       </xs:complexType>
+       <xs:complexType name="CreditorReferenceInformation2">
+               <xs:sequence>
+                       <xs:element name="Tp" type="CreditorReferenceType2" 
minOccurs="0"/>
+                       <xs:element name="Ref" type="Max35Text" minOccurs="0"/>
+               </xs:sequence>
+       </xs:complexType>
+       <xs:complexType name="CreditorReferenceType1Choice">
+               <xs:sequence>
+                       <xs:choice>
+                               <xs:element name="Cd" type="DocumentType3Code"/>
+                               <xs:element name="Prtry" type="Max35Text"/>
+                       </xs:choice>
+               </xs:sequence>
+       </xs:complexType>
+       <xs:complexType name="CreditorReferenceType2">
+               <xs:sequence>
+                       <xs:element name="CdOrPrtry" 
type="CreditorReferenceType1Choice"/>
+                       <xs:element name="Issr" type="Max35Text" minOccurs="0"/>
+               </xs:sequence>
+       </xs:complexType>
+       <xs:complexType name="CustomerCreditTransferInitiationV03-CH">
+               <xs:sequence>
+                       <xs:element name="GrpHdr" type="GroupHeader32-CH"/>
+                       <xs:element name="PmtInf" 
type="PaymentInstructionInformation3-CH" maxOccurs="unbounded"/>
+               </xs:sequence>
+       </xs:complexType>
+       <xs:complexType name="DateAndPlaceOfBirth">
+               <xs:sequence>
+                       <xs:element name="BirthDt" type="ISODate"/>
+                       <xs:element name="PrvcOfBirth" type="Max35Text" 
minOccurs="0"/>
+                       <xs:element name="CityOfBirth" type="Max35Text"/>
+                       <xs:element name="CtryOfBirth" type="CountryCode"/>
+               </xs:sequence>
+       </xs:complexType>
+       <!-- V01: unused
+       <xs:complexType name="DatePeriodDetails">
+               <xs:sequence>
+                       <xs:element name="FrDt" type="ISODate"/>
+                       <xs:element name="ToDt" type="ISODate"/>
+               </xs:sequence>
+       </xs:complexType>
+    -->
+       <xs:simpleType name="DecimalNumber">
+               <xs:restriction base="xs:decimal">
+                       <xs:fractionDigits value="17"/>
+                       <xs:totalDigits value="18"/>
+               </xs:restriction>
+       </xs:simpleType>
+       <xs:complexType name="Document">
+               <xs:sequence>
+                       <xs:element name="CstmrCdtTrfInitn" 
type="CustomerCreditTransferInitiationV03-CH"/>
+               </xs:sequence>
+       </xs:complexType>
+       <xs:complexType name="DocumentAdjustment1">
+               <xs:sequence>
+                       <xs:element name="Amt" 
type="ActiveOrHistoricCurrencyAndAmount"/>
+                       <xs:element name="CdtDbtInd" type="CreditDebitCode" 
minOccurs="0"/>
+                       <xs:element name="Rsn" type="Max4Text" minOccurs="0"/>
+                       <xs:element name="AddtlInf" type="Max140Text" 
minOccurs="0"/>
+               </xs:sequence>
+       </xs:complexType>
+       <xs:simpleType name="DocumentType3Code">
+               <xs:restriction base="xs:string">
+                       <xs:enumeration value="RADM"/>
+                       <xs:enumeration value="RPIN"/>
+                       <xs:enumeration value="FXDR"/>
+                       <xs:enumeration value="DISP"/>
+                       <xs:enumeration value="PUOR"/>
+                       <xs:enumeration value="SCOR"/>
+               </xs:restriction>
+       </xs:simpleType>
+       <xs:simpleType name="DocumentType5Code">
+               <xs:restriction base="xs:string">
+                       <xs:enumeration value="MSIN"/>
+                       <xs:enumeration value="CNFA"/>
+                       <xs:enumeration value="DNFA"/>
+                       <xs:enumeration value="CINV"/>
+                       <xs:enumeration value="CREN"/>
+                       <xs:enumeration value="DEBN"/>
+                       <xs:enumeration value="HIRI"/>
+                       <xs:enumeration value="SBIN"/>
+                       <xs:enumeration value="CMCN"/>
+                       <xs:enumeration value="SOAC"/>
+                       <xs:enumeration value="DISP"/>
+                       <xs:enumeration value="BOLD"/>
+                       <xs:enumeration value="VCHR"/>
+                       <xs:enumeration value="AROI"/>
+                       <xs:enumeration value="TSUT"/>
+               </xs:restriction>
+       </xs:simpleType>
+       <xs:complexType name="EquivalentAmount2">
+               <xs:sequence>
+                       <xs:element name="Amt" 
type="ActiveOrHistoricCurrencyAndAmount"/>
+                       <xs:element name="CcyOfTrf" 
type="ActiveOrHistoricCurrencyCode"/>
+               </xs:sequence>
+       </xs:complexType>
+       <xs:complexType name="ExchangeRateInformation1">
+               <xs:sequence>
+                       <xs:element name="XchgRate" type="BaseOneRate" 
minOccurs="0"/>
+                       <xs:element name="RateTp" type="ExchangeRateType1Code" 
minOccurs="0"/>
+                       <xs:element name="CtrctId" type="Max35Text" 
minOccurs="0"/>
+               </xs:sequence>
+       </xs:complexType>
+       <xs:simpleType name="ExchangeRateType1Code">
+               <xs:restriction base="xs:string">
+                       <xs:enumeration value="SPOT"/>
+                       <xs:enumeration value="SALE"/>
+                       <xs:enumeration value="AGRD"/>
+               </xs:restriction>
+       </xs:simpleType>
+       <!-- V01:  unused:
+       <xs:simpleType name="ExternalAccountIdentification1Code">
+               <xs:restriction base="xs:string">
+                       <xs:minLength value="1"/>
+                       <xs:maxLength value="4"/>
+               </xs:restriction>
+       </xs:simpleType>
+    -->
+       <xs:simpleType name="ExternalCategoryPurpose1Code">
+               <xs:restriction base="xs:string">
+                       <xs:minLength value="1"/>
+                       <xs:maxLength value="4"/>
+               </xs:restriction>
+       </xs:simpleType>
+       <xs:simpleType name="ExternalClearingSystemIdentification1Code">
+               <xs:restriction base="xs:string">
+                       <xs:minLength value="1"/>
+                       <xs:maxLength value="5"/>
+               </xs:restriction>
+       </xs:simpleType>
+       <xs:simpleType name="ExternalFinancialInstitutionIdentification1Code">
+               <xs:restriction base="xs:string">
+                       <xs:minLength value="1"/>
+                       <xs:maxLength value="4"/>
+               </xs:restriction>
+       </xs:simpleType>
+       <xs:simpleType name="ExternalLocalInstrument1Code">
+               <xs:restriction base="xs:string">
+                       <xs:minLength value="1"/>
+                       <xs:maxLength value="35"/>
+               </xs:restriction>
+       </xs:simpleType>
+       <xs:simpleType name="ExternalOrganisationIdentification1Code">
+               <xs:restriction base="xs:string">
+                       <xs:minLength value="1"/>
+                       <xs:maxLength value="4"/>
+               </xs:restriction>
+       </xs:simpleType>
+       <xs:simpleType name="ExternalPersonIdentification1Code">
+               <xs:restriction base="xs:string">
+                       <xs:minLength value="1"/>
+                       <xs:maxLength value="4"/>
+               </xs:restriction>
+       </xs:simpleType>
+       <xs:simpleType name="ExternalPurpose1Code">
+               <xs:restriction base="xs:string">
+                       <xs:minLength value="1"/>
+                       <xs:maxLength value="4"/>
+               </xs:restriction>
+       </xs:simpleType>
+       <xs:simpleType name="ExternalServiceLevel1Code">
+               <xs:restriction base="xs:string">
+                       <xs:minLength value="1"/>
+                       <xs:maxLength value="4"/>
+               </xs:restriction>
+       </xs:simpleType>
+       <xs:complexType name="FinancialIdentificationSchemeName1Choice">
+               <xs:sequence>
+                       <xs:choice>
+                               <xs:element name="Cd" 
type="ExternalFinancialInstitutionIdentification1Code"/>
+                               <xs:element name="Prtry" type="Max35Text"/>
+                       </xs:choice>
+               </xs:sequence>
+       </xs:complexType>
+       <xs:complexType name="FinancialInstitutionIdentification7">
+               <xs:sequence>
+                       <xs:element name="BIC" type="BICIdentifier" 
minOccurs="0"/>
+                       <xs:element name="ClrSysMmbId" 
type="ClearingSystemMemberIdentification2" minOccurs="0"/>
+                       <xs:element name="Nm" type="Max140Text" minOccurs="0"/>
+                       <xs:element name="PstlAdr" type="PostalAddress6" 
minOccurs="0"/>
+                       <xs:element name="Othr" 
type="GenericFinancialIdentification1" minOccurs="0"/>
+               </xs:sequence>
+       </xs:complexType>
+       <!-- V01: added: definition of FI where only BIC or Clearing Id is 
allowed -->
+       <xs:complexType 
name="FinancialInstitutionIdentification7-CH_BicOrClrId">
+               <xs:sequence>
+                       <xs:element name="BIC" type="BICIdentifier" 
minOccurs="0"/>
+                       <xs:element name="ClrSysMmbId" 
type="ClearingSystemMemberIdentification2" minOccurs="0"/>
+                       <!-- V01: unused
+                       <xs:element name="Nm" type="Max140Text" minOccurs="0"/>
+                       <xs:element name="PstlAdr" type="PostalAddress6" 
minOccurs="0"/>
+                       <xs:element name="Othr" 
type="GenericFinancialIdentification1" minOccurs="0"/>
+                       -->
+               </xs:sequence>
+       </xs:complexType>
+       <!-- V01: added: definition of FI where all elements are allowed (in a 
CH version) -->
+       <xs:complexType name="FinancialInstitutionIdentification7-CH">
+               <xs:sequence>
+                       <xs:element name="BIC" type="BICIdentifier" 
minOccurs="0"/>
+                       <xs:element name="ClrSysMmbId" 
type="ClearingSystemMemberIdentification2" minOccurs="0"/>
+                       <xs:element name="Nm" type="Max70Text" minOccurs="0"/>
+                       <xs:element name="PstlAdr" type="PostalAddress6-CH" 
minOccurs="0"/>
+                       <xs:element name="Othr" 
type="GenericFinancialIdentification1-CH" minOccurs="0"/>
+                       <!-- V01: unused
+                       -->
+               </xs:sequence>
+       </xs:complexType>
+       <!-- V01: changed: only element ID allowed in CH version -->
+       <xs:complexType name="GenericAccountIdentification1-CH">
+               <xs:sequence>
+                       <xs:element name="Id" type="Max34Text"/>
+                       <!-- V01: unused
+                       <xs:element name="SchmeNm" 
type="AccountSchemeName1Choice" minOccurs="0"/>
+                       <xs:element name="Issr" type="Max35Text" minOccurs="0"/>
+                       -->
+               </xs:sequence>
+       </xs:complexType>
+       <xs:complexType name="GenericFinancialIdentification1">
+               <xs:sequence>
+                       <xs:element name="Id" type="Max35Text"/>
+                       <xs:element name="SchmeNm" 
type="FinancialIdentificationSchemeName1Choice" minOccurs="0"/>
+                       <xs:element name="Issr" type="Max35Text" minOccurs="0"/>
+               </xs:sequence>
+       </xs:complexType>
+       <!-- V01: added: only element Id allowed in CH version -->
+       <xs:complexType name="GenericFinancialIdentification1-CH">
+               <xs:sequence>
+                       <xs:element name="Id" type="Max35Text"/>
+                       <!-- V01: unused
+                       <xs:element name="SchmeNm" 
type="FinancialIdentificationSchemeName1Choice" minOccurs="0"/>
+                       <xs:element name="Issr" type="Max35Text" minOccurs="0"/>
+                       -->
+               </xs:sequence>
+       </xs:complexType>
+       <xs:complexType name="GenericOrganisationIdentification1">
+               <xs:sequence>
+                       <xs:element name="Id" type="Max35Text"/>
+                       <xs:element name="SchmeNm" 
type="OrganisationIdentificationSchemeName1Choice" minOccurs="0"/>
+                       <xs:element name="Issr" type="Max35Text" minOccurs="0"/>
+               </xs:sequence>
+       </xs:complexType>
+       <xs:complexType name="GenericPersonIdentification1">
+               <xs:sequence>
+                       <xs:element name="Id" type="Max35Text"/>
+                       <xs:element name="SchmeNm" 
type="PersonIdentificationSchemeName1Choice" minOccurs="0"/>
+                       <xs:element name="Issr" type="Max35Text" minOccurs="0"/>
+               </xs:sequence>
+       </xs:complexType>
+       <xs:complexType name="GroupHeader32-CH">
+               <xs:sequence>
+                       <xs:element name="MsgId" type="Max35Text-Swift"/>
+                       <xs:element name="CreDtTm" type="ISODateTime"/>
+                       <xs:element name="NbOfTxs" type="Max15NumericText"/>
+                       <xs:element name="CtrlSum" type="DecimalNumber" 
minOccurs="0"/>
+                       <!-- V02: changed: include Contact Details for Software 
name and version -->
+                       <xs:element name="InitgPty" 
type="PartyIdentification32-CH_NameAndId"/>
+                       <xs:element name="FwdgAgt" 
type="BranchAndFinancialInstitutionIdentification4" minOccurs="0"/>
+                       <!-- V01: unused: type Authorisation1Choice is not 
allowed or used in CH Version
+                       <xs:element name="Authstn" type="Authorisation1Choice" 
minOccurs="0" maxOccurs="2"/>
+                       -->
+                       <!-- V01: changed: Initiating party only to contain 
name and id in CH version
+                       <xs:element name="InitgPty" 
type="PartyIdentification32"/>
+                       -->
+               </xs:sequence>
+       </xs:complexType>
+       <xs:simpleType name="IBAN2007Identifier">
+               <xs:restriction base="xs:string">
+                       <xs:pattern 
value="[A-Z]{2,2}[0-9]{2,2}[a-zA-Z0-9]{1,30}"/>
+               </xs:restriction>
+       </xs:simpleType>
+       <xs:simpleType name="ISODate">
+               <xs:restriction base="xs:date"/>
+       </xs:simpleType>
+       <xs:simpleType name="ISODateTime">
+               <xs:restriction base="xs:dateTime"/>
+       </xs:simpleType>
+       <xs:simpleType name="Instruction3Code">
+               <xs:restriction base="xs:string">
+                       <xs:enumeration value="CHQB"/>
+                       <xs:enumeration value="HOLD"/>
+                       <xs:enumeration value="PHOB"/>
+                       <xs:enumeration value="TELB"/>
+               </xs:restriction>
+       </xs:simpleType>
+       <xs:complexType name="InstructionForCreditorAgent1">
+               <xs:sequence>
+                       <xs:element name="Cd" type="Instruction3Code" 
minOccurs="0"/>
+                       <xs:element name="InstrInf" type="Max140Text" 
minOccurs="0"/>
+               </xs:sequence>
+       </xs:complexType>
+       <xs:complexType name="LocalInstrument2Choice">
+               <xs:sequence>
+                       <xs:choice>
+                               <xs:element name="Cd" 
type="ExternalLocalInstrument1Code"/>
+                               <xs:element name="Prtry" type="Max35Text"/>
+                       </xs:choice>
+               </xs:sequence>
+       </xs:complexType>
+       <xs:simpleType name="Max10Text">
+               <xs:restriction base="BasicText-CH">
+                       <xs:minLength value="1"/>
+                       <xs:maxLength value="10"/>
+               </xs:restriction>
+       </xs:simpleType>
+       <!-- V01: unused
+       <xs:simpleType name="Max128Text">
+               <xs:restriction base="BasicText-CH">
+                       <xs:minLength value="1"/>
+                       <xs:maxLength value="128"/>
+               </xs:restriction>
+       </xs:simpleType>
+    -->
+       <xs:simpleType name="Max140Text">
+               <xs:restriction base="BasicText-CH">
+                       <xs:minLength value="1"/>
+                       <xs:maxLength value="140"/>
+               </xs:restriction>
+       </xs:simpleType>
+       <xs:simpleType name="Max15NumericText">
+               <xs:restriction base="xs:string">
+                       <xs:pattern value="[0-9]{1,15}"/>
+               </xs:restriction>
+       </xs:simpleType>
+       <xs:simpleType name="Max16Text">
+               <xs:restriction base="BasicText-CH">
+                       <xs:minLength value="1"/>
+                       <xs:maxLength value="16"/>
+               </xs:restriction>
+       </xs:simpleType>
+       <xs:simpleType name="Max2048Text">
+               <xs:restriction base="BasicText-CH">
+                       <xs:minLength value="1"/>
+                       <xs:maxLength value="2048"/>
+               </xs:restriction>
+       </xs:simpleType>
+       <xs:simpleType name="Max34Text">
+               <xs:restriction base="BasicText-CH">
+                       <xs:minLength value="1"/>
+                       <xs:maxLength value="34"/>
+               </xs:restriction>
+       </xs:simpleType>
+       <xs:simpleType name="Max35Text">
+               <xs:restriction base="BasicText-CH">
+                       <xs:minLength value="1"/>
+                       <xs:maxLength value="35"/>
+               </xs:restriction>
+       </xs:simpleType>
+       <!-- V01: added: replacement type for Max35Text where only the Swift 
character set is allowed -->
+       <xs:simpleType name="Max35Text-Swift">
+               <xs:restriction base="BasicText-Swift">
+                       <xs:minLength value="1"/>
+                       <xs:maxLength value="35"/>
+               </xs:restriction>
+       </xs:simpleType>
+       <xs:simpleType name="Max4Text">
+               <xs:restriction base="BasicText-CH">
+                       <xs:minLength value="1"/>
+                       <xs:maxLength value="4"/>
+               </xs:restriction>
+       </xs:simpleType>
+       <xs:simpleType name="Max70Text">
+               <xs:restriction base="BasicText-CH">
+                       <xs:minLength value="1"/>
+                       <xs:maxLength value="70"/>
+               </xs:restriction>
+       </xs:simpleType>
+       <!-- V01: unused
+       <xs:complexType name="NameAndAddress10">
+               <xs:sequence>
+                       <xs:element name="Nm" type="Max140Text"/>
+                       <xs:element name="Adr" type="PostalAddress6"/>
+               </xs:sequence>
+       </xs:complexType>
+    -->
+       <!-- V01: added: CH-Version: unused (prepared for later usage)
+       <xs:complexType name="NameAndAddress10-CH">
+               <xs:sequence>
+                       <xs:element name="Nm" type="Max70Text"/>
+                       <xs:element name="Adr" type="PostalAddress6-CH"/>
+               </xs:sequence>
+       </xs:complexType>
+    -->
+       <xs:simpleType name="NamePrefix1Code">
+               <xs:restriction base="xs:string">
+                       <xs:enumeration value="DOCT"/>
+                       <xs:enumeration value="MIST"/>
+                       <xs:enumeration value="MISS"/>
+                       <xs:enumeration value="MADM"/>
+               </xs:restriction>
+       </xs:simpleType>
+       <!-- V01: unused
+       <xs:simpleType name="Number">
+               <xs:restriction base="xs:decimal">
+                       <xs:fractionDigits value="0"/>
+                       <xs:totalDigits value="18"/>
+               </xs:restriction>
+       </xs:simpleType>
+    -->
+       <xs:complexType name="OrganisationIdentification4">
+               <xs:sequence>
+                       <xs:element name="BICOrBEI" type="AnyBICIdentifier" 
minOccurs="0"/>
+                       <xs:element name="Othr" 
type="GenericOrganisationIdentification1" minOccurs="0" maxOccurs="unbounded"/>
+               </xs:sequence>
+       </xs:complexType>
+       <!-- V01: added:  only one occurance of element other allowed in CH 
version -->
+       <xs:complexType name="OrganisationIdentification4-CH">
+               <xs:sequence>
+                       <xs:element name="BICOrBEI" type="AnyBICIdentifier" 
minOccurs="0"/>
+                       <xs:element name="Othr" 
type="GenericOrganisationIdentification1" minOccurs="0"/>
+               </xs:sequence>
+       </xs:complexType>
+       <xs:complexType name="OrganisationIdentificationSchemeName1Choice">
+               <xs:sequence>
+                       <xs:choice>
+                               <xs:element name="Cd" 
type="ExternalOrganisationIdentification1Code"/>
+                               <xs:element name="Prtry" type="Max35Text"/>
+                       </xs:choice>
+               </xs:sequence>
+       </xs:complexType>
+       <xs:complexType name="Party6Choice">
+               <xs:sequence>
+                       <xs:choice>
+                               <xs:element name="OrgId" 
type="OrganisationIdentification4"/>
+                               <xs:element name="PrvtId" 
type="PersonIdentification5"/>
+                       </xs:choice>
+               </xs:sequence>
+       </xs:complexType>
+       <!-- V01: added:  -->
+       <xs:complexType name="Party6Choice-CH">
+               <xs:sequence>
+                       <xs:choice>
+                               <xs:element name="OrgId" 
type="OrganisationIdentification4-CH"/>
+                               <xs:element name="PrvtId" 
type="PersonIdentification5-CH"/>
+                       </xs:choice>
+               </xs:sequence>
+       </xs:complexType>
+       <xs:complexType name="PartyIdentification32">
+               <xs:sequence>
+                       <xs:element name="Nm" type="Max140Text" minOccurs="0"/>
+                       <xs:element name="PstlAdr" type="PostalAddress6" 
minOccurs="0"/>
+                       <xs:element name="Id" type="Party6Choice" 
minOccurs="0"/>
+                       <xs:element name="CtryOfRes" type="CountryCode" 
minOccurs="0"/>
+                       <xs:element name="CtctDtls" type="ContactDetails2" 
minOccurs="0"/>
+               </xs:sequence>
+       </xs:complexType>
+       <!-- V01: added: replacement type for PartyIdentification8 where only 
elements Name and Id may be used -->
+       <xs:complexType name="PartyIdentification32-CH_NameAndId">
+               <xs:sequence>
+                       <xs:element name="Nm" type="Max70Text" minOccurs="0"/>
+                       <xs:element name="Id" type="Party6Choice-CH" 
minOccurs="0"/>
+                       <!-- V02: added: Contact Details for Software name and 
version -->
+                       <xs:element name="CtctDtls" type="ContactDetails2-CH" 
minOccurs="0"/>
+               </xs:sequence>
+       </xs:complexType>
+       <!-- V01: added -->
+       <xs:complexType name="PartyIdentification32-CH">
+               <xs:sequence>
+                       <xs:element name="Nm" type="Max70Text" minOccurs="0"/>
+                       <xs:element name="PstlAdr" type="PostalAddress6-CH" 
minOccurs="0"/>
+                       <xs:element name="Id" type="Party6Choice-CH" 
minOccurs="0"/>
+                       <!-- changed -->
+                       <!-- unused
+                       <xs:element name="CtryOfRes" type="CountryCode" 
minOccurs="0"/>
+                       -->
+               </xs:sequence>
+       </xs:complexType>
+       <!-- V02: changed: element Name mandatory -->
+       <xs:complexType name="PartyIdentification32-CH_Name">
+               <xs:sequence>
+                       <xs:element name="Nm" type="Max70Text"/>
+                       <xs:element name="PstlAdr" type="PostalAddress6-CH" 
minOccurs="0"/>
+                       <xs:element name="Id" type="Party6Choice-CH" 
minOccurs="0"/>
+                       <!-- changed -->
+                       <!-- unused
+                       <xs:element name="CtryOfRes" type="CountryCode" 
minOccurs="0"/>
+                       -->
+               </xs:sequence>
+       </xs:complexType>
+       <!--
+       <xs:complexType name="PartyIdentification32-CH_Debtor">
+               <xs:sequence>
+                       <xs:element name="Nm" type="Max70Text" minOccurs="0"/>
+                       <xs:element name="PstlAdr" type="PostalAddress6-CH" 
minOccurs="0"/>
+                       <xs:element name="Id" type="Party6Choice-CH" 
minOccurs="0"/>
+
+                       <xs:element name="CtryOfRes" type="CountryCode" 
minOccurs="0"/>
+                       <xs:element name="CtctDtls" type="ContactDetails2" 
minOccurs="0"/>
+
+               </xs:sequence>
+       </xs:complexType>
+
+       <xs:complexType name="PartyIdentification32-CH_Creditor">
+               <xs:sequence>
+                       <xs:element name="Nm" type="Max70Text" minOccurs="0"/>
+                       <xs:element name="PstlAdr" type="PostalAddress6-CH" 
minOccurs="0"/>
+                       <xs:element name="Id" type="Party6Choice-CH" 
minOccurs="0"/>
+
+                       <xs:element name="CtryOfRes" type="CountryCode" 
minOccurs="0"/>
+                       <xs:element name="CtctDtls" type="ContactDetails2" 
minOccurs="0"/>
+
+               </xs:sequence>
+       </xs:complexType>
+       -->
+       <xs:complexType name="PaymentIdentification1">
+               <xs:sequence>
+                       <xs:element name="InstrId" type="Max35Text-Swift" 
minOccurs="0"/>
+                       <xs:element name="EndToEndId" type="Max35Text-Swift"/>
+               </xs:sequence>
+       </xs:complexType>
+       <!-- V01: changed: CH-version changes applied -->
+       <xs:complexType name="PaymentInstructionInformation3-CH">
+               <xs:sequence>
+                       <xs:element name="PmtInfId" type="Max35Text-Swift"/>
+                       <xs:element name="PmtMtd" type="PaymentMethod3Code"/>
+                       <xs:element name="BtchBookg" 
type="BatchBookingIndicator" minOccurs="0"/>
+                       <xs:element name="NbOfTxs" type="Max15NumericText" 
minOccurs="0"/>
+                       <xs:element name="CtrlSum" type="DecimalNumber" 
minOccurs="0"/>
+                       <xs:element name="PmtTpInf" 
type="PaymentTypeInformation19-CH" minOccurs="0"/>
+                       <xs:element name="ReqdExctnDt" type="ISODate"/>
+                       <xs:element name="Dbtr" 
type="PartyIdentification32-CH"/>
+                       <xs:element name="DbtrAcct" 
type="CashAccount16-CH_IdTpCcy"/>
+                       <xs:element name="DbtrAgt" 
type="BranchAndFinancialInstitutionIdentification4-CH_BicOrClrId"/>
+                       <xs:element name="UltmtDbtr" 
type="PartyIdentification32-CH" minOccurs="0"/>
+                       <xs:element name="ChrgBr" type="ChargeBearerType1Code" 
minOccurs="0"/>
+                       <xs:element name="ChrgsAcct" 
type="CashAccount16-CH_IdAndCurrency" minOccurs="0"/>
+                       <xs:element name="CdtTrfTxInf" 
type="CreditTransferTransactionInformation10-CH" maxOccurs="unbounded"/>
+                       <!-- V01: unused
+                       <xs:element name="PoolgAdjstmntDt" type="ISODate" 
minOccurs="0"/>
+                       <xs:element name="DbtrAgtAcct" type="CashAccount16" 
minOccurs="0"/>
+                       <xs:element name="ChrgsAcctAgt" 
type="BranchAndFinancialInstitutionIdentification4" minOccurs="0"/>
+                       -->
+               </xs:sequence>
+       </xs:complexType>
+       <xs:simpleType name="PaymentMethod3Code">
+               <xs:restriction base="xs:string">
+                       <xs:enumeration value="CHK"/>
+                       <xs:enumeration value="TRF"/>
+                       <xs:enumeration value="TRA"/>
+               </xs:restriction>
+       </xs:simpleType>
+       <!-- V01: changed: CH version changes applied -->
+       <xs:complexType name="PaymentTypeInformation19-CH">
+               <xs:sequence>
+                       <xs:element name="InstrPrty" type="Priority2Code" 
minOccurs="0"/>
+                       <xs:element name="SvcLvl" type="ServiceLevel8Choice" 
minOccurs="0"/>
+                       <xs:element name="LclInstrm" 
type="LocalInstrument2Choice" minOccurs="0"/>
+                       <xs:element name="CtgyPurp" 
type="CategoryPurpose1-CH_Code" minOccurs="0"/>
+               </xs:sequence>
+       </xs:complexType>
+       <!-- V01: unused
+       <xs:simpleType name="PercentageRate">
+               <xs:restriction base="xs:decimal">
+                       <xs:fractionDigits value="10"/>
+                       <xs:totalDigits value="11"/>
+               </xs:restriction>
+       </xs:simpleType>
+    -->
+       <xs:complexType name="PersonIdentification5">
+               <xs:sequence>
+                       <xs:element name="DtAndPlcOfBirth" 
type="DateAndPlaceOfBirth" minOccurs="0"/>
+                       <xs:element name="Othr" 
type="GenericPersonIdentification1" minOccurs="0" maxOccurs="unbounded"/>
+               </xs:sequence>
+       </xs:complexType>
+       <!-- V01: changed: only one occurance of element Othr allowed in CH 
version -->
+       <xs:complexType name="PersonIdentification5-CH">
+               <xs:sequence>
+                       <xs:element name="DtAndPlcOfBirth" 
type="DateAndPlaceOfBirth" minOccurs="0"/>
+                       <xs:element name="Othr" 
type="GenericPersonIdentification1" minOccurs="0"/>
+               </xs:sequence>
+       </xs:complexType>
+       <xs:complexType name="PersonIdentificationSchemeName1Choice">
+               <xs:sequence>
+                       <xs:choice>
+                               <xs:element name="Cd" 
type="ExternalPersonIdentification1Code"/>
+                               <xs:element name="Prtry" type="Max35Text"/>
+                       </xs:choice>
+               </xs:sequence>
+       </xs:complexType>
+       <xs:simpleType name="PhoneNumber">
+               <xs:restriction base="xs:string">
+                       <xs:pattern value="\+[0-9]{1,3}-[0-9()+\-]{1,30}"/>
+               </xs:restriction>
+       </xs:simpleType>
+       <xs:complexType name="PostalAddress6">
+               <xs:sequence>
+                       <xs:element name="AdrTp" type="AddressType2Code" 
minOccurs="0"/>
+                       <xs:element name="Dept" type="Max70Text" minOccurs="0"/>
+                       <xs:element name="SubDept" type="Max70Text" 
minOccurs="0"/>
+                       <xs:element name="StrtNm" type="Max70Text" 
minOccurs="0"/>
+                       <xs:element name="BldgNb" type="Max16Text" 
minOccurs="0"/>
+                       <xs:element name="PstCd" type="Max16Text" 
minOccurs="0"/>
+                       <xs:element name="TwnNm" type="Max35Text" 
minOccurs="0"/>
+                       <xs:element name="CtrySubDvsn" type="Max35Text" 
minOccurs="0"/>
+                       <xs:element name="Ctry" type="CountryCode" 
minOccurs="0"/>
+                       <xs:element name="AdrLine" type="Max70Text" 
minOccurs="0" maxOccurs="7"/>
+               </xs:sequence>
+       </xs:complexType>
+       <!-- V01: added: only 2 lines of address lines allowed in CH version -->
+       <xs:complexType name="PostalAddress6-CH">
+               <xs:sequence>
+                       <xs:element name="AdrTp" type="AddressType2Code" 
minOccurs="0"/>
+                       <xs:element name="Dept" type="Max70Text" minOccurs="0"/>
+                       <xs:element name="SubDept" type="Max70Text" 
minOccurs="0"/>
+                       <xs:element name="StrtNm" type="Max70Text" 
minOccurs="0"/>
+                       <xs:element name="BldgNb" type="Max16Text" 
minOccurs="0"/>
+                       <xs:element name="PstCd" type="Max16Text" 
minOccurs="0"/>
+                       <xs:element name="TwnNm" type="Max35Text" 
minOccurs="0"/>
+                       <xs:element name="CtrySubDvsn" type="Max35Text" 
minOccurs="0"/>
+                       <xs:element name="Ctry" type="CountryCode" 
minOccurs="0"/>
+                       <xs:element name="AdrLine" type="Max70Text" 
minOccurs="0" maxOccurs="2"/>
+                       <!-- V01: changed: max. 2 occurence -->
+               </xs:sequence>
+       </xs:complexType>
+       <xs:simpleType name="Priority2Code">
+               <xs:restriction base="xs:string">
+                       <xs:enumeration value="HIGH"/>
+                       <xs:enumeration value="NORM"/>
+               </xs:restriction>
+       </xs:simpleType>
+       <!-- V01: changed: CH-version changes applied -->
+       <xs:complexType name="Purpose2-CH_Code">
+               <xs:sequence>
+                       <xs:element name="Cd" type="ExternalPurpose1Code"/>
+               </xs:sequence>
+       </xs:complexType>
+       <xs:complexType name="ReferredDocumentInformation3">
+               <xs:sequence>
+                       <xs:element name="Tp" type="ReferredDocumentType2" 
minOccurs="0"/>
+                       <xs:element name="Nb" type="Max35Text" minOccurs="0"/>
+                       <xs:element name="RltdDt" type="ISODate" minOccurs="0"/>
+               </xs:sequence>
+       </xs:complexType>
+       <xs:complexType name="ReferredDocumentType1Choice">
+               <xs:sequence>
+                       <xs:choice>
+                               <xs:element name="Cd" type="DocumentType5Code"/>
+                               <xs:element name="Prtry" type="Max35Text"/>
+                       </xs:choice>
+               </xs:sequence>
+       </xs:complexType>
+       <xs:complexType name="ReferredDocumentType2">
+               <xs:sequence>
+                       <xs:element name="CdOrPrtry" 
type="ReferredDocumentType1Choice"/>
+                       <xs:element name="Issr" type="Max35Text" minOccurs="0"/>
+               </xs:sequence>
+       </xs:complexType>
+       <xs:complexType name="RegulatoryAuthority2">
+               <xs:sequence>
+                       <xs:element name="Nm" type="Max140Text" minOccurs="0"/>
+                       <xs:element name="Ctry" type="CountryCode" 
minOccurs="0"/>
+               </xs:sequence>
+       </xs:complexType>
+       <xs:complexType name="RegulatoryReporting3">
+               <xs:sequence>
+                       <xs:element name="DbtCdtRptgInd" 
type="RegulatoryReportingType1Code" minOccurs="0"/>
+                       <xs:element name="Authrty" type="RegulatoryAuthority2" 
minOccurs="0"/>
+                       <xs:element name="Dtls" 
type="StructuredRegulatoryReporting3" minOccurs="0" maxOccurs="unbounded"/>
+               </xs:sequence>
+       </xs:complexType>
+       <xs:simpleType name="RegulatoryReportingType1Code">
+               <xs:restriction base="xs:string">
+                       <xs:enumeration value="CRED"/>
+                       <xs:enumeration value="DEBT"/>
+                       <xs:enumeration value="BOTH"/>
+               </xs:restriction>
+       </xs:simpleType>
+       <xs:complexType name="RemittanceAmount1">
+               <xs:sequence>
+                       <xs:element name="DuePyblAmt" 
type="ActiveOrHistoricCurrencyAndAmount" minOccurs="0"/>
+                       <xs:element name="DscntApldAmt" 
type="ActiveOrHistoricCurrencyAndAmount" minOccurs="0"/>
+                       <xs:element name="CdtNoteAmt" 
type="ActiveOrHistoricCurrencyAndAmount" minOccurs="0"/>
+                       <xs:element name="TaxAmt" 
type="ActiveOrHistoricCurrencyAndAmount" minOccurs="0"/>
+                       <xs:element name="AdjstmntAmtAndRsn" 
type="DocumentAdjustment1" minOccurs="0" maxOccurs="unbounded"/>
+                       <xs:element name="RmtdAmt" 
type="ActiveOrHistoricCurrencyAndAmount" minOccurs="0"/>
+               </xs:sequence>
+       </xs:complexType>
+       <xs:complexType name="RemittanceInformation5-CH">
+               <xs:sequence>
+                       <xs:element name="Ustrd" type="Max140Text" 
minOccurs="0"/>
+                       <xs:element name="Strd" 
type="StructuredRemittanceInformation7" minOccurs="0"/>
+               </xs:sequence>
+       </xs:complexType>
+       <!-- V01: unused
+       <xs:complexType name="RemittanceLocation2">
+               <xs:sequence>
+                       <xs:element name="RmtId" type="Max35Text" 
minOccurs="0"/>
+                       <xs:element name="RmtLctnMtd" 
type="RemittanceLocationMethod2Code" minOccurs="0"/>
+                       <xs:element name="RmtLctnElctrncAdr" type="Max2048Text" 
minOccurs="0"/>
+                       <xs:element name="RmtLctnPstlAdr" 
type="NameAndAddress10" minOccurs="0"/>
+               </xs:sequence>
+       </xs:complexType>
+       <xs:simpleType name="RemittanceLocationMethod2Code">
+               <xs:restriction base="xs:string">
+                       <xs:enumeration value="FAXI"/>
+                       <xs:enumeration value="EDIC"/>
+                       <xs:enumeration value="URID"/>
+                       <xs:enumeration value="EMAL"/>
+                       <xs:enumeration value="POST"/>
+                       <xs:enumeration value="SMSM"/>
+               </xs:restriction>
+       </xs:simpleType>
+    -->
+       <xs:complexType name="ServiceLevel8Choice">
+               <xs:sequence>
+                       <xs:choice>
+                               <xs:element name="Cd" 
type="ExternalServiceLevel1Code"/>
+                               <xs:element name="Prtry" type="Max35Text"/>
+                       </xs:choice>
+               </xs:sequence>
+       </xs:complexType>
+       <xs:complexType name="StructuredRegulatoryReporting3">
+               <xs:sequence>
+                       <xs:element name="Tp" type="Max35Text" minOccurs="0"/>
+                       <xs:element name="Dt" type="ISODate" minOccurs="0"/>
+                       <xs:element name="Ctry" type="CountryCode" 
minOccurs="0"/>
+                       <xs:element name="Cd" type="Max10Text" minOccurs="0"/>
+                       <xs:element name="Amt" 
type="ActiveOrHistoricCurrencyAndAmount" minOccurs="0"/>
+                       <xs:element name="Inf" type="Max35Text" minOccurs="0" 
maxOccurs="unbounded"/>
+               </xs:sequence>
+       </xs:complexType>
+       <xs:complexType name="StructuredRemittanceInformation7">
+               <xs:sequence>
+                       <xs:element name="RfrdDocInf" 
type="ReferredDocumentInformation3" minOccurs="0" maxOccurs="unbounded"/>
+                       <xs:element name="RfrdDocAmt" type="RemittanceAmount1" 
minOccurs="0"/>
+                       <xs:element name="CdtrRefInf" 
type="CreditorReferenceInformation2" minOccurs="0"/>
+                       <xs:element name="Invcr" type="PartyIdentification32" 
minOccurs="0"/>
+                       <xs:element name="Invcee" type="PartyIdentification32" 
minOccurs="0"/>
+                       <xs:element name="AddtlRmtInf" type="Max140Text" 
minOccurs="0" maxOccurs="3"/>
+               </xs:sequence>
+       </xs:complexType>
+       <!-- V01: unused
+       <xs:complexType name="TaxAmount1">
+               <xs:sequence>
+                       <xs:element name="Rate" type="PercentageRate" 
minOccurs="0"/>
+                       <xs:element name="TaxblBaseAmt" 
type="ActiveOrHistoricCurrencyAndAmount" minOccurs="0"/>
+                       <xs:element name="TtlAmt" 
type="ActiveOrHistoricCurrencyAndAmount" minOccurs="0"/>
+                       <xs:element name="Dtls" type="TaxRecordDetails1" 
minOccurs="0" maxOccurs="unbounded"/>
+               </xs:sequence>
+       </xs:complexType>
+       <xs:complexType name="TaxAuthorisation1">
+               <xs:sequence>
+                       <xs:element name="Titl" type="Max35Text" minOccurs="0"/>
+                       <xs:element name="Nm" type="Max140Text" minOccurs="0"/>
+               </xs:sequence>
+       </xs:complexType>
+       <xs:complexType name="TaxInformation3">
+               <xs:sequence>
+                       <xs:element name="Cdtr" type="TaxParty1" minOccurs="0"/>
+                       <xs:element name="Dbtr" type="TaxParty2" minOccurs="0"/>
+                       <xs:element name="AdmstnZn" type="Max35Text" 
minOccurs="0"/>
+                       <xs:element name="RefNb" type="Max140Text" 
minOccurs="0"/>
+                       <xs:element name="Mtd" type="Max35Text" minOccurs="0"/>
+                       <xs:element name="TtlTaxblBaseAmt" 
type="ActiveOrHistoricCurrencyAndAmount" minOccurs="0"/>
+                       <xs:element name="TtlTaxAmt" 
type="ActiveOrHistoricCurrencyAndAmount" minOccurs="0"/>
+                       <xs:element name="Dt" type="ISODate" minOccurs="0"/>
+                       <xs:element name="SeqNb" type="Number" minOccurs="0"/>
+                       <xs:element name="Rcrd" type="TaxRecord1" minOccurs="0" 
maxOccurs="unbounded"/>
+               </xs:sequence>
+       </xs:complexType>
+       <xs:complexType name="TaxParty1">
+               <xs:sequence>
+                       <xs:element name="TaxId" type="Max35Text" 
minOccurs="0"/>
+                       <xs:element name="RegnId" type="Max35Text" 
minOccurs="0"/>
+                       <xs:element name="TaxTp" type="Max35Text" 
minOccurs="0"/>
+               </xs:sequence>
+       </xs:complexType>
+       <xs:complexType name="TaxParty2">
+               <xs:sequence>
+                       <xs:element name="TaxId" type="Max35Text" 
minOccurs="0"/>
+                       <xs:element name="RegnId" type="Max35Text" 
minOccurs="0"/>
+                       <xs:element name="TaxTp" type="Max35Text" 
minOccurs="0"/>
+                       <xs:element name="Authstn" type="TaxAuthorisation1" 
minOccurs="0"/>
+               </xs:sequence>
+       </xs:complexType>
+       <xs:complexType name="TaxPeriod1">
+               <xs:sequence>
+                       <xs:element name="Yr" type="ISODate" minOccurs="0"/>
+                       <xs:element name="Tp" type="TaxRecordPeriod1Code" 
minOccurs="0"/>
+                       <xs:element name="FrToDt" type="DatePeriodDetails" 
minOccurs="0"/>
+               </xs:sequence>
+       </xs:complexType>
+       <xs:complexType name="TaxRecord1">
+               <xs:sequence>
+                       <xs:element name="Tp" type="Max35Text" minOccurs="0"/>
+                       <xs:element name="Ctgy" type="Max35Text" minOccurs="0"/>
+                       <xs:element name="CtgyDtls" type="Max35Text" 
minOccurs="0"/>
+                       <xs:element name="DbtrSts" type="Max35Text" 
minOccurs="0"/>
+                       <xs:element name="CertId" type="Max35Text" 
minOccurs="0"/>
+                       <xs:element name="FrmsCd" type="Max35Text" 
minOccurs="0"/>
+                       <xs:element name="Prd" type="TaxPeriod1" minOccurs="0"/>
+                       <xs:element name="TaxAmt" type="TaxAmount1" 
minOccurs="0"/>
+                       <xs:element name="AddtlInf" type="Max140Text" 
minOccurs="0"/>
+               </xs:sequence>
+       </xs:complexType>
+       <xs:complexType name="TaxRecordDetails1">
+               <xs:sequence>
+                       <xs:element name="Prd" type="TaxPeriod1" minOccurs="0"/>
+                       <xs:element name="Amt" 
type="ActiveOrHistoricCurrencyAndAmount"/>
+               </xs:sequence>
+       </xs:complexType>
+       <xs:simpleType name="TaxRecordPeriod1Code">
+               <xs:restriction base="xs:string">
+                       <xs:enumeration value="MM01"/>
+                       <xs:enumeration value="MM02"/>
+                       <xs:enumeration value="MM03"/>
+                       <xs:enumeration value="MM04"/>
+                       <xs:enumeration value="MM05"/>
+                       <xs:enumeration value="MM06"/>
+                       <xs:enumeration value="MM07"/>
+                       <xs:enumeration value="MM08"/>
+                       <xs:enumeration value="MM09"/>
+                       <xs:enumeration value="MM10"/>
+                       <xs:enumeration value="MM11"/>
+                       <xs:enumeration value="MM12"/>
+                       <xs:enumeration value="QTR1"/>
+                       <xs:enumeration value="QTR2"/>
+                       <xs:enumeration value="QTR3"/>
+                       <xs:enumeration value="QTR4"/>
+                       <xs:enumeration value="HLF1"/>
+                       <xs:enumeration value="HLF2"/>
+               </xs:restriction>
+       </xs:simpleType>
+    -->
+</xs:schema>

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