commit 299211675baba02d2f224c1783c13e3bece18549
parent 53d7a0b60b371d7bb2f6d7af425e436b78e073e8
Author: Iván Ávalos <avalos@disroot.org>
Date: Tue, 15 Apr 2025 17:31:11 +0200
[wallet] check B-I-W status after scanning URI
bug 0009683
Diffstat:
6 files changed, 73 insertions(+), 50 deletions(-)
diff --git a/wallet/src/main/java/net/taler/wallet/MainViewModel.kt b/wallet/src/main/java/net/taler/wallet/MainViewModel.kt
@@ -119,7 +119,7 @@ class MainViewModel(
val refundManager = RefundManager(api, viewModelScope)
val balanceManager = BalanceManager(api, viewModelScope)
val exchangeManager: ExchangeManager = ExchangeManager(api, viewModelScope)
- val withdrawManager = WithdrawManager(api, viewModelScope, exchangeManager)
+ val withdrawManager = WithdrawManager(api, viewModelScope, exchangeManager, transactionManager)
val peerManager: PeerManager = PeerManager(api, exchangeManager, viewModelScope)
val settingsManager: SettingsManager = SettingsManager(app.applicationContext, api, viewModelScope, balanceManager)
val accountManager: AccountManager = AccountManager(api, viewModelScope)
diff --git a/wallet/src/main/java/net/taler/wallet/transactions/TransactionWithdrawalFragment.kt b/wallet/src/main/java/net/taler/wallet/transactions/TransactionWithdrawalFragment.kt
@@ -82,6 +82,7 @@ class TransactionWithdrawalFragment : TransactionDetailFragment(), ActionListene
if (tx !is TransactionWithdrawal) return
if (tx.withdrawalDetails !is ManualTransfer) return
if (tx.withdrawalDetails.exchangeCreditAccountDetails.isNullOrEmpty()) return
+ if (tx.exchangeBaseUrl == null) return
withdrawManager.viewManualWithdrawal(
transactionId = tx.transactionId,
@@ -89,10 +90,10 @@ class TransactionWithdrawalFragment : TransactionDetailFragment(), ActionListene
amountRaw = tx.amountRaw,
amountEffective = tx.amountEffective,
withdrawalAccountList = tx.withdrawalDetails.exchangeCreditAccountDetails,
- scopeInfo = transactionManager.selectedScope.value ?: ScopeInfo.Exchange(
- currency = tx.amountRaw.currency,
- url = tx.exchangeBaseUrl,
- ),
+ scopeInfo = transactionManager.selectedScope.value
+ ?: tx.exchangeBaseUrl.let {
+ ScopeInfo.Exchange(currency = tx.amountRaw.currency, url = it)
+ },
)
findNavController().navigate(
diff --git a/wallet/src/main/java/net/taler/wallet/transactions/Transactions.kt b/wallet/src/main/java/net/taler/wallet/transactions/Transactions.kt
@@ -161,7 +161,7 @@ class TransactionWithdrawal(
override val txState: TransactionState,
override val txActions: List<TransactionAction>,
val kycUrl: String? = null,
- val exchangeBaseUrl: String,
+ val exchangeBaseUrl: String? = null,
val withdrawalDetails: WithdrawalDetails,
override val error: TalerErrorInfo? = null,
override val amountRaw: Amount,
diff --git a/wallet/src/main/java/net/taler/wallet/withdraw/PromptWithdrawFragment.kt b/wallet/src/main/java/net/taler/wallet/withdraw/PromptWithdrawFragment.kt
@@ -58,6 +58,7 @@ import net.taler.wallet.exchanges.ExchangeItem
import net.taler.wallet.exchanges.ExchangeTosStatus
import net.taler.wallet.exchanges.SelectExchangeDialogFragment
import net.taler.wallet.showError
+import net.taler.wallet.withdraw.WithdrawStatus.Status.AlreadyConfirmed
import net.taler.wallet.withdraw.WithdrawStatus.Status.InfoReceived
import net.taler.wallet.withdraw.WithdrawStatus.Status.Loading
import net.taler.wallet.withdraw.WithdrawStatus.Status.ManualTransferRequired
@@ -65,7 +66,7 @@ import net.taler.wallet.withdraw.WithdrawStatus.Status.None
import net.taler.wallet.withdraw.WithdrawStatus.Status.Success
import net.taler.wallet.withdraw.WithdrawStatus.Status.TosReviewRequired
import net.taler.wallet.withdraw.WithdrawStatus.Status.Updating
-import net.taler.wallet.withdraw.WithdrawalOperationStatusFlag.*
+import net.taler.wallet.withdraw.WithdrawalOperationStatusFlag.Pending
class PromptWithdrawFragment: Fragment() {
private val model: MainViewModel by activityViewModels()
@@ -110,7 +111,7 @@ class PromptWithdrawFragment: Fragment() {
if (status.status == None) {
if (withdrawUri != null) {
// get withdrawal details for taler://withdraw URI
- withdrawManager.getWithdrawalDetails(withdrawUri, loading = true)
+ withdrawManager.prepareBankIntegratedWithdrawal(withdrawUri, loading = true)
} else if (withdrawExchangeUri != null) {
// get withdrawal details for taler://withdraw-exchange URI
withdrawManager.prepareManualWithdrawal(withdrawExchangeUri)
@@ -140,17 +141,13 @@ class PromptWithdrawFragment: Fragment() {
return@let
}
- if (s.uriInfo?.status == Confirmed) {
- return@let
- }
-
if (defaultCurrency == null) {
LoadingScreen()
return@let
}
when (s.status) {
- Loading -> LoadingScreen()
+ Loading, AlreadyConfirmed -> LoadingScreen()
None, InfoReceived, TosReviewRequired, Updating -> {
// TODO: use scopeInfo instead of currency!
@@ -198,22 +195,23 @@ class PromptWithdrawFragment: Fragment() {
showError(status.error)
}
- if (status.uriInfo?.status == Confirmed) {
- Snackbar.make(requireView(), R.string.withdraw_error_already_confirmed, LENGTH_LONG).show()
- if (!navigating) {
- navigating = true
- findNavController().navigate(R.id.action_promptWithdraw_to_nav_main)
- }
- }
-
if (status.exchangeBaseUrl == null
&& selectExchangeDialog.dialog?.isShowing != true) {
selectExchange()
}
when (status.status) {
- Success, ManualTransferRequired -> lifecycleScope.launch {
- Snackbar.make(requireView(), R.string.withdraw_initiated, LENGTH_LONG).show()
+ Success, ManualTransferRequired, AlreadyConfirmed -> lifecycleScope.launch {
+ Snackbar.make(
+ requireView(),
+ if (status.status == AlreadyConfirmed) {
+ R.string.withdraw_error_already_confirmed
+ } else {
+ R.string.withdraw_initiated
+ },
+ LENGTH_LONG,
+ ).show()
+
status.transactionId?.let {
if (!navigating) {
navigating = true
@@ -221,10 +219,10 @@ class PromptWithdrawFragment: Fragment() {
if (transactionManager.selectTransaction(it)) {
status.amountInfo?.scopeInfo?.let { s -> transactionManager.selectScope(s) }
- if (status.status == Success) {
- findNavController().navigate(R.id.action_promptWithdraw_to_nav_transactions_detail_withdrawal)
- } else {
- findNavController().navigate(R.id.action_promptWithdraw_to_nav_exchange_manual_withdrawal_success)
+ when (status.status) {
+ Success, AlreadyConfirmed -> findNavController().navigate(R.id.action_promptWithdraw_to_nav_transactions_detail_withdrawal)
+ ManualTransferRequired -> findNavController().navigate(R.id.action_promptWithdraw_to_nav_exchange_manual_withdrawal_success)
+ else -> error("unreachable")
}
} else {
findNavController().navigate(R.id.action_promptWithdraw_to_nav_main)
diff --git a/wallet/src/main/java/net/taler/wallet/withdraw/TransactionWithdrawalComposable.kt b/wallet/src/main/java/net/taler/wallet/withdraw/TransactionWithdrawalComposable.kt
@@ -111,10 +111,12 @@ fun TransactionWithdrawalComposable(
amountType = AmountType.Positive,
)
- TransactionInfoComposable(
- label = stringResource(id = R.string.withdraw_exchange),
- info = cleanExchange(t.exchangeBaseUrl),
- )
+ if (t.exchangeBaseUrl != null) {
+ TransactionInfoComposable(
+ label = stringResource(id = R.string.withdraw_exchange),
+ info = cleanExchange(t.exchangeBaseUrl),
+ )
+ }
TransitionsComposable(t, devMode, onTransition)
diff --git a/wallet/src/main/java/net/taler/wallet/withdraw/WithdrawManager.kt b/wallet/src/main/java/net/taler/wallet/withdraw/WithdrawManager.kt
@@ -42,6 +42,8 @@ import net.taler.wallet.exchanges.ExchangeTosStatus
import net.taler.wallet.transactions.WithdrawalExchangeAccountDetails
import net.taler.wallet.withdraw.WithdrawStatus.Status.*
import androidx.core.net.toUri
+import net.taler.wallet.transactions.TransactionMajorState
+import net.taler.wallet.transactions.TransactionManager
sealed class TestWithdrawStatus {
data object None : TestWithdrawStatus()
@@ -73,6 +75,7 @@ data class WithdrawStatus(
Loading,
Updating,
InfoReceived,
+ AlreadyConfirmed,
TosReviewRequired,
ManualTransferRequired,
Success,
@@ -138,6 +141,12 @@ enum class WithdrawalOperationStatusFlag {
}
@Serializable
+data class PrepareBankIntegratedWithdrawalResponse(
+ val transactionId: String,
+ val info: WithdrawalDetailsForUri,
+)
+
+@Serializable
data class WithdrawalDetailsForUri(
val amount: Amount? = null,
val currency: String,
@@ -230,6 +239,7 @@ class WithdrawManager(
private val api: WalletBackendApi,
private val scope: CoroutineScope,
private val exchangeManager: ExchangeManager,
+ private val transactionManager: TransactionManager,
) {
private val _withdrawStatus = MutableStateFlow(WithdrawStatus())
val withdrawStatus: StateFlow<WithdrawStatus> = _withdrawStatus.asStateFlow()
@@ -266,7 +276,7 @@ class WithdrawManager(
_withdrawTestStatus.value = TestWithdrawStatus.None
}
- fun getWithdrawalDetails(
+ fun prepareBankIntegratedWithdrawal(
uri: String,
loading: Boolean = true,
) = scope.launch {
@@ -278,28 +288,40 @@ class WithdrawManager(
}
// first get URI details
- api.request("getWithdrawalDetailsForUri", WithdrawalDetailsForUri.serializer()) {
+ api.request(
+ "prepareBankIntegratedWithdrawal",
+ PrepareBankIntegratedWithdrawalResponse.serializer(),
+ ) {
put("talerWithdrawUri", uri)
}.onError { error ->
- handleError("getWithdrawalDetailsForUri", error)
+ handleError("prepareBankIntegratedWithdrawal", error)
}.onSuccess { details ->
Log.d(TAG, "Withdraw details: $details")
- val status = _withdrawStatus.updateAndGet { value ->
- value.copy(
- status = InfoReceived,
- uriInfo = details,
- currency = details.currency,
- exchangeBaseUrl = details.defaultExchangeBaseUrl,
- )
- }
+ scope.launch {
+ val tx = transactionManager.getTransactionById(details.transactionId)
+ ?: error("transaction ${details.transactionId} not found")
+ val status = _withdrawStatus.updateAndGet { value ->
+ value.copy(
+ status = if (tx.txState.major == TransactionMajorState.Dialog) {
+ InfoReceived
+ } else {
+ AlreadyConfirmed
+ },
+ uriInfo = details.info,
+ currency = details.info.currency,
+ exchangeBaseUrl = details.info.defaultExchangeBaseUrl,
+ transactionId = details.transactionId,
+ )
+ }
- // then extend with amount details (not for cash acceptor)
- if (!status.isCashAcceptor) {
- getWithdrawalDetails(
- amount = details.amount,
- exchangeBaseUrl = details.defaultExchangeBaseUrl,
- loading = loading,
- )
+ // then extend with amount details (not for cash acceptor)
+ if (!status.isCashAcceptor) {
+ getWithdrawalDetails(
+ amount = details.info.amount,
+ exchangeBaseUrl = details.info.defaultExchangeBaseUrl,
+ loading = loading,
+ )
+ }
}
}
}
@@ -498,7 +520,7 @@ class WithdrawManager(
*/
fun viewManualWithdrawal(
transactionId: String,
- exchangeBaseUrl: String,
+ exchangeBaseUrl: String? = null,
amountRaw: Amount,
amountEffective: Amount,
withdrawalAccountList: List<WithdrawalExchangeAccountDetails>,