From 3ab6f1569b307b155de6049ad7207e10bdf97567 Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Tue, 11 Aug 2020 17:35:16 -0300 Subject: [wallet] upgrade wallet-core and adapt payment API --- .../net/taler/wallet/payment/PaymentManager.kt | 72 ++++++++++++---------- .../net/taler/wallet/payment/PaymentResponses.kt | 17 +++++ .../taler/wallet/payment/PromptPaymentFragment.kt | 7 +-- 3 files changed, 58 insertions(+), 38 deletions(-) (limited to 'wallet/src/main/java/net/taler/wallet/payment') diff --git a/wallet/src/main/java/net/taler/wallet/payment/PaymentManager.kt b/wallet/src/main/java/net/taler/wallet/payment/PaymentManager.kt index db21da4..041fcd3 100644 --- a/wallet/src/main/java/net/taler/wallet/payment/PaymentManager.kt +++ b/wallet/src/main/java/net/taler/wallet/payment/PaymentManager.kt @@ -22,11 +22,13 @@ import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.module.kotlin.readValue +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.launch import net.taler.common.Amount import net.taler.common.ContractTerms import net.taler.wallet.TAG import net.taler.wallet.backend.WalletBackendApi -import net.taler.wallet.getErrorString +import net.taler.wallet.backend.WalletErrorInfo import net.taler.wallet.payment.PayStatus.AlreadyPaid import net.taler.wallet.payment.PayStatus.InsufficientBalance import net.taler.wallet.payment.PreparePayResponse.AlreadyConfirmedResponse @@ -47,14 +49,20 @@ sealed class PayStatus { val amountEffective: Amount ) : PayStatus() - data class InsufficientBalance(val contractTerms: ContractTerms) : PayStatus() + data class InsufficientBalance( + val contractTerms: ContractTerms, + val amountRaw: Amount + ) : PayStatus() + + // TODO bring user to fulfilment URI object AlreadyPaid : PayStatus() data class Error(val error: String) : PayStatus() data class Success(val currency: String) : PayStatus() } class PaymentManager( - private val walletBackendApi: WalletBackendApi, + private val api: WalletBackendApi, + private val scope: CoroutineScope, private val mapper: ObjectMapper ) { @@ -65,21 +73,21 @@ class PaymentManager( internal val detailsShown: LiveData = mDetailsShown @UiThread - fun preparePay(url: String) { + fun preparePay(url: String) = scope.launch { mPayStatus.value = PayStatus.Loading mDetailsShown.value = false - - val args = JSONObject(mapOf("talerPayUri" to url)) - walletBackendApi.sendRequest("preparePay", args) { isError, result -> - if (isError) { - handleError("preparePay", getErrorString(result)) - return@sendRequest - } - val response: PreparePayResponse = mapper.readValue(result.toString()) - Log.e(TAG, "PreparePayResponse $response") + api.request("preparePay", mapper) { + put("talerPayUri", url) + }.onError { + handleError("preparePay", it) + }.onSuccess { response -> + Log.e(TAG, "PreparePayResponse $response") // TODO remove mPayStatus.value = when (response) { is PaymentPossibleResponse -> response.toPayStatusPrepared() - is InsufficientBalanceResponse -> InsufficientBalance(response.contractTerms) + is InsufficientBalanceResponse -> InsufficientBalance( + response.contractTerms, + response.amountRaw + ) is AlreadyConfirmedResponse -> AlreadyPaid } } @@ -99,13 +107,12 @@ class PaymentManager( return terms } - fun confirmPay(proposalId: String, currency: String) { - val args = JSONObject(mapOf("proposalId" to proposalId)) - walletBackendApi.sendRequest("confirmPay", args) { isError, result -> - if (isError) { - handleError("preparePay", getErrorString(result)) - return@sendRequest - } + fun confirmPay(proposalId: String, currency: String) = scope.launch { + api.request("confirmPay", ConfirmPayResult.serializer()) { + put("proposalId", proposalId) + }.onError { + handleError("confirmPay", it) + }.onSuccess { mPayStatus.postValue(PayStatus.Success(currency)) } } @@ -119,17 +126,14 @@ class PaymentManager( resetPayStatus() } - internal fun abortProposal(proposalId: String) { - val args = JSONObject(mapOf("proposalId" to proposalId)) - + internal fun abortProposal(proposalId: String) = scope.launch { Log.i(TAG, "aborting proposal") - - walletBackendApi.sendRequest("abortProposal", args) { isError, result -> - if (isError) { - handleError("abortProposal", getErrorString(result)) - Log.e(TAG, "received error response to abortProposal") - return@sendRequest - } + api.request("abortProposal", mapper) { + put("proposalId", proposalId) + }.onError { + Log.e(TAG, "received error response to abortProposal") + handleError("abortProposal", it) + }.onSuccess { mPayStatus.postValue(PayStatus.None) } } @@ -145,9 +149,9 @@ class PaymentManager( mPayStatus.value = PayStatus.None } - private fun handleError(operation: String, msg: String) { - Log.e(TAG, "got $operation error result $msg") - mPayStatus.value = PayStatus.Error(msg) + private fun handleError(operation: String, error: WalletErrorInfo) { + Log.e(TAG, "got $operation error result $error") + mPayStatus.value = PayStatus.Error(error.userFacingMsg) } } diff --git a/wallet/src/main/java/net/taler/wallet/payment/PaymentResponses.kt b/wallet/src/main/java/net/taler/wallet/payment/PaymentResponses.kt index 1ff8867..120489d 100644 --- a/wallet/src/main/java/net/taler/wallet/payment/PaymentResponses.kt +++ b/wallet/src/main/java/net/taler/wallet/payment/PaymentResponses.kt @@ -19,8 +19,11 @@ package net.taler.wallet.payment import com.fasterxml.jackson.annotation.JsonTypeInfo import com.fasterxml.jackson.annotation.JsonTypeInfo.Id.NAME import com.fasterxml.jackson.annotation.JsonTypeName +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable import net.taler.common.Amount import net.taler.common.ContractTerms +import net.taler.wallet.transactions.TransactionError @JsonTypeInfo(use = NAME, property = "status") sealed class PreparePayResponse(open val proposalId: String) { @@ -42,6 +45,7 @@ sealed class PreparePayResponse(open val proposalId: String) { @JsonTypeName("insufficient-balance") data class InsufficientBalanceResponse( override val proposalId: String, + val amountRaw: Amount, val contractTerms: ContractTerms ) : PreparePayResponse(proposalId) @@ -52,6 +56,8 @@ sealed class PreparePayResponse(open val proposalId: String) { * Did the payment succeed? */ val paid: Boolean, + val amountRaw: Amount, + val amountEffective: Amount, /** * Redirect URL for the fulfillment page, only given if paid==true. @@ -59,3 +65,14 @@ sealed class PreparePayResponse(open val proposalId: String) { val nextUrl: String? ) : PreparePayResponse(proposalId) } + +@Serializable +sealed class ConfirmPayResult { + @Serializable + @SerialName("done") + data class Done(val nextUrl: String) : ConfirmPayResult() + + @Serializable + @SerialName("pending") + data class Pending(val lastError: TransactionError) : ConfirmPayResult() +} diff --git a/wallet/src/main/java/net/taler/wallet/payment/PromptPaymentFragment.kt b/wallet/src/main/java/net/taler/wallet/payment/PromptPaymentFragment.kt index ce2b6f7..40664e3 100644 --- a/wallet/src/main/java/net/taler/wallet/payment/PromptPaymentFragment.kt +++ b/wallet/src/main/java/net/taler/wallet/payment/PromptPaymentFragment.kt @@ -96,7 +96,7 @@ class PromptPaymentFragment : Fragment(), ProductImageClickListener { is PayStatus.Prepared -> { showLoading(false) val fees = payStatus.amountEffective - payStatus.amountRaw - showOrder(payStatus.contractTerms, fees) + showOrder(payStatus.contractTerms, payStatus.amountRaw, fees) confirmButton.isEnabled = true confirmButton.setOnClickListener { model.showProgressBar.value = true @@ -110,7 +110,7 @@ class PromptPaymentFragment : Fragment(), ProductImageClickListener { } is PayStatus.InsufficientBalance -> { showLoading(false) - showOrder(payStatus.contractTerms) + showOrder(payStatus.contractTerms, payStatus.amountRaw) errorView.setText(R.string.payment_balance_insufficient) errorView.fadeIn() } @@ -142,11 +142,10 @@ class PromptPaymentFragment : Fragment(), ProductImageClickListener { } } - private fun showOrder(contractTerms: ContractTerms, totalFees: Amount? = null) { + private fun showOrder(contractTerms: ContractTerms, amount:Amount, totalFees: Amount? = null) { orderView.text = contractTerms.summary adapter.setItems(contractTerms.products) if (contractTerms.products.size == 1) paymentManager.toggleDetailsShown() - val amount = contractTerms.amount totalView.text = amount.toString() if (totalFees != null && !totalFees.isZero()) { feeView.text = getString(R.string.payment_fee, totalFees) -- cgit v1.2.3