From 35349257d8ba621ea78abc938fb93234299b877c Mon Sep 17 00:00:00 2001 From: AnirudhBhat Date: Mon, 13 Jan 2025 08:57:41 +0530 Subject: [PATCH 01/12] Remove price filter from products screen --- .../home/items/products/WooPosProductsDataSource.kt | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/items/products/WooPosProductsDataSource.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/items/products/WooPosProductsDataSource.kt index d81928eabf4..261e4b4786b 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/items/products/WooPosProductsDataSource.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/items/products/WooPosProductsDataSource.kt @@ -45,7 +45,7 @@ class WooPosProductsDataSource @Inject constructor( ) if (result.isSuccess) { - val remoteProducts = handler.productsFlow.first().applyPosProductFilter() + val remoteProducts = handler.productsFlow.first() updateProductCache(remoteProducts) emit(ProductsResult.Remote(Result.success(productCache))) } else { @@ -63,7 +63,7 @@ class WooPosProductsDataSource @Inject constructor( suspend fun loadMore(): Result> = withContext(Dispatchers.IO) { val result = handler.loadMore() if (result.isSuccess) { - val moreProducts = handler.productsFlow.first().applyPosProductFilter() + val moreProducts = handler.productsFlow.first() updateProductCache(moreProducts) Result.success(productCache) } else { @@ -82,13 +82,6 @@ class WooPosProductsDataSource @Inject constructor( WooLog.e(WooLog.T.POS, "Loading products failed - $errorMessage", error) } - private fun List.applyPosProductFilter() = this.filter { product -> - isProductHasAPrice(product) - } - - private fun isProductHasAPrice(product: Product) = - (product.price != null) - sealed class ProductsResult { data class Cached(val products: List) : ProductsResult() data class Remote(val productsResult: Result>) : ProductsResult() From 1695808a0dfd6782357d6b713e4670317d504c84 Mon Sep 17 00:00:00 2001 From: AnirudhBhat Date: Mon, 13 Jan 2025 08:57:49 +0530 Subject: [PATCH 02/12] Remove price filter from variations screen --- .../woopos/home/items/variations/WooPosVariationsDataSource.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/items/variations/WooPosVariationsDataSource.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/items/variations/WooPosVariationsDataSource.kt index ea7c91963c8..ecef6c40570 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/items/variations/WooPosVariationsDataSource.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/items/variations/WooPosVariationsDataSource.kt @@ -89,5 +89,5 @@ sealed class FetchResult { } private fun List.applyFilter(): List { - return filter { it.price != null && !it.isDownloadable } + return filter { !it.isDownloadable } } From 6be3917334bad7260adfec04b50912de81d12d5b Mon Sep 17 00:00:00 2001 From: AnirudhBhat Date: Mon, 13 Jan 2025 08:58:03 +0530 Subject: [PATCH 03/12] Remove price filter unit test from products screen --- .../items/WooPosProductsDataSourceTest.kt | 36 ------------------- 1 file changed, 36 deletions(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/items/WooPosProductsDataSourceTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/items/WooPosProductsDataSourceTest.kt index 06dffa4505f..7fb88fa3f65 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/items/WooPosProductsDataSourceTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/items/WooPosProductsDataSourceTest.kt @@ -296,42 +296,6 @@ class WooPosProductsDataSourceTest { assertFalse(cachedResult.products.any { it.remoteId == 1L }) } - @Test - fun `given remote products, when loadSimpleProducts called, then filter in only products that has price`() = - runTest { - // GIVEN - whenever(handler.canLoadMore).thenReturn(AtomicBoolean(true)) - whenever(handler.productsFlow).thenReturn( - flowOf( - listOf( - ProductTestUtils.generateProduct( - productId = 1, - productName = "Product 1", - amount = "", - productType = "simple", - isDownloadable = false, - ), - ProductTestUtils.generateProduct( - productId = 2, - productName = "Product 2", - amount = "20.0", - productType = "simple", - isDownloadable = false - ).copy(firstImageUrl = "https://test.com") - ) - ) - ) - whenever(handler.loadFromCacheAndFetch(any(), any(), any(), any(), any())).thenReturn(Result.success(Unit)) - val sut = WooPosProductsDataSource(handler) - - // WHEN - val flow = sut.loadSimpleProducts(forceRefreshProducts = true).toList() - - // THEN - val remoteResult = flow[1] as WooPosProductsDataSource.ProductsResult.Remote - assertThat(remoteResult.productsResult.getOrNull()?.any { it.remoteId == 1L }).isFalse() - } - @Test fun `given cached products, when loadSimpleProducts called, then filter out downloadable products`() = runTest { From cc201eb3f27e1fa41f9c655546610d9f3a834606 Mon Sep 17 00:00:00 2001 From: AnirudhBhat Date: Mon, 13 Jan 2025 08:58:09 +0530 Subject: [PATCH 04/12] Remove price filter unit test from variation screen --- .../WooPosVariationsDataSourceTest.kt | 32 ------------------- 1 file changed, 32 deletions(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/variations/WooPosVariationsDataSourceTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/variations/WooPosVariationsDataSourceTest.kt index 812c7a8fef3..24001a69654 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/variations/WooPosVariationsDataSourceTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/variations/WooPosVariationsDataSourceTest.kt @@ -289,38 +289,6 @@ class WooPosVariationsDataSourceTest { assertFalse(cachedResult.data.any { it.remoteVariationId == 1L }) } - @Test - fun `given remote variations, when fetchFirstPage called, then filter in only variations that have price`() = runTest { - // GIVEN - val productId = 1L - whenever(handler.canLoadMore(5)).thenReturn(true) - whenever(handler.getVariationsFlow(productId)).thenReturn( - flowOf( - listOf( - ProductTestUtils.generateProductVariation( - variationId = 1, - amount = "", - ), - ProductTestUtils.generateProductVariation( - variationId = 2, - amount = "20.0", - ) - ) - ) - ) - whenever(variationsCache.get(productId)).thenReturn(sampleProducts) - whenever(handler.fetchVariations(productId, forceRefresh = true)).thenReturn(Result.success(Unit)) - val sut = WooPosVariationsDataSource(handler, variationsCache) - - // WHEN - val flow = sut.fetchFirstPage(productId, forceRefresh = true).toList() - - // THEN - val remoteResult = flow[1] as FetchResult.Remote - - assertThat(remoteResult.result.getOrNull()?.any { it.remoteVariationId == 1L }).isFalse() - } - @Test fun `given cached variations, when fetchFirstPage called, then filter out virtual variations`() = runTest { // GIVEN From f62b5fea3c1391911497a0a07a8403de5698acf6 Mon Sep 17 00:00:00 2001 From: AnirudhBhat Date: Wed, 15 Jan 2025 11:58:32 +0530 Subject: [PATCH 05/12] Add a boolean param to indicate whether the order is free or not --- .../android/ui/woopos/home/totals/WooPosTotalsViewState.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/WooPosTotalsViewState.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/WooPosTotalsViewState.kt index 9ccfe65b940..67634f6bfde 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/WooPosTotalsViewState.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/WooPosTotalsViewState.kt @@ -12,6 +12,7 @@ sealed class WooPosTotalsViewState : Parcelable { val orderTaxText: String, val orderTotalText: String, val readerStatus: ReaderStatus, + val isFreeOrder: Boolean, ) : WooPosTotalsViewState() data class PaymentSuccess(val orderTotalText: String) : WooPosTotalsViewState() From 82710980d981bbde25f02a59666d3286a57fb4ef Mon Sep 17 00:00:00 2001 From: AnirudhBhat Date: Wed, 15 Jan 2025 11:59:06 +0530 Subject: [PATCH 06/12] Update view state when there is free order added to cart --- .../android/ui/woopos/home/totals/WooPosTotalsViewModel.kt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/WooPosTotalsViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/WooPosTotalsViewModel.kt index 40da8f0109e..f341e21aa6e 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/WooPosTotalsViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/WooPosTotalsViewModel.kt @@ -122,6 +122,7 @@ class WooPosTotalsViewModel @Inject constructor( uiState.value = state.copy(readerStatus = buildTotalsReaderNotConnectedError()) cancelPaymentAction() } + is Connected -> { val state = uiState.value if (state !is WooPosTotalsViewState.Totals) return@collect @@ -253,7 +254,10 @@ class WooPosTotalsViewModel @Inject constructor( } else { val orderId = dataState.value.orderId check(orderId != EMPTY_ORDER_ID) - if (cardReaderFacade.readerStatus.value is Connected) { + if ( + cardReaderFacade.readerStatus.value is Connected && + dataState.value.orderTotal?.compareTo(BigDecimal.ZERO) == 1 + ) { val state = uiState.value check(state is WooPosTotalsViewState.Totals) check(uiState.value is WooPosTotalsViewState.Totals) @@ -458,6 +462,7 @@ class WooPosTotalsViewModel @Inject constructor( orderTaxText = priceFormat(taxAmount), orderTotalText = priceFormat(totalAmount), readerStatus = readerStatus, + isFreeOrder = totalAmount.compareTo(BigDecimal.ZERO) == 1 ) } From a61c31e4a3e3af685eb9d9a0155a43aae94c4f5f Mon Sep 17 00:00:00 2001 From: AnirudhBhat Date: Wed, 15 Jan 2025 11:59:21 +0530 Subject: [PATCH 07/12] Hide card payment screen for free orders --- .../woopos/home/totals/WooPosTotalsScreen.kt | 71 +++++++++++++------ 1 file changed, 49 insertions(+), 22 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/WooPosTotalsScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/WooPosTotalsScreen.kt index a0c3b906785..bc033e7215d 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/WooPosTotalsScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/WooPosTotalsScreen.kt @@ -151,26 +151,28 @@ private fun TotalsLoaded( horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center, ) { - Column( - modifier = Modifier - .fillMaxWidth() - .weight(1.1f) - .background(WooPosTheme.colors.totalsErrorBackground), - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.Center, - ) { - when (val readerStatus = state.readerStatus) { - is WooPosTotalsViewState.ReaderStatus.Disconnected -> { - ReaderDisconnected(modifier = Modifier, status = readerStatus, onUIEvent = onUIEvent) - } - - is WooPosTotalsViewState.ReaderStatus.Preparing, - is WooPosTotalsViewState.ReaderStatus.CheckingOrder -> { - PreparingReader(readerStatus) - } - - is WooPosTotalsViewState.ReaderStatus.ReadyForPayment -> { - ReaderReadyForPayment(readerStatus) + if (!state.isFreeOrder) { + Column( + modifier = Modifier + .fillMaxWidth() + .weight(1.1f) + .background(WooPosTheme.colors.totalsErrorBackground), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center, + ) { + when (val readerStatus = state.readerStatus) { + is WooPosTotalsViewState.ReaderStatus.Disconnected -> { + ReaderDisconnected(modifier = Modifier, status = readerStatus, onUIEvent = onUIEvent) + } + + is WooPosTotalsViewState.ReaderStatus.Preparing, + is WooPosTotalsViewState.ReaderStatus.CheckingOrder -> { + PreparingReader(readerStatus) + } + + is WooPosTotalsViewState.ReaderStatus.ReadyForPayment -> { + ReaderReadyForPayment(readerStatus) + } } } } @@ -418,6 +420,7 @@ fun WooPosTotalsScreenPreview(modifier: Modifier = Modifier) { title = "Ready for payment", subtitle = "Tap, swipe or insert card" ), + isFreeOrder = false ), onUIEvent = {}, ) @@ -438,7 +441,8 @@ fun WooPosTotalsScreenPreviewReaderNotConnected(modifier: Modifier = Modifier) { title = "Reader not connected", subtitle = "To process this payment, please connect your reader.", actionButtonLabel = "Connect to a reader", - ) + ), + isFreeOrder = false ), onUIEvent = {}, ) @@ -459,7 +463,30 @@ fun WooPosTotalsScreenPreviewWithCashPaymentAvailable() { title = "Reader not connected", subtitle = "To process this payment, please connect your reader.", actionButtonLabel = "Connect to a reader", - ) + ), + isFreeOrder = false + ), + onUIEvent = {}, + ) + } +} + +@Composable +@WooPosPreview +fun WooPosTotalsScreenPreviewForFreeOrders() { + WooPosTheme { + WooPosTotalsScreen( + modifier = Modifier, + state = WooPosTotalsViewState.Totals( + orderSubtotalText = "$420.00", + orderTotalText = "$462.00", + orderTaxText = "$42.00", + readerStatus = WooPosTotalsViewState.ReaderStatus.Disconnected( + title = "Reader not connected", + subtitle = "To process this payment, please connect your reader.", + actionButtonLabel = "Connect to a reader", + ), + isFreeOrder = true ), onUIEvent = {}, ) From 5e38fc5740d5d7ec38bff8f0f59e80751953fdf1 Mon Sep 17 00:00:00 2001 From: AnirudhBhat Date: Wed, 15 Jan 2025 13:22:07 +0530 Subject: [PATCH 08/12] Change logic to identify whether the order is free or not. --- .../android/ui/woopos/home/totals/WooPosTotalsViewModel.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/WooPosTotalsViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/WooPosTotalsViewModel.kt index f341e21aa6e..04828815e95 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/WooPosTotalsViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/totals/WooPosTotalsViewModel.kt @@ -462,7 +462,7 @@ class WooPosTotalsViewModel @Inject constructor( orderTaxText = priceFormat(taxAmount), orderTotalText = priceFormat(totalAmount), readerStatus = readerStatus, - isFreeOrder = totalAmount.compareTo(BigDecimal.ZERO) == 1 + isFreeOrder = totalAmount.compareTo(BigDecimal.ZERO) == 0 ) } From 601ad2eb0c54eeff7f4b726e8608f8c8bf96ff2a Mon Sep 17 00:00:00 2001 From: AnirudhBhat Date: Wed, 15 Jan 2025 14:32:29 +0530 Subject: [PATCH 09/12] Remove unnecessary tests --- .../WooPosVariationsDataSourceTest.kt | 70 ------------------- 1 file changed, 70 deletions(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/variations/WooPosVariationsDataSourceTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/variations/WooPosVariationsDataSourceTest.kt index aa0ea1678ad..ba244fe8f96 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/variations/WooPosVariationsDataSourceTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/variations/WooPosVariationsDataSourceTest.kt @@ -335,74 +335,4 @@ class WooPosVariationsDataSourceTest { assertFalse(cachedResult.data.any { it.remoteVariationId == 1L }) } - - @Test - fun `given cached variations, when fetchFirstPage called, then filter out downloadable variations`() = runTest { - // GIVEN - val productId = 1L - whenever(handler.canLoadMore(5)).thenReturn(false) - whenever(handler.getVariationsFlow(productId)).thenReturn( - flowOf( - listOf( - ProductTestUtils.generateProductVariation( - variationId = 1, - amount = "0", - isDownloadable = true - ), - ProductTestUtils.generateProductVariation( - variationId = 2, - amount = "20.0", - isVirtual = false, - isDownloadable = false - ) - ) - ) - ) - whenever(handler.fetchVariations(productId, forceRefresh = false)).thenReturn(Result.success(Unit)) - whenever(variationsCache.get(productId)).thenReturn(sampleProducts) - val sut = WooPosVariationsDataSource(handler, variationsCache) - - // WHEN - val flow = sut.fetchFirstPage(productId, forceRefresh = false).toList() - - // THEN - val cachedResult = flow[0] as FetchResult.Cached - - assertFalse(cachedResult.data.any { it.remoteVariationId == 1L }) - } - - @Test - fun `given remote variations, when fetchFirstPage called, then filter out downloadable variations`() = runTest { - // GIVEN - val productId = 1L - whenever(handler.canLoadMore(5)).thenReturn(true) - whenever(handler.getVariationsFlow(productId)).thenReturn( - flowOf( - listOf( - ProductTestUtils.generateProductVariation( - variationId = 1, - amount = "0", - isDownloadable = true - ), - ProductTestUtils.generateProductVariation( - variationId = 2, - amount = "20.0", - isVirtual = false, - isDownloadable = false - ) - ) - ) - ) - whenever(handler.fetchVariations(productId, forceRefresh = true)).thenReturn(Result.success(Unit)) - whenever(variationsCache.get(productId)).thenReturn(sampleProducts) - val sut = WooPosVariationsDataSource(handler, variationsCache) - - // WHEN - val flow = sut.fetchFirstPage(productId, forceRefresh = true).toList() - - // THEN - val remoteResult = flow[1] as FetchResult.Remote - - assertThat(remoteResult.result.getOrNull()?.any { it.remoteVariationId == 1L }).isFalse() - } } From 9dfff656518b781f5bb19c2536ed54433b8a2447 Mon Sep 17 00:00:00 2001 From: AnirudhBhat Date: Wed, 15 Jan 2025 14:34:28 +0530 Subject: [PATCH 10/12] Remove unused import --- .../ui/woopos/home/items/products/WooPosProductsDataSource.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/items/products/WooPosProductsDataSource.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/items/products/WooPosProductsDataSource.kt index 20dbdb233e3..261e4b4786b 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/items/products/WooPosProductsDataSource.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/items/products/WooPosProductsDataSource.kt @@ -2,7 +2,6 @@ package com.woocommerce.android.ui.woopos.home.items.products import com.woocommerce.android.model.Product import com.woocommerce.android.ui.products.ProductStatus -import com.woocommerce.android.ui.products.ProductType.VARIABLE import com.woocommerce.android.ui.products.selector.ProductListHandler import com.woocommerce.android.util.WooLog import kotlinx.coroutines.Dispatchers From 57c3d6477b5913512cd6e9b03f15ea45572cbda4 Mon Sep 17 00:00:00 2001 From: AnirudhBhat Date: Thu, 16 Jan 2025 16:26:42 +0530 Subject: [PATCH 11/12] Add test to verify free products in the cart updates the checkout state appropriately. --- .../home/totals/WooPosTotalsViewModelTest.kt | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/totals/WooPosTotalsViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/totals/WooPosTotalsViewModelTest.kt index b3c13bd998a..06a2496e46e 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/totals/WooPosTotalsViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/totals/WooPosTotalsViewModelTest.kt @@ -1125,6 +1125,63 @@ class WooPosTotalsViewModelTest { assertThat(successState.orderTotalText).isEqualTo("Paid 5.00$ in Cash") } + @Test + fun `given checkout started and order contains only free products, when vm created, then totals state correctly calculated`() = + runTest { + // GIVEN + whenever(resourceProvider.getString(R.string.woopos_totals_reader_getting_ready)) + .thenReturn("Getting ready") + whenever(resourceProvider.getString(R.string.woopos_totals_reader_checking_order)) + .thenReturn("Checking order") + whenever(resourceProvider.getString(R.string.woopos_no_internet_message)) + .thenReturn("No internet") + val itemClickedData = listOf( + WooPosItemsViewModel.ItemClickedData.SimpleProduct(id = 1L) + ) + val parentToChildrenEventFlow = MutableStateFlow(ParentToChildrenEvent.CheckoutClicked(itemClickedData)) + val parentToChildrenEventReceiver: WooPosParentToChildrenEventReceiver = mock { + on { events }.thenReturn(parentToChildrenEventFlow) + } + val order = Order.getEmptyOrder( + dateCreated = Date(), + dateModified = Date() + ).copy( + totalTax = BigDecimal("0.00"), + items = listOf( + Order.Item.EMPTY.copy( + subtotal = BigDecimal("0.00"), + ), + Order.Item.EMPTY.copy( + subtotal = BigDecimal("0.00"), + ), + Order.Item.EMPTY.copy( + subtotal = BigDecimal("0.00"), + ) + ), + total = BigDecimal("0.00"), + productsTotal = BigDecimal("0.00"), + ) + val totalsRepository: WooPosTotalsRepository = mock { + onBlocking { createOrderWithProducts(itemClickedData) }.thenReturn( + Result.success(order) + ) + } + val priceFormat: WooPosFormatPrice = mock { + onBlocking { invoke(BigDecimal("0.00")) }.thenReturn("0.00$") + } + + // WHEN + val viewModel = createViewModel( + parentToChildrenEventReceiver = parentToChildrenEventReceiver, + totalsRepository = totalsRepository, + priceFormat = priceFormat, + ) + + // THEN + val totals = viewModel.state.value as WooPosTotalsViewState.Totals + assertTrue(totals.isFreeOrder) + } + private fun createNonEmptyOrder() = Order.getEmptyOrder( dateCreated = Date(), dateModified = Date() From a95316688f02a5bb1a92d9f335fbcc1bf00276f1 Mon Sep 17 00:00:00 2001 From: AnirudhBhat Date: Thu, 16 Jan 2025 16:30:42 +0530 Subject: [PATCH 12/12] Add test to verify non-free products in the cart updates the checkout state appropriately. --- .../home/totals/WooPosTotalsViewModelTest.kt | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/totals/WooPosTotalsViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/totals/WooPosTotalsViewModelTest.kt index 06a2496e46e..14165485a9d 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/totals/WooPosTotalsViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/totals/WooPosTotalsViewModelTest.kt @@ -66,6 +66,7 @@ import org.wordpress.android.fluxc.store.WooCommerceStore import java.math.BigDecimal import java.util.Date import kotlin.test.Test +import kotlin.test.assertFalse @ExperimentalCoroutinesApi class WooPosTotalsViewModelTest { @@ -1182,6 +1183,65 @@ class WooPosTotalsViewModelTest { assertTrue(totals.isFreeOrder) } + @Test + fun `given checkout started and order contains non-free products, when vm created, then totals state correctly calculated`() = + runTest { + // GIVEN + whenever(resourceProvider.getString(R.string.woopos_totals_reader_getting_ready)) + .thenReturn("Getting ready") + whenever(resourceProvider.getString(R.string.woopos_totals_reader_checking_order)) + .thenReturn("Checking order") + whenever(resourceProvider.getString(R.string.woopos_no_internet_message)) + .thenReturn("No internet") + val itemClickedData = listOf( + WooPosItemsViewModel.ItemClickedData.SimpleProduct(id = 1L) + ) + val parentToChildrenEventFlow = MutableStateFlow(ParentToChildrenEvent.CheckoutClicked(itemClickedData)) + val parentToChildrenEventReceiver: WooPosParentToChildrenEventReceiver = mock { + on { events }.thenReturn(parentToChildrenEventFlow) + } + val order = Order.getEmptyOrder( + dateCreated = Date(), + dateModified = Date() + ).copy( + totalTax = BigDecimal("2.00"), + items = listOf( + Order.Item.EMPTY.copy( + subtotal = BigDecimal("1.00"), + ), + Order.Item.EMPTY.copy( + subtotal = BigDecimal("1.00"), + ), + Order.Item.EMPTY.copy( + subtotal = BigDecimal("1.00"), + ) + ), + total = BigDecimal("5.00"), + productsTotal = BigDecimal("3.00"), + ) + val totalsRepository: WooPosTotalsRepository = mock { + onBlocking { createOrderWithProducts(itemClickedData) }.thenReturn( + Result.success(order) + ) + } + val priceFormat: WooPosFormatPrice = mock { + onBlocking { invoke(BigDecimal("2.00")) }.thenReturn("2.00$") + onBlocking { invoke(BigDecimal("3.00")) }.thenReturn("3.00$") + onBlocking { invoke(BigDecimal("5.00")) }.thenReturn("5.00$") + } + + // WHEN + val viewModel = createViewModel( + parentToChildrenEventReceiver = parentToChildrenEventReceiver, + totalsRepository = totalsRepository, + priceFormat = priceFormat, + ) + + // THEN + val totals = viewModel.state.value as WooPosTotalsViewState.Totals + assertFalse(totals.isFreeOrder) + } + private fun createNonEmptyOrder() = Order.getEmptyOrder( dateCreated = Date(), dateModified = Date()