Skip to content

Commit

Permalink
Merge pull request #12766 from woocommerce/issue/12752-subscriptions-…
Browse files Browse the repository at this point in the history
…meta-1

[Products] Extract subscriptions outside of the Product DB table - Part 1
  • Loading branch information
hichamboushaba authored Oct 16, 2024
2 parents 06fce27 + 57e9381 commit d1751be
Show file tree
Hide file tree
Showing 16 changed files with 820 additions and 693 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,6 @@ data class Product(
override val width: Float,
override val height: Float,
override val weight: Float,
val subscription: SubscriptionDetails?,
val isSampleProduct: Boolean,
val specialStockStatus: ProductStockStatus? = null,
val isConfigurable: Boolean = false,
Expand Down Expand Up @@ -153,7 +152,6 @@ data class Product(
downloadExpiry == product.downloadExpiry &&
isDownloadable == product.isDownloadable &&
attributes == product.attributes &&
subscription == product.subscription &&
specialStockStatus == product.specialStockStatus &&
minAllowedQuantity == product.minAllowedQuantity &&
maxAllowedQuantity == product.maxAllowedQuantity &&
Expand All @@ -169,8 +167,7 @@ data class Product(
get() {
return weight > 0 ||
length > 0 || width > 0 || height > 0 ||
shippingClass.isNotEmpty() ||
subscription?.oneTimeShipping == true
shippingClass.isNotEmpty()
}
val productType get() = ProductType.fromString(type)
val variationEnabledAttributes
Expand Down Expand Up @@ -334,7 +331,6 @@ data class Product(
downloads = updatedProduct.downloads,
downloadLimit = updatedProduct.downloadLimit,
downloadExpiry = updatedProduct.downloadExpiry,
subscription = updatedProduct.subscription,
specialStockStatus = specialStockStatus,
minAllowedQuantity = updatedProduct.minAllowedQuantity,
maxAllowedQuantity = updatedProduct.maxAllowedQuantity,
Expand Down Expand Up @@ -482,20 +478,10 @@ fun Product.toDataModel(storedProductModel: WCProductModel? = null): WCProductMo
it.groupOfQuantity = groupOfQuantity ?: -1
it.combineVariationQuantities = combineVariationQuantities ?: false
it.password = password
// Subscription details are currently the only editable metadata fields from the app.
it.metadata = subscription?.toMetadataJson().toString()
}
}

fun WCProductModel.toAppModel(): Product {
val productType = ProductType.fromString(type)
val subscription = if (
productType == ProductType.SUBSCRIPTION || productType == ProductType.VARIABLE_SUBSCRIPTION
) {
SubscriptionDetailsMapper.toAppModel(this.metadata)
} else {
null
}
return Product(
remoteId = this.remoteProductId,
parentId = this.parentId,
Expand Down Expand Up @@ -580,7 +566,6 @@ fun WCProductModel.toAppModel(): Product {
upsellProductIds = this.getUpsellProductIdList(),
variationIds = this.getVariationIdList(),
isPurchasable = this.purchasable,
subscription = subscription,
isSampleProduct = isSampleProduct,
specialStockStatus = if (this.specialStockStatus.isNotNullOrEmpty()) {
ProductStockStatus.fromString(this.specialStockStatus)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.woocommerce.android.model

import android.os.Parcelable
import kotlinx.parcelize.Parcelize

/**
* Container class for product and any additional details that are stored as product metadata.
*
* For now, the additional details include subscription details only.
*
* @param product The product.
* @param subscription The subscription details.
*/
@Parcelize
data class ProductAggregate(
val product: Product,
val subscription: SubscriptionDetails? = null
) : Parcelable {
val remoteId: Long
get() = product.remoteId

val hasShipping: Boolean
get() = product.hasShipping || subscription?.oneTimeShipping == true

fun isSame(other: ProductAggregate): Boolean {
return product.isSameProduct(other.product) && subscription == other.subscription
}

fun merge(other: ProductAggregate): ProductAggregate {
return copy(
product = product.mergeProduct(other.product),
subscription = other.subscription
)
}
}
Original file line number Diff line number Diff line change
@@ -1,85 +1,81 @@
package com.woocommerce.android.model

import com.google.gson.Gson
import com.google.gson.JsonArray
import com.google.gson.JsonElement
import com.google.gson.JsonObject
import com.google.gson.JsonParser
import org.wordpress.android.fluxc.model.WCProductModel.SubscriptionMetadataKeys
import org.wordpress.android.fluxc.model.metadata.WCMetaData
import org.wordpress.android.fluxc.model.metadata.get

object SubscriptionDetailsMapper {
private val gson by lazy { Gson() }
fun toAppModel(metadata: String): SubscriptionDetails? {
val jsonArray = gson.fromJson(metadata, JsonArray::class.java) ?: return null
fun toAppModel(metadata: List<WCMetaData>): SubscriptionDetails? {
if (metadata.none { it.key in SubscriptionMetadataKeys.ALL_KEYS }) {
return null
}

val subscriptionInformation = jsonArray
.mapNotNull { it as? JsonObject }
.filter { jsonObject -> jsonObject[WCMetaData.KEY].asString in SubscriptionMetadataKeys.ALL_KEYS }
.associate { jsonObject ->
jsonObject[WCMetaData.KEY].asString to jsonObject[WCMetaData.VALUE]
}
val price = metadata[SubscriptionMetadataKeys.SUBSCRIPTION_PRICE]?.valueAsString?.toBigDecimalOrNull()

return if (subscriptionInformation.isNotEmpty()) {
val price = subscriptionInformation[SubscriptionMetadataKeys.SUBSCRIPTION_PRICE]?.asString
?.toBigDecimalOrNull()

val periodString = subscriptionInformation[SubscriptionMetadataKeys.SUBSCRIPTION_PERIOD]?.asString ?: ""
val period = SubscriptionPeriod.fromValue(periodString)

val periodIntervalString = subscriptionInformation[SubscriptionMetadataKeys.SUBSCRIPTION_PERIOD_INTERVAL]
?.asString ?: ""
val periodInterval = periodIntervalString.toIntOrNull() ?: 0

val lengthInt = subscriptionInformation[SubscriptionMetadataKeys.SUBSCRIPTION_LENGTH]?.asString
?.toIntOrNull()
val length = if (lengthInt != null && lengthInt > 0) lengthInt else null

val signUpFee = subscriptionInformation[SubscriptionMetadataKeys.SUBSCRIPTION_SIGN_UP_FEE]?.asString
?.toBigDecimalOrNull()

val trialPeriodString = subscriptionInformation[SubscriptionMetadataKeys.SUBSCRIPTION_TRIAL_PERIOD]
?.asString
val trialPeriod = trialPeriodString?.let { SubscriptionPeriod.fromValue(trialPeriodString) }

val trialLengthInt = subscriptionInformation[SubscriptionMetadataKeys.SUBSCRIPTION_TRIAL_LENGTH]
?.asString?.toIntOrNull()
val trialLength = if (trialLengthInt != null && trialLengthInt > 0) trialLengthInt else null

val oneTimeShipping = subscriptionInformation[SubscriptionMetadataKeys.SUBSCRIPTION_ONE_TIME_SHIPPING]
?.asString == "yes"

val paymentsSyncDate = subscriptionInformation[SubscriptionMetadataKeys.SUBSCRIPTION_PAYMENT_SYNC_DATE]
?.extractPaymentsSyncDate()

SubscriptionDetails(
price = price,
period = period,
periodInterval = periodInterval,
length = length,
signUpFee = signUpFee,
trialPeriod = trialPeriod,
trialLength = trialLength,
oneTimeShipping = oneTimeShipping,
paymentsSyncDate = paymentsSyncDate
)
} else {
null
}
val periodString = metadata[SubscriptionMetadataKeys.SUBSCRIPTION_PERIOD]?.valueAsString ?: ""
val period = SubscriptionPeriod.fromValue(periodString)

val periodIntervalString = metadata[SubscriptionMetadataKeys.SUBSCRIPTION_PERIOD_INTERVAL]
?.valueAsString ?: ""
val periodInterval = periodIntervalString.toIntOrNull() ?: 0

val lengthInt = metadata[SubscriptionMetadataKeys.SUBSCRIPTION_LENGTH]?.valueAsString
?.toIntOrNull()
val length = if (lengthInt != null && lengthInt > 0) lengthInt else null

val signUpFee = metadata[SubscriptionMetadataKeys.SUBSCRIPTION_SIGN_UP_FEE]?.valueAsString
?.toBigDecimalOrNull()

val trialPeriodString = metadata[SubscriptionMetadataKeys.SUBSCRIPTION_TRIAL_PERIOD]
?.valueAsString
val trialPeriod = trialPeriodString?.let { SubscriptionPeriod.fromValue(trialPeriodString) }

val trialLengthInt = metadata[SubscriptionMetadataKeys.SUBSCRIPTION_TRIAL_LENGTH]
?.valueAsString?.toIntOrNull()
val trialLength = if (trialLengthInt != null && trialLengthInt > 0) trialLengthInt else null

val oneTimeShipping = metadata[SubscriptionMetadataKeys.SUBSCRIPTION_ONE_TIME_SHIPPING]
?.valueAsString == "yes"

val paymentsSyncDate = metadata[SubscriptionMetadataKeys.SUBSCRIPTION_PAYMENT_SYNC_DATE]
?.extractPaymentsSyncDate()

return SubscriptionDetails(
price = price,
period = period,
periodInterval = periodInterval,
length = length,
signUpFee = signUpFee,
trialPeriod = trialPeriod,
trialLength = trialLength,
oneTimeShipping = oneTimeShipping,
paymentsSyncDate = paymentsSyncDate
)
}

fun toAppModel(metadata: String): SubscriptionDetails? {
val metadataList = gson.fromJson(metadata, Array<WCMetaData>::class.java)?.toList() ?: return null

return toAppModel(metadataList)
}

private fun JsonElement.extractPaymentsSyncDate(): SubscriptionPaymentSyncDate? {
return when {
isJsonObject -> asJsonObject.let {
val day = it["day"].asInt
val month = it["month"].asInt
private fun WCMetaData.extractPaymentsSyncDate(): SubscriptionPaymentSyncDate? {
return when (isJson) {
true -> value.stringValue.let {
val jsonObject = JsonParser.parseString(it).asJsonObject
val day = jsonObject["day"].asInt
val month = jsonObject["month"].asInt
if (day == 0) {
SubscriptionPaymentSyncDate.None
} else {
SubscriptionPaymentSyncDate.MonthDay(day, month)
SubscriptionPaymentSyncDate.MonthDay(month = month, day = day)
}
}

else -> asString?.toIntOrNull()?.let { day ->
false -> valueAsString.toIntOrNull()?.let { day ->
if (day == 0) {
SubscriptionPaymentSyncDate.None
} else {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
package com.woocommerce.android.ui.products

import com.woocommerce.android.model.Product
import com.woocommerce.android.model.ProductAggregate
import com.woocommerce.android.model.SubscriptionDetails
import com.woocommerce.android.model.SubscriptionPeriod
import com.woocommerce.android.ui.products.ProductBackorderStatus.NotAvailable
import com.woocommerce.android.ui.products.ProductStatus.DRAFT
import com.woocommerce.android.ui.products.ProductStatus.PUBLISH
import com.woocommerce.android.ui.products.ProductStockStatus.InStock
import com.woocommerce.android.ui.products.ProductType.SUBSCRIPTION
import com.woocommerce.android.ui.products.ProductType.VARIABLE_SUBSCRIPTION
import com.woocommerce.android.ui.products.settings.ProductCatalogVisibility.VISIBLE
import java.math.BigDecimal
import java.util.Date
Expand Down Expand Up @@ -93,12 +92,6 @@ object ProductHelper {
variationIds = listOf(),
downloads = listOf(),
isPurchasable = false,
subscription =
if (productType == SUBSCRIPTION || productType == VARIABLE_SUBSCRIPTION) {
getDefaultSubscriptionDetails()
} else {
null
},
isSampleProduct = false,
parentId = 0,
minAllowedQuantity = null,
Expand All @@ -111,6 +104,19 @@ object ProductHelper {
)
}

fun getDefaultProductAggregate(productType: ProductType, isVirtual: Boolean): ProductAggregate {
return ProductAggregate(
product = getDefaultNewProduct(productType, isVirtual),
subscription = if (productType == ProductType.SUBSCRIPTION ||
productType == ProductType.VARIABLE_SUBSCRIPTION
) {
getDefaultSubscriptionDetails()
} else {
null
}
)
}

fun getDefaultSubscriptionDetails(): SubscriptionDetails =
SubscriptionDetails(
price = null,
Expand Down
Loading

0 comments on commit d1751be

Please sign in to comment.