libeufin

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

commit 039845992553cb0f8816279479ee4d028e75d0de
parent f1e70b7e610e5aa4f7069f384b43495034eb0eda
Author: MS <ms@taler.net>
Date:   Mon, 30 Aug 2021 21:46:38 -1100

Completing Camt generation after "ticks".

Querying Camt statements is now missing, as now each bank
account has many available.

Diffstat:
Msandbox/src/main/kotlin/tech/libeufin/sandbox/DB.kt | 13+++++++++----
Msandbox/src/main/kotlin/tech/libeufin/sandbox/EbicsProtocolBackend.kt | 22+++++++++++++---------
Msandbox/src/main/kotlin/tech/libeufin/sandbox/Helpers.kt | 17++++++++++++++---
Msandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt | 39++++++++++++++++++++++++++-------------
4 files changed, 62 insertions(+), 29 deletions(-)

diff --git a/sandbox/src/main/kotlin/tech/libeufin/sandbox/DB.kt b/sandbox/src/main/kotlin/tech/libeufin/sandbox/DB.kt @@ -380,17 +380,22 @@ object BankAccountStatementsTable : IntIdTable() { val creationTime = long("creationTime") val xmlMessage = text("xmlMessage") val bankAccount = reference("bankAccount", BankAccountsTable) - val balancePrcd = text("balancePrcd") // normally, a BigDecimal + /** + * Storing the closing balance (= the one obtained after all + * the transactions mentioned in the statement), a.k.a. CLBD. + * For statement S, this value will act as the opening balance + * (a.k.a. PRCD) of statement S+1. + */ + val balanceClbd = text("balanceClbd") // normally, a BigDecimal } class BankAccountStatementEntity(id: EntityID<Int>) : IntEntity(id) { companion object : IntEntityClass<BankAccountStatementEntity>(BankAccountStatementsTable) - - var statementId by BankAccountStatementsTable.id + var statementId by BankAccountStatementsTable.statementId var creationTime by BankAccountStatementsTable.creationTime var xmlMessage by BankAccountStatementsTable.xmlMessage var bankAccount by BankAccountEntity referencedOn BankAccountStatementsTable.bankAccount - var balancePrcd by BankAccountStatementsTable.balancePrcd + var balanceClbd by BankAccountStatementsTable.balanceClbd } object BankAccountReportsTable : IntIdTable() { diff --git a/sandbox/src/main/kotlin/tech/libeufin/sandbox/EbicsProtocolBackend.kt b/sandbox/src/main/kotlin/tech/libeufin/sandbox/EbicsProtocolBackend.kt @@ -44,7 +44,6 @@ import tech.libeufin.util.ebics_hev.SystemReturnCodeType import tech.libeufin.util.ebics_s001.SignatureTypes import tech.libeufin.util.ebics_s001.UserSignatureData import java.math.BigDecimal -import java.math.BigInteger import java.security.interfaces.RSAPrivateCrtKey import java.security.interfaces.RSAPublicKey import java.time.Instant @@ -204,7 +203,7 @@ fun buildCamtString( freshHistory: MutableList<RawPayment>, balancePrcd: BigDecimal, // Balance up to freshHistory (excluded). balanceClbd: BigDecimal -): String { +): SandboxCamt { /** * ID types required: * @@ -217,11 +216,11 @@ fun buildCamtString( * - Proprietary code of the bank transaction * - Id of the servicer (Issuer and Code) */ - val now = LocalDateTime.now() - val dashedDate = now.toDashedDate() - val zonedDateTime = now.toZonedString() - - return constructXml(indent = true) { + val creationTime = LocalDateTime.now() + val dashedDate = creationTime.toDashedDate() + val zonedDateTime = creationTime.toZonedString() + val messageId = "sandbox-${creationTime.millis()}" + val camtMessage = constructXml(indent = true) { root("Document") { attribute("xmlns", "urn:iso:std:iso:20022:tech:xsd:camt.0${type}.001.02") attribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance") @@ -232,7 +231,7 @@ fun buildCamtString( element("BkToCstmrStmt") { element("GrpHdr") { element("MsgId") { - text("sandbox-${now.millis()}") + text(messageId) } element("CreDtTm") { text(zonedDateTime) @@ -441,6 +440,11 @@ fun buildCamtString( } } } + return SandboxCamt( + camtMessage = camtMessage, + messageId = messageId, + creationTime = creationTime.millis() + ) } /** @@ -473,7 +477,7 @@ private fun constructCamtResponse(type: Int, subscriber: EbicsSubscriberEntity): history, balancePrcd = baseBalance, balanceClbd = balanceForAccount(history, baseBalance) - ) + ).camtMessage } /** diff --git a/sandbox/src/main/kotlin/tech/libeufin/sandbox/Helpers.kt b/sandbox/src/main/kotlin/tech/libeufin/sandbox/Helpers.kt @@ -19,14 +19,25 @@ package tech.libeufin.sandbox -import com.google.common.io.Resources -import com.hubspot.jinjava.Jinjava -import com.hubspot.jinjava.lib.fn.ELFunctionDefinition import io.ktor.http.HttpStatusCode import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq import org.jetbrains.exposed.sql.and import org.jetbrains.exposed.sql.transactions.transaction +/** + * Helps to communicate Camt values without having + * to parse the XML each time one is needed. + */ +data class SandboxCamt( + val camtMessage: String, + val messageId: String, + /** + * That is the number of SECONDS since Epoch. This + * value is exactly what goes into the Camt document. + */ + val creationTime: Long +) + fun SandboxAssert(condition: Boolean, reason: String) { if (!condition) throw SandboxError(HttpStatusCode.InternalServerError, reason) } diff --git a/sandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt b/sandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt @@ -122,6 +122,12 @@ class Config : CliktCommand("Insert one configuration into the database") { } } +/** + * This command generates Camt53 statements - for all the bank accounts - + * every time it gets run. The statements are only stored them into the database. + * The user should then query either via Ebics or via the JSON interface, + * in order to retrieve their statements. + */ class Camt053Tick : CliktCommand( "Make a new Camt.053 time tick; all the fresh transactions" + "will be inserted in a new Camt.053 report" @@ -133,10 +139,6 @@ class Camt053Tick : CliktCommand( transaction { BankAccountEntity.all().forEach { accountIter-> /** - * TBD: here the statements for each account need to be generated. - */ - - /** * Map of 'account name' -> fresh history */ val histories = mutableMapOf< @@ -167,24 +169,33 @@ class Camt053Tick : CliktCommand( ) ) } - // still need lastBalance + /** + * Resorting the closing (CLBD) balance of the last statement; will + * become the PRCD balance of the _new_ one. + */ val lastStatement = BankAccountStatementEntity.find { BankAccountStatementsTable.bankAccount eq accountIter.id }.firstOrNull() val lastBalance = if (lastStatement == null) { - BigDecimal.ZERO } else { BigDecimal(lastStatement.balancePrcd) } - val balancePrcd = balanceForAccount( + BigDecimal.ZERO } else { BigDecimal(lastStatement.balanceClbd) } + val balanceClbd = balanceForAccount( history = histories[accountIter.label] ?: mutableListOf(), baseBalance = lastBalance ) - val camt53 = buildCamtString( + val camtData = buildCamtString( 53, accountIter.iban, histories[accountIter.label] ?: mutableListOf(), - balanceClbd = lastBalance, - balancePrcd = balancePrcd + balanceClbd = balanceClbd, + balancePrcd = lastBalance ) - println(camt53) + BankAccountStatementEntity.new { + statementId = camtData.messageId + creationTime = Instant.now().toEpochMilli() + xmlMessage = camtData.camtMessage + bankAccount = accountIter + this.balanceClbd = balanceClbd.toPlainString() + } } BankAccountFreshTransactionsTable.deleteAll() } @@ -585,7 +596,7 @@ fun serverMain(dbName: String, port: Int) { SandboxAssert(body.type == 53, "Only Camt.053 is implemented" ) - val camt53 = buildCamtString( + val camtData = buildCamtString( body.type, bankaccount.iban, history, @@ -595,7 +606,9 @@ fun serverMain(dbName: String, port: Int) { baseBalance = BigDecimal.ZERO ) ) - call.respondText(camt53, ContentType.Text.Xml, HttpStatusCode.OK) + call.respondText( + camtData.camtMessage, ContentType.Text.Xml, HttpStatusCode.OK + ) return@post }