summaryrefslogtreecommitdiff
path: root/nexus/src/main/kotlin/tech/libeufin/nexus/xlibeufinbank/XLibeufinBankNexus.kt
diff options
context:
space:
mode:
authorMS <ms@taler.net>2023-04-03 01:28:24 +0200
committerMS <ms@taler.net>2023-04-03 01:28:24 +0200
commitf16ab461f917b03dca44487c9d2c7b9084a7431c (patch)
treea4667702d13d7f35f121f2e858642ecff1dbae25 /nexus/src/main/kotlin/tech/libeufin/nexus/xlibeufinbank/XLibeufinBankNexus.kt
parent19dfeb6704d5dee54a83ce3f8c16f563cd162fa7 (diff)
downloadlibeufin-f16ab461f917b03dca44487c9d2c7b9084a7431c.tar.gz
libeufin-f16ab461f917b03dca44487c9d2c7b9084a7431c.tar.bz2
libeufin-f16ab461f917b03dca44487c9d2c7b9084a7431c.zip
x-libeufin-bank connection
extending the connect() method to also store bank account information.
Diffstat (limited to 'nexus/src/main/kotlin/tech/libeufin/nexus/xlibeufinbank/XLibeufinBankNexus.kt')
-rw-r--r--nexus/src/main/kotlin/tech/libeufin/nexus/xlibeufinbank/XLibeufinBankNexus.kt69
1 files changed, 57 insertions, 12 deletions
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/xlibeufinbank/XLibeufinBankNexus.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/xlibeufinbank/XLibeufinBankNexus.kt
index 9c2596cf..6cec7e41 100644
--- a/nexus/src/main/kotlin/tech/libeufin/nexus/xlibeufinbank/XLibeufinBankNexus.kt
+++ b/nexus/src/main/kotlin/tech/libeufin/nexus/xlibeufinbank/XLibeufinBankNexus.kt
@@ -10,6 +10,7 @@ import io.ktor.client.statement.*
import io.ktor.http.*
import io.ktor.server.util.*
import io.ktor.util.*
+import io.ktor.util.date.*
import org.jetbrains.exposed.sql.statements.api.ExposedBlob
import org.jetbrains.exposed.sql.transactions.transaction
import tech.libeufin.nexus.*
@@ -39,25 +40,67 @@ fun getXLibeufinBankCredentials(conn: NexusBankConnectionEntity): XLibeufinBankT
fun getXLibeufinBankCredentials(connId: String): XLibeufinBankTransport {
val conn = getBankConnection(connId)
return getXLibeufinBankCredentials(conn)
-
}
class XlibeufinBankConnectionProtocol : BankConnectionProtocol {
+ /**
+ * Together with checking the credentials, this method downloads
+ * additional details from the bank, and stores them in the table
+ * that holds offered bank accounts. That saves one call to the
+ * "import" method by recycling the information obtained here.
+ */
override suspend fun connect(client: HttpClient, connId: String) {
- // Only checking that the credentials + bank URL are correct.
val conn = getBankConnection(connId)
- val credentials = getXLibeufinBankCredentials(conn)
+ val connDetails = getXLibeufinBankCredentials(conn)
// Defining the URL to request the bank account balance.
- val url = credentials.baseUrl + "/accounts/${credentials.username}"
+ val url = connDetails.baseUrl + "/accounts/${connDetails.username}"
// Error handling expected by the caller.
- client.get(url) {
+ val details = client.get(url) {
expectSuccess = true
- basicAuth(credentials.username, credentials.password)
+ basicAuth(connDetails.username, connDetails.password)
+ }
+ val txtDetails = details.bodyAsText()
+ val jDetails = jacksonObjectMapper().readTree(txtDetails)
+ val paytoUri: String = try { jDetails.get("paytoUri").asText() }
+ catch (e: Exception) {
+ logger.error("Did not find 'paytoUri' along the connection" +
+ " operation from x-libeufin-bank connection $connId." +
+ " Bank says: $txtDetails"
+ )
+ throw badGateway("Bank missed basic account information ('paytoUri' field)")
+ }
+ val paytoObj = parsePayto(payto = paytoUri)
+ val maybeOfferedAccount = transaction {
+ OfferedBankAccountEntity.find {
+ // Sandbox reliably names the bank account with the owner's username
+ OfferedBankAccountsTable.offeredAccountId eq connDetails.username
+ }.firstOrNull()
+ }
+ // Bank account already imported.
+ if (maybeOfferedAccount != null)
+ return
+ // Import it.
+ transaction {
+ OfferedBankAccountEntity.new {
+ offeredAccountId = connDetails.username
+ bankConnection = conn
+ accountHolder = paytoObj.receiverName ?: "Not given by the bank"
+ bankCode = paytoObj.bic ?: "SANDBOXX"
+ iban = paytoObj.iban
+ }
}
}
+ /**
+ * This operation is carried along connect(), because as a side
+ * effect of checking the credentials it ALSO gets all the offered
+ * bank account information that this function WOULD have obtained.
+ *
+ * Therefore, this method throws error when called, in order to raise
+ * the clients' awareness not to rely on it.
+ */
override suspend fun fetchAccounts(client: HttpClient, connId: String) {
- throw NotImplementedError("x-libeufin-bank does not need to fetch accounts")
+ throw NotImplementedError("Please skip this method when using x-libeufin-bank.")
}
override fun createConnectionFromBackup(
@@ -72,7 +115,8 @@ class XlibeufinBankConnectionProtocol : BankConnectionProtocol {
override fun createConnection(
connId: String,
user: NexusUserEntity,
- data: JsonNode) {
+ data: JsonNode
+ ) {
val bankConn = transaction {
NexusBankConnectionEntity.new {
this.connectionId = connId
@@ -211,6 +255,7 @@ class XlibeufinBankConnectionProtocol : BankConnectionProtocol {
val baseUrl = URL(credentials.baseUrl)
val fetchUrl = url {
protocol = URLProtocol(name = baseUrl.protocol, defaultPort = -1)
+ port = baseUrl.port
appendPathSegments(
baseUrl.path.dropLastWhile { it == '/' },
"accounts/${credentials.username}/transactions")
@@ -223,10 +268,10 @@ class XlibeufinBankConnectionProtocol : BankConnectionProtocol {
* timestamp that was seen in this connection */
is FetchSpecSinceLastJson -> {
val localBankAccount = getBankAccount(accountId)
- val lastMessagesTimes = getLastMessagesTimes(localBankAccount)
- // Sandbox doesn't have report vs. statement, defaulting to report time
+ // Sandbox doesn't have report vs. statement, defaulting to statement time
// and so does the ingestion routine when storing the last message time.
- this.parameters["from_ms"] = "${lastMessagesTimes.lastStatement ?: 0}"
+ // The sought time must be incremented by one because the filter is _inclusive_.
+ this.parameters["from_ms"] = "${localBankAccount.lastStatementCreationTimestamp?.plus(1) ?: 0}"
}
// This wants ALL the transactions, hence it sets the from_ms to zero.
is FetchSpecAllJson -> {
@@ -331,7 +376,7 @@ fun processXLibeufinBankMessage(
this.accountTransactionId = it.uid
this.transactionJson = jacksonObjectMapper(
).writeValueAsString(it.exportAsCamtModel())
- this.creditDebitIndicator = direction.direction
+ this.creditDebitIndicator = direction.exportAsCamtDirection()
newTxs++
logger.debug("x-libeufin-bank transaction with subject '${it.subject}' ingested.")
}