libeufin

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

commit f3ad293d57dab27868a83ab09e670ed8e75072ac
parent ce9962fb1743c1570568f806fa94af0f9613e1f4
Author: Marcello Stanisci <stanisci.m@gmail.com>
Date:   Wed, 25 Mar 2020 20:44:54 +0100

cli requests c53 transactions collection

Diffstat:
Mcli/python/libeufin-cli | 26++++++++++++++++++++++++++
Mnexus/src/main/kotlin/tech/libeufin/nexus/Main.kt | 38++++++++++++++++++++++++++++++++++++--
Mutil/src/main/kotlin/XMLUtil.kt | 6++++++
3 files changed, 68 insertions(+), 2 deletions(-)

diff --git a/cli/python/libeufin-cli b/cli/python/libeufin-cli @@ -422,6 +422,32 @@ def crz(obj, account_id, date_range, nexus_base_url): resp = post(url, json=req) print(resp.content.decode("utf-8")) + +@ebics.command(help="Send C53 message AND instruct the Nexus to persist the result") +@click.pass_obj +@click.option( + "--account-id", + help="Numerical ID of the customer at the Nexus", + required=True +) +@click.option( + "--date-range", + help="Date range for the query", + nargs=2, + required=False, +) +@click.argument( + "nexus-base-url" +) +def collect_c53(obj, account_id, date_range, nexus_base_url): + if date_range is not None and len(date_range) == 2: + req = dict(dateRange=dict(start=date_range[0], end=date_range[1])) + else: + req = dict() + url = urljoin(nexus_base_url, "/ebics/subscribers/{}/collect-transactions-c53".format(account_id)) + resp = post(url, json=req) + print(resp.content.decode("utf-8")) + @ebics.command(help="Send C53 message") @click.pass_obj @click.option( diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt @@ -517,7 +517,6 @@ fun main() { call.respond(ret) return@get } - /** * This function triggers the Nexus to perform all those un-submitted payments. * Ideally, this logic will be moved into some more automatic mechanism. @@ -629,6 +628,41 @@ fun main() { post("/ebics/subscribers/{id}/collect-transactions-c53") { // FIXME(florian): Download C53 and store the result in the right database table + val id = expectId(call.parameters["id"]) + val paramsJson = call.receive<EbicsStandardOrderParamsJson>() + val orderParams = paramsJson.toOrderParams() + val subscriberData = getSubscriberDetailsFromId(id) + val response = doEbicsDownloadTransaction(client, subscriberData, "C53", orderParams) + when (response) { + is EbicsDownloadSuccessResult -> { + /** + * The current code is _heavily_ dependent on the way GLS returns + * data. For example, GLS makes one ZIP entry for each "Ntry" element + * (a bank transfer), but per the specifications one bank can choose to + * return all the "Ntry" elements into one single ZIP entry, or even unzipped + * at all. + */ + response.orderData.unzipWithLoop { + // parse the camt.053 here, and persist into database. + val camt53doc = XMLUtil.parseStringIntoDom(it) + val creditorIban = XMLUtil.getStringViaXpath(camt53doc, "//CdtrAcct/Id/IBAN") + val creditOrDebit = XMLUtil.getStringViaXpath(camt53doc, "//Ntry/CdtDbtInd") + logger.debug("Creditor IBAN: $creditorIban, credit-or-debit: $creditOrDebit") + } + call.respondText( + "C53 data persisted into the database (WIP).", + ContentType.Text.Plain, + HttpStatusCode.OK + ) + } + is EbicsDownloadBankErrorResult -> { + call.respond( + HttpStatusCode.BadGateway, + EbicsErrorJson(EbicsErrorDetailJson("bankError", response.returnCode.errorCode)) + ) + } + } + } post("/ebics/subscribers/{id}/collect-transactions-c54") { @@ -694,7 +728,7 @@ fun main() { when (response) { is EbicsDownloadSuccessResult -> { call.respondText( - response.orderData.unzipWithLoop(), + response.orderData.prettyPrintUnzip(), ContentType.Text.Plain, HttpStatusCode.OK ) diff --git a/util/src/main/kotlin/XMLUtil.kt b/util/src/main/kotlin/XMLUtil.kt @@ -37,6 +37,7 @@ import java.io.* import java.security.PrivateKey import java.security.PublicKey import java.security.interfaces.RSAPrivateCrtKey +import javax.print.DocFlavor import javax.xml.XMLConstants import javax.xml.bind.JAXBContext import javax.xml.bind.JAXBElement @@ -407,5 +408,10 @@ class XMLUtil private constructor() { sig.signedInfo.references[0].validate(dvc) return valResult } + + fun getStringViaXpath(doc: Document, query: String): String { + val xpath = XPathFactory.newInstance().newXPath() + return xpath.compile(query).evaluate(doc, XPathConstants.STRING).toString() + } } }