gnunet-svn
[Top][All Lists]
Advanced

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

[libeufin] branch master updated (c8bcfc1 -> ae7897d)


From: gnunet
Subject: [libeufin] branch master updated (c8bcfc1 -> ae7897d)
Date: Fri, 04 Dec 2020 15:00:03 +0100

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

ms pushed a change to branch master
in repository libeufin.

    from c8bcfc1  adapt unit test to new camt-parser policy
     new ebaf98b  evolving sandbox
     new 5132e4e  more abstraction at sandbox
     new 338960b  Refactoring Camt generation.
     new 722e2cf  sandbox payment API: ask the payment direction too
     new d96b782  address validation issues
     new 80415f7  Get unit tests from Sandbox to pass.
     new d446014  prefer wrapping lists into JSON field
     new ae7897d  abstract over Camt type

The 8 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 integration-tests/tests.py                         |  28 ++
 .../src/main/kotlin/tech/libeufin/sandbox/DB.kt    |  43 +-
 .../tech/libeufin/sandbox/EbicsProtocolBackend.kt  | 453 ++++++++++-----------
 .../main/kotlin/tech/libeufin/sandbox/Helpers.kt   |   4 +
 .../src/main/kotlin/tech/libeufin/sandbox/JSON.kt  |   5 +
 .../src/main/kotlin/tech/libeufin/sandbox/Main.kt  |  87 +---
 .../kotlin/tech/libeufin/sandbox/bankAccount.kt    |  52 +++
 sandbox/src/test/kotlin/CamtTest.kt                |   5 +-
 sandbox/src/test/kotlin/DBTest.kt                  |   1 +
 util/src/main/kotlin/JSON.kt                       |  10 +-
 10 files changed, 328 insertions(+), 360 deletions(-)
 create mode 100644 sandbox/src/main/kotlin/tech/libeufin/sandbox/bankAccount.kt

diff --git a/integration-tests/tests.py b/integration-tests/tests.py
index 262c85f..27e2246 100755
--- a/integration-tests/tests.py
+++ b/integration-tests/tests.py
@@ -358,3 +358,31 @@ def test_ingestion_camt53():
     with open("camt53-gls-style-0.json") as f:
         expected_txs = f.read()
     assert not dd(resp.json(), json.loads(expected_txs), ignore_order=True)
+
+def test_sandbox_camt():
+    payment_instruction = dict(
+        # NOTE: this format is very outdated in the docs repo.
+        creditorIban="GB33BUKB20201555555555",
+        creditorBic="BUKBGB22",
+        creditorName="Oliver Smith",
+        debitorIban="FR00000000000000000000",
+        debitorBic="BUKBGB22",
+        debitorName="Max Mustermann",
+        amount=5,
+        currency="EUR",
+        subject="Reimbursement",
+        direction="CRDT"
+    )
+    assertResponse(
+        post(
+            f"{S}/admin/payments/",
+            json=payment_instruction
+        )
+    )
+
+    assertResponse(
+        post(
+            f"{S}/admin/payments/camt",
+            json=dict(iban="GB33BUKB20201555555555", type=53)
+        )
+    )
diff --git a/sandbox/src/main/kotlin/tech/libeufin/sandbox/DB.kt 
b/sandbox/src/main/kotlin/tech/libeufin/sandbox/DB.kt
index 2a34039..5d9a6ca 100644
--- a/sandbox/src/main/kotlin/tech/libeufin/sandbox/DB.kt
+++ b/sandbox/src/main/kotlin/tech/libeufin/sandbox/DB.kt
@@ -248,10 +248,10 @@ class EbicsUploadTransactionChunkEntity(id: 
EntityID<String>) : Entity<String>(i
  */
 object BankAccountTransactionsTable : Table() {
     val creditorIban = text("creditorIban")
-    val creditorBic = text("creditorBic").nullable()
+    val creditorBic = text("creditorBic")
     val creditorName = text("creditorName")
     val debitorIban = text("debitorIban")
-    val debitorBic = text("debitorBic").nullable()
+    val debitorBic = text("debitorBic")
     val debitorName = text("debitorName")
     val subject = text("subject")
     val amount = text("amount")
@@ -259,31 +259,12 @@ object BankAccountTransactionsTable : Table() {
     val date = long("date")
     val pmtInfId = text("pmtInfId")
     val msgId = text("msgId")
+    val direction = text("direction")
     val account = reference("account", BankAccountsTable)
 
     override val primaryKey = PrimaryKey(pmtInfId, msgId)
 }
 
-/*
-class BankAccountTransactionsEntity(id: EntityID<Int>) : IntEntity(id) {
-    companion object : 
IntEntityClass<BankAccountTransactionsEntity>(BankAccountTransactionsTable)
-
-    var creditorIban by BankAccountTransactionsTable.creditorIban
-    var creditorBic by BankAccountTransactionsTable.creditorBic
-    var creditorName by BankAccountTransactionsTable.creditorName
-    var debitorIban by BankAccountTransactionsTable.debitorIban
-    var debitorBic by BankAccountTransactionsTable.debitorBic
-    var debitorName by BankAccountTransactionsTable.debitorName
-    var subject by BankAccountTransactionsTable.subject
-    var amount by BankAccountTransactionsTable.amount
-    var currency by BankAccountTransactionsTable.currency
-    var date by BankAccountTransactionsTable.date
-    var pmtInfId by BankAccountTransactionsTable.pmtInfId
-    var msgId by BankAccountTransactionsTable.msgId
-    var account by BankAccountEntity referencedOn 
BankAccountTransactionsTable.account
-}
-*/
-
 /**
  * Table that keeps information about which bank accounts (iban+bic+name)
  * are active in the system.
@@ -313,15 +294,6 @@ object BankAccountStatementsTable : IntIdTable() {
     val bankAccount = reference("bankAccount", BankAccountsTable)
 }
 
-class BankAccountStatementsEntity(id: EntityID<Int>) : IntEntity(id) {
-    companion object : 
IntEntityClass<BankAccountStatementsEntity>(BankAccountStatementsTable)
-
-    var statementId by BankAccountStatementsTable.statementId
-    var xmlMessage by BankAccountStatementsTable.xmlMessage
-    var creationTime by BankAccountStatementsTable.creationTime
-    var bankAccount by BankAccountEntity referencedOn 
BankAccountStatementsTable.bankAccount
-}
-
 object BankAccountReportsTable : IntIdTable() {
     val reportId = text("reportId")
     val creationTime = long("creationTime")
@@ -329,15 +301,6 @@ object BankAccountReportsTable : IntIdTable() {
     val bankAccount = reference("bankAccount", BankAccountsTable)
 }
 
-class BankAccountReportsTableEntity(id: EntityID<Int>) : IntEntity(id) {
-    companion object : 
IntEntityClass<BankAccountReportsTableEntity>(BankAccountReportsTable)
-
-    var reportId by BankAccountReportsTable.reportId
-    var xmlMessage by BankAccountReportsTable.xmlMessage
-    var creationTime by BankAccountReportsTable.creationTime
-    var bankAccount by BankAccountEntity referencedOn 
BankAccountReportsTable.bankAccount
-}
-
 fun dbCreateTables(dbName: String) {
     Database.connect("jdbc:sqlite:${dbName}", "org.sqlite.JDBC")
     TransactionManager.manager.defaultIsolationLevel = 
Connection.TRANSACTION_SERIALIZABLE
diff --git 
a/sandbox/src/main/kotlin/tech/libeufin/sandbox/EbicsProtocolBackend.kt 
b/sandbox/src/main/kotlin/tech/libeufin/sandbox/EbicsProtocolBackend.kt
index e93c79d..08c7242 100644
--- a/sandbox/src/main/kotlin/tech/libeufin/sandbox/EbicsProtocolBackend.kt
+++ b/sandbox/src/main/kotlin/tech/libeufin/sandbox/EbicsProtocolBackend.kt
@@ -42,7 +42,7 @@ import tech.libeufin.sandbox.BankAccountTransactionsTable.date
 import tech.libeufin.sandbox.BankAccountTransactionsTable.debitorBic
 import tech.libeufin.sandbox.BankAccountTransactionsTable.debitorIban
 import tech.libeufin.sandbox.BankAccountTransactionsTable.debitorName
-import tech.libeufin.sandbox.BankAccountTransactionsTable.msgId
+import tech.libeufin.sandbox.BankAccountTransactionsTable.direction
 import tech.libeufin.sandbox.BankAccountTransactionsTable.pmtInfId
 import tech.libeufin.sandbox.BankAccountTransactionsTable.subject
 import tech.libeufin.util.*
@@ -54,7 +54,6 @@ import tech.libeufin.util.ebics_s001.SignatureTypes
 import tech.libeufin.util.ebics_s001.UserSignatureData
 import java.security.interfaces.RSAPrivateCrtKey
 import java.security.interfaces.RSAPublicKey
-import java.sql.SQLException
 import java.time.Instant
 import java.time.LocalDateTime
 import java.util.*
@@ -167,13 +166,43 @@ fun <T> expectNonNull(x: T?): T {
     return x;
 }
 
-/**
- * Returns a list of camt strings.  Note: each element in the
- * list accounts for only one payment in the history.  In other
- * words, the camt constructor does create always only one "Ntry"
- * node.
- */
-fun buildCamtString(type: Int, subscriberIban: String, history: 
MutableList<RawPayment>): MutableList<String> {
+private fun getRelatedParty(branch: XmlElementBuilder, payment: RawPayment) {
+    val otherParty = object {
+        var ibanPath = "CdtrAcct/Id/IBAN"
+        var namePath = "Cdtr/Nm"
+        var iban = payment.creditorIban
+        var name = payment.creditorName
+        var bicPath = "CdtrAgt/FinInstnId/BIC"
+        var bic = payment.creditorBic
+    }
+    if (payment.direction == "CRDT") {
+        otherParty.iban = payment.debitorIban
+        otherParty.ibanPath = "DbtrAcct/Id/IBAN"
+        otherParty.namePath = "Dbtr/Nm"
+        otherParty.name = payment.debitorName
+        otherParty.bic = payment.debitorBic
+        otherParty.bicPath = "DbtrAgt/FinInstnId/BIC"
+    }
+    branch.element("RltdPties") {
+        element(otherParty.namePath) {
+            text(otherParty.name)
+        }
+        element(otherParty.ibanPath) {
+            text(otherParty.iban)
+        }
+    }
+    branch.element("RltdAgts") {
+        element(otherParty.bicPath) {
+            text(otherParty.bic)
+        }
+    }
+}
+
+fun buildCamtString(
+    type: Int,
+    subscriberIban: String,
+    history: List<RawPayment>
+): String {
     /**
      * ID types required:
      *
@@ -186,156 +215,190 @@ fun buildCamtString(type: Int, subscriberIban: String, 
history: MutableList<RawP
      * - Proprietary code of the bank transaction
      * - Id of the servicer (Issuer and Code)
      */
-    val ret = mutableListOf<String>()
-    history.forEach {
-        logger.debug(
-            "Building CAMT over payment: ${it.debitorIban} => 
${it.creditorIban}, ${it.currency}:${it.amount}, ${it.subject}"
-        )
-        val dashedDate = expectNonNull(it.date)
-        val now = LocalDateTime.now()
-        val zonedDateTime = now.toZonedString()
-        ret.add(
-            constructXml(indent = true) {
-                root("Document") {
-                    attribute("xmlns", 
"urn:iso:std:iso:20022:tech:xsd:camt.053.001.02")
-                    attribute("xmlns:xsi", 
"http://www.w3.org/2001/XMLSchema-instance";)
-                    attribute(
-                        "xsi:schemaLocation",
-                        "urn:iso:std:iso:20022:tech:xsd:camt.053.001.02 
camt.053.001.02.xsd"
-                    )
-                    element("BkToCstmrStmt") {
-                        element("GrpHdr") {
-                            element("MsgId") {
-                                text("sandbox-${now.millis()}")
-                            }
-                            element("CreDtTm") {
-                                text(zonedDateTime)
+    val now = LocalDateTime.now()
+    val dashedDate = now.toDashedDate()
+    val zonedDateTime = now.toZonedString()
+    return constructXml(indent = true) {
+        root("Document") {
+            attribute("xmlns", 
"urn:iso:std:iso:20022:tech:xsd:camt.053.001.02")
+            attribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance";)
+            attribute(
+                "xsi:schemaLocation",
+                "urn:iso:std:iso:20022:tech:xsd:camt.053.001.02 
camt.053.001.02.xsd"
+            )
+            element("BkToCstmrStmt") {
+                element("GrpHdr") {
+                    element("MsgId") {
+                        text("sandbox-${now.millis()}")
+                    }
+                    element("CreDtTm") {
+                        text(zonedDateTime)
+                    }
+                    element("MsgPgntn") {
+                        element("PgNb") {
+                            text("001")
+                        }
+                        element("LastPgInd") {
+                            text("true")
+                        }
+                    }
+                }
+                element(if (type == 52) "Rpt" else "Stmt") {
+                    element("Id") {
+                        text("0")
+                    }
+                    element("ElctrncSeqNb") {
+                        text("0")
+                    }
+                    element("LglSeqNb") {
+                        text("0")
+                    }
+                    element("CreDtTm") {
+                        text(zonedDateTime)
+                    }
+                    element("Acct") {
+                        // mandatory account identifier
+                        element("Id/IBAN") {
+                            text(subscriberIban)
+                        }
+                        element("Ccy") {
+                            text("EUR")
+                        }
+                        element("Ownr/Nm") {
+                            text("Debitor/Owner Name")
+                        }
+                        element("Svcr/FinInstnId") {
+                            element("Nm") {
+                                text("Libeufin Bank")
                             }
-                            element("MsgPgntn") {
-                                element("PgNb") {
-                                    text("001")
+                            element("Othr") {
+                                element("Id") {
+                                    text("0")
                                 }
-                                element("LastPgInd") {
-                                    text("true")
+                                element("Issr") {
+                                    text("XY")
                                 }
                             }
                         }
-                        element(if (type == 52) "Rpt" else "Stmt") {
-                            element("Id") {
-                                text("0")
-                            }
-                            element("ElctrncSeqNb") {
-                                text("0")
+                    }
+                    element("Bal") {
+                        element("Tp/CdOrPrtry/Cd") {
+                            /* Balance type, in a coded format.  PRCD stands
+                               for "Previously closed booked" and shows the
+                               balance at the time _before_ all the entries
+                               reported in this document were posted to the
+                               involved bank account.  */
+                            text("PRCD")
+                        }
+                        element("Amt") {
+                            attribute("Ccy", "EUR")
+                            text(Amount(0).toPlainString())
+                        }
+                        element("CdtDbtInd") {
+                            // a temporary value to get the camt to validate.
+                            // Should be fixed along #6269
+                            text("CRDT")
+                        }
+                        element("Dt/Dt") {
+                            // date of this balance
+                            text(dashedDate)
+                        }
+                    }
+                    element("Bal") {
+                        element("Tp/CdOrPrtry/Cd") {
+                            /* CLBD stands for "Closing booked balance", and it
+                               is calculated by summing the PRCD with all the
+                               entries reported in this document */
+                            text("CLBD")
+                        }
+                        element("Amt") {
+                            attribute("Ccy", "EUR")
+                            text(Amount(0).toPlainString())
+                        }
+                        element("CdtDbtInd") {
+                            // a temporary value to get the camt to validate.
+                            // Should be fixed along #6269
+                            text("DBIT")
+                        }
+                        element("Dt/Dt") {
+                            text(dashedDate)
+                        }
+                    }
+                    history.forEach {
+                        this.element("Ntry") {
+                            element("Amt") {
+                                attribute("Ccy", it.currency)
+                                text(it.amount)
                             }
-                            element("LglSeqNb") {
-                                text("0")
+                            element("CdtDbtInd") {
+                                text(
+                                    if (subscriberIban.equals(it.creditorIban))
+                                        "CRDT" else "DBIT"
+                                )
                             }
-                            element("CreDtTm") {
-                                text(zonedDateTime)
+                            element("Sts") {
+                                /* Status of the entry (see 2.4.2.15.5 from 
the ISO20022 reference document.)
+                                    * From the original text:
+                                    * "Status of an entry on the books of the 
account servicer" */
+                                text("BOOK")
                             }
-                            element("Acct") {
-                                // mandatory account identifier
-                                element("Id/IBAN") {
-                                    text(subscriberIban)
-                                }
-                                element("Ccy") {
-                                    text("EUR")
-                                }
-                                element("Ownr/Nm") {
-                                    text("Debitor/Owner Name")
+                            element("BookgDt/Dt") {
+                                text(dashedDate)
+                            } // date of the booking
+                            element("ValDt/Dt") {
+                                text(dashedDate)
+                            } // date of assets' actual (un)availability
+                            element("AcctSvcrRef") {
+                                val uid = if (it.uid != null) 
it.uid.toString() else {
+                                    throw EbicsRequestError(
+                                        errorCode = "091116",
+                                        errorText = "EBICS_PROCESSING_ERROR"
+                                    )
                                 }
-                                element("Svcr/FinInstnId") {
-                                    element("Nm") {
-                                        text("Libeufin Bank")
+                                text(uid)
+                            }
+                            element("BkTxCd") {
+                                /*  "Set of elements used to fully identify 
the type of underlying
+                                 *   transaction resulting in an entry".  */
+                                element("Domn") {
+                                    element("Cd") {
+                                        text("PMNT")
                                     }
-                                    element("Othr") {
-                                        element("Id") {
-                                            text("0")
+                                    element("Fmly") {
+                                        element("Cd") {
+                                            text("ICDT")
                                         }
-                                        element("Issr") {
-                                            text("XY")
+                                        element("SubFmlyCd") {
+                                            text("ESCT")
                                         }
                                     }
                                 }
-                            }
-                            element("Bal") {
-                                element("Tp/CdOrPrtry/Cd") {
-                                    /* Balance type, in a coded format.  PRCD 
stands
-                                       for "Previously closed booked" and 
shows the
-                                       balance at the time _before_ all the 
entries
-                                       reported in this document were posted 
to the
-                                       involved bank account.  */
-                                    text("PRCD")
-                                }
-                                element("Amt") {
-                                    attribute("Ccy", "EUR")
-                                    text(Amount(0).toPlainString())
-                                }
-                                element("CdtDbtInd") {
-                                    // a temporary value to get the camt to 
validate.
-                                    // Should be fixed along #6269
-                                    text("CRDT")
-                                }
-                                element("Dt/Dt") {
-                                    // date of this balance
-                                    text(dashedDate)
+                                element("Prtry") {
+                                    element("Cd") {
+                                        text("0")
+                                    }
+                                    element("Issr") {
+                                        text("XY")
+                                    }
                                 }
                             }
-                            element("Bal") {
-                                element("Tp/CdOrPrtry/Cd") {
-                                    /* CLBD stands for "Closing booked 
balance", and it
-                                       is calculated by summing the PRCD with 
all the
-                                       entries reported in this document */
-                                    text("CLBD")
+                            element("NtryDtls/TxDtls") {
+                                element("Refs") {
+                                    element("MsgId") {
+                                        text("0")
+                                    }
+                                    element("PmtInfId") {
+                                        text("0")
+                                    }
+                                    element("EndToEndId") {
+                                        text("NOTPROVIDED")
+                                    }
                                 }
-                                element("Amt") {
+                                element("AmtDtls/TxAmt/Amt") {
                                     attribute("Ccy", "EUR")
-                                    text(Amount(0).toPlainString())
-                                }
-                                element("CdtDbtInd") {
-                                    // a temporary value to get the camt to 
validate.
-                                    // Should be fixed along #6269
-                                    text("DBIT")
-                                }
-                                element("Dt/Dt") {
-                                    text(dashedDate)
-                                }
-                            }
-                            element("Ntry") {
-                                element("Amt") {
-                                    attribute("Ccy", it.currency)
                                     text(it.amount)
                                 }
-                                element("CdtDbtInd") {
-                                    text(
-                                        if 
(subscriberIban.equals(it.creditorIban))
-                                            "CRDT" else "DBIT"
-                                    )
-                                }
-                                element("Sts") {
-                                    /* Status of the entry (see 2.4.2.15.5 
from the ISO20022 reference document.)
-                                        * From the original text:
-                                        * "Status of an entry on the books of 
the account servicer" */
-                                    text("BOOK")
-                                }
-                                element("BookgDt/Dt") {
-                                    text(dashedDate)
-                                } // date of the booking
-                                element("ValDt/Dt") {
-                                    text(dashedDate)
-                                } // date of assets' actual (un)availability
-                                element("AcctSvcrRef") {
-                                    val uid = if (it.uid != null) 
it.uid.toString() else {
-                                        throw EbicsRequestError(
-                                            errorCode = "091116",
-                                            errorText = 
"EBICS_PROCESSING_ERROR"
-                                        )
-                                    }
-                                    text(uid)
-                                }
                                 element("BkTxCd") {
-                                    /*  "Set of elements used to fully 
identify the type of underlying
-                                     *   transaction resulting in an entry".  
*/
                                     element("Domn") {
                                         element("Cd") {
                                             text("PMNT")
@@ -358,88 +421,17 @@ fun buildCamtString(type: Int, subscriberIban: String, 
history: MutableList<RawP
                                         }
                                     }
                                 }
-                                element("NtryDtls/TxDtls") {
-                                    element("Refs") {
-                                        element("MsgId") {
-                                            text("0")
-                                        }
-                                        element("PmtInfId") {
-                                            text("0")
-                                        }
-                                        element("EndToEndId") {
-                                            text("NOTPROVIDED")
-                                        }
-                                    }
-                                    element("AmtDtls/TxAmt/Amt") {
-                                        attribute("Ccy", "EUR")
-                                        text(it.amount)
-                                    }
-                                    element("BkTxCd") {
-                                        element("Domn") {
-                                            element("Cd") {
-                                                text("PMNT")
-                                            }
-                                            element("Fmly") {
-                                                element("Cd") {
-                                                    text("ICDT")
-                                                }
-                                                element("SubFmlyCd") {
-                                                    text("ESCT")
-                                                }
-                                            }
-                                        }
-                                        element("Prtry") {
-                                            element("Cd") {
-                                                text("0")
-                                            }
-                                            element("Issr") {
-                                                text("XY")
-                                            }
-                                        }
-                                    }
-                                    element("RltdPties") {
-                                        element("Dbtr/Nm") {
-                                            text(it.debitorName)
-                                        }
-                                        element("DbtrAcct/Id/IBAN") {
-                                            text(it.debitorIban)
-                                        }
-                                        element("Cdtr/Nm") {
-                                            text(it.creditorName)
-                                        }
-                                        element("CdtrAcct/Id/IBAN") {
-                                            text(it.creditorIban)
-                                        }
-                                    }
-//                                    element("RltdAgts") {
-//                                        element("CdtrAgt/FinInstnId/BIC") {
-//                                            // FIXME: explain this!
-//                                            text(
-//                                                if 
(subscriberIban.equals(it.creditorIban))
-//                                                    it.debitorBic else 
it.creditorBic
-//                                            )
-//                                        }
-//                                        element("DbtrAgt/FinInstnId/BIC") {
-//                                            // FIXME: explain this!
-//                                            text(
-//                                                if 
(subscriberIban.equals(it.creditorIban))
-//                                                    it.creditorBic else 
it.debitorBic
-//                                            )
-//                                        }
-//
-//                                    }
-                                    element("RmtInf/Ustrd") {
-                                        text(it.subject)
-                                    }
+                                getRelatedParty(this, it)
+                                element("RmtInf/Ustrd") {
+                                    text(it.subject)
                                 }
                             }
                         }
                     }
                 }
             }
-        )
+        }
     }
-    return ret
 }
 
 /**
@@ -460,40 +452,8 @@ private fun constructCamtResponse(
             
importDateFromMillis(dateRange.end.toGregorianCalendar().timeInMillis)
         )
     } else Pair(parseDashedDate("1970-01-01"), LocalDateTime.now())
-    val history = mutableListOf<RawPayment>()
     val bankAccount = getBankAccountFromSubscriber(subscriber)
-    transaction {
-        logger.debug("Querying transactions involving: ${bankAccount.iban}")
-        BankAccountTransactionsTable.select {
-            BankAccountTransactionsTable.creditorIban eq bankAccount.iban or
-                    (BankAccountTransactionsTable.debitorIban eq 
bankAccount.iban)
-            /**
-            FIXME: add the following condition too:
-            and (BankAccountTransactionsTable.date.between(start.millis, 
end.millis))
-             */
-        }.forEach {
-            history.add(
-                RawPayment(
-                    subject = it[subject],
-                    creditorIban = it[creditorIban],
-                    creditorBic = it[creditorBic],
-                    creditorName = it[creditorName],
-                    debitorIban = it[debitorIban],
-                    debitorBic = it[debitorBic],
-                    debitorName = it[debitorName],
-                    date = importDateFromMillis(it[date]).toDashedDate(),
-                    amount = it[amount],
-                    currency = it[currency],
-                    // The line below produces a value too long (>35 chars),
-                    // and it makes the document invalid!
-                    // uid = "${it[pmtInfId]}-${it[msgId]}"
-                    uid = "${it[pmtInfId]}"
-                )
-            )
-        }
-        history
-    }
-    return buildCamtString(type, bankAccount.iban, history)
+    return mutableListOf(buildCamtString(type, bankAccount.iban, 
historyForAccount(bankAccount.iban)))
 }
 
 /**
@@ -585,6 +545,7 @@ private fun handleCct(paymentRequest: String, 
initiatorName: String, ctx: Reques
                 it[date] = Instant.now().toEpochMilli()
                 it[pmtInfId] = parseResult.pmtInfId
                 it[msgId] = parseResult.msgId
+                it[direction] = "DBIT"
             }
         } catch (e: ExposedSQLException) {
             logger.warn("Could not insert new payment into the database: ${e}")
diff --git a/sandbox/src/main/kotlin/tech/libeufin/sandbox/Helpers.kt 
b/sandbox/src/main/kotlin/tech/libeufin/sandbox/Helpers.kt
index 67d17a9..0ea1927 100644
--- a/sandbox/src/main/kotlin/tech/libeufin/sandbox/Helpers.kt
+++ b/sandbox/src/main/kotlin/tech/libeufin/sandbox/Helpers.kt
@@ -24,6 +24,10 @@ import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
 import org.jetbrains.exposed.sql.and
 import org.jetbrains.exposed.sql.transactions.transaction
 
+fun SandboxAssert(condition: Boolean, reason: String) {
+    if (!condition) throw SandboxError(HttpStatusCode.InternalServerError, 
reason)
+}
+
 fun getOrderTypeFromTransactionId(transactionID: String): String {
     val uploadTransaction = transaction {
         EbicsUploadTransactionEntity.findById(transactionID)
diff --git a/sandbox/src/main/kotlin/tech/libeufin/sandbox/JSON.kt 
b/sandbox/src/main/kotlin/tech/libeufin/sandbox/JSON.kt
index 9716bc2..ad46123 100644
--- a/sandbox/src/main/kotlin/tech/libeufin/sandbox/JSON.kt
+++ b/sandbox/src/main/kotlin/tech/libeufin/sandbox/JSON.kt
@@ -77,6 +77,11 @@ data class DateRange(
     val endDate: Long
 )
 
+data class CamtParams(
+    val iban: String,
+    val type: Int
+)
+
 data class BankAccountStatements(
     var bankAccountStatements: MutableList<BankAccountStatement> = 
mutableListOf()
 )
diff --git a/sandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt 
b/sandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt
index 38469a9..6ea2a02 100644
--- a/sandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt
+++ b/sandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt
@@ -28,8 +28,6 @@ import io.ktor.features.ContentNegotiation
 import io.ktor.features.StatusPages
 import io.ktor.http.ContentType
 import io.ktor.http.HttpStatusCode
-import io.ktor.request.receive
-import io.ktor.request.uri
 import io.ktor.response.respond
 import io.ktor.response.respondText
 import io.ktor.routing.get
@@ -61,6 +59,7 @@ import com.github.ajalt.clikt.core.CliktCommand
 import com.github.ajalt.clikt.core.subcommands
 import com.github.ajalt.clikt.parameters.options.default
 import com.github.ajalt.clikt.parameters.options.option
+import io.ktor.request.*
 import io.ktor.util.AttributeKey
 import tech.libeufin.sandbox.BankAccountTransactionsTable
 import tech.libeufin.sandbox.BankAccountTransactionsTable.amount
@@ -72,6 +71,7 @@ import tech.libeufin.sandbox.BankAccountTransactionsTable.date
 import tech.libeufin.sandbox.BankAccountTransactionsTable.debitorBic
 import tech.libeufin.sandbox.BankAccountTransactionsTable.debitorIban
 import tech.libeufin.sandbox.BankAccountTransactionsTable.debitorName
+import tech.libeufin.sandbox.BankAccountTransactionsTable.direction
 import tech.libeufin.util.*
 import tech.libeufin.util.ebics_h004.EbicsResponse
 import tech.libeufin.util.ebics_h004.EbicsTypes
@@ -234,6 +234,15 @@ fun serverMain(dbName: String) {
             get("/") {
                 call.respondText("Hello, this is Sandbox\n", 
ContentType.Text.Plain)
             }
+            // only reason for a post is to hide the iban (to some degree.)
+            post("/admin/payments/camt") {
+                val body = call.receive<CamtParams>()
+                val history = historyForAccount(body.iban)
+                SandboxAssert(body.type == 53, "Only Camt.053 is implemented")
+                val camt53 = buildCamtString(body.type, body.iban, history)
+                call.respondText(camt53, ContentType.Text.Xml, 
HttpStatusCode.OK)
+                return@post
+            }
             get("/admin/payments") {
                 val ret = PaymentsResponse()
                 transaction {
@@ -249,12 +258,17 @@ fun serverMain(dbName: String) {
                                 creditorName = it[creditorName],
                                 debitorBic = it[debitorBic],
                                 debitorName = it[debitorName],
-                                currency = it[currency]
+                                currency = it[currency],
+                                direction = it[direction]
                             )
                         )
                     }
                 }
-                call.respond(ret)
+                call.respond(
+                    object {
+                        val payments = ret
+                    }
+                )
                 return@get
             }
 
@@ -265,7 +279,7 @@ fun serverMain(dbName: String) {
                 val body = call.receive<RawPayment>()
                 val random = Random.nextLong()
                 transaction {
-                    val debitorBankAccount = 
getBankAccountFromIban(body.debitorIban).id
+                    val localIban = if (body.direction == "DBIT") 
body.debitorIban else body.creditorIban
                     BankAccountTransactionsTable.insert {
                         it[creditorIban] = body.creditorIban
                         it[creditorBic] = body.creditorBic
@@ -279,7 +293,8 @@ fun serverMain(dbName: String) {
                         it[date] = Instant.now().toEpochMilli()
                         it[pmtInfId] = random.toString()
                         it[msgId] = random.toString()
-                        it[account] = debitorBankAccount
+                        it[account] = getBankAccountFromIban(localIban).id
+                        it[direction] = body.direction
                     }
                 }
                 call.respondText("Payment created")
@@ -388,66 +403,6 @@ fun serverMain(dbName: String) {
             post("/ebicsweb") {
                 call.ebicsweb()
             }
-            /**
-             * Shows all bank account statements.
-             */
-            /*
-              FIXME: Heng Yeow.
-
-            get("/admin/statements") {
-                var ret = BankAccountStatement()
-                ret.creationTime = Instant.now().toEpochMilli()
-                ret.statementId = "C52-" + 
Instant.now().toEpochMilli().toHttpDateString() + "-" + 
UUID.randomUUID().toString()
-                ret.message = mutableListOf<String>()
-                transaction {
-                    BankAccountTransactionsTable.selectAll().forEach {
-                        ret.message.add(
-                            constructXml(indent = true) {
-                                root("Document") {
-                                    attribute("xmlns", 
"urn:iso:std:iso:20022:tech:xsd:camt.053.001.02")
-                                    attribute("xmlns:xsi", 
"http://www.w3.org/2001/XMLSchema-instance";)
-                                    attribute(
-                                        "xsi:schemaLocation",
-                                        
"urn:iso:std:iso:20022:tech:xsd:camt.053.001.02 camt.053.001.02.xsd"
-                                    )
-                                    element("Ntry") {
-                                        element("Amt") {
-                                            attribute("Ccy", it.currency)
-                                            text(it.amount)
-                                        }
-                                    }
-                                }
-                            }
-                        )
-                    }
-                }
-                transaction {
-                    BankAccountStatementsTable.insert {
-                        it[statementId] = ret.statementId
-                        it[creationTime] = ret.creationTime
-                        it[xmlMessage] = ret.message.toString()
-                    }
-                }
-                call.respond(ret)
-                return@get
-            }
-
-             */
-            /**
-             * Shows all bank account reports.
-             */
-            /*
-              FIXME: Heng Yeow.
-
-            get("/admin/reports") {
-                val body = call.receive<DateRange>()
-                var ret = BankAccountReport()
-
-                call.respond(ret)
-                return@get
-            }
-            
-             */
         }
     }
     LOGGER.info("Up and running")
diff --git a/sandbox/src/main/kotlin/tech/libeufin/sandbox/bankAccount.kt 
b/sandbox/src/main/kotlin/tech/libeufin/sandbox/bankAccount.kt
new file mode 100644
index 0000000..aff6fa5
--- /dev/null
+++ b/sandbox/src/main/kotlin/tech/libeufin/sandbox/bankAccount.kt
@@ -0,0 +1,52 @@
+package tech.libeufin.sandbox
+
+import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
+import org.jetbrains.exposed.sql.or
+import org.jetbrains.exposed.sql.select
+import org.jetbrains.exposed.sql.transactions.transaction
+import tech.libeufin.util.RawPayment
+import tech.libeufin.util.importDateFromMillis
+import tech.libeufin.util.logger
+import tech.libeufin.util.toDashedDate
+
+fun historyForAccount(iban: String): List<RawPayment> {
+    val history = mutableListOf<RawPayment>()
+    transaction {
+        logger.debug("Querying transactions involving: ${iban}")
+        BankAccountTransactionsTable.select {
+            BankAccountTransactionsTable.creditorIban eq iban or
+                    (BankAccountTransactionsTable.debitorIban eq iban)
+            /**
+            FIXME: add the following condition too:
+            and (BankAccountTransactionsTable.date.between(start.millis, 
end.millis))
+             */
+            /**
+            FIXME: add the following condition too:
+            and (BankAccountTransactionsTable.date.between(start.millis, 
end.millis))
+             */
+
+        }.forEach {
+            history.add(
+                RawPayment(
+                    subject = it[BankAccountTransactionsTable.subject],
+                    creditorIban = 
it[BankAccountTransactionsTable.creditorIban],
+                    creditorBic = it[BankAccountTransactionsTable.creditorBic],
+                    creditorName = 
it[BankAccountTransactionsTable.creditorName],
+                    debitorIban = it[BankAccountTransactionsTable.debitorIban],
+                    debitorBic = it[BankAccountTransactionsTable.debitorBic],
+                    debitorName = it[BankAccountTransactionsTable.debitorName],
+                    date = 
importDateFromMillis(it[BankAccountTransactionsTable.date]).toDashedDate(),
+                    amount = it[BankAccountTransactionsTable.amount],
+                    currency = it[BankAccountTransactionsTable.currency],
+                    // The line below produces a value too long (>35 chars),
+                    // and it makes the document invalid!
+                    // uid = "${it[pmtInfId]}-${it[msgId]}"
+                    uid = "${it[BankAccountTransactionsTable.pmtInfId]}",
+                    direction = it[BankAccountTransactionsTable.direction]
+                )
+            )
+        }
+
+    }
+    return history
+}
diff --git a/sandbox/src/test/kotlin/CamtTest.kt 
b/sandbox/src/test/kotlin/CamtTest.kt
index 8c06558..4556868 100644
--- a/sandbox/src/test/kotlin/CamtTest.kt
+++ b/sandbox/src/test/kotlin/CamtTest.kt
@@ -19,7 +19,8 @@ class CamtTest {
             currency = "EUR",
             subject = "reimbursement",
             date = "1000-02-02",
-            uid = "0"
+            uid = "0",
+            direction = "DBIT"
         )
         val xml = buildCamtString(
             53,
@@ -27,7 +28,7 @@ class CamtTest {
             mutableListOf(payment)
         )
         assertTrue {
-            XMLUtil.validateFromString(xml.get(0))
+            XMLUtil.validateFromString(xml)
         }
     }
 }
\ No newline at end of file
diff --git a/sandbox/src/test/kotlin/DBTest.kt 
b/sandbox/src/test/kotlin/DBTest.kt
index 23aea8b..b529936 100644
--- a/sandbox/src/test/kotlin/DBTest.kt
+++ b/sandbox/src/test/kotlin/DBTest.kt
@@ -82,6 +82,7 @@ class DBTest {
                     it[currency] = "EUR"
                     it[pmtInfId] = "0"
                     it[msgId] = "0"
+                    it[direction] = "DBIT"
                 }
             }
             val result = transaction {
diff --git a/util/src/main/kotlin/JSON.kt b/util/src/main/kotlin/JSON.kt
index d7ddd89..834f4b0 100644
--- a/util/src/main/kotlin/JSON.kt
+++ b/util/src/main/kotlin/JSON.kt
@@ -26,17 +26,15 @@ package tech.libeufin.util
  */
 data class RawPayment(
     val creditorIban: String,
-    val creditorBic: String? = null,
+    val creditorBic: String,
     val creditorName: String,
     val debitorIban: String,
-    val debitorBic: String? = null,
+    val debitorBic: String,
     val debitorName: String,
     val amount: String,
     val currency: String,
     val subject: String,
     val date: String? = null,
-    // this (uid) field is null when RawPayment is a _requested_ payment
-    // over the admin API, and it's not null when RawPayment represent
-    // a database row of a settled payment.
-    val uid: String? = null
+    val uid: String? = null,
+    val direction: String
 )
\ No newline at end of file

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



reply via email to

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