Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Expand Up @@ -2,6 +2,7 @@ package com.woocommerce.android.ui.woopos.common.data.models

import android.os.Parcelable
import kotlinx.parcelize.Parcelize
import org.wordpress.android.fluxc.network.rest.wpcom.wc.product.CoreProductStatus
import java.math.BigDecimal

/**
Expand Down Expand Up @@ -61,26 +62,26 @@ data class WooPosProductModelVersion2(
get() = displayPrice?.toPlainString() ?: ""
}

enum class WooPosProductType {
SIMPLE,
VARIABLE,
GROUPED,
EXTERNAL,
VARIATION,
SUBSCRIPTION,
VARIABLE_SUBSCRIPTION,
CUSTOM,
BUNDLE,
COMPOSITE
enum class WooPosProductType(val value: String) {
SIMPLE("simple"),
VARIABLE("variable"),
GROUPED("grouped"),
EXTERNAL("external"),
VARIATION("variation"),
SUBSCRIPTION("subscription"),
VARIABLE_SUBSCRIPTION("variable-subscription"),
CUSTOM("custom"),
BUNDLE("bundle"),
COMPOSITE("composite"),
}

enum class WooPosProductStatus {
PUBLISH,
DRAFT,
PENDING,
PRIVATE,
TRASH,
UNKNOWN
enum class WooPosProductStatus(val value: String) {
PUBLISH(CoreProductStatus.PUBLISH.value),
DRAFT(CoreProductStatus.DRAFT.value),
PENDING(CoreProductStatus.PENDING.value),
PRIVATE(CoreProductStatus.PRIVATE.value),
TRASH(CoreProductStatus.TRASH.value),
UNKNOWN("unknown")
}

@Parcelize
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package com.woocommerce.android.ui.woopos.common.data.searchbyidentifier

import com.woocommerce.android.model.Product
import com.woocommerce.android.ui.woopos.common.data.WooPosProductsTypesFilterConfig
import com.woocommerce.android.ui.woopos.common.data.WooPosVariation
import com.woocommerce.android.ui.woopos.common.data.WooPosVariationsTypesFilterConfig
import com.woocommerce.android.ui.woopos.common.data.models.WooPosProductModelVersion2
import com.woocommerce.android.ui.woopos.common.util.WooPosLogWrapper
import org.wordpress.android.fluxc.store.WCProductStore
import org.wordpress.android.fluxc.store.WCProductStore.DownloadableOptions
Expand Down Expand Up @@ -52,15 +52,15 @@ class WooPosSearchByIdentifier @Inject constructor(
}
}

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

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

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

return (hasValidStatus && meetsDownloadableRequirement && hasValidType)
.also { meetsRequirements ->
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.woocommerce.android.ui.woopos.common.data.searchbyidentifier

import com.woocommerce.android.model.toAppModel
import com.woocommerce.android.tools.SelectedSite
import com.woocommerce.android.ui.woopos.common.data.models.WCProductToWooPosProductModelMapper
import com.woocommerce.android.ui.woopos.common.util.WooPosLogWrapper
import org.wordpress.android.fluxc.network.rest.wpcom.wc.WooError
import org.wordpress.android.fluxc.network.rest.wpcom.wc.WooErrorType.API_ERROR
Expand All @@ -23,6 +23,7 @@ class WooPosSearchByIdentifierGlobalUniqueSearch @Inject constructor(
private val selectedSite: SelectedSite,
private val productStore: WCProductStore,
private val wooPosLogWrapper: WooPosLogWrapper,
private val posProductMapper: WCProductToWooPosProductModelMapper,
) {
suspend operator fun invoke(globalUniqueId: String): WooPosSearchByIdentifierResult {
val result = productStore.searchProducts(
Expand All @@ -39,7 +40,7 @@ class WooPosSearchByIdentifierGlobalUniqueSearch @Inject constructor(

result.model != null -> {
val productSearchResult = result.model!!
val products = productSearchResult.products.map { it.toAppModel() }
val products = productSearchResult.products.map { posProductMapper.map(it) }
if (products.isEmpty()) {
WooPosSearchByIdentifierResult.Failure(
WooPosSearchByIdentifierResult.Error.NotFound
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
package com.woocommerce.android.ui.woopos.common.data.searchbyidentifier

import com.woocommerce.android.model.toAppModel
import com.woocommerce.android.tools.SelectedSite
import com.woocommerce.android.ui.woopos.common.data.WooPosProductsCache
import com.woocommerce.android.ui.woopos.common.data.models.WCProductToWooPosProductModelMapper
import org.wordpress.android.fluxc.store.WCProductStore
import javax.inject.Inject

class WooPosSearchByIdentifierProductGetOrFetch @Inject constructor(
private val selectedSite: SelectedSite,
private val productStore: WCProductStore,
private val productsCache: WooPosProductsCache,
private val errorMapper: WooPosSearchByIdentifierProductErrorMapper
private val errorMapper: WooPosSearchByIdentifierProductErrorMapper,
private val posProductMapper: WCProductToWooPosProductModelMapper,
) {
suspend operator fun invoke(productId: Long): WooPosSearchByIdentifierResult {
productsCache.getProductById(productId)?.let { cachedProduct ->
Expand All @@ -28,7 +29,9 @@ class WooPosSearchByIdentifierProductGetOrFetch @Inject constructor(
result.isError -> WooPosSearchByIdentifierResult.Failure(errorMapper(result.error))

else -> {
val product = productStore.getProduct(selectedSite.get(), productId)?.toAppModel()
val product = productStore.getProduct(selectedSite.get(), productId)?.let {
posProductMapper.map(it)
}
if (product != null) {
productsCache.addAll(listOf(product))
WooPosSearchByIdentifierResult.Success(product)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package com.woocommerce.android.ui.woopos.common.data.searchbyidentifier

import com.woocommerce.android.model.Product
import com.woocommerce.android.ui.woopos.common.data.WooPosVariation
import com.woocommerce.android.ui.woopos.common.data.models.WooPosProductModelVersion2

sealed class WooPosSearchByIdentifierResult {
data class Success(val product: Product) : WooPosSearchByIdentifierResult()
data class VariationSuccess(val variation: WooPosVariation, val parentProduct: Product) :
data class Success(val product: WooPosProductModelVersion2) : WooPosSearchByIdentifierResult()
data class VariationSuccess(val variation: WooPosVariation, val parentProduct: WooPosProductModelVersion2) :
WooPosSearchByIdentifierResult()

data class Failure(val error: Error) : WooPosSearchByIdentifierResult()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ package com.woocommerce.android.ui.woopos.home.items.products

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.woocommerce.android.model.Product
import com.woocommerce.android.ui.products.ProductType
import com.woocommerce.android.ui.woopos.common.data.models.WooPosProductModelVersion2
import com.woocommerce.android.ui.woopos.home.ChildToParentEvent
import com.woocommerce.android.ui.woopos.home.ParentToChildrenEvent
import com.woocommerce.android.ui.woopos.home.WooPosChildrenToParentEventSender
Expand Down Expand Up @@ -229,29 +228,29 @@ class WooPosProductsViewModel @Inject constructor(
is WooPosProductsViewState.Empty -> state.copy(pullToRefreshState = WooPosPullToRefreshState.Refreshing)
}

private suspend fun List<Product>.toContentState(
private suspend fun List<WooPosProductModelVersion2>.toContentState(
paginationState: WooPosPaginationState = WooPosPaginationState.None
) = WooPosProductsViewState.Content(
items = map { it.toItemSelectionViewState() },
paginationState = paginationState,
pullToRefreshState = WooPosPullToRefreshState.Enabled,
)

private suspend fun Product.toItemSelectionViewState(): WooPosItemSelectionViewState {
private suspend fun WooPosProductModelVersion2.toItemSelectionViewState(): WooPosItemSelectionViewState {
return if (this.isVariable()) {
WooPosItemSelectionViewState.Product.Variable(
id = this.remoteId,
name = this.name,
price = priceFormat(this.price),
price = priceFormat(this.pricing.displayPrice),
imageUrl = this.firstImageUrl,
numOfVariations = this.numVariations,
numOfVariations = this.variationIds.size,
variationIds = this.variationIds
)
} else {
WooPosItemSelectionViewState.Product.Simple(
id = this.remoteId,
name = this.name,
price = priceFormat(this.price),
price = priceFormat(this.pricing.displayPrice),
imageUrl = this.firstImageUrl,
)
}
Expand Down Expand Up @@ -316,7 +315,7 @@ class WooPosProductsViewModel @Inject constructor(
viewModelScope.launch { fromChildToParentEventSender.sendToParent(event) }
}

private fun Product.isVariable() =
productType == ProductType.VARIABLE ||
productType == ProductType.VARIATION
private fun WooPosProductModelVersion2.isVariable() =
type == WooPosProductModelVersion2.WooPosProductType.VARIABLE ||
type == WooPosProductModelVersion2.WooPosProductType.VARIATION
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import com.woocommerce.android.model.toAppModel
import com.woocommerce.android.tools.SelectedSite
import com.woocommerce.android.ui.products.ProductTestUtils
import com.woocommerce.android.ui.woopos.common.data.WooPosProductsCache
import com.woocommerce.android.ui.woopos.common.data.models.WCProductToWooPosProductModelMapper
import com.woocommerce.android.ui.woopos.util.generateWooPosProduct
import kotlinx.coroutines.test.runTest
import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
Expand All @@ -24,11 +26,18 @@ class WooPosSearchByIdentifierProductGetOrFetchTest {
private val productStore: WCProductStore = mock()
private val productsCache: WooPosProductsCache = mock()
private val site: SiteModel = mock()
private val posProductMapper: WCProductToWooPosProductModelMapper = mock()
private val errorMapper: WooPosSearchByIdentifierProductErrorMapper = WooPosSearchByIdentifierProductErrorMapper()

@Before
fun setup() {
sut = WooPosSearchByIdentifierProductGetOrFetch(selectedSite, productStore, productsCache, errorMapper)
sut = WooPosSearchByIdentifierProductGetOrFetch(
selectedSite,
productStore,
productsCache,
errorMapper,
posProductMapper
)
whenever(selectedSite.get()).thenReturn(site)
}

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

// WHEN
Expand All @@ -75,31 +84,32 @@ class WooPosSearchByIdentifierProductGetOrFetchTest {
}

@Test
fun `given successful fetch but product not found in store, when invoke called, then return failure with unknown error`() = runTest {
// GIVEN
val productId = 123L
val result: WCProductStore.OnProductChanged = mock {
on { isError }.thenReturn(false)
fun `given successful fetch but product not found in store, when invoke called, then return failure with unknown error`() =
runTest {
// GIVEN
val productId = 123L
val result: WCProductStore.OnProductChanged = mock {
on { isError }.thenReturn(false)
}

whenever(
productStore.fetchSingleProduct(any())
).thenReturn(result)

whenever(productStore.getProduct(site, productId)).thenReturn(null)

// WHEN
val actualResult = sut(productId)

// THEN
assertEquals(
WooPosSearchByIdentifierResult.Failure(
WooPosSearchByIdentifierResult.Error.UnknownError("Product not found for ID: $productId")
),
actualResult
)
}

whenever(
productStore.fetchSingleProduct(any())
).thenReturn(result)

whenever(productStore.getProduct(site, productId)).thenReturn(null)

// WHEN
val actualResult = sut(productId)

// THEN
assertEquals(
WooPosSearchByIdentifierResult.Failure(
WooPosSearchByIdentifierResult.Error.UnknownError("Product not found for ID: $productId")
),
actualResult
)
}

@Test
fun `given fetch error, when invoke called, then return failure with mapped error`() = runTest {
// GIVEN
Expand Down
Loading