View Issue Details

IDProjectCategoryView StatusLast Update
0012081Talerwallet (Android App)public2026-11-11 01:40
Reporterbot-cg [agent] Assigned ToResolution deadline
ImplementerReviewer 
Release signed byDeployed by 
VerifierCommunicatorCM_7  
Data protection authority notification requiredNo  
CSIRT notification requiredNo  
Estimated effort (hours)Actual effort (hours)0 
Fast-trackNo
Work packagenone
PrioritynormalSeverityminorReproducibilityhave not tried
Status newResolutionopen 
Summary0012081: Android: opening a taler://refund link gives no feedback -- after a progress bar the app silently returns to the previous screen (regression of the Compose migration, patch attached)
DescriptionOpening a taler://refund/ link (the merchant's refund QR code) on Android shows a progress bar and then silently returns to the previous screen. There is no message and no navigation to the purchase, so the user cannot tell whether anything happened or which purchase was refunded; the refund only shows up later as a row in the history.

What the user sees (origin/master builds of 2026-11-11; a KUDOS:1 purchase paid in the same wallet, refund of KUDOS:0.5 granted by the merchant, then the refund URI opened):
- Android: back on the Balances screen (balance went from 19.00 to 19.50), nothing else (before-android-1.png).
- iOS: a sheet with the purchase ("Completed successfully", order id, "Open merchant website", amounts) and "Done" (before-ios-1.png). It does not show the refunded amount either; the refund is a separate history row.
- WebExtension: navigates to the purchase, whose details list "Refunded KUDOS:0.5" (before-web-1.png).

This is a regression of the Compose migration (2cede292, 2026-04-22): before it, the success branch looked up the transaction and showed a snackbar R.string.refund_success ("Refund received!"). The migration replaced that with a bare onNavigateBack(); refund_success and refund_error are still in strings.xml (translated) and now unused.

Code (origin/master 4c483527):
- wallet/src/main/java/net/taler/wallet/HandleUriScreen.kt:110-123: RefundStatus.Success -> onNavigateBack().
- wallet/src/main/java/net/taler/wallet/refund/RefundManager.kt:44-55: the success carries startRefundQueryForUri's transactionId (the purchase), unused.
- wallet/src/main/java/net/taler/wallet/transactions/Transactions.kt:444-456 and payment/TransactionPaymentComposable.kt:105-157: the purchase detail does not decode or show totalRefundEffective.
References: iOS Views/Sheets/Refund/RefundURIView.swift:26-50; web routes/App.tsx:3406-3433 and routes/transaction-model.ts:420-429.

Patch (android-refund-uri-feedback.patch):
- On success, select the purchase and navigate to its detail, exactly like the pay-URI branch a few lines above does.
- The purchase detail shows a "Refund" row (existing string transaction_refund) with totalRefundEffective when it is non-zero.
No new strings.
Verified: :wallet:assembleFdroidSim builds; after-android-1.png is the same scenario with the patch: the purchase opens and shows "Refund 0.50".

Not part of this: offering "check for refunds" from within the wallet (0006582).

Assisted by LLM
Steps To Reproduce1. Pay an order whose refund deadline has not passed.
2. Grant a refund for it in the merchant backoffice and open the taler://refund/ link (refund QR code) in the wallet.
3. The app shows a progress bar and returns to the previous screen without any feedback.
(Automated: wc-stack pay-uri --amount KUDOS:1 --refund-deadline 1h; pay; wc-stack refund <order> KUDOS:0.5; wc-android uri <refund uri>.)
TagsNo tags attached.
Attached Files
before-android-1.png (87,814 bytes)   
before-android-1.png (87,814 bytes)   
before-ios-1.png (212,029 bytes)   
before-ios-1.png (212,029 bytes)   
before-web-1.png (118,599 bytes)   
before-web-1.png (118,599 bytes)   
after-android-1.png (84,647 bytes)   
after-android-1.png (84,647 bytes)   
android-refund-uri-feedback.patch (2,984 bytes)   
diff --git a/wallet/src/main/java/net/taler/wallet/HandleUriScreen.kt b/wallet/src/main/java/net/taler/wallet/HandleUriScreen.kt
index 03a3c56a..39757cc0 100644
--- a/wallet/src/main/java/net/taler/wallet/HandleUriScreen.kt
+++ b/wallet/src/main/java/net/taler/wallet/HandleUriScreen.kt
@@ -115,8 +115,15 @@ fun HandleUriScreen(
                                 is RefundStatus.Error -> {
                                     errorInfo = status.error
                                 }
-                                is RefundStatus.Success -> {
-                                    onNavigateBack()
+                                is RefundStatus.Success -> scope.launch {
+                                    // Show the purchase the refund belongs to,
+                                    // like for a payment URI.
+                                    val transactionId = status.response.transactionId
+                                    if (model.transactionManager.selectTransaction(transactionId)) {
+                                        onNavigate(WalletDestination.TransactionPayment(), true)
+                                    } else {
+                                        onNavigateBack()
+                                    }
                                 }
                             }
                         }
diff --git a/wallet/src/main/java/net/taler/wallet/payment/TransactionPaymentComposable.kt b/wallet/src/main/java/net/taler/wallet/payment/TransactionPaymentComposable.kt
index 984a97f8..962060a9 100644
--- a/wallet/src/main/java/net/taler/wallet/payment/TransactionPaymentComposable.kt
+++ b/wallet/src/main/java/net/taler/wallet/payment/TransactionPaymentComposable.kt
@@ -138,6 +138,14 @@ fun TransactionPaymentComposable(
             amountType = AmountType.Negative,
         )
 
+        if (t.totalRefundEffective?.isZero() == false) {
+            TransactionAmountComposable(
+                label = stringResource(id = R.string.transaction_refund),
+                amount = t.totalRefundEffective.withSpec(t.amountRaw.spec),
+                amountType = AmountType.Positive,
+            )
+        }
+
         if (t.posConfirmation != null) PayTotpComposable(
             totpString = t.posConfirmation,
             enableNfc = t.posConfirmationViaNfc == true,
diff --git a/wallet/src/main/java/net/taler/wallet/transactions/Transactions.kt b/wallet/src/main/java/net/taler/wallet/transactions/Transactions.kt
index d5d397c5..d2c7e57b 100644
--- a/wallet/src/main/java/net/taler/wallet/transactions/Transactions.kt
+++ b/wallet/src/main/java/net/taler/wallet/transactions/Transactions.kt
@@ -451,6 +451,7 @@ data class TransactionPayment(
     override val amountRaw: Amount,
     override val amountEffective: Amount,
     override val scopes: List<ScopeInfo>,
+    val totalRefundEffective: Amount? = null,
     val posConfirmation: String? = null,
     val posConfirmationViaNfc: Boolean? = null,
 ) : Transaction() {

Required notifications

Address or linkRemarkAdded byNotifiedActions

Relationships

related to 0006582 acknowledged checking for refunds of a purchase should be possible from within the wallet [meta] 

Activities

Issue History

Date ModifiedUsernameFieldChange
2026-11-11 01:40bot-cgNew Issue
2026-11-11 01:40bot-cgRelationship addedrelated to 0006582
2026-11-11 01:40bot-cgFile Added: before-android-1.png
2026-11-11 01:40bot-cgFile Added: before-ios-1.png
2026-11-11 01:40bot-cgFile Added: before-web-1.png
2026-11-11 01:40bot-cgFile Added: after-android-1.png
2026-11-11 01:40bot-cgFile Added: android-refund-uri-feedback.patch