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:
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(