libeufin

Integration and sandbox testing for FinTech APIs and data formats
Log | Files | Refs | Submodules | README | LICENSE

commit 75d4f6dd9ff07884710e18ee2b2cdc980a178e5a
parent 71201a801ddc58a06392941f808c3ca5148edeea
Author: MS <ms@taler.net>
Date:   Tue, 21 Jul 2020 14:23:39 +0200

Addressing 6394 (PAIN de- duplication).

Changing the Table layout and getting the code
to compile.  Actual tests to check whether the
primary key works are still needed.

Diffstat:
Msandbox/src/main/kotlin/tech/libeufin/sandbox/DB.kt | 24+++++-------------------
Msandbox/src/main/kotlin/tech/libeufin/sandbox/EbicsProtocolBackend.kt | 67++++++++++++++++++++++++++++++++++++++++++++-----------------------
Msandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt | 54++++++++++++++++++++++++++++++++----------------------
Msandbox/src/test/kotlin/DBTest.kt | 34+++++++++++++++++-----------------
Mutil/src/main/kotlin/JSON.kt | 2+-
5 files changed, 99 insertions(+), 82 deletions(-)

diff --git a/sandbox/src/main/kotlin/tech/libeufin/sandbox/DB.kt b/sandbox/src/main/kotlin/tech/libeufin/sandbox/DB.kt @@ -26,10 +26,7 @@ import org.jetbrains.exposed.dao.IntEntityClass import org.jetbrains.exposed.dao.id.EntityID import org.jetbrains.exposed.dao.id.IdTable import org.jetbrains.exposed.dao.id.IntIdTable -import org.jetbrains.exposed.sql.Database -import org.jetbrains.exposed.sql.SchemaUtils -import org.jetbrains.exposed.sql.StdOutSqlLogger -import org.jetbrains.exposed.sql.addLogger +import org.jetbrains.exposed.sql.* import org.jetbrains.exposed.sql.transactions.TransactionManager import org.jetbrains.exposed.sql.transactions.transaction import java.sql.Connection @@ -249,7 +246,7 @@ class EbicsUploadTransactionChunkEntity(id: EntityID<String>) : Entity<String>(i /** * Table that keeps all the payments initiated by PAIN.001. */ -object PaymentsTable : IntIdTable() { +object PaymentsTable : Table() { val creditorIban = text("creditorIban") val creditorBic = text("creditorBic").nullable() val creditorName = text("creditorName") @@ -260,21 +257,10 @@ object PaymentsTable : IntIdTable() { val amount = text("amount") val currency = text("currency") val date = long("date") -} + val pmtInfId = text("pmtInfId") + val msgId = text("msgId") -class PaymentEntity(id: EntityID<Int>) : IntEntity(id) { - companion object : IntEntityClass<PaymentEntity>(PaymentsTable) - - var creditorIban by PaymentsTable.creditorIban - var creditorBic by PaymentsTable.creditorBic - var creditorName by PaymentsTable.creditorName - var debitorIban by PaymentsTable.debitorIban - var debitorBic by PaymentsTable.debitorBic - var debitorName by PaymentsTable.debitorName - var subject by PaymentsTable.subject - var amount by PaymentsTable.amount - var currency by PaymentsTable.currency - var date by PaymentsTable.date + override val primaryKey = PrimaryKey(pmtInfId, msgId) } /** diff --git a/sandbox/src/main/kotlin/tech/libeufin/sandbox/EbicsProtocolBackend.kt b/sandbox/src/main/kotlin/tech/libeufin/sandbox/EbicsProtocolBackend.kt @@ -32,6 +32,17 @@ import org.jetbrains.exposed.sql.statements.api.ExposedBlob import org.jetbrains.exposed.sql.transactions.transaction import org.w3c.dom.Document import tech.libeufin.sandbox.PaymentsTable.amount +import tech.libeufin.sandbox.PaymentsTable.creditorBic +import tech.libeufin.sandbox.PaymentsTable.creditorIban +import tech.libeufin.sandbox.PaymentsTable.creditorName +import tech.libeufin.sandbox.PaymentsTable.currency +import tech.libeufin.sandbox.PaymentsTable.date +import tech.libeufin.sandbox.PaymentsTable.debitorBic +import tech.libeufin.sandbox.PaymentsTable.debitorIban +import tech.libeufin.sandbox.PaymentsTable.debitorName +import tech.libeufin.sandbox.PaymentsTable.msgId +import tech.libeufin.sandbox.PaymentsTable.pmtInfId +import tech.libeufin.sandbox.PaymentsTable.subject import tech.libeufin.util.* import tech.libeufin.util.XMLUtil.Companion.signEbicsResponse import tech.libeufin.util.ebics_h004.* @@ -54,7 +65,9 @@ data class PainParseResult( val debitorName: String, val subject: String, val amount: Amount, - val currency: String + val currency: String, + val pmtInfId: String, + val msgId: String ) open class EbicsRequestError(errorText: String, errorCode: String) : @@ -445,7 +458,7 @@ private fun constructCamtResponse( val bankAccount = getBankAccountFromSubscriber(subscriber) transaction { logger.debug("Querying transactions involving: ${bankAccount.iban}") - PaymentEntity.find { + PaymentsTable.select { PaymentsTable.creditorIban eq bankAccount.iban or (PaymentsTable.debitorIban eq bankAccount.iban) /** @@ -455,17 +468,17 @@ private fun constructCamtResponse( }.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, - uid = it.id.value + 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], + uid = "${it[pmtInfId]}-${it[msgId]}" ) ) } @@ -496,7 +509,11 @@ private fun parsePain001(paymentRequest: String, initiatorName: String): PainPar return destructXml(painDoc) { requireRootElement("Document") { requireUniqueChildNamed("CstmrCdtTrfInitn") { + val msgId = requireOnlyChild { + requireUniqueChildNamed("MsgId") { focusElement.textContent } + } requireUniqueChildNamed("PmtInf") { + val pmtInfId = requireUniqueChildNamed("PmtInfId") { focusElement.textContent } val creditorIban = requireUniqueChildNamed("CdtTrfTxInf") { requireUniqueChildNamed("CdtrAcct") { requireUniqueChildNamed("id") { @@ -527,7 +544,9 @@ private fun parsePain001(paymentRequest: String, initiatorName: String): PainPar debitorIban = debitorIban, debitorName = initiatorName, creditorName = creditorName, - creditorIban = creditorIban + creditorIban = creditorIban, + pmtInfId = pmtInfId, + msgId = msgId ) } } @@ -542,15 +561,17 @@ private fun handleCct(paymentRequest: String, initiatorName: String) { val parseResult = parsePain001(paymentRequest, initiatorName) transaction { - PaymentEntity.new { - this.creditorIban = parseResult.creditorIban - this.creditorName = parseResult.creditorName - this.debitorIban = parseResult.debitorIban - this.debitorName = parseResult.debitorName - this.subject = parseResult.subject - this.amount = parseResult.amount.toString() - this.currency = parseResult.currency - this.date = Instant.now().toEpochMilli() + PaymentsTable.insert { + it[creditorIban] = parseResult.creditorIban + it[creditorName] = parseResult.creditorName + it[debitorIban] = parseResult.debitorIban + it[debitorName] = parseResult.debitorName + it[subject] = parseResult.subject + it[amount] = parseResult.amount.toString() + it[currency] = parseResult.currency + it[date] = Instant.now().toEpochMilli() + it[pmtInfId] = parseResult.pmtInfId + it[msgId] = parseResult.msgId } } } diff --git a/sandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt b/sandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt @@ -61,6 +61,16 @@ 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 tech.libeufin.sandbox.PaymentsTable +import tech.libeufin.sandbox.PaymentsTable.amount +import tech.libeufin.sandbox.PaymentsTable.creditorBic +import tech.libeufin.sandbox.PaymentsTable.creditorIban +import tech.libeufin.sandbox.PaymentsTable.creditorName +import tech.libeufin.sandbox.PaymentsTable.currency +import tech.libeufin.sandbox.PaymentsTable.date +import tech.libeufin.sandbox.PaymentsTable.debitorBic +import tech.libeufin.sandbox.PaymentsTable.debitorIban +import tech.libeufin.sandbox.PaymentsTable.debitorName import tech.libeufin.util.* class CustomerNotFound(id: String?) : Exception("Customer ${id} not found") @@ -210,19 +220,19 @@ fun serverMain(dbName: String) { get("/admin/payments") { val ret = PaymentsResponse() transaction { - PaymentEntity.all().forEach { + PaymentsTable.selectAll().forEach { ret.payments.add( RawPayment( - creditorIban = it.creditorIban, - debitorIban = it.debitorIban, - subject = it.subject, - date = it.date.toHttpDateString(), - amount = it.amount, - creditorBic = it.creditorBic, - creditorName = it.creditorName, - debitorBic = it.debitorBic, - debitorName = it.debitorName, - currency = it.currency + creditorIban = it[creditorIban], + debitorIban = it[debitorIban], + subject = it[PaymentsTable.subject], + date = it[date].toHttpDateString(), + amount = it[amount], + creditorBic = it[creditorBic], + creditorName = it[creditorName], + debitorBic = it[debitorBic], + debitorName = it[debitorName], + currency = it[currency] ) ) } @@ -237,17 +247,17 @@ fun serverMain(dbName: String) { post("/admin/payments") { val body = call.receive<RawPayment>() transaction { - PaymentEntity.new { - creditorIban = body.creditorIban - creditorBic = body.creditorBic - creditorName = body.creditorName - debitorIban = body.debitorIban - debitorBic = body.debitorBic - debitorName = body.debitorName - subject = body.subject - amount = body.amount - currency = body.currency - date = Instant.now().toEpochMilli() + PaymentsTable.insert { + it[creditorIban] = body.creditorIban + it[creditorBic] = body.creditorBic + it[creditorName] = body.creditorName + it[debitorIban] = body.debitorIban + it[debitorBic] = body.debitorBic + it[debitorName] = body.debitorName + it[subject] = body.subject + it[amount] = body.amount + it[currency] = body.currency + it[date] = Instant.now().toEpochMilli() } } call.respondText("Payment created") diff --git a/sandbox/src/test/kotlin/DBTest.kt b/sandbox/src/test/kotlin/DBTest.kt @@ -17,15 +17,13 @@ * <http://www.gnu.org/licenses/> */ -import org.jetbrains.exposed.sql.Database -import org.jetbrains.exposed.sql.SchemaUtils -import org.jetbrains.exposed.sql.StdOutSqlLogger -import org.jetbrains.exposed.sql.addLogger +import org.jetbrains.exposed.sql.* import org.jetbrains.exposed.sql.transactions.TransactionManager import org.jetbrains.exposed.sql.transactions.transaction import org.junit.Test -import tech.libeufin.sandbox.PaymentEntity import tech.libeufin.sandbox.PaymentsTable +import tech.libeufin.sandbox.PaymentsTable.msgId +import tech.libeufin.sandbox.PaymentsTable.pmtInfId import tech.libeufin.util.millis import tech.libeufin.util.parseDashedDate import java.io.File @@ -68,22 +66,24 @@ class DBTest { withTestDatabase { transaction { SchemaUtils.create(PaymentsTable) - PaymentEntity.new { - creditorIban = "earns" - creditorBic = "BIC" - creditorName = "Creditor Name" - debitorIban = "spends" - debitorBic = "BIC" - debitorName = "Debitor Name" - subject = "deal" - amount = "EUR:1" - date = LocalDateTime.now().millis() - currency = "EUR" + PaymentsTable.insert { + it[creditorIban] = "earns" + it[creditorBic] = "BIC" + it[creditorName] = "Creditor Name" + it[debitorIban] = "spends" + it[debitorBic] = "BIC" + it[debitorName] = "Debitor Name" + it[subject] = "deal" + it[amount] = "EUR:1" + it[date] = LocalDateTime.now().millis() + it[currency] = "EUR" + it[pmtInfId] = "0" + it[msgId] = "0" } } val result = transaction { addLogger(StdOutSqlLogger) - PaymentEntity.find { + PaymentsTable.select { PaymentsTable.date.between( parseDashedDate( "1970-01-01" diff --git a/util/src/main/kotlin/JSON.kt b/util/src/main/kotlin/JSON.kt @@ -38,5 +38,5 @@ data class RawPayment( // 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: Int? = null + val uid: String? = null ) \ No newline at end of file