summaryrefslogtreecommitdiff
path: root/nexus/src/main/kotlin
diff options
context:
space:
mode:
authorMS <ms@taler.net>2023-07-19 15:53:59 +0200
committerMS <ms@taler.net>2023-07-19 15:53:59 +0200
commitd13f040a2acb7b832a959f94a215b5e25340ed5b (patch)
tree7fb5caa126f842373027e43adbd0e77b275a9d43 /nexus/src/main/kotlin
parentfdddd2f9f2f4d1b3daa0a74d3aeb51b51d5c8e02 (diff)
downloadlibeufin-d13f040a2acb7b832a959f94a215b5e25340ed5b.tar.gz
libeufin-d13f040a2acb7b832a959f94a215b5e25340ed5b.tar.bz2
libeufin-d13f040a2acb7b832a959f94a215b5e25340ed5b.zip
Fix /admin/add-incoming.
Avoid double-requesting in Nexus and instead create and ingest the incoming payment within the same handler.
Diffstat (limited to 'nexus/src/main/kotlin')
-rw-r--r--nexus/src/main/kotlin/tech/libeufin/nexus/BankConnectionProtocol.kt4
-rw-r--r--nexus/src/main/kotlin/tech/libeufin/nexus/Taler.kt67
-rw-r--r--nexus/src/main/kotlin/tech/libeufin/nexus/bankaccount/BankAccount.kt2
-rw-r--r--nexus/src/main/kotlin/tech/libeufin/nexus/ebics/EbicsNexus.kt5
-rw-r--r--nexus/src/main/kotlin/tech/libeufin/nexus/xlibeufinbank/XLibeufinBankNexus.kt20
5 files changed, 61 insertions, 37 deletions
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/BankConnectionProtocol.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/BankConnectionProtocol.kt
index e87e9444..8607d3c9 100644
--- a/nexus/src/main/kotlin/tech/libeufin/nexus/BankConnectionProtocol.kt
+++ b/nexus/src/main/kotlin/tech/libeufin/nexus/BankConnectionProtocol.kt
@@ -35,6 +35,10 @@ val bankConnectionRegistry: Map<BankConnectionType, BankConnectionProtocol> = ma
)
interface BankConnectionProtocol {
+ // Get the bank URL in the same format that
+ // it was given when the connection was created.
+ // This helps the /admin/add-incoming handler.
+ fun getBankUrl(connId: String): String
// Initialize the connection. Usually uploads keys to the bank.
suspend fun connect(client: HttpClient, connId: String)
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/Taler.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/Taler.kt
index 2aa02121..670d714c 100644
--- a/nexus/src/main/kotlin/tech/libeufin/nexus/Taler.kt
+++ b/nexus/src/main/kotlin/tech/libeufin/nexus/Taler.kt
@@ -48,6 +48,7 @@ import tech.libeufin.nexus.bankaccount.addPaymentInitiation
import tech.libeufin.nexus.bankaccount.fetchBankAccountTransactions
import tech.libeufin.nexus.iso20022.*
import tech.libeufin.nexus.server.*
+import tech.libeufin.nexus.xlibeufinbank.ingestXLibeufinBankMessage
import tech.libeufin.util.*
import java.net.URL
import kotlin.math.abs
@@ -587,30 +588,24 @@ private suspend fun addIncoming(call: ApplicationCall) {
val conn = NexusBankConnectionEntity.findByName(facadeState.bankConnection) ?: throw internalServerError(
"state of facade $facadeId has no bank connection!"
)
- val ebicsData = NexusEbicsSubscribersTable.select {
- NexusEbicsSubscribersTable.nexusBankConnection eq conn.id
- }.firstOrNull() ?: throw internalServerError(
- "Connection '${conn.connectionId}' doesn't have EBICS"
- )
- // Resort Sandbox URL from EBICS endpoint.
- val sandboxUrl = URL(ebicsData[NexusEbicsSubscribersTable.ebicsURL])
+ val sandboxUrl = URL(getConnectionPlugin(conn.type).getBankUrl(conn.connectionId))
// NOTE: the exchange username must be 'exchange', at the Sandbox.
return@transaction Pair(
url {
protocol = URLProtocol(sandboxUrl.protocol, 80)
host = sandboxUrl.host
- if (sandboxUrl.port != 80)
- port = sandboxUrl.port
- path(
- "demobanks",
- "default",
- "taler-wire-gateway",
- "exchange",
- "admin",
- "add-incoming"
- )
- },
- facadeState.bankAccount
+ if (sandboxUrl.port != 80)
+ port = sandboxUrl.port
+ path(
+ "demobanks",
+ "default",
+ "taler-wire-gateway",
+ "exchange",
+ "admin",
+ "add-incoming"
+ )
+ }, // first
+ facadeState.bankAccount // second
)
}
val client = HttpClient { followRedirects = true }
@@ -630,20 +625,26 @@ private suspend fun addIncoming(call: ApplicationCall) {
logger.error("Client-side error for /admin/add-incoming. Sandbox says: ${resp.bodyAsText()}")
call.respond(resp.status, resp.bodyAsText())
}
- /**
- * At this point, Sandbox booked the payment. Now the "row_id"
- * value to put in the response needs to be resorted; that may
- * be known by fetching a fresh C52 report, then let Nexus ingest
- * the result, and finally _optimistically_ pick the latest entry
- * in the received payments. NOTE: if this fails, the global handler
- * responds 500 as this should _never_ fail. */
- fetchBankAccountTransactions(
- client,
- FetchSpecLatestJson(
- FetchLevel.REPORT,
- null
- ),
- fromDb.second
+ // x-libeufin-bank-ingest
+ val ingestionResult = ingestXLibeufinBankMessage(
+ fromDb.second,
+ resp.bodyAsText()
+ )
+ if (ingestionResult.newTransactions != 1)
+ throw internalServerError("/admin/add-incoming was ingested into ${ingestionResult.newTransactions} new transactions, but it must have one.")
+ if (ingestionResult.errors != null) {
+ val errors = ingestionResult.errors
+ errors?.forEach {
+ logger.error(it.message)
+ }
+ throw internalServerError("/admin/add-incoming ingestion failed.")
+ }
+ // TWG ingest.
+ ingestFacadeTransactions(
+ bankAccountId = fromDb.second,
+ facadeType = NexusFacadeType.TALER,
+ incomingFilterCb = ::talerFilter,
+ refundCb = ::maybeTalerRefunds
)
/**
* The latest incoming payment should now be found among
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/bankaccount/BankAccount.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/bankaccount/BankAccount.kt
index 8f1f6ca5..26453fac 100644
--- a/nexus/src/main/kotlin/tech/libeufin/nexus/bankaccount/BankAccount.kt
+++ b/nexus/src/main/kotlin/tech/libeufin/nexus/bankaccount/BankAccount.kt
@@ -431,7 +431,7 @@ suspend fun fetchBankAccountTransactions(
accountId
)
/**
- * The following two functions further processe the banking data
+ * The following two functions further process the banking data
* that was recently downloaded, according to the particular facade
* being honored.
*/
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/EbicsNexus.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/EbicsNexus.kt
index b1fdf816..fbb128f8 100644
--- a/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/EbicsNexus.kt
+++ b/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/EbicsNexus.kt
@@ -633,6 +633,11 @@ class EbicsBankConnectionProtocol: BankConnectionProtocol {
}
}
}
+
+ override fun getBankUrl(connId: String): String {
+ val subscriberDetails = transaction { getEbicsSubscriberDetails(connId) }
+ return subscriberDetails.ebicsUrl
+ }
override suspend fun fetchTransactions(
fetchSpec: FetchSpecJson,
client: HttpClient,
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 2bb86643..b6f025bf 100644
--- a/nexus/src/main/kotlin/tech/libeufin/nexus/xlibeufinbank/XLibeufinBankNexus.kt
+++ b/nexus/src/main/kotlin/tech/libeufin/nexus/xlibeufinbank/XLibeufinBankNexus.kt
@@ -30,7 +30,7 @@ import java.net.URL
import java.time.LocalDate
// Gets Sandbox URL and credentials, taking the connection name as input.
-fun getXLibeufinBankCredentials(conn: NexusBankConnectionEntity): XLibeufinBankTransport {
+private fun getXLibeufinBankCredentials(conn: NexusBankConnectionEntity): XLibeufinBankTransport {
val maybeCredentials = transaction {
XLibeufinBankUserEntity.find {
XLibeufinBankUsersTable.nexusBankConnection eq conn.id
@@ -45,12 +45,14 @@ fun getXLibeufinBankCredentials(conn: NexusBankConnectionEntity): XLibeufinBankT
baseUrl = maybeCredentials.baseUrl
)
}
-fun getXLibeufinBankCredentials(connId: String): XLibeufinBankTransport {
+private fun getXLibeufinBankCredentials(connId: String): XLibeufinBankTransport {
val conn = getBankConnection(connId)
return getXLibeufinBankCredentials(conn)
}
-
class XlibeufinBankConnectionProtocol : BankConnectionProtocol {
+ override fun getBankUrl(connId: String): String {
+ return getXLibeufinBankCredentials(connId).baseUrl
+ }
/**
* Together with checking the credentials, this method downloads
* additional details from the bank, and stores them in the table
@@ -316,6 +318,18 @@ class XlibeufinBankConnectionProtocol : BankConnectionProtocol {
}
}
+fun ingestXLibeufinBankMessage(
+ bankAccountId: String,
+ data: String // JSON
+): IngestedTransactionsCount {
+ val jMessage = try { jacksonObjectMapper().readTree(data) }
+ catch (e: Exception) {
+ logger.error("Bank message $data could not" +
+ " be parsed into JSON by the x-libeufin-bank ingestion.")
+ throw internalServerError("Could not ingest x-libeufin-bank message.")
+ }
+ return ingestXLibeufinBankMessage(bankAccountId, jMessage)
+}
/**
* Parses one x-libeufin-bank message and INSERTs Nexus local
* transaction records into the database. After this function