-
Notifications
You must be signed in to change notification settings - Fork 136
[POS][Local Catalog] WooPosVariation #14564
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
Changes from 18 commits
5ac8671
24f6350
f10a079
62474bf
f5af9f9
bf1f27a
4d83ab3
74ad241
5095fb6
abc8221
64a0510
b4997b7
2c8b8fb
e2dc6d0
43257a1
ed12b16
d12819b
a4c3903
cf5cecd
abba849
2dc7ce9
4ae74f9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,168 @@ | ||
| package com.woocommerce.android.ui.woopos.common.data | ||
|
|
||
| import com.google.gson.Gson | ||
| import com.google.gson.JsonSyntaxException | ||
| import com.google.gson.reflect.TypeToken | ||
| import com.woocommerce.android.R | ||
| import com.woocommerce.android.model.Product | ||
| import com.woocommerce.android.model.ProductVariation | ||
| import com.woocommerce.android.viewmodel.ResourceProvider | ||
| import org.wordpress.android.fluxc.model.WCProductVariationModel | ||
| import org.wordpress.android.fluxc.persistence.entity.pos.WCPosVariationModel | ||
| import java.math.BigDecimal | ||
|
|
||
| /** | ||
| * POS-specific product variation model containing only the fields needed for POS functionality. | ||
| * This model provides better performance and cleaner separation compared to the general ProductVariation model. | ||
| */ | ||
| data class WooPosVariation( | ||
| val remoteVariationId: Long, | ||
| val remoteProductId: Long, | ||
| val globalUniqueId: String, | ||
| val price: BigDecimal?, | ||
| val image: WooPosVariationImage?, | ||
| val attributes: List<WooPosVariationAttribute>, | ||
| val isVisible: Boolean, | ||
| val isDownloadable: Boolean | ||
| ) { | ||
|
|
||
| data class WooPosVariationImage( | ||
| val source: String | ||
| ) | ||
|
|
||
| data class WooPosVariationAttribute( | ||
| val id: Long?, | ||
| val name: String?, | ||
| val option: String? | ||
| ) | ||
| } | ||
|
|
||
| fun ProductVariation.toWooPosVariation(): WooPosVariation { | ||
| return WooPosVariation( | ||
| remoteVariationId = remoteVariationId, | ||
| remoteProductId = remoteProductId, | ||
| globalUniqueId = globalUniqueId, | ||
| price = price, | ||
| image = image?.let { WooPosVariation.WooPosVariationImage(it.source) }, | ||
| attributes = attributes.map { | ||
| WooPosVariation.WooPosVariationAttribute( | ||
| id = it.id, | ||
| name = it.name, | ||
| option = it.option | ||
| ) | ||
| }, | ||
| isVisible = isVisible, | ||
| isDownloadable = isDownloadable | ||
| ) | ||
| } | ||
|
|
||
| @Suppress("SwallowedException") | ||
| fun WCProductVariationModel.toWooPosVariation(): WooPosVariation { | ||
| val attributesList = attributeList?.map { attribute -> | ||
| WooPosVariation.WooPosVariationAttribute( | ||
| id = attribute.id, | ||
| name = attribute.name, | ||
| option = attribute.option | ||
| ) | ||
| } ?: emptyList() | ||
|
|
||
| val imageModel = try { | ||
| if (image.isNotEmpty()) getImageModel() else null | ||
| } catch (e: JsonSyntaxException) { | ||
| null | ||
| } | ||
|
|
||
| return WooPosVariation( | ||
| remoteVariationId = remoteVariationId.value, | ||
| remoteProductId = remoteProductId.value, | ||
| globalUniqueId = globalUniqueId, | ||
| price = price.toBigDecimalOrNull(), | ||
| image = imageModel?.src?.let { WooPosVariation.WooPosVariationImage(it) }, | ||
| attributes = attributesList, | ||
| isVisible = status == "publish", | ||
| isDownloadable = downloadable | ||
| ) | ||
| } | ||
|
|
||
| @Suppress("SwallowedException") | ||
| fun WCPosVariationModel.toWooPosVariation(): WooPosVariation { | ||
| val attributesList = try { | ||
| if (attributesJson.isNotEmpty()) { | ||
| parseAttributesJson(attributesJson) | ||
| } else { | ||
| emptyList() | ||
| } | ||
| } catch (e: JsonSyntaxException) { | ||
|
||
| emptyList() | ||
| } | ||
|
|
||
| return WooPosVariation( | ||
| remoteVariationId = remoteVariationId.value, | ||
| remoteProductId = remoteProductId.value, | ||
| globalUniqueId = globalUniqueId, | ||
| price = price.toBigDecimalOrNull(), | ||
| image = if (imageUrl.isNotEmpty()) WooPosVariation.WooPosVariationImage(imageUrl) else null, | ||
| attributes = attributesList, | ||
| isVisible = status == "publish", | ||
| isDownloadable = downloadable | ||
| ) | ||
| } | ||
|
|
||
| private val gson by lazy { Gson() } | ||
|
||
|
|
||
| @Suppress("SwallowedException") | ||
| private fun parseAttributesJson(attributesJson: String): List<WooPosVariation.WooPosVariationAttribute> { | ||
| return try { | ||
| val type = object : TypeToken<List<AttributeJsonItem>>() {}.type | ||
| val items: List<AttributeJsonItem> = gson.fromJson(attributesJson, type) | ||
| items.map { item -> | ||
| WooPosVariation.WooPosVariationAttribute( | ||
| id = item.id, | ||
| name = item.name, | ||
| option = item.option | ||
| ) | ||
| } | ||
| } catch (e: JsonSyntaxException) { | ||
| emptyList() | ||
| } | ||
| } | ||
|
|
||
| private data class AttributeJsonItem( | ||
| val id: Long?, | ||
| val name: String?, | ||
| val option: String? | ||
| ) | ||
|
|
||
| fun WooPosVariation.getNameForPOS( | ||
| parentProduct: Product? = null, | ||
| resourceProvider: ResourceProvider, | ||
| ): String { | ||
| return parentProduct?.variationEnabledAttributes?.joinToString(", ") { attribute -> | ||
| val option = attributes.firstOrNull { it.name == attribute.name } | ||
| if (option?.option != null) { | ||
| "${attribute.name}: ${option.option}" | ||
| } else { | ||
| resourceProvider.getString( | ||
| R.string.woopos_variations_any_variation, | ||
| attribute.name | ||
| ) | ||
| } | ||
| } ?: attributes.joinToString(", ") { attribute -> | ||
| when { | ||
| attribute.option != null && attribute.name != null -> "${attribute.name}: ${attribute.option}" | ||
| attribute.option != null -> attribute.option | ||
| attribute.name != null -> resourceProvider.getString( | ||
| R.string.woopos_variations_any_variation, | ||
| attribute.name | ||
| ) | ||
| else -> "" | ||
samiuelson marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
| } | ||
| } | ||
|
|
||
| fun WooPosVariation.getName(parentProduct: Product? = null): String { | ||
| return parentProduct?.variationEnabledAttributes?.joinToString(" - ") { attribute -> | ||
| val option = attributes.firstOrNull { it.name == attribute.name } | ||
| option?.option ?: "Any ${attribute.name}" | ||
| } ?: attributes.mapNotNull { it.option }.joinToString(" - ") | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,8 +1,9 @@ | ||
| package com.woocommerce.android.ui.woopos.common.data.searchbyidentifier | ||
|
|
||
| import com.woocommerce.android.model.ProductVariation | ||
| import com.woocommerce.android.model.toAppModel | ||
| import com.woocommerce.android.tools.SelectedSite | ||
| import com.woocommerce.android.ui.woopos.common.data.WooPosVariation | ||
| import com.woocommerce.android.ui.woopos.common.data.toWooPosVariation | ||
| import com.woocommerce.android.ui.woopos.home.items.variations.WooPosVariationsLRUCache | ||
| import org.wordpress.android.fluxc.store.WCProductStore | ||
| import javax.inject.Inject | ||
|
|
@@ -14,7 +15,7 @@ class WooPosSearchByIdentifierVariationFetch @Inject constructor( | |
| private val errorMapper: WooPosSearchByIdentifierProductErrorMapper | ||
| ) { | ||
| sealed class VariationFetchResult { | ||
| data class Success(val variation: ProductVariation) : VariationFetchResult() | ||
| data class Success(val variation: WooPosVariation) : VariationFetchResult() | ||
| data class Failure(val error: WooPosSearchByIdentifierResult.Error) : VariationFetchResult() | ||
| } | ||
|
|
||
|
|
@@ -34,7 +35,7 @@ class WooPosSearchByIdentifierVariationFetch @Inject constructor( | |
| selectedSite.get(), | ||
| parentId, | ||
| variationId | ||
| )?.toAppModel() | ||
| )?.toAppModel()?.toWooPosVariation() | ||
|
||
|
|
||
| return if (variation != null) { | ||
| variationsCache.add(parentId, variation) | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 This is technically enough for now, but we'll likely need to have access to both sale and regular prices quite soon, so I'd consider including them similarly to how we do it in the product model. Having said that, feel free to leave it as is.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd leave these props for now and update the model when we need them.