libeufin

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

commit f2cc89f7f03b81c4c6ce97961c934688f26c2005
parent b089a12c8009bb58f35026c43ce8963b6dc050ea
Author: Marcello Stanisci <stanisci.m@gmail.com>
Date:   Wed, 12 Feb 2020 18:37:48 +0100

Parse and store in DB HTD responses.

Diffstat:
Mnexus/src/main/kotlin/tech/libeufin/nexus/Db.kt | 19++++++++++++++++++-
Mnexus/src/main/kotlin/tech/libeufin/nexus/JSON.kt | 11+++++++++++
Mnexus/src/main/kotlin/tech/libeufin/nexus/Main.kt | 47++++++++++++++++++++++++++++++++++++++++++++---
Msandbox/src/main/kotlin/tech/libeufin/sandbox/DB.kt | 3---
Msandbox/src/main/python/libeufin-cli | 22++++++++++++++++++++++
5 files changed, 95 insertions(+), 7 deletions(-)

diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/Db.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/Db.kt @@ -56,6 +56,22 @@ const val ID_MAX_LENGTH = 50 // //} +object EbicsAccountsInfoTable : IntIdTable() { + val accountId = text("accountId") + val subscriber = reference("subscriber", EbicsSubscribersTable) + val accountHolder = text("accountHolder").nullable() + val iban = text("iban") + val bankCode = text("bankCode") +} + +class EbicsAccountInfoEntity(id: EntityID<Int>) : IntEntity(id) { + companion object : IntEntityClass<EbicsAccountInfoEntity>(EbicsAccountsInfoTable) + var accountId by EbicsAccountsInfoTable.accountId + var subscriber by EbicsSubscriberEntity referencedOn EbicsAccountsInfoTable.subscriber + var accountHolder by EbicsAccountsInfoTable.accountHolder + var iban by EbicsAccountsInfoTable.iban + var bankCode by EbicsAccountsInfoTable.bankCode +} object EbicsSubscribersTable : IdTable<String>() { override val id = varchar("id", ID_MAX_LENGTH).entityId().primaryKey() @@ -91,7 +107,8 @@ fun dbCreateTables() { transaction { addLogger(StdOutSqlLogger) SchemaUtils.create( - EbicsSubscribersTable + EbicsSubscribersTable, + EbicsAccountsInfoTable ) } } \ No newline at end of file diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/JSON.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/JSON.kt @@ -107,4 +107,15 @@ data class EbicsErrorDetailJson( data class EbicsErrorJson( val error: EbicsErrorDetailJson +) + +data class EbicsAccountInfoElement( + var accountHolderName: String? = null, + var iban: String, + var bankCode: String, + var accountId: String +) + +data class EbicsAccountsInfoResponse( + var accounts: MutableList<EbicsAccountInfoElement> = mutableListOf() ) \ No newline at end of file diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt @@ -50,6 +50,8 @@ import org.slf4j.LoggerFactory import org.slf4j.event.Level import tech.libeufin.util.* import tech.libeufin.util.InvalidSubscriberStateError +import tech.libeufin.util.ebics_h004.EbicsTypes +import tech.libeufin.util.ebics_h004.HTDResponseOrderData import java.lang.StringBuilder import java.security.interfaces.RSAPublicKey import java.text.DateFormat @@ -295,6 +297,27 @@ fun main() { get("/ebics/subscribers/{id}/accounts") { // FIXME(marcello): return bank accounts associated with the subscriber, // this information is only avaiable *after* HTD or HKD has been called + val id = expectId(call.parameters["id"]) + val ret = EbicsAccountsInfoResponse() + transaction { + EbicsAccountInfoEntity.find { + EbicsAccountsInfoTable.subscriber eq id + }.forEach { + ret.accounts.add( + EbicsAccountInfoElement( + accountHolderName = it.accountHolder, + iban = it.iban, + bankCode = it.bankCode, + accountId = it.accountId + ) + ) + } + } + call.respond( + HttpStatusCode.OK, + ret + ) + return@get } post("/ebics/subscribers/{id}/accounts/{acctid}/prepare-payment") { @@ -366,7 +389,6 @@ fun main() { s.append(zipFile.getInputStream(entry).readAllBytes().toString(Charsets.UTF_8)) s.append("\n") } - call.respondText( s.toString(), ContentType.Text.Plain, @@ -407,13 +429,32 @@ fun main() { } post("/ebics/subscribers/{id}/sendHtd") { - val id = expectId(call.parameters["id"]) + val customerIdAtNexus = expectId(call.parameters["id"]) val paramsJson = call.receive<EbicsStandardOrderParamsJson>() val orderParams = paramsJson.toOrderParams() - val subscriberData = getSubscriberDetailsFromId(id) + val subscriberData = getSubscriberDetailsFromId(customerIdAtNexus) val response = doEbicsDownloadTransaction(client, subscriberData, "HTD", orderParams) when (response) { is EbicsDownloadSuccessResult -> { + val payload = XMLUtil.convertStringToJaxb<HTDResponseOrderData>(response.orderData.toString(Charsets.UTF_8)) + if (null == payload.value.partnerInfo.accountInfoList) { + throw Exception( + "Inconsistent state: customers MUST have at least one bank account" + ) + } + transaction { + val subscriber = EbicsSubscriberEntity.findById(customerIdAtNexus) + payload.value.partnerInfo.accountInfoList!!.forEach { + EbicsAccountInfoEntity.new { + this.subscriber = subscriber!! /* Checked at the beginning of this function */ + accountId = it.id + accountHolder = it.accountHolder + /* FIXME: how to figure out whether that's a general or national account number? */ + iban = (it.accountNumberList?.get(0) as EbicsTypes.GeneralAccountNumber).value // FIXME: eventually get *all* of them + bankCode = (it.bankCodeList?.get(0) as EbicsTypes.GeneralBankCode).value // FIXME: eventually get *all* of them + } + } + } call.respondText( response.orderData.toString(Charsets.UTF_8), ContentType.Text.Plain, diff --git a/sandbox/src/main/kotlin/tech/libeufin/sandbox/DB.kt b/sandbox/src/main/kotlin/tech/libeufin/sandbox/DB.kt @@ -245,13 +245,10 @@ object EbicsSubscribersTable : IntIdTable() { val partnerId = text("partnerID") val systemId = text("systemID").nullable() val hostId = text("hostID") - val signatureKey = reference("signatureKey", EbicsSubscriberPublicKeysTable).nullable() val encryptionKey = reference("encryptionKey", EbicsSubscriberPublicKeysTable).nullable() val authenticationKey = reference("authorizationKey", EbicsSubscriberPublicKeysTable).nullable() - val nextOrderID = integer("nextOrderID") - val state = enumeration("state", SubscriberState::class) val bankCustomer = reference("bankCustomer", BankCustomersTable) } diff --git a/sandbox/src/main/python/libeufin-cli b/sandbox/src/main/python/libeufin-cli @@ -220,6 +220,28 @@ def backup(obj, account_id, output_file, nexus_base_url): print("Backup stored in {}".format(output_file)) +@ebics.command(help="Ask for list of Subscriber's bank accounts (requires HTD first)") +@click.pass_obj +@click.option( + "--account-id", + help="Numerical ID of the customer at the Nexus", + required=True +) +@click.argument( + "nexus-base-url" +) +def bankAccounts(obj, account_id, nexus_base_url): + + url = urljoin(nexus_base_url, "/ebics/subscribers/{}/accounts".format(account_id)) + try: + resp = get(url) + except Exception: + print("Could not reach the nexus") + return + + print(resp.content.decode("utf-8")) + + @ebics.command(help="Send test upload message (TSU)") @click.pass_obj @click.option(