libeufin

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

commit 48f777aaaec036dc06083cc34cd1160898e67a9e
parent 3a738ca06c616e6bab151d816f5eb1f5bad432f9
Author: Marcello Stanisci <stanisci.m@gmail.com>
Date:   Wed,  4 Dec 2019 21:15:57 +0100

Amount format.

No need to use value/fraction pairs to represent amounts,
at least for the moment.  Using floats for now.

Diffstat:
M.gitignore | 1+
Msandbox/build.gradle | 8+++++++-
Msandbox/src/main/kotlin/tech/libeufin/sandbox/DB.kt | 28+++++-----------------------
Msandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt | 29+++++++++++++----------------
Msandbox/src/main/python/libeufin-cli | 32+++++++++++++++++++++++++++++---
Msandbox/src/test/kotlin/DbTest.kt | 31++++++++++++++++++-------------
6 files changed, 73 insertions(+), 56 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -2,3 +2,4 @@ build .gradle out *.sqlite3 +*.swp diff --git a/sandbox/build.gradle b/sandbox/build.gradle @@ -9,7 +9,9 @@ sourceCompatibility = "11" targetCompatibility = "11" version '1.0-snapshot' + compileKotlin { + kotlinOptions { jvmTarget = "11" } @@ -46,12 +48,15 @@ dependencies { testImplementation 'org.jetbrains.kotlin:kotlin-test:1.3.50' } + application { + mainClassName = "tech.libeufin.sandbox.MainKt" } + jar { manifest { attributes "Main-Class": "tech.libeufin.sandbox.MainKt" } -} +} +\ No newline at end of file diff --git a/sandbox/src/main/kotlin/tech/libeufin/sandbox/DB.kt b/sandbox/src/main/kotlin/tech/libeufin/sandbox/DB.kt @@ -90,22 +90,6 @@ fun Blob.toByteArray(): ByteArray { return this.binaryStream.readAllBytes() } -object BalancesTable : IntIdTable() { - // Customer ID is the default 'id' field provided by the constructor. - val value = integer("value") - val fraction = integer("fraction").check { - LessEqOp(it, intParam(100)) - } // enforcing fractional values to be up to 100 - -} - -class BalanceEntity(id: EntityID<Int>) : IntEntity(id) { - companion object : IntEntityClass<BalanceEntity>(BalancesTable) - - var value by BalancesTable.value - var fraction by BalancesTable.fraction -} - /** * This table information *not* related to EBICS, for all * its customers. @@ -113,13 +97,13 @@ class BalanceEntity(id: EntityID<Int>) : IntEntity(id) { object BankCustomersTable : IntIdTable() { // Customer ID is the default 'id' field provided by the constructor. val name = varchar("name", CUSTOMER_NAME_MAX_LENGTH).primaryKey() - val balance = reference("balance", BalancesTable) + val balance = float("balance") } class BankCustomerEntity(id: EntityID<Int>) : IntEntity(id) { companion object : IntEntityClass<BankCustomerEntity>(BankCustomersTable) var name by BankCustomersTable.name - var balance by BalanceEntity referencedOn BankCustomersTable.balance + var balance by BankCustomersTable.balance } /** @@ -130,7 +114,6 @@ object EbicsSubscriberPublicKeysTable : IntIdTable() { val state = enumeration("state", KeyState::class) } - /** * Definition of a row in the [EbicsSubscriberPublicKeyEntity] table */ @@ -177,9 +160,10 @@ object EbicsSubscribersTable : IntIdTable() { val nextOrderID = integer("nextOrderID") val state = enumeration("state", SubscriberState::class) - val balance = reference("balance", BalancesTable) + val bankCustomer = reference("bankCustomer", BankCustomersTable) } + class EbicsSubscriberEntity(id: EntityID<Int>) : IntEntity(id) { companion object : IntEntityClass<EbicsSubscriberEntity>(EbicsSubscribersTable) @@ -192,9 +176,8 @@ class EbicsSubscriberEntity(id: EntityID<Int>) : IntEntity(id) { var authenticationKey by EbicsSubscriberPublicKeyEntity optionalReferencedOn EbicsSubscribersTable.authenticationKey var nextOrderID by EbicsSubscribersTable.nextOrderID - var state by EbicsSubscribersTable.state - var balance by BalanceEntity referencedOn EbicsSubscribersTable.balance + var bankCustomer by BankCustomerEntity referencedOn EbicsSubscribersTable.bankCustomer } @@ -297,7 +280,6 @@ fun dbCreateTables() { // addLogger(StdOutSqlLogger) SchemaUtils.createMissingTablesAndColumns( - BalancesTable, BankCustomersTable, EbicsSubscribersTable, EbicsHostsTable, diff --git a/sandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt b/sandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt @@ -17,6 +17,7 @@ * <http://www.gnu.org/licenses/> */ + package tech.libeufin.sandbox import io.ktor.application.ApplicationCallPipeline @@ -42,7 +43,6 @@ import org.jetbrains.exposed.sql.transactions.transaction import org.slf4j.Logger import org.slf4j.LoggerFactory import org.w3c.dom.Document -import java.lang.NumberFormatException import java.security.interfaces.RSAPublicKey import java.text.DateFormat import javax.sql.rowset.serial.SerialBlob @@ -92,7 +92,6 @@ data class Subscriber( val keys: SubscriberKeys ) - data class SubscriberKeys( val authenticationPublicKey: RSAPublicKey, val encryptionPublicKey: RSAPublicKey, @@ -128,21 +127,20 @@ fun main() { signaturePrivateKey = SerialBlob(pairC.private.encoded) } + val customerEntity = BankCustomerEntity.new { name = "Mina" - balance = BalanceEntity.new { - value = 0 - fraction = 99 + balance = 0.toFloat() } - } - val subscriber = EbicsSubscriberEntity.new { + + EbicsSubscriberEntity.new { partnerId = "PARTNER1" userId = "USER1" systemId = null state = SubscriberState.NEW nextOrderID = 1 - balance = customerEntity.balance + bankCustomer = customerEntity } } @@ -170,18 +168,17 @@ fun main() { routing { get("/{id}/balance") { - val (name, value, fraction) = transaction { + val (name, balanceFloat) = transaction { val tmp = findCustomer(call.parameters["id"]) - Triple(tmp.name, tmp.balance.value, tmp.balance.fraction) + Pair(tmp.name, tmp.balance) } - call.respond(CustomerBalance( + call.respond( + CustomerBalance( name = name, - balance = "EUR:${value}.${fraction}" - )) + balance = "EUR:${balanceFloat}" + ) + ) } - - - //trace { logger.info(it.buildText()) } get("/") { call.respondText("Hello LibEuFin!\n", ContentType.Text.Plain) } diff --git a/sandbox/src/main/python/libeufin-cli b/sandbox/src/main/python/libeufin-cli @@ -14,10 +14,15 @@ from getpass import getpass @click.group() @click.option( "--base-url", default="http://localhost:5001/", - help="Base URL of the nexus (defaults to http://localhost:5001/)") + help="Base URL of the nexus (defaults to http://localhost:5001/)" +) +@click.option( + "--bank-base-url", default="http://localhost:5000/", + help="Base URL of the bank (defaults to http://localhost:5000/)" +) @click.pass_context -def cli(ctx, base_url): - ctx.obj = dict(base_url=base_url) +def cli(ctx, base_url, bank_base_url): + ctx.obj = dict(base_url=base_url, bank_base_url=bank_base_url) @cli.group() def ebics(): @@ -290,4 +295,25 @@ def new(obj, user_id, partner_id, system_id, host_id, ebics_url): print(resp.content.decode("utf-8")) + +@ebics.command(help="Ask the balance for a given customer of the bank") +@click.pass_obj +@click.option( + "--user-id", + help="ID of the bank customer (no EBICS correlation implied/needed)" , + required=False, + default=1 +) +def balance(obj, user_id): + + url = urljoin(obj["bank_base_url"], f"/{user_id}/balance") + print(url) + try: + resp = get(url) + except Exception: + print("Could not reach the bank") + return + + print(resp.content.decode("utf-8")) + cli() diff --git a/sandbox/src/test/kotlin/DbTest.kt b/sandbox/src/test/kotlin/DbTest.kt @@ -16,23 +16,28 @@ class DbTest { Database.connect("jdbc:h2:mem:test;DB_CLOSE_DELAY=-1", driver = "org.h2.Driver") transaction { - SchemaUtils.create(BalancesTable) - } - assertFailsWith<ExposedSQLException> { - transaction { - BalanceEntity.new { - value = 101 - fraction = 101 - } + SchemaUtils.create(BankCustomersTable) + SchemaUtils.create(EbicsSubscribersTable) + SchemaUtils.create(EbicsSubscriberPublicKeysTable) + + val customer = BankCustomerEntity.new { + name = "username" + balance = Float.MIN_VALUE } - } - transaction { - BalanceEntity.new { - value = 101 - fraction = 100 + val row = EbicsSubscriberEntity.new { + userId = "user id" + partnerId = "partner id" + nextOrderID = 0 + state = SubscriberState.NEW + bankCustomer = customer } + + customer.balance = 100.toFloat() + + logger.info("${row.bankCustomer.balance}") + assertTrue(row.bankCustomer.balance.equals(100.toFloat())) } } } \ No newline at end of file