Skip to content

Commit f4b5bc3

Browse files
authored
Merge pull request #14588 from woocommerce/issue/woomob-1280-woo-poslocal-catalog-use-new-pos-specific-product-model
POS Product Migration Step 5
2 parents 616b935 + 41e2881 commit f4b5bc3

File tree

10 files changed

+146
-177
lines changed

10 files changed

+146
-177
lines changed

WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/common/data/models/WooPosProductModelVersion2.kt

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package com.woocommerce.android.ui.woopos.common.data.models
22

33
import android.os.Parcelable
44
import kotlinx.parcelize.Parcelize
5+
import org.wordpress.android.fluxc.network.rest.wpcom.wc.product.CoreProductStatus
56
import java.math.BigDecimal
67

78
/**
@@ -61,26 +62,26 @@ data class WooPosProductModelVersion2(
6162
get() = displayPrice?.toPlainString() ?: ""
6263
}
6364

64-
enum class WooPosProductType {
65-
SIMPLE,
66-
VARIABLE,
67-
GROUPED,
68-
EXTERNAL,
69-
VARIATION,
70-
SUBSCRIPTION,
71-
VARIABLE_SUBSCRIPTION,
72-
CUSTOM,
73-
BUNDLE,
74-
COMPOSITE
65+
enum class WooPosProductType(val value: String) {
66+
SIMPLE("simple"),
67+
VARIABLE("variable"),
68+
GROUPED("grouped"),
69+
EXTERNAL("external"),
70+
VARIATION("variation"),
71+
SUBSCRIPTION("subscription"),
72+
VARIABLE_SUBSCRIPTION("variable-subscription"),
73+
CUSTOM("custom"),
74+
BUNDLE("bundle"),
75+
COMPOSITE("composite"),
7576
}
7677

77-
enum class WooPosProductStatus {
78-
PUBLISH,
79-
DRAFT,
80-
PENDING,
81-
PRIVATE,
82-
TRASH,
83-
UNKNOWN
78+
enum class WooPosProductStatus(val value: String) {
79+
PUBLISH(CoreProductStatus.PUBLISH.value),
80+
DRAFT(CoreProductStatus.DRAFT.value),
81+
PENDING(CoreProductStatus.PENDING.value),
82+
PRIVATE(CoreProductStatus.PRIVATE.value),
83+
TRASH(CoreProductStatus.TRASH.value),
84+
UNKNOWN("unknown")
8485
}
8586

8687
@Parcelize

WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/common/data/searchbyidentifier/WooPosSearchByIdentifier.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
package com.woocommerce.android.ui.woopos.common.data.searchbyidentifier
22

3-
import com.woocommerce.android.model.Product
43
import com.woocommerce.android.ui.woopos.common.data.WooPosProductsTypesFilterConfig
54
import com.woocommerce.android.ui.woopos.common.data.WooPosVariation
65
import com.woocommerce.android.ui.woopos.common.data.WooPosVariationsTypesFilterConfig
6+
import com.woocommerce.android.ui.woopos.common.data.models.WooPosProductModelVersion2
77
import com.woocommerce.android.ui.woopos.common.util.WooPosLogWrapper
88
import org.wordpress.android.fluxc.store.WCProductStore
99
import org.wordpress.android.fluxc.store.WCProductStore.DownloadableOptions
@@ -52,15 +52,15 @@ class WooPosSearchByIdentifier @Inject constructor(
5252
}
5353
}
5454

55-
private fun meetsFilterRequirements(product: Product): Boolean {
56-
val hasValidStatus = product.status?.value == filterConfig.filters[ProductFilterOption.STATUS]
55+
private fun meetsFilterRequirements(product: WooPosProductModelVersion2): Boolean {
56+
val hasValidStatus = product.status.value == filterConfig.filters[ProductFilterOption.STATUS]
5757

5858
val meetsDownloadableRequirement = !product.isDownloadable ||
5959
filterConfig.filters[ProductFilterOption.DOWNLOADABLE] != DownloadableOptions.FALSE.toString()
6060

6161
val hasValidType = filterConfig.includeTypes
6262
.filterNot { it == WCProductStore.IncludeType.Variable }
63-
.any { it.toString().equals(product.type, ignoreCase = true) }
63+
.any { it.value.equals(product.type.value, ignoreCase = true) }
6464

6565
return (hasValidStatus && meetsDownloadableRequirement && hasValidType)
6666
.also { meetsRequirements ->

WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/common/data/searchbyidentifier/WooPosSearchByIdentifierGlobalUniqueSearch.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package com.woocommerce.android.ui.woopos.common.data.searchbyidentifier
22

3-
import com.woocommerce.android.model.toAppModel
43
import com.woocommerce.android.tools.SelectedSite
4+
import com.woocommerce.android.ui.woopos.common.data.models.WCProductToWooPosProductModelMapper
55
import com.woocommerce.android.ui.woopos.common.util.WooPosLogWrapper
66
import org.wordpress.android.fluxc.network.rest.wpcom.wc.WooError
77
import org.wordpress.android.fluxc.network.rest.wpcom.wc.WooErrorType.API_ERROR
@@ -23,6 +23,7 @@ class WooPosSearchByIdentifierGlobalUniqueSearch @Inject constructor(
2323
private val selectedSite: SelectedSite,
2424
private val productStore: WCProductStore,
2525
private val wooPosLogWrapper: WooPosLogWrapper,
26+
private val posProductMapper: WCProductToWooPosProductModelMapper,
2627
) {
2728
suspend operator fun invoke(globalUniqueId: String): WooPosSearchByIdentifierResult {
2829
val result = productStore.searchProducts(
@@ -39,7 +40,7 @@ class WooPosSearchByIdentifierGlobalUniqueSearch @Inject constructor(
3940

4041
result.model != null -> {
4142
val productSearchResult = result.model!!
42-
val products = productSearchResult.products.map { it.toAppModel() }
43+
val products = productSearchResult.products.map { posProductMapper.map(it) }
4344
if (products.isEmpty()) {
4445
WooPosSearchByIdentifierResult.Failure(
4546
WooPosSearchByIdentifierResult.Error.NotFound

WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/common/data/searchbyidentifier/WooPosSearchByIdentifierProductGetOrFetch.kt

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
11
package com.woocommerce.android.ui.woopos.common.data.searchbyidentifier
22

3-
import com.woocommerce.android.model.toAppModel
43
import com.woocommerce.android.tools.SelectedSite
54
import com.woocommerce.android.ui.woopos.common.data.WooPosProductsCache
5+
import com.woocommerce.android.ui.woopos.common.data.models.WCProductToWooPosProductModelMapper
66
import org.wordpress.android.fluxc.store.WCProductStore
77
import javax.inject.Inject
88

99
class WooPosSearchByIdentifierProductGetOrFetch @Inject constructor(
1010
private val selectedSite: SelectedSite,
1111
private val productStore: WCProductStore,
1212
private val productsCache: WooPosProductsCache,
13-
private val errorMapper: WooPosSearchByIdentifierProductErrorMapper
13+
private val errorMapper: WooPosSearchByIdentifierProductErrorMapper,
14+
private val posProductMapper: WCProductToWooPosProductModelMapper,
1415
) {
1516
suspend operator fun invoke(productId: Long): WooPosSearchByIdentifierResult {
1617
productsCache.getProductById(productId)?.let { cachedProduct ->
@@ -28,7 +29,9 @@ class WooPosSearchByIdentifierProductGetOrFetch @Inject constructor(
2829
result.isError -> WooPosSearchByIdentifierResult.Failure(errorMapper(result.error))
2930

3031
else -> {
31-
val product = productStore.getProduct(selectedSite.get(), productId)?.toAppModel()
32+
val product = productStore.getProduct(selectedSite.get(), productId)?.let {
33+
posProductMapper.map(it)
34+
}
3235
if (product != null) {
3336
productsCache.addAll(listOf(product))
3437
WooPosSearchByIdentifierResult.Success(product)

WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/common/data/searchbyidentifier/WooPosSearchByIdentifierResult.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
package com.woocommerce.android.ui.woopos.common.data.searchbyidentifier
22

3-
import com.woocommerce.android.model.Product
43
import com.woocommerce.android.ui.woopos.common.data.WooPosVariation
4+
import com.woocommerce.android.ui.woopos.common.data.models.WooPosProductModelVersion2
55

66
sealed class WooPosSearchByIdentifierResult {
7-
data class Success(val product: Product) : WooPosSearchByIdentifierResult()
8-
data class VariationSuccess(val variation: WooPosVariation, val parentProduct: Product) :
7+
data class Success(val product: WooPosProductModelVersion2) : WooPosSearchByIdentifierResult()
8+
data class VariationSuccess(val variation: WooPosVariation, val parentProduct: WooPosProductModelVersion2) :
99
WooPosSearchByIdentifierResult()
1010

1111
data class Failure(val error: Error) : WooPosSearchByIdentifierResult()

WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/items/products/WooPosProductsViewModel.kt

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@ package com.woocommerce.android.ui.woopos.home.items.products
22

33
import androidx.lifecycle.ViewModel
44
import androidx.lifecycle.viewModelScope
5-
import com.woocommerce.android.model.Product
6-
import com.woocommerce.android.ui.products.ProductType
5+
import com.woocommerce.android.ui.woopos.common.data.models.WooPosProductModelVersion2
76
import com.woocommerce.android.ui.woopos.home.ChildToParentEvent
87
import com.woocommerce.android.ui.woopos.home.ParentToChildrenEvent
98
import com.woocommerce.android.ui.woopos.home.WooPosChildrenToParentEventSender
@@ -229,29 +228,29 @@ class WooPosProductsViewModel @Inject constructor(
229228
is WooPosProductsViewState.Empty -> state.copy(pullToRefreshState = WooPosPullToRefreshState.Refreshing)
230229
}
231230

232-
private suspend fun List<Product>.toContentState(
231+
private suspend fun List<WooPosProductModelVersion2>.toContentState(
233232
paginationState: WooPosPaginationState = WooPosPaginationState.None
234233
) = WooPosProductsViewState.Content(
235234
items = map { it.toItemSelectionViewState() },
236235
paginationState = paginationState,
237236
pullToRefreshState = WooPosPullToRefreshState.Enabled,
238237
)
239238

240-
private suspend fun Product.toItemSelectionViewState(): WooPosItemSelectionViewState {
239+
private suspend fun WooPosProductModelVersion2.toItemSelectionViewState(): WooPosItemSelectionViewState {
241240
return if (this.isVariable()) {
242241
WooPosItemSelectionViewState.Product.Variable(
243242
id = this.remoteId,
244243
name = this.name,
245-
price = priceFormat(this.price),
244+
price = priceFormat(this.pricing.displayPrice),
246245
imageUrl = this.firstImageUrl,
247-
numOfVariations = this.numVariations,
246+
numOfVariations = this.variationIds.size,
248247
variationIds = this.variationIds
249248
)
250249
} else {
251250
WooPosItemSelectionViewState.Product.Simple(
252251
id = this.remoteId,
253252
name = this.name,
254-
price = priceFormat(this.price),
253+
price = priceFormat(this.pricing.displayPrice),
255254
imageUrl = this.firstImageUrl,
256255
)
257256
}
@@ -316,7 +315,7 @@ class WooPosProductsViewModel @Inject constructor(
316315
viewModelScope.launch { fromChildToParentEventSender.sendToParent(event) }
317316
}
318317

319-
private fun Product.isVariable() =
320-
productType == ProductType.VARIABLE ||
321-
productType == ProductType.VARIATION
318+
private fun WooPosProductModelVersion2.isVariable() =
319+
type == WooPosProductModelVersion2.WooPosProductType.VARIABLE ||
320+
type == WooPosProductModelVersion2.WooPosProductType.VARIATION
322321
}

WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/common/data/searchbyidentifier/WooPosSearchByIdentifierProductGetOrFetchTest.kt

Lines changed: 35 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import com.woocommerce.android.model.toAppModel
44
import com.woocommerce.android.tools.SelectedSite
55
import com.woocommerce.android.ui.products.ProductTestUtils
66
import com.woocommerce.android.ui.woopos.common.data.WooPosProductsCache
7+
import com.woocommerce.android.ui.woopos.common.data.models.WCProductToWooPosProductModelMapper
8+
import com.woocommerce.android.ui.woopos.util.generateWooPosProduct
79
import kotlinx.coroutines.test.runTest
810
import org.junit.Assert.assertEquals
911
import org.junit.Assert.assertTrue
@@ -24,11 +26,18 @@ class WooPosSearchByIdentifierProductGetOrFetchTest {
2426
private val productStore: WCProductStore = mock()
2527
private val productsCache: WooPosProductsCache = mock()
2628
private val site: SiteModel = mock()
29+
private val posProductMapper: WCProductToWooPosProductModelMapper = mock()
2730
private val errorMapper: WooPosSearchByIdentifierProductErrorMapper = WooPosSearchByIdentifierProductErrorMapper()
2831

2932
@Before
3033
fun setup() {
31-
sut = WooPosSearchByIdentifierProductGetOrFetch(selectedSite, productStore, productsCache, errorMapper)
34+
sut = WooPosSearchByIdentifierProductGetOrFetch(
35+
selectedSite,
36+
productStore,
37+
productsCache,
38+
errorMapper,
39+
posProductMapper
40+
)
3241
whenever(selectedSite.get()).thenReturn(site)
3342
}
3443

@@ -62,7 +71,7 @@ class WooPosSearchByIdentifierProductGetOrFetchTest {
6271
fun `given product found in cache, when invoke called, then return cached product without fetching`() = runTest {
6372
// GIVEN
6473
val productId = 123L
65-
val cachedProduct = ProductTestUtils.generateProduct(productId)
74+
val cachedProduct = generateWooPosProduct(productId)
6675
whenever(productsCache.getProductById(productId)).thenReturn(cachedProduct)
6776

6877
// WHEN
@@ -75,31 +84,32 @@ class WooPosSearchByIdentifierProductGetOrFetchTest {
7584
}
7685

7786
@Test
78-
fun `given successful fetch but product not found in store, when invoke called, then return failure with unknown error`() = runTest {
79-
// GIVEN
80-
val productId = 123L
81-
val result: WCProductStore.OnProductChanged = mock {
82-
on { isError }.thenReturn(false)
87+
fun `given successful fetch but product not found in store, when invoke called, then return failure with unknown error`() =
88+
runTest {
89+
// GIVEN
90+
val productId = 123L
91+
val result: WCProductStore.OnProductChanged = mock {
92+
on { isError }.thenReturn(false)
93+
}
94+
95+
whenever(
96+
productStore.fetchSingleProduct(any())
97+
).thenReturn(result)
98+
99+
whenever(productStore.getProduct(site, productId)).thenReturn(null)
100+
101+
// WHEN
102+
val actualResult = sut(productId)
103+
104+
// THEN
105+
assertEquals(
106+
WooPosSearchByIdentifierResult.Failure(
107+
WooPosSearchByIdentifierResult.Error.UnknownError("Product not found for ID: $productId")
108+
),
109+
actualResult
110+
)
83111
}
84112

85-
whenever(
86-
productStore.fetchSingleProduct(any())
87-
).thenReturn(result)
88-
89-
whenever(productStore.getProduct(site, productId)).thenReturn(null)
90-
91-
// WHEN
92-
val actualResult = sut(productId)
93-
94-
// THEN
95-
assertEquals(
96-
WooPosSearchByIdentifierResult.Failure(
97-
WooPosSearchByIdentifierResult.Error.UnknownError("Product not found for ID: $productId")
98-
),
99-
actualResult
100-
)
101-
}
102-
103113
@Test
104114
fun `given fetch error, when invoke called, then return failure with mapped error`() = runTest {
105115
// GIVEN

0 commit comments

Comments
 (0)