commit 4c7ac921c6cc83dab60a349c14a0a2d93906e57b
parent d221d36099e9033790e4a9ada7a91cee738991ea
Author: Antoine A <>
Date: Fri, 23 Aug 2024 20:35:20 +0200
nexus: fix transfer status
Diffstat:
7 files changed, 57 insertions(+), 46 deletions(-)
diff --git a/database-versioning/libeufin-nexus-0007.sql b/database-versioning/libeufin-nexus-0007.sql
@@ -0,0 +1,22 @@
+--
+-- This file is part of TALER
+-- Copyright (C) 2024 Taler Systems SA
+--
+-- TALER is free software; you can redistribute it and/or modify it under the
+-- terms of the GNU General Public License as published by the Free Software
+-- Foundation; either version 3, or (at your option) any later version.
+--
+-- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+-- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+-- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License along with
+-- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+
+BEGIN;
+
+SELECT _v.register_patch('libeufin-nexus-0007', NULL, NULL);
+
+ALTER TYPE submission_state RENAME VALUE 'never_heard_back' TO 'pending';
+
+COMMIT;
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/cli/EbicsFetch.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/cli/EbicsFetch.kt
@@ -132,7 +132,7 @@ private suspend fun ingestPayload(
is OutgoingPayment -> ingestOutgoingPayment(db, it)
is TxNotification.Reversal -> {
logger.error("BOUNCE '${it.msgId}': ${it.reason}")
- db.initiated.reversal(it.msgId, "Payment bounced: ${it.reason}")
+ db.initiated.failure(it.msgId, "Payment bounced: ${it.reason}")
}
}
}
@@ -171,7 +171,7 @@ private suspend fun ingestPayload(
val msg = status.msg()
logger.debug("{}", status)
if (status.paymentCode == ExternalPaymentGroupStatusCode.RJCT) {
- db.initiated.bankFailure(status.msgId, msg)
+ db.initiated.failure(status.msgId, msg)
logger.error("Transaction '${status.msgId}' was rejected : $msg")
} else {
db.initiated.bankMessage(status.msgId, msg)
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/db/Database.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/db/Database.kt
@@ -44,7 +44,8 @@ enum class SubmissionState {
unsubmitted,
transient_failure,
permanent_failure,
- success
+ success,
+ pending
}
/**
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/db/ExchangeDAO.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/db/ExchangeDAO.kt
@@ -160,7 +160,7 @@ class ExchangeDAO(private val db: Database) {
oneOrNull {
TransferStatus(
status = when (it.getEnum<SubmissionState>("submitted")) {
- SubmissionState.unsubmitted -> TransferStatusState.pending
+ SubmissionState.unsubmitted, SubmissionState.pending -> TransferStatusState.pending
SubmissionState.transient_failure -> TransferStatusState.transient_failure
SubmissionState.permanent_failure -> TransferStatusState.permanent_failure
SubmissionState.success -> TransferStatusState.success
@@ -191,28 +191,33 @@ class ExchangeDAO(private val db: Database) {
,initiation_time
FROM transfer_operations
JOIN initiated_outgoing_transactions USING (initiated_outgoing_transaction_id)
- WHERE ${if (params.status != null) "submitted=?::submission_state AND" else ""}
+ WHERE ${
+ when (params.status) {
+ null -> ""
+ TransferStatusState.pending -> "(submitted=?::submission_state OR submitted=?::submission_state) AND"
+ else -> "submitted=?::submission_state AND"
+ }
+ }
""",
{
- val state = when (params.status) {
- TransferStatusState.pending -> SubmissionState.unsubmitted
- TransferStatusState.transient_failure -> SubmissionState.transient_failure
- TransferStatusState.permanent_failure -> SubmissionState.permanent_failure
- TransferStatusState.success -> SubmissionState.success
- null -> null
- }
- if (state != null) {
- setString(1, state.name)
- 1
- } else {
- 0
+ when (params.status) {
+ null -> 0
+ TransferStatusState.pending -> {
+ setString(1, SubmissionState.pending.name)
+ setString(2, SubmissionState.unsubmitted.name)
+ 2
+ }
+ else -> {
+ setString(1, params.status?.name)
+ 1
+ }
}
}
) {
TransferListStatus(
row_id = it.getLong("initiated_outgoing_transaction_id"),
status = when (it.getEnum<SubmissionState>("submitted")) {
- SubmissionState.unsubmitted -> TransferStatusState.pending
+ SubmissionState.unsubmitted, SubmissionState.pending -> TransferStatusState.pending
SubmissionState.transient_failure -> TransferStatusState.transient_failure
SubmissionState.permanent_failure -> TransferStatusState.permanent_failure
SubmissionState.success -> TransferStatusState.success
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/db/InitiatedDAO.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/db/InitiatedDAO.kt
@@ -69,7 +69,7 @@ class InitiatedDAO(private val db: Database) {
) = db.serializable(
"""
UPDATE initiated_outgoing_transactions SET
- submitted = 'success'::submission_state
+ submitted = 'pending'::submission_state
,last_submission_time = ?
,failure_message = NULL
,order_id = ?
@@ -91,7 +91,7 @@ class InitiatedDAO(private val db: Database) {
) = db.serializable(
"""
UPDATE initiated_outgoing_transactions SET
- submitted = 'transient_failure'::submission_state
+ submitted = 'transient_failure'::submission_state
,last_submission_time = ?
,failure_message = ?
,submission_counter = submission_counter + 1
@@ -143,8 +143,8 @@ class InitiatedDAO(private val db: Database) {
/** Register bank status message */
suspend fun bankMessage(requestUID: String, msg: String) = db.serializable(
"""
- UPDATE initiated_outgoing_transactions
- SET failure_message = ?
+ UPDATE initiated_outgoing_transactions SET
+ failure_message = ?
WHERE request_uid = ?
"""
) {
@@ -153,8 +153,8 @@ class InitiatedDAO(private val db: Database) {
execute()
}
- /** Register bank failure */
- suspend fun bankFailure(requestUID: String, msg: String) = db.serializable(
+ /** Register transaction failure */
+ suspend fun failure(requestUID: String, msg: String) = db.serializable(
"""
UPDATE initiated_outgoing_transactions SET
submitted = 'permanent_failure'::submission_state
@@ -167,20 +167,6 @@ class InitiatedDAO(private val db: Database) {
execute()
}
- /** Register reversal */
- suspend fun reversal(requestUID: String, msg: String) = db.serializable(
- """
- UPDATE initiated_outgoing_transactions SET
- submitted = 'permanent_failure'::submission_state
- ,failure_message = ?
- WHERE request_uid = ?
- """
- ) {
- setString(1, msg)
- setString(2, requestUID)
- execute()
- }
-
/** List every initiated payment pending submission in the order they should be submitted */
suspend fun submittable(currency: String): List<InitiatedPayment> {
val selectPart = """
diff --git a/nexus/src/test/kotlin/DatabaseTest.kt b/nexus/src/test/kotlin/DatabaseTest.kt
@@ -273,13 +273,13 @@ class PaymentInitiationsTest {
db.initiated.create(genInitPay(requestUid = "PAY4"))
)
db.initiated.bankMessage("PAY4", "status progress")
- db.initiated.bankFailure("PAY4", "status failure")
+ db.initiated.failure("PAY4", "status failure")
assertIs<PaymentInitiationResult.Success>(
db.initiated.create(genInitPay(requestUid = "PAY5"))
)
db.initiated.bankMessage("PAY5", "status progress")
- db.initiated.reversal("PAY5", "status reversal")
+ db.initiated.failure("PAY5", "status reversal")
}
@Test
@@ -309,12 +309,12 @@ class PaymentInitiationsTest {
)
// Check persistent failure not submitable
- db.initiated.bankFailure("PAY3", "status failure")
+ db.initiated.failure("PAY3", "status failure")
assertEquals(
listOf("PAY2", "PAY4", "PAY5", "PAY1"),
db.initiated.submittable("KUDOS").map { it.requestUid }
)
- db.initiated.reversal("PAY4", "status reversal")
+ db.initiated.failure("PAY4", "status reversal")
assertEquals(
listOf("PAY2", "PAY5", "PAY1"),
db.initiated.submittable("KUDOS").map { it.requestUid }
diff --git a/nexus/src/test/kotlin/WireGatewayApiTest.kt b/nexus/src/test/kotlin/WireGatewayApiTest.kt
@@ -173,14 +173,11 @@ class WireGatewayApiTest {
db.initiated.submissionSuccess(1, Instant.now(), "ORDER1")
db.initiated.submissionFailure(2, Instant.now(), "Failure")
db.initiated.submissionFailure(3, Instant.now(), "Failure")
- client.getA("/taler-wire-gateway/transfers?status=success").assertOkJson<TransferList> {
- assertEquals(1, it.transfers.size)
- }
client.getA("/taler-wire-gateway/transfers?status=transient_failure").assertOkJson<TransferList> {
assertEquals(2, it.transfers.size)
}
client.getA("/taler-wire-gateway/transfers?status=pending").assertOkJson<TransferList> {
- assertEquals(3, it.transfers.size)
+ assertEquals(4, it.transfers.size)
}
}