[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[libeufin] 03/03: Nexus database.
From: |
gnunet |
Subject: |
[libeufin] 03/03: Nexus database. |
Date: |
Tue, 24 Oct 2023 10:57:50 +0200 |
This is an automated email from the git hooks/post-receive script.
ms pushed a commit to branch master
in repository libeufin.
commit f803d69f428be15486efc58d07eb3b2ee2b0c327
Author: MS <ms@taler.net>
AuthorDate: Tue Oct 24 10:56:54 2023 +0200
Nexus database.
Creating incoming payments and setting them as submitted.
---
database-versioning/libeufin-nexus-0001.sql | 2 +-
.../main/kotlin/tech/libeufin/nexus/Database.kt | 81 +++++++++++++++++++++-
nexus/src/test/kotlin/Common.kt | 11 +++
nexus/src/test/kotlin/DatabaseTest.kt | 30 +++++++-
util/src/main/kotlin/DB.kt | 2 +-
5 files changed, 119 insertions(+), 7 deletions(-)
diff --git a/database-versioning/libeufin-nexus-0001.sql
b/database-versioning/libeufin-nexus-0001.sql
index 97dbb527..003bd423 100644
--- a/database-versioning/libeufin-nexus-0001.sql
+++ b/database-versioning/libeufin-nexus-0001.sql
@@ -58,7 +58,7 @@ CREATE TABLE IF NOT EXISTS initiated_outgoing_transactions
,hidden BOOL DEFAULT FALSE -- FIXME: explain this.
,client_request_uuid TEXT UNIQUE
,failure_message TEXT -- NOTE: that may mix soon failures (those found at
initiation time), or late failures (those found out along a fetch operation)
- );
+ );
COMMENT ON COLUMN initiated_outgoing_transactions.outgoing_transaction_id
IS 'Points to the bank transaction that was found via nexus-fetch. If
"submitted" is false or nexus-fetch could not download this initiation, this
column is expected to be NULL.';
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/Database.kt
b/nexus/src/main/kotlin/tech/libeufin/nexus/Database.kt
index 45558da8..77086257 100644
--- a/nexus/src/main/kotlin/tech/libeufin/nexus/Database.kt
+++ b/nexus/src/main/kotlin/tech/libeufin/nexus/Database.kt
@@ -12,14 +12,28 @@ import java.sql.PreparedStatement
import java.sql.SQLException
import java.time.Instant
-/* only importing TalerAmount from bank ONCE that Nexus has
-* its httpd component. */
data class TalerAmount(
val value: Long,
val fraction: Int,
val currency: String
)
+// INCOMING PAYMENTS STRUCTS
+
+/**
+ * Represents an incoming payment in the database.
+ */
+data class IncomingPayment(
+ val amount: TalerAmount,
+ val wireTransferSubject: String,
+ val debitPaytoUri: String,
+ val executionTime: Instant,
+ val bankTransferId: String,
+ val bounced: Boolean
+)
+
+// INITIATED PAYMENTS STRUCTS
+
/**
* Minimal set of information to initiate a new payment in
* the database.
@@ -97,6 +111,69 @@ class Database(dbConfig: String): java.io.Closeable {
}
}
+ // INCOMING PAYMENTS METHODS
+
+ /**
+ * Flags an incoming payment as bounced. NOTE: the flag merely means
+ * that the payment had an invalid subject for a Taler withdrawal _and_
+ * it got sent to the initiated outgoing payments. In NO way this flag
+ * means that the actual value was returned to the initial debtor.
+ *
+ * FIXME: this needs to run within the same transaction where the payment
gets initiated.
+ *
+ * @param rowId row ID of the payment to flag as bounced.
+ * @return true on success, false otherwise.
+ */
+ suspend fun incomingPaymentSetAsBounced(rowId: Long): Boolean = runConn {
conn ->
+ val stmt = conn.prepareStatement("""
+ UPDATE incoming_transactions
+ SET bounced = true
+ WHERE incoming_transaction_id=?
+ """
+ )
+ stmt.setLong(1, rowId)
+ return@runConn stmt.maybeUpdate()
+ }
+
+ /**
+ * Creates a new incoming payment record in the database.
+ *
+ * @param paymentData information related to the incoming payment.
+ * @return true on success, false otherwise.
+ */
+ suspend fun incomingPaymentCreate(paymentData: IncomingPayment): Boolean =
runConn { conn ->
+ val stmt = conn.prepareStatement("""
+ INSERT INTO incoming_transactions (
+ amount
+ ,wire_transfer_subject
+ ,execution_time
+ ,debit_payto_uri
+ ,bank_transfer_id
+ ,bounced
+ ) VALUES (
+ (?,?)::taler_amount
+ ,?
+ ,?
+ ,?
+ ,?
+ ,?
+ )
+ """)
+ stmt.setLong(1, paymentData.amount.value)
+ stmt.setInt(2, paymentData.amount.fraction)
+ stmt.setString(3, paymentData.wireTransferSubject)
+ val executionTime = paymentData.executionTime.toDbMicros() ?: run {
+ throw Exception("Execution time could not be converted to
microseconds for the database.")
+ }
+ stmt.setLong(4, executionTime)
+ stmt.setString(5, paymentData.debitPaytoUri)
+ stmt.setString(6, paymentData.bankTransferId)
+ stmt.setBoolean(7, paymentData.bounced)
+ return@runConn stmt.maybeUpdate()
+ }
+
+ // INITIATED PAYMENTS METHODS
+
/**
* Sets payment initiation as submitted.
*
diff --git a/nexus/src/test/kotlin/Common.kt b/nexus/src/test/kotlin/Common.kt
index eed13cc1..3e89c854 100644
--- a/nexus/src/test/kotlin/Common.kt
+++ b/nexus/src/test/kotlin/Common.kt
@@ -79,4 +79,15 @@ fun genInitPay(subject: String, rowUuid: String? = null) =
wireTransferSubject = subject,
initiationTime = Instant.now(),
clientRequestUuid = rowUuid
+ )
+
+// Generates an incoming payment, given its subject.
+fun genIncPay(subject: String, rowUuid: String? = null) =
+ IncomingPayment(
+ amount = TalerAmount(44, 0, "KUDOS"),
+ debitPaytoUri = "payto://iban/not-used",
+ wireTransferSubject = subject,
+ executionTime = Instant.now(),
+ bounced = false,
+ bankTransferId = "entropic"
)
\ No newline at end of file
diff --git a/nexus/src/test/kotlin/DatabaseTest.kt
b/nexus/src/test/kotlin/DatabaseTest.kt
index 72a04b4e..d5301063 100644
--- a/nexus/src/test/kotlin/DatabaseTest.kt
+++ b/nexus/src/test/kotlin/DatabaseTest.kt
@@ -1,16 +1,41 @@
+import io.ktor.client.*
+import io.ktor.client.request.*
import kotlinx.coroutines.runBlocking
import org.junit.Test
import tech.libeufin.nexus.InitiatedPayment
import tech.libeufin.nexus.NEXUS_CONFIG_SOURCE
import tech.libeufin.nexus.PaymentInitiationOutcome
import tech.libeufin.nexus.TalerAmount
-import tech.libeufin.util.connectWithSchema
+import tech.libeufin.util.transaction
import java.time.Instant
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertTrue
-class DatabaseTest {
+class IncomingPaymentsTest {
+ // Tests the creation of an incoming payment.
+ @Test
+ fun incomingPaymentCreation() {
+ val db = prepDb(TalerConfig(NEXUS_CONFIG_SOURCE))
+ val countRows = "SELECT count(*) AS how_many FROM
incoming_transactions"
+ runBlocking {
+ // Asserting the table is empty.
+ db.runConn {
+ val res = it.execSQLQuery(countRows)
+ assertTrue(res.next())
+ assertEquals(0, res.getInt("how_many"))
+ }
+ db.incomingPaymentCreate(genIncPay("singleton"))
+ // Asserting the table has one.
+ db.runConn {
+ val res = it.execSQLQuery(countRows)
+ assertTrue(res.next())
+ assertEquals(1, res.getInt("how_many"))
+ }
+ }
+ }
+}
+class PaymentInitiationsTest {
// Tests the flagging of payments as submitted.
@Test
fun paymentInitiationSetAsSubmitted() {
@@ -34,7 +59,6 @@ class DatabaseTest {
}
// Switching the submitted state to true.
assertTrue(db.initiatedPaymentSetSubmitted(1))
-
// Asserting on the submitted state being TRUE now.
db.runConn { conn ->
val isSubmitted = conn.execSQLQuery(getRowOne)
diff --git a/util/src/main/kotlin/DB.kt b/util/src/main/kotlin/DB.kt
index 2966880a..3e0b55fe 100644
--- a/util/src/main/kotlin/DB.kt
+++ b/util/src/main/kotlin/DB.kt
@@ -345,6 +345,7 @@ fun pgDataSource(dbConfig: String): PGSimpleDataSource {
fun PGSimpleDataSource.pgConnection(): PgConnection {
val conn = connection.unwrap(PgConnection::class.java)
+ // FIXME: bring the DB schema to a function argument.
conn.execSQLUpdate("SET search_path TO libeufin_bank;")
return conn
}
@@ -401,7 +402,6 @@ fun initializeDatabaseTables(cfg: DatabaseConfig,
sqlFilePrefix: String) {
conn.execSQLUpdate(sqlPatchText)
}
val sqlProcedures = File("${cfg.sqlDir}/procedures.sql")
- // Nexus doesn't have any procedures.
if (!sqlProcedures.exists()) {
logger.info("No procedures.sql for the SQL collection:
$sqlFilePrefix")
return@transaction
--
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.