Skip to content

[Payment Method Improvements] Cash Payment Improvements #11414

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 36 commits into from
May 15, 2024
Merged
Show file tree
Hide file tree
Changes from 34 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
97b0a24
Initial FF check
backwardstruck Apr 29, 2024
5607c0d
Clean up the disorder
backwardstruck Apr 29, 2024
1eddaf5
Add data class
backwardstruck Apr 29, 2024
8920cc0
Start adding navigation logic
backwardstruck Apr 29, 2024
4a3249e
Add placeholder UI
backwardstruck Apr 30, 2024
e4c2823
Merge branch 'trunk' into 10941-cash-payment-improvements
backwardstruck May 10, 2024
3d77aa0
Add title string
backwardstruck May 10, 2024
0face8a
No need to pop up
backwardstruck May 10, 2024
23eb91d
Dialog fragment
backwardstruck May 10, 2024
18f5e20
Changes to fragment and viewmodel
backwardstruck May 10, 2024
85a6b79
Static code analysis
backwardstruck May 13, 2024
62a5205
Add test class
backwardstruck May 13, 2024
4ad0eb7
Update test class
backwardstruck May 13, 2024
020cb3b
Update test class
backwardstruck May 13, 2024
c21d8a1
Update test class
backwardstruck May 13, 2024
cb30201
Update test class
backwardstruck May 13, 2024
de54aa8
Update test class
backwardstruck May 13, 2024
8c45aa3
Detekt first pass
backwardstruck May 13, 2024
a905ee5
Detekt second pass
backwardstruck May 13, 2024
886a518
Detekt third pass
backwardstruck May 13, 2024
6b05cc5
Detekt fourth pass
backwardstruck May 13, 2024
71a082d
Detekt imports
backwardstruck May 13, 2024
ec6e679
Merge remote-tracking branch 'origin/trunk' into 10941-cash-payment-i…
backwardstruck May 14, 2024
5222b8f
Update detekt configuration
backwardstruck May 14, 2024
f676784
Move test to the module
backwardstruck May 14, 2024
27412c1
Remove unused import
backwardstruck May 14, 2024
dcd90b0
Test simplified
backwardstruck May 14, 2024
a73d119
Address PR comments
backwardstruck May 14, 2024
cb6c05a
Use ScopedViewModel
backwardstruck May 14, 2024
76ad3ab
Use ScopedViewModel
backwardstruck May 14, 2024
ff19eca
Don't try/catch
backwardstruck May 14, 2024
9776bc2
It should be non-null.
backwardstruck May 14, 2024
5acadcb
Assert TODO
backwardstruck May 14, 2024
81fe1fc
FF as false for now
backwardstruck May 14, 2024
c919f23
Update test and method
backwardstruck May 15, 2024
3a5645c
Detekt change
backwardstruck May 15, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package com.woocommerce.android.ui.payments.methodselection

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.viewModels
import com.woocommerce.android.R
import dagger.hilt.android.AndroidEntryPoint

@AndroidEntryPoint
class ChangeDueCalculatorFragment : DialogFragment() {

private val viewModel: ChangeDueCalculatorViewModel by viewModels()

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
return ComposeView(requireContext()).apply {
setContent {
ChangeDueCalculatorScreen()
}
}
}

@Composable
fun ChangeDueCalculatorScreen() {
val uiState by viewModel.uiState.collectAsState()

Column(
modifier = Modifier
.fillMaxSize()
.padding(16.dp),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
// Display dynamic content based on UI state
when (uiState) {
is ChangeDueCalculatorViewModel.UiState.Loading -> {
Text(text = stringResource(R.string.loading), style = MaterialTheme.typography.h5)
}

is ChangeDueCalculatorViewModel.UiState.Success -> {
val state = uiState as ChangeDueCalculatorViewModel.UiState.Success
Text(
text = stringResource(R.string.cash_payments_take_payment_title, state.amountDue),
style = MaterialTheme.typography.h5,
modifier = Modifier.padding(bottom = 16.dp)
)
}

is ChangeDueCalculatorViewModel.UiState.Error -> {
Text(text = stringResource(R.string.error_generic), style = MaterialTheme.typography.h5)
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package com.woocommerce.android.ui.payments.methodselection

import androidx.annotation.VisibleForTesting
import androidx.lifecycle.SavedStateHandle
import com.woocommerce.android.ui.orders.details.OrderDetailRepository
import com.woocommerce.android.viewmodel.ScopedViewModel
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
import java.math.BigDecimal
import javax.inject.Inject

@HiltViewModel
class ChangeDueCalculatorViewModel @Inject constructor(
savedStateHandle: SavedStateHandle,
private val orderDetailRepository: OrderDetailRepository
) : ScopedViewModel(savedStateHandle) {

private val orderId: Long = savedStateHandle.get<Long>("orderId")
?: throw IllegalArgumentException("OrderId is required")

sealed class UiState {
data object Loading : UiState()
data class Success(val amountDue: BigDecimal, val change: BigDecimal) : UiState()
data object Error : UiState()
}

private val _uiState = MutableStateFlow<UiState>(UiState.Loading)
val uiState: StateFlow<UiState> = _uiState

init {
loadOrderDetails()
}

@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
internal fun loadOrderDetails() {
launch {
val order = orderDetailRepository.getOrderById(orderId)!!
_uiState.value = UiState.Success(amountDue = order.total, 0.00.toBigDecimal())
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,8 @@ data class NavigateBackToOrderList(
val order: Order
) : MultiLiveEvent.Event()

data class NavigateToChangeDueCalculatorScreen(
val order: Order
) : MultiLiveEvent.Event()

data class OpenGenericWebView(val url: String) : MultiLiveEvent.Event()
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,15 @@ class SelectPaymentMethodFragment : BaseFragment(R.layout.fragment_select_paymen
findNavController().navigateSafely(action)
}

is NavigateToChangeDueCalculatorScreen -> {
val action =
SelectPaymentMethodFragmentDirections
.actionSelectPaymentMethodFragmentToChangeDueCalculatorFragment(
orderId = event.order.id
)
findNavController().navigate(action)
}

is NavigateToTapToPaySummary -> {
findNavController().navigateSafely(
SelectPaymentMethodFragmentDirections
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import com.woocommerce.android.ui.payments.tracking.CardReaderTrackingInfoKeeper
import com.woocommerce.android.ui.payments.tracking.PaymentsFlowTracker
import com.woocommerce.android.util.CoroutineDispatchers
import com.woocommerce.android.util.CurrencyFormatter
import com.woocommerce.android.util.FeatureFlag
import com.woocommerce.android.viewmodel.MultiLiveEvent
import com.woocommerce.android.viewmodel.ScopedViewModel
import com.woocommerce.android.viewmodel.navArgs
Expand Down Expand Up @@ -229,23 +230,34 @@ class SelectPaymentMethodViewModel @Inject constructor(
}

fun onCashPaymentClicked() {
if (FeatureFlag.OTHER_PAYMENT_METHODS.isEnabled()) {
handleCashPaymentClick()
} else {
launch {
trackPaymentMethodSelection(VALUE_SIMPLE_PAYMENTS_COLLECT_CASH)
val messageIdForPaymentType = when (cardReaderPaymentFlowParam.paymentType) {
SIMPLE, TRY_TAP_TO_PAY -> R.string.simple_payments_cash_dlg_message
ORDER, ORDER_CREATION -> R.string.existing_order_cash_dlg_message
}
triggerEvent(
MultiLiveEvent.Event.ShowDialog(
titleId = R.string.simple_payments_cash_dlg_title,
messageId = messageIdForPaymentType,
positiveButtonId = R.string.simple_payments_cash_dlg_button,
positiveBtnAction = { _, _ ->
onCashPaymentConfirmed()
},
negativeButtonId = R.string.cancel
)
)
}
}
}

private fun handleCashPaymentClick() {
launch {
trackPaymentMethodSelection(VALUE_SIMPLE_PAYMENTS_COLLECT_CASH)
val messageIdForPaymentType = when (cardReaderPaymentFlowParam.paymentType) {
SIMPLE, TRY_TAP_TO_PAY -> R.string.simple_payments_cash_dlg_message
ORDER, ORDER_CREATION -> R.string.existing_order_cash_dlg_message
}
triggerEvent(
MultiLiveEvent.Event.ShowDialog(
titleId = R.string.simple_payments_cash_dlg_title,
messageId = messageIdForPaymentType,
positiveButtonId = R.string.simple_payments_cash_dlg_button,
positiveBtnAction = { _, _ ->
onCashPaymentConfirmed()
},
negativeButtonId = R.string.cancel
)
)
triggerEvent(NavigateToChangeDueCalculatorScreen(order.first()))
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ enum class FeatureFlag {
PackageUtils.isDebugBuild() || context != null && PackageUtils.isBetaBuild(context)
}

OTHER_PAYMENT_METHODS,
OTHER_PAYMENT_METHODS -> false

MORE_MENU_INBOX,
WOO_POS,
WC_SHIPPING_BANNER,
Expand Down
13 changes: 13 additions & 0 deletions WooCommerce/src/main/res/navigation/nav_graph_payment_flow.xml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,13 @@
android:name="orderId"
app:argType="long" />
</action>
<action
android:id="@+id/action_selectPaymentMethodFragment_to_changeDueCalculatorFragment"
app:destination="@+id/changeDueCalculatorFragment">
<argument
android:name="orderId"
app:argType="long" />
</action>
<action
android:id="@+id/action_selectPaymentMethodFragment_to_tapToPaySummaryFragment"
app:destination="@id/tapToPaySummaryFragment"
Expand All @@ -56,6 +63,12 @@
app:destination="@id/scanToPayDialogFragment" />
</fragment>

<fragment
android:id="@+id/changeDueCalculatorFragment"
android:name="com.woocommerce.android.ui.payments.methodselection.ChangeDueCalculatorFragment"
android:label="ChangeDueCalculatorFragment" />


<!-- Onboarding flow -->
<dialog
android:id="@+id/cardReaderStatusCheckerDialogFragment"
Expand Down
5 changes: 5 additions & 0 deletions WooCommerce/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -565,6 +565,11 @@
<string name="simple_payments_share_payment_link">Share Payment Link</string>
<string name="simple_payments_share_payment_dialog_title">Checkout - %s</string>

<!--
Cash Payments
-->
<string name="cash_payments_take_payment_title">Take payment (%s)</string>

<!--
Custom Amounts
-->
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.woocommerce.android.ui.payments.methodselection

import com.woocommerce.android.viewmodel.BaseUnitTest
import kotlinx.coroutines.ExperimentalCoroutinesApi
import org.junit.Test
import org.mockito.kotlin.mock

@ExperimentalCoroutinesApi
class ChangeDueCalculatorViewModelTest : BaseUnitTest() {

private val viewModel: ChangeDueCalculatorViewModel = mock()

@Test
fun `given valid order id, when order details are requested, then success state is emitted`() = testBlocking {
// GIVEN
// TODO

// WHEN
viewModel.loadOrderDetails()

// THEN
// TODO
}

@Test
fun `given order details retrieval failure, when order details are loaded, then error state is emitted`() = testBlocking {
// GIVEN
// TODO

// WHEN
viewModel.loadOrderDetails()

// THEN
// TODO assertThat(viewModel.uiState.value).isEqualTo(ChangeDueCalculatorViewModel.UiState.Error)
}
}
Loading